peerd-preview-v0.2.6
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
explicittabIdargument againstactorInstanceId. That field is the
fixed literal'web', the actor's stablemessage_actoraddress, 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, andfetch_urldoes not follow redirects (by
design: seedocs/security/THREAT-MODEL.mdINV-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_notebooknow marks
such resultsevalErrorand 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 pinspeerd:wasi+demoModule()as
importable and runnable from ascriptjob (a field session reported
the import unreachable; current source proves green, so a stale install
is the likely culprit, reload the extension).
Added
peerd:wasiships a self-test module.demoModule()(exported next
torunWasi) 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 fromtests/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 thescript/js_createlore and the code-mode
prompt.
Fixed
resp.bytes()works in sandboxed code now. The sealed-realm fetch
bridge (Notebook / script / a2a runs) listedbyteson its response but
as a raw data property, soresp.bytes()(the platformResponse.bytes()
shape every model reaches for) threw "not a function". It's a method
returningPromise<Uint8Array>now, matching the platform. Found in the
field: an agent burned several turns rediscoveringarrayBuffer()while
smoke-testingrunWasi.- 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
(navigatelazily 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'smessage_actorteaching 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_subagenttool isactor_create,subagent_cancelis
actor_cancel,subagent_tasksisactor_tasks(pairs with
sandbox_create: a sandbox always has a dedicated bound actor;
actor_createalone makes an ephemeral one). Internally the
peerd-runtime/subagent/module ispeerd-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 isturn/spawned-*. Breaking for stored
sessions from earlier builds (0.x posture: no migration shims): old
kind:'subagent'records and skills/evals namingspawn_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/.