Skip to content

peerd-preview-v0.2.6

Choose a tag to compare

@github-actions github-actions released this 07 Jul 03:31
092f1ca

Fixed

  • A web actor could be wrongly refused a read of its own tab. The
    dispatcher gate that pins a web actor to the one tab it owns compared an
    explicit tabId argument against actorInstanceId. That field is the
    fixed literal 'web', the actor's stable message_actor address, not a
    tab id (only an API actor's instanceId is still a real identifier, its
    origin). So the comparison could never match, and any DOM tool call that
    named its own tab explicitly (read_page, click, and so on) was refused
    with a confusing "pinned to tab web" error, even though it was the actor's
    own tab. The gate now compares against the actor's actually-owned tab
    instead. This was a false-positive refusal, not a security gap: the
    independent execute-time resolver already only ever targeted the owned
    tab or failed closed.
  • The search shortcut in the web actor's own prompt pointed at a URL that
    always redirects.
    The prompt told the actor to search with
    fetch_url https://duckduckgo.com/html/?q=..., but that path 302s to
    html.duckduckgo.com, and fetch_url does not follow redirects (by
    design: see docs/security/THREAT-MODEL.md INV-7). Every search burned a
    turn on a guaranteed redirect error before the actor retried correctly.
    The prompt now names the right host (html.duckduckgo.com/html/?q=...)
    and says why the bare host fails, so search works on the first try.
  • A oneShot delegation whose CODE crashed now gets its recovery turn.
    The oneShot contract always said "an errored round falls through to the
    normal loop", but the clean-round test only saw tool-LEVEL errors, and a
    notebook eval whose code threw (a CompileError, a bad import) returns
    ok:true with the [ERROR] text as its content. So the crash
    short-circuited straight back to the orchestrator as the raw reply and
    the actor never debugged its own sandbox (field transcript: a notebook
    actor bounced the same CompileError back twice). js_notebook now marks
    such results evalError and the one-shot latch disarms on it, exactly
    like a tool failure: the actor recovers and iterates, as promised. A
    headless CI test also now pins peerd:wasi + demoModule() as
    importable and runnable from a script job (a field session reported
    the import unreachable; current source proves green, so a stale install
    is the likely culprit, reload the extension).

Added

  • peerd:wasi ships a self-test module. demoModule() (exported next
    to runWasi) returns a tiny (187-byte) known-good wasm32-wasi hello
    module, embedded in the extension, so the agent can smoke-test
    runWasi(demoModule()) inside the sealed worker with no network and no
    toolchain, instead of hunting the web for a working binary (a live
    session burned itself on exactly that hunt). The blob is hand-assembled,
    regenerable from tests/notebook-tab/wasi-test-module.ts, and the bun
    suite pins the embedded bytes against that builder so blob and source
    cannot drift. Taught in the script / js_create lore and the code-mode
    prompt.

Fixed

  • resp.bytes() works in sandboxed code now. The sealed-realm fetch
    bridge (Notebook / script / a2a runs) listed bytes on its response but
    as a raw data property, so resp.bytes() (the platform Response.bytes()
    shape every model reaches for) threw "not a function". It's a method
    returning Promise<Uint8Array> now, matching the platform. Found in the
    field: an agent burned several turns rediscovering arrayBuffer() while
    smoke-testing runWasi.
  • The web actor no longer talks itself out of rendering. Field
    transcript: asked for live sports schedules, the web actor tried fetches,
    declared itself "fetch-only", claimed it lacked an open-tab tool, and
    bounced the task back to the user, while the render path was fully wired
    (navigate lazily opens + adopts its tab in the 0-tab state). The
    machinery was right; the words were wrong. Three model-facing fixes:
    navigate's description now states it OPENS the tab when the actor owns
    none (it read "navigate the target tab", implying one must exist); the web
    actor's lore states it can ALWAYS render and must never report itself
    fetch-only; the shared actor rules forbid addressing the user ("would you
    like me to…" has no one to answer it, do the work or report what
    blocked). And the orchestrator's message_actor teaching now says: never
    narrate unobserved actor progress, and re-send with the capability
    restated when an actor wrongly claims its kind can't do something.

Changed

  • "Subagent" is now "actor" everywhere. The heap-split already made a
    subagent an ephemeral actor on the same substrate as the bound (sandbox /
    web / dweb) actors; the vocabulary now matches. Model-facing: the
    spawn_subagent tool is actor_create, subagent_cancel is
    actor_cancel, subagent_tasks is actor_tasks (pairs with
    sandbox_create: a sandbox always has a dedicated bound actor;
    actor_create alone makes an ephemeral one). Internally the
    peerd-runtime/subagent/ module is peerd-runtime/actor/, and the
    spawned-child concept keeps a distinct name where it must not collide
    with bound actors: session kind 'subagent' is now 'spawned', and
    the child transcript stream is turn/spawned-*. Breaking for stored
    sessions from earlier builds (0.x posture: no migration shims): old
    kind:'subagent' records and skills/evals naming spawn_subagent
    need the new names.

Install (preview): Firefox: click the .xpi on this page. Chrome: drag
the .crx into chrome://extensions with Developer mode on. Most users
want the store packages (see the README). The auto-update feeds are
attached here and served at peerd.ai/updates/.