Bound model tool envelopes with ranged artifacts and process cursors #676
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/anima-a3-model-envelopes"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Bound the complete model-visible tool result while retaining complete broker evidence and scoped ranged reads; collect the new bulk storage after declared retention.
Targets #674 branch; supplies Anima S2. No PR merge, deployment, live recovery or canary.
Review fixes
Handles are bounded to2KiB including encoded keys/values, with explicit handles_elided rather than quarantining a job after its tool executed. Artifacts have16MiB per-result serialization and128MiB per-job caps. Process captures have24h retention independent of permanent effect receipts and are collected by idle lease maintenance; live cursor polls encode only their requested slice. Artifacts survive archival/prior-job reads but terminal inactive jobs expire after7days. GC removes chunks/manifests/counters/indexes. Codex text-only results intentionally use the same structured success/receipt transport as other ToolResults.
Exact consumer contract
Tool output v1 (A3 output; Anima S2)
The model-facing text path bounds the serialized ToolResult to 16 KiB,
including nested JSON and receipt wrapping. Oversized results retain exactly one
head/tail excerpt, the original
successandreceipt, anddata:Hash/size cover the complete original serialized ToolResult, before model elision.
The runtime commits all bytes as hashed chunks before returning an excerpt. Identical
artifacts deduplicate under a 128 MiB/job budget; exhausting storage refuses the
model callback rather than silently discarding evidence. Original broker/executor
receipts retain their authority. Large ToolCompleted event details already have
lossless job-scoped references; this extends the distinct provider-input boundary.
ToolCompleted details also include the model output reference as provenance.
GET /v1/jobs/{job}/tool-output/{sha256}?offset=0&limit=8192requires existingsession-service authentication and an existing job owned by this runtime. Model
access is through the runtime-local read-only
akh_read_tool_outputtool:job_iddefaults to the current job. Prior jobs require the same exact session;foreign-session references are denied. Offset is a UTF-8 byte cursor. Limit is
1..8192; the model tool may return fewer bytes to reserve JSON-envelope space.
The response contains
{schema_version:1,sha256,bytes,offset,next_offset,done,text}.Continue at
next_offset. Mid-codepoint cursors are refused; range ends shortenon UTF-8 boundaries; no replacement character conceals omitted bytes. Chunk hashes
are verified on read; each range reads only the needed chunks, not the whole artifact.
Codex emits one serialized result rather than dropping receipt metadata on its
text-only path. Codex and internal role/tool messages check the final escaped
provider-facing envelope against 64 KiB. Every runtime-host text result is bounded
before native adapter wrapping. Native Candle image reads retain the existing
image modality path and its tokenizer/context budget; arbitrary base64 text files
are not image exemptions. Prompt contents and credential-bearing URLs are never
metric labels.
Process cursors and retained capture
Existing #394 24 KiB per-stream head/tail clipping remains for legacy polls.
exec_polloptionally acceptsstdout_offset,stderr_offsetandmax_output_bytes(1..8192, default4096). With either offset supplied, responsecontains
cursor_mode:true, process ID/status, terminal success/receipt/exit code,and stdout/stderr ranges
{sha256,bytes,offset,next_offset,done,text,base64}.UTF-8 text is present only when the complete captured stream is valid UTF-8;
base64 always preserves exact bytes. Process ownership/generation checks remain.
Each poll receipt freezes the observed range and replay returns the same observation.
Complete captured stdout/stderr are committed with the terminal receipt before
clipped text becomes visible. Cursor reads survive executor restart. The existing
1 MiB/stream capture cap stays explicit (
capture_truncated); this is lossless forcaptured bytes, not a claim to recover bytes beyond that pre-existing cap. Old or
interrupted processes without durable capture return explicit unavailable.
Controller/model tool schemas must allow the new optional cursor fields to use
this path; ordinary polls keep their previous meaning.
The internal HTTP endpoint optionally declares
max_input_bytesin 1..8388608.The final serialized body includes mandatory instructions, schemas and history.
An over-budget request is refused without dropping mandatory text. Absent setting
preserves the existing 8 MiB hard limit; it does not assert a token-window fit.
Broader per-call usage/model/context provenance is the separate A3 telemetry PR.
Deployment and authorized canary pending; historical producers are not inferred.
Review bounds: serialized handles map <=2KiB (including escaped keys/values), extra handles explicitly marked handles_elided and remain in the full artifact. Per-result serialization caps at16MiB before chunking; per-job budget128MiB remains. Codex serializes every ToolResult, including text-only values, to preserve receipt/success metadata; the final escaped64KiB envelope guard is separately tested.
Complete process captures expire after24h independently of permanent effect receipts; deleting a collected read receipt also deletes its capture/index. The existing executor sweep runs from lease maintenance as well as operations, so idle executors collect. Live cursor polls slice before base64 encoding. Runtime tool artifacts survive archival/prior-job reads but expire after7days for terminal inactive jobs, in up-to64-job sweeps. Unknown/active jobs retain their bounded evidence. GC removes manifests/chunks/budget/index atomically; post-expiry range reads return unavailable, not fabricated empty output.
Prior validation
Fable Round2 approved reviewed head
621027446d49. Previous follow-up head:dae86ef17b02dc41b2123842dc19c0595471de70.The64 collection budget is applied after active/nonterminal/missing owner checks. As CoS explicitly requested, missing and Unknown owners retain evidence and consume no collection slots. The regression places64 Internal Unknown and64 missing jobs before65 terminal jobs: successive rounds collect64, then1, then0, while stale owners remain. This implements the operator request to skip missing owners rather than the optional review suggestion to collect orphan evidence.
Current-head collector regression:1 passed (r2-followup-output.log). Final integrated #678 suite115 passed/1 existing real-backend ignored. Full exact-head Solstice CI remains a merge gate; local results do not substitute for it. No merge, force-push, deployment or canary.
Finished task target was reclaimed after verifying no open files;37.08GiB free at10:16Z. Peer target preserved.
CI4360 follow-up
Current head:
c8a1ea495fa299ebef79bdbe89686955d09da033.Solstice exact-head evidence for #676
dae86ef17bidentifies failed request e257c6a0-5f0a-4a9e-8b58-d372ffb7ad0f, categorystep:cargo-test-features-postgres-lib. The root suite had3961 passed,22 ignored and1 failure:agent::runtime::tests::codex_tools_use_typed_akh_registry_and_record_evidence, src/agent/runtime/tests.rs:117, expecting plain "7" while the fixture echoed the complete ToolResult JSON. This was a missed regression expectation from the reviewed complete-envelope contract, not a refused connection or runner fault. It reproduced locally before the fix. Reported Forgejo job: /toasterson/akh-medu/actions/runs/4360/jobs/7.The root regression now checks all decoded fields
{success:true,text:"7",data:null,receipt:null}and keeps its tool-evidence trace assertion. New Codex envelope coverage preserves both text-only and structured data/receipt results alongside the existing64KiB escaped-envelope refusal. The production envelope implementation hash is unchanged; no wire contract change. The identical stale root test and implementation existed on #677/#678, so normal stack integration carries this fix through both. No force-push or PR merge.Current-head local receipts:
ci4360-root-fixed.log: test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 3984 filtered out; finished in 0.23sci4360-envelope.log: test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 14 filtered out; finished in 0.01sci4360-provider.log: test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 13 filtered out; finished in 0.46sLocal workspace packages were cleaned between worktrees to exclude stale Cargo reuse. Final full Linux CI is still a separate gate. No blind rerun was requested; the normal follow-up commits publish the diagnosed fix. No deployment, Talos/Ptah change or live provider probe. Builds used31.5GiB stop/32GiB preflight guards; the finished task target is reclaimed on handoff.
Own finished target was verified without open files and deleted; 37.269GiB free at 2026-10-19T11:58:41.253438+00:00. Peer targets were untouched.
toasterson referenced this pull request2026-10-19 08:46:04 +00:00