Agent web-search/report pipeline: 8 fixes proven on the clean soul — patch ready for main (soul.c + chat.el upstream) #74

Open
opened 2026-07-11 17:59:44 +00:00 by tim.lingo · 4 comments
Member

Tim's 'research MSFT + build HTML report' failed silently (real server-side searches ran, zero shown, no report). Root-caused and FIXED on the clean :7798 soul, E2E-proven (full report on disk, all actions visible). Patch: neuron-container-build/soul-webfix-20260711.patch (185 lines vs origin/main dist/soul.c) — needs your .el-side mirror + regen for main/prod.

The 8 fixes, each E2E-verified:

  1. main regression: web_search request flag ignored — handle_chat_agentic never attaches the server-side search tool (older deployed binaries had it). Restored, honoring the app's flag.
  2. pause_turn never resumed — Anthropic's server-tool loop pauses mid-turn; docs require re-send-and-resume; failing = silently truncated answers. Resume loop added (cap 8→12).
  3. Server-side work invisibleserver_tool_use blocks now counted generically by name into tools_used (future server tools appear automatically — code_execution already shows up via the new search variant's dynamic filtering).
  4. Tool version future-proofingweb_search_20250305 (deprecated) → config-driven via state key web_search_tool_version, default web_search_20260209; on API rejection falls back to 20250305, logs [soul] DRIFT: + sets state web_search_version_drift (verified with a bogus version end-to-end).
  5. Duplicate tool name — homegrown client web_search stripped when the server tool is attached (model was picking nondeterministically between the two).
  6. container_id contract — the 20260209 variant's code-execution filtering requires echoing container.id on follow-ups or the API 400s; now captured + carried.
  7. Honest tools_used + cap notice — client tools only logged when actually dispatched/bridged (a max_tokens-truncated tool block was being logged as 'used' without running); on cap-hit mid-action the reply now says so. max_tokens 4096→16384 for report-sized write_file inputs.
  8. LLM error logging — the loop was swallowing API error bodies entirely; first 220 chars now logged.

Also: runtime env EL_HTTP_TIMEOUT_MS=300000 needed for long agentic turns (60s default times out; knob already existed). launch-clean.sh sets it; prod launcher should too.

Architecture recommendation (your call): provider-facing literals (model IDs, tool versions, stop reasons, wire shapes) are sprinkled through chat.el — by VBD they belong in one accessor layer with config overrides. Today's drift class keeps recurring until then.

App-side companion: neuron-ui PR #123 (workspace grounding line). Monthly drift audit now in our BACKLOG (next due 2026-08-11).

— Tim + Neuron

Tim's 'research MSFT + build HTML report' failed silently (real server-side searches ran, zero shown, no report). Root-caused and FIXED on the clean :7798 soul, E2E-proven (full report on disk, all actions visible). Patch: `neuron-container-build/soul-webfix-20260711.patch` (185 lines vs origin/main dist/soul.c) — needs your .el-side mirror + regen for main/prod. **The 8 fixes, each E2E-verified:** 1. **main regression: `web_search` request flag ignored** — handle_chat_agentic never attaches the server-side search tool (older deployed binaries had it). Restored, honoring the app's flag. 2. **pause_turn never resumed** — Anthropic's server-tool loop pauses mid-turn; docs require re-send-and-resume; failing = silently truncated answers. Resume loop added (cap 8→12). 3. **Server-side work invisible** — `server_tool_use` blocks now counted generically by name into tools_used (future server tools appear automatically — code_execution already shows up via the new search variant's dynamic filtering). 4. **Tool version future-proofing** — `web_search_20250305` (deprecated) → config-driven via state key `web_search_tool_version`, default `web_search_20260209`; on API rejection falls back to 20250305, logs `[soul] DRIFT:` + sets state `web_search_version_drift` (verified with a bogus version end-to-end). 5. **Duplicate tool name** — homegrown client `web_search` stripped when the server tool is attached (model was picking nondeterministically between the two). 6. **container_id contract** — the 20260209 variant's code-execution filtering requires echoing `container.id` on follow-ups or the API 400s; now captured + carried. 7. **Honest tools_used + cap notice** — client tools only logged when actually dispatched/bridged (a max_tokens-truncated tool block was being logged as 'used' without running); on cap-hit mid-action the reply now says so. max_tokens 4096→16384 for report-sized write_file inputs. 8. **LLM error logging** — the loop was swallowing API error bodies entirely; first 220 chars now logged. **Also:** runtime env `EL_HTTP_TIMEOUT_MS=300000` needed for long agentic turns (60s default times out; knob already existed). launch-clean.sh sets it; prod launcher should too. **Architecture recommendation (your call):** provider-facing literals (model IDs, tool versions, stop reasons, wire shapes) are sprinkled through chat.el — by VBD they belong in one accessor layer with config overrides. Today's drift class keeps recurring until then. App-side companion: neuron-ui PR #123 (workspace grounding line). Monthly drift audit now in our BACKLOG (next due 2026-08-11). — Tim + Neuron
will.anderson was assigned by tim.lingo 2026-07-11 17:59:46 +00:00
Author
Member

Addendum: the sandbox soul now also implements GET/POST /api/safety-contact per issue #97's spec and the app's exact contract (DaemonClient.kt shapes; 988 auto-fill; RFC3339 set_at; persist path env-overridable via SOUL_SAFETY_CONTACT_PATH so clean-profile testing never writes ~/.neuron). Round-trip verified: unset GET -> {configured:false}; POST 988 -> full record + ok; GET -> persists. This unblocked the Hard Bell gate (BUG-5) on the clean profile — main's soul.c still needs your .el-side implementation for prod. Updated patch: neuron-container-build/soul-webfix-20260711.patch superseded by the full diff in ~/soul-fix-build/soul.c (regenerating the .patch file now includes safety-contact + all 8 web fixes).

Addendum: the sandbox soul now also implements GET/POST /api/safety-contact per issue #97's spec and the app's exact contract (DaemonClient.kt shapes; 988 auto-fill; RFC3339 set_at; persist path env-overridable via SOUL_SAFETY_CONTACT_PATH so clean-profile testing never writes ~/.neuron). Round-trip verified: unset GET -> {configured:false}; POST 988 -> full record + ok; GET -> persists. This unblocked the Hard Bell gate (BUG-5) on the clean profile — main's soul.c still needs your .el-side implementation for prod. Updated patch: neuron-container-build/soul-webfix-20260711.patch superseded by the full diff in ~/soul-fix-build/soul.c (regenerating the .patch file now includes safety-contact + all 8 web fixes).
Author
Member

Second addendum — RUNTIME BUG FOUND during the safety-contact work, worth its own attention: HTTP responses that embed an fs_read string get clamped to the FILE's byte count (Content-Length pinned to file size, body truncated mid-JSON). Reproduced deterministically; survived three dodges (fresh str_slice copy, full rebuild-from-parsed-fields — truncation persisted as long as fs_read ran in the request). Workaround shipped: read the file via exec_capture('cat ...') whose buffer path flows through responses intact. This same aliasing may explain the historical /api/graph/edges emptiness and other truncation ghosts. Suspect: response writer measuring an aliased/stale allocation from fs_read. el_runtime-level fix belongs with you. Sandbox soul now serves valid safety-contact JSON both verbs (strict-validated); Hard Bell gate cleared; tamper-notice dialog fired correctly for the out-of-band change — L1 behaving beautifully.

Second addendum — RUNTIME BUG FOUND during the safety-contact work, worth its own attention: **HTTP responses that embed an fs_read string get clamped to the FILE's byte count** (Content-Length pinned to file size, body truncated mid-JSON). Reproduced deterministically; survived three dodges (fresh str_slice copy, full rebuild-from-parsed-fields — truncation persisted as long as fs_read ran in the request). Workaround shipped: read the file via exec_capture('cat ...') whose buffer path flows through responses intact. This same aliasing may explain the historical /api/graph/edges emptiness and other truncation ghosts. Suspect: response writer measuring an aliased/stale allocation from fs_read. el_runtime-level fix belongs with you. Sandbox soul now serves valid safety-contact JSON both verbs (strict-validated); Hard Bell gate cleared; tamper-notice dialog fired correctly for the out-of-band change — L1 behaving beautifully.
Author
Member

Second addendum — RUNTIME BUG FOUND during the safety-contact work: HTTP responses embedding an fs_read string get clamped to the FILE's byte count (Content-Length pinned to file size, body truncated mid-JSON). Deterministic; survived three dodges (str_slice copy, rebuild-from-parsed-fields) — truncation persisted whenever fs_read ran in-request. Workaround: read via exec_capture('cat ...'), whose buffers flow through responses intact. May explain historical /api/graph/edges emptiness + other truncation ghosts. el_runtime-level fix belongs with you. Sandbox now serves valid safety-contact JSON both verbs (strict-validated); Hard Bell gate cleared; tamper-notice fired correctly for the out-of-band change — L1 behaving exactly as designed.

Second addendum — RUNTIME BUG FOUND during the safety-contact work: HTTP responses embedding an fs_read string get clamped to the FILE's byte count (Content-Length pinned to file size, body truncated mid-JSON). Deterministic; survived three dodges (str_slice copy, rebuild-from-parsed-fields) — truncation persisted whenever fs_read ran in-request. Workaround: read via exec_capture('cat ...'), whose buffers flow through responses intact. May explain historical /api/graph/edges emptiness + other truncation ghosts. el_runtime-level fix belongs with you. Sandbox now serves valid safety-contact JSON both verbs (strict-validated); Hard Bell gate cleared; tamper-notice fired correctly for the out-of-band change — L1 behaving exactly as designed.
Author
Member

Second addendum — RUNTIME BUG FOUND during the safety-contact work, worth separate attention:

HTTP responses that embed an fs_read string get clamped to the FILE's byte count — Content-Length pinned to the file's size, body truncated mid-JSON. Deterministic repro; survived three dodges (fresh str_slice copy, full rebuild-from-parsed-fields) — the truncation persisted as long as fs_read ran anywhere in the request. Workaround shipped: read the file via exec_capture("cat ..."), whose buffer path provably flows through responses intact. This same aliasing may explain the historical /api/graph/edges emptiness and other truncation ghosts. Suspect: the response writer measuring a stale/aliased allocation from fs_read. The el_runtime-level fix belongs with you.

Status: sandbox soul now serves valid safety-contact JSON on both verbs (strict-validated); the Hard Bell gate cleared; and the tamper-notice dialog fired correctly for the out-of-band contact change — the L1 layer behaving exactly as designed. Full updated patch: neuron-container-build/soul-webfix-20260711.patch.

Second addendum — RUNTIME BUG FOUND during the safety-contact work, worth separate attention: **HTTP responses that embed an `fs_read` string get clamped to the FILE's byte count** — Content-Length pinned to the file's size, body truncated mid-JSON. Deterministic repro; survived three dodges (fresh `str_slice` copy, full rebuild-from-parsed-fields) — the truncation persisted as long as `fs_read` ran anywhere in the request. Workaround shipped: read the file via `exec_capture("cat ...")`, whose buffer path provably flows through responses intact. This same aliasing may explain the historical `/api/graph/edges` emptiness and other truncation ghosts. Suspect: the response writer measuring a stale/aliased allocation from `fs_read`. The el_runtime-level fix belongs with you. Status: sandbox soul now serves valid safety-contact JSON on both verbs (strict-validated); the Hard Bell gate cleared; and the tamper-notice dialog fired correctly for the out-of-band contact change — the L1 layer behaving exactly as designed. Full updated patch: `neuron-container-build/soul-webfix-20260711.patch`.
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: neuron-technologies/neuron#74