feat(missions): keep the tool's arguments, not just its name
The container tier's first measured mission recorded `Bash × 6` and not one of them said what it ran. Every behavioural question about the phase — did it run the tests, did it commit, did it call an API a skill forbids — was unanswerable from a record that looked complete. `vm_tool_tap::parse` already read `tool_input` to pull the path out of it, then dropped the rest on the floor. It now keeps it, bounded: file bodies (`content`, `new_string`, `old_string`, `edits`) become a byte count, and any other over-long string is truncated with a marker saying so. Bounded rather than whitelisted, because a whitelist silently loses the one argument that matters the first time a tool grows a field. `file.touch` keeps the absolute path in `detail.abs` alongside the repo-relative `target`. Normalising is what the map needs and exactly what destroys "did this write land outside the checkout". `tool.call` also gains `detail.path`, which the World's SSE has been reading and getting a null from on every container-tier call. `mission_events::tool_evidence_for_mission` is the reader — the counterpart to `narrative_for_mission`, and the reason it exists: the narrative is what an agent SAID it did. Host-side only. No image rebuild: the arguments were always in the tap file, the first parse threw them away. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_018i9Ten1LU4jUr5d7TAWda9
This commit is contained in:
co-authored by
Claude Opus 5
parent
0b4d91889a
commit
8cb38d1320
@@ -1114,9 +1114,13 @@ pub async fn world_live(
|
||||
// the durable source: `reasoning` rows carry the agent's own step
|
||||
// output, `tool.call` rows its actions.
|
||||
//
|
||||
// NOTE: on the container tier `tool.call` legitimately stays empty —
|
||||
// those agents are tool-free behind the §15 door. Reasoning flows on
|
||||
// every tier; tool lines appear where agents actually hold tools.
|
||||
// This used to say the container tier "legitimately stays empty —
|
||||
// those agents are tool-free". That was wrong, and it was wrong in
|
||||
// the most expensive way: it explained the silence, so nobody
|
||||
// looked. Those agents call `Bash` and `Write` constantly; the
|
||||
// calls happen inside claude's own subprocess and so never reached
|
||||
// ZeroClaw's executor. `container_tool_hooks` records them now, and
|
||||
// `tool.call` is populated on both tiers.
|
||||
if agent_ev_cursor < 0 {
|
||||
agent_ev_cursor = sqlx::query_scalar(
|
||||
"SELECT coalesce(max(id), 0) FROM mission_events",
|
||||
|
||||
Reference in New Issue
Block a user