Release v0.0.284 — ACP images, #708/#711/#712/#714/#716 - #713
Merged
Conversation
… an inbox read (#708) The one-line [peer] wake appended to a user turn ended in the imperative 'peer_message action=inbox', so a bare greeting made the agent spend the turn reading the mailbox. The wake now says messages are parked, keeps the how-to-read hint inline, and asks that the user's actual request be answered first; an empty inbox no longer carries a read command at all. Co-Authored-By: Codegraff <blackfloofie@codegraff.com>
The advisory framing added in the parent commit wrapped across several dim rows in the pager. Keep the parked/read-when-relevant tone, drop the second clause. Co-Authored-By: Codegraff <blackfloofie@codegraff.com>
The ACP turn path appended the prompt as a plain text message, so an image attached from a client rode to the model as literal @[path] text and the pixels never did. mainloop and the REPL both stage and consume the marker; ACP now does the same via a shared userMessage helper, with a regression test covering both the image and non-image cases. Co-Authored-By: Codegraff <blackfloofie@codegraff.com>
Co-Authored-By: Codegraff <blackfloofie@codegraff.com>
defaultProvider returned the first provider in spec order holding a key, and the gateway sits at index 1 — above every subscription login. Merely having a stored gateway key therefore seated a fresh launch (no --model, no saved model) on the gateway while a valid Codex/xAI/Kimi credential further down the array lost. Sessions the user believed were direct drew on gateway credits instead, and a gateway outage broke launches that had no business touching it. providerFor already demotes the gateway to its phase 2 for exactly this reason: #294 fixed the model-routing half and left the startup half. Give defaultProvider the same demotion through one shared predicate — direct providers first in spec order, the gateway only when nothing else answers. A gateway-only user still boots on it.
provider_fallback carries to_provider, to_model and to_context, but the
TUI sink forwarded only the model name. The drain then set g_model_name
and left g_model_provider on the previous provider, so after an automatic
failover the status bar paired the new model with the OLD provider id — a
seat that serves nothing — and models.isCurrent, which compares the
provider precisely so two same-named seats stay apart, marked the wrong
picker row or none at all.
Widen the event to ModelChanged{model, provider}, forward both from the
sink, and move the ownership into Model.adoptFailover beside adoptModel,
which already documents the split: a provider id is a static spec literal,
while the model string dies with the drain that delivered it.
The sink test already built the event with to_provider set and never
asserted on it; it does now, on both sides of the boundary.
The nudge walked all history, so a past SPEC.md re-armed every later turn, and adopt/ACP re-injected the same user row. Settle a mention once tools run or the nudge fires; skip duplicate user payloads and fail closed after three copies (ADR 0060).
Learn-auto (and a re-typed prompt) sends the same words after an assistant reply. Treat that as a new ask. Dedup only when history already ends on that exact user prompt.
…lobal A scout's beginTurn stored remembered_task as a pointer into the child arena. After the child exited, the parent's handle() walked that slice and crashed in hasNamedSource (test-model-shape). Copy the text onto the Agent so a sibling cannot poison the root.
Fullscreen /goal was published through the generic state callback, which minted standing=true. attempt_completion then left the objective active, and /resume steered the next unrelated prompt at finished work. Route TUI /goal through the shared lifecycle (set/pause/unpause/clear). status and bare /goal report; they do not mint an objective named "status".
An undefined Agent.sys_base skipped the empty-prefix guard and overflowed setSystemPrompts. Tests now start from a blank prefix like every other goal-flow fixture.
parsePorcelain handed back Entry slices pointing into the caller's buffer. listEntries frees git's stdout the moment it returns, so every row's path and branch referenced released memory: reused pages read back as NUL, which printed blank rows for `workspace action=list` and made `action=use` match neither a worktree's name nor its exact path, though git listed it fine. Copy path, head and branch into the arena the rows themselves live in. Both regression tests fail without the fix. The existing ones could not catch it: every one parses a comptime literal, which is never freed. The new pair zeroes an owned source buffer, and runs the real listEntries path against git so a released buffer is actually exercised.
Same-session grok-4.6 table on this tip: all three harnesses 12/12. OpenCode wins wall (235s vs graff 242s); graff still wins calls, tokens, list$, and RSS. Last unique-frontier pin stays the 282 table.
Composite run-20260901-121759: graff 219.6s / 53 / $0.32 / 8.7M vs OpenCode 234.8s / 77 / $0.68. Symlink stall (115s, 4 calls) retried at 67.8s. x_search stayed on; catalog unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Cut of the next release: merges the ACP image-attachment fix and the advisory peer-wake change onto the release line, adds the v0.0.284 changelog entry and release notes, and raises the test-count baseline to 1882.
Why
Pasted images from ACP clients reached the model as path text instead of pixels, and the peer inbox wake read as a command that displaced trivial turns. Both fixes are merged here so they ship in the next release cycle. No tag until asked, per the release-notes convention.
#714 named-source UAF
named_work.remembered_taskwas process-global. A scoutbeginTurnleft a pointer into the child's freed arena; the parent's laterhandle()crashed inhasNamedSource(Sol root → Terra scout → synthesis). The mention is now stored on the Agent (named_work_task/named_work_settled), so a sibling cannot poison the root. Test #714 covers handle reading the Agent copy, not a leftover global.