Skip to content

fix: post-merge edge cases in stream retry, serve behind a proxy, and script artifacts - #407

Merged
Broccolito merged 4 commits into
mainfrom
claude/postmerge-fixes
Oct 18, 2026
Merged

Broccolito merged 4 commits into
mainfrom
claude/postmerge-fixes

Conversation

@Broccolito

Copy link
Copy Markdown
Collaborator

Summary

Fixes for the edge cases the live post-merge tests found after #403, #404, #405 and #406 landed, plus two desktop renderer bugs from the same sweep.

Stream retry (#403/#405)

  • A tool call cut by a retryable error was shown and saved. If a local model was writing a tool call as text when a retryable error cut it, the fragment (for example {"name": "developer__shell", "arguments": {"comm) was shown, saved as a reply, and the retry was told to continue it.
    • Text recovery now marks text it releases only because of an error.
    • The reply loop drops that text when the error will be retried (MistakeTracker::would_retry, the same decision observe_provider_error makes) and shows it otherwise.
  • A whitespace-only partial reply no longer counts as a partial reply.
  • The <info-msg> block dropped out of later requests. It went missing from every request after a stored reply that ended in whitespace, because inject_moim read the normal trailing-whitespace and empty-message cleanups as its own fault.
  • The mid-task note no longer reads "Server does.. No tool ran".
  • The compute-error notice no longer asks the person to try again right before Biorouter retries.

biorouter serve behind a proxy (#404)

  • A stale cookie no longer blocks a fresh token. Every value of the session and app cookies is now read, so a stale cookie at a longer path doesn't shadow a fresh one. Before, a restart without --public-url refused every new link.
  • Cookies set at an https address are marked Secure. They never are on plain http, loopback included.
  • A valid token used outside the declared --public-url path now gets a page naming the right address, not "This link needs its access token".
  • The shell links its icon relative to <base>, so /favicon.ico is no longer requested outside the prefix.
  • The browser marketplace now fetches the live registry, with no referrer and no credentials, instead of requesting <mount>/undefined.
  • A daemon with no token configured no longer copies ?t= into Set-Cookie, where a ; could add attributes and a CR/LF caused a 500.
  • browser-access.md covers the "No Biorouter backend" app banner behind an https,http proxy chain; the fix is --public-url.

Desktop renderer

  • The artifact panel now offers files a Code Execution script wrote, including when the command or path is held in a variable. It reads the script's ok call records first and falls back to the source scan.
  • Script rows now use the step's own verb: "Running ls -la" instead of "Ran run ls -la".

Test plan

  • New tests for each finding. Each was checked to fail with its fix undone.
  • cargo test -p biorouter --lib -- providers:: agents::: 2873 passed.
  • cargo test -p biorouter --test output_recovery_agent_loop: 14 passed.
  • Stack-margin and steer binaries: soft_interrupt_agent_loop, turn_abort_tests, subagent_delegation, steer_always_lands.
  • cargo test -p biorouter-server --lib: 1011 passed, plus the new tokenless-cookie test.
  • cargo test -p biorouter-cli --test serve_lifecycle: 9 passed.
  • npx vitest run: 14742 passed.
  • npm run lint:check, npm run format:check, check-no-goose-block.sh and check-crew-manual.mjs pass.
  • Live: the mock llama-server scenarios (K, K2, BW, B, C, and MG through the managed sidecar), and serve behind a JupyterHub-style https proxy: stale cookie, Secure flags, favicon, wrong address, marketplace.

🤖 Generated with Claude Code

…'s verb

Two renderer bugs measured with GPT-5.5 under Code Execution.

The artifact panel never offered a file a script wrote when the command or
path sat in a variable (`const cmd = "printf ... > /p/notes.md";
shell({ command: cmd })`). The source scan looked a name up only inside a
`${...}` template, never as the argument itself.

- fileArtifactPathsFromToolCall takes the tool result. For execute_code it
  now reads the result meta's `biorouter/tool-calls` records, which carry
  the arguments each call really ran with; only calls recorded `ok` count.
  A record cut at the backend's 2 KB cap is read from its complete leading
  fields, and a cut that hides a field a rule needs marks the answer
  incomplete. The source scan stays as the fallback for results without
  records, and fills in (minus paths of failed calls) when the records are
  incomplete or some calls went unrecorded.
- The source scan reads call objects by their top-level properties (string
  and comment aware, shorthand and quoted keys), resolves a value that is
  one string literal or a name bound to one, and leaves out names bound or
  assigned twice and literals followed by more expression (`"/w/" + name`
  used to yield "/w/"). str_replace_editor gets the same command gate as
  text_editor.
- File-link provenance now trusts a script's `ok` write records, never its
  source, so an unexecuted branch still promotes nothing.

Script rows read "Ran run ls -la", "Failed to run write the requested
markdown file": summarizeToolGraph put "Running" in front of a step the
model wrote as an imperative. The step's own opening verb now becomes the
gerund toolRowLabel conjugates ("Running ls -la", "Ran ls -la", "Failed to
write the requested markdown file"); a step that opens with no known verb
stands in sentence case and fails as "Failed: Attempt the command", the
existing non-verb form. A step named only by its tool still runs that tool.
Found by the live tests after #403, #404 and #405 merged.

Stream retry (#403/#405):
- A tool call written as text and cut by a retryable error was shown and
  saved as a reply, and the retry was told to continue it. The local
  providers' text recovery now marks text it releases only because of an
  error; the reply loop drops it when the error will be retried
  (MistakeTracker::would_retry) and shows it otherwise.
- A whitespace-only partial reply counted as a partial reply.
- The <info-msg> block was dropped from every request after a stored reply
  ending in whitespace: inject_moim no longer treats the trailing-whitespace
  and empty-message cleanups as its own fault.
- The mid-task note read "Server does.. No tool ran".
- The compute-error notice no longer asks the person to try again right
  before Biorouter does.

Serve behind a proxy (#404):
- Every session and app cookie value is read, so a stale cookie at a
  longer path no longer shadows a fresh token.
- Cookies set at an https address are marked Secure; plain http never.
- A valid token redeemed outside the declared --public-url path says which
  address to use instead of "needs its access token".
- The shell links its icon relative to <base>, so /favicon.ico is no
  longer requested outside the prefix.
- The browser's marketplace fetches the live registry (no referrer, no
  credentials) instead of requesting <mount>/undefined.
- A daemon with no token configured no longer copies ?t= into Set-Cookie.
- browser-access.md covers the app "No Biorouter backend" banner behind an
  https,http chain (fix: --public-url).
Broccolito added a commit that referenced this pull request Oct 18, 2026
…he site updated for #399-#407

Models and providers gains "Choose a computer for local models": what has to
fit in the memory the GPU can use, a memory table (under 32 GB, 32, 48, 64 to
128 GB), why an Intel Mac or a computer without a fast GPU is slow whatever its
memory, disk space per model, and what to do when the first reply times out.
Every figure is taken from the Llama Server catalog, its context-window tiers
and the timeout defaults. The Local paragraph points to it instead of repeating
the memory figures.

The rest follows this cycle's merges:
- Command line: serve behind an HTTPS reverse proxy, with --public-url for an
  address under a path prefix, and the browser's marketplace row.
- Crew: open workspaces by default (and older ones staying managed), setup
  giving agents "As me on the server" with --agent-access for less, @agent in
  the message box, deleting a workspace, and which models server access needs.
- The desktop app: the Crew tasks model setting.
@Broccolito
Broccolito merged commit 3becc5c into main Oct 18, 2026
17 checks passed
@Broccolito
Broccolito deleted the claude/postmerge-fixes branch October 18, 2026 03:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant