WIP: The akh emits tool activity as prose in agent_thought, not as structured ToolCall/ToolCallUpdate ACP events #295

Draft
toasterson wants to merge 2 commits from claude/wi-019fbe82-the-akh-emits-tool-activity-as-prose-in into main
Owner

Anima work item 019fbe82-fe37-73e3-88be-616f969c1394.

The gap

Compare two sessions on the same Anima server, same day:

tecton (akhomed) 019fba31 claude-code 019faec4
acp.agent_thought × 9 acp.tool_call × 102
acp.tool_call_update × 100
acp.plan × 5

The akh emits zero structured tool events. Its tool activity arrives as prose
stuffed inside agent_thought:

[exec:shell_exec_1] cd /data/akh-medu/workspaces/tecton/scratch/anima-worktrees/…
[shell_exec_41:ok] Command: …
[exec:file_io_20] ? /data/akh-medu/…

That is a human-readable log line, not an event. akh-medu WI-220
("akhomed: emit structured ToolCall/ToolCallUpdate session updates over ACP") is
marked done, so either it regressed, shipped for a different code path, or was
closed on a partial. Establish which before writing code — do not assume a
regression.

Why it matters (measured, not theoretical)

  1. last_step is uninformative. LastStepTracker classifies the in-flight
    step from emitted messages. With everything arriving as narrative, every stall
    line in the 2026-07-28→31 investigation read last_step="narrative" — there
    was no other value it could take. A field added specifically to name the stuck
    step could never name anything.
  2. No per-tool timing on this lane. The 2026-08-01 instrumented run showed 20
    LLM requests totalling ~250s inside a 3600s turn. Attributing the rest between
    model latency and tool execution was impossible, because tool start/end is not
    an event. #280 gave us per-request LLM metrics; the tool half is still dark.
  3. Consumers cannot render akh work. The PWA shows claude-code sessions as
    tool calls with status and results, and akh sessions as opaque prose blobs.

Required

  1. Determine why WI-220's structured events do not appear on the akhomed ACP path.
    Say plainly what you find — "it was never wired for X" is a fine answer.
  2. Emit ToolCall when a tool starts and ToolCallUpdate on completion, over ACP,
    from the akh's tool-execution path — the same shape the ACP client already
    consumes from other agents (kind, title, status, content, toolCallId).
    ToolExecutionTracker already wraps the ChannelSink for exactly this purpose
    (src/acp/mod.rs:753); prefer extending it over a new mechanism.
  3. Include duration on the completion update so per-tool timing becomes
    answerable.
  4. Keep the narrative line or drop it — your call, but do not emit the same
    information twice in two shapes.

Acceptance

  • A tecton session run through Anima produces acp.tool_call and
    acp.tool_call_update events, verifiable with list_sessions /
    the activity stream for the session.
  • Each completion update carries a duration.
  • A stall line during a tool call reports last_step as that tool, not
    "narrative".
  • No double-reporting of the same tool call.

Notes for the implementer

The tree moved a lot in the last 48 hours — #276, #279, #280, #281 all
touched src/acp/mod.rs, src/agent/agentic_chat.rs and src/agent/ollama.rs.
Start from current origin/main and read those files as they are now, not as you
may remember them.

Anima work item `019fbe82-fe37-73e3-88be-616f969c1394`. ## The gap Compare two sessions on the same Anima server, same day: | tecton (akhomed) `019fba31` | claude-code `019faec4` | |---|---| | `acp.agent_thought` × 9 | `acp.tool_call` × 102 | | — | `acp.tool_call_update` × 100 | | — | `acp.plan` × 5 | The akh emits **zero** structured tool events. Its tool activity arrives as prose stuffed inside `agent_thought`: ``` [exec:shell_exec_1] cd /data/akh-medu/workspaces/tecton/scratch/anima-worktrees/… [shell_exec_41:ok] Command: … [exec:file_io_20] ? /data/akh-medu/… ``` That is a human-readable log line, not an event. akh-medu WI-220 ("akhomed: emit structured ToolCall/ToolCallUpdate session updates over ACP") is marked **done**, so either it regressed, shipped for a different code path, or was closed on a partial. **Establish which before writing code** — do not assume a regression. ## Why it matters (measured, not theoretical) 1. **`last_step` is uninformative.** `LastStepTracker` classifies the in-flight step from emitted messages. With everything arriving as narrative, every stall line in the 2026-07-28→31 investigation read `last_step="narrative"` — there was no other value it could take. A field added specifically to name the stuck step could never name anything. 2. **No per-tool timing on this lane.** The 2026-08-01 instrumented run showed 20 LLM requests totalling ~250s inside a 3600s turn. Attributing the rest between model latency and tool execution was impossible, because tool start/end is not an event. `#280` gave us per-request LLM metrics; the tool half is still dark. 3. **Consumers cannot render akh work.** The PWA shows claude-code sessions as tool calls with status and results, and akh sessions as opaque prose blobs. ## Required 1. Determine why WI-220's structured events do not appear on the akhomed ACP path. Say plainly what you find — "it was never wired for X" is a fine answer. 2. Emit `ToolCall` when a tool starts and `ToolCallUpdate` on completion, over ACP, from the akh's tool-execution path — the same shape the ACP client already consumes from other agents (`kind`, `title`, `status`, `content`, `toolCallId`). `ToolExecutionTracker` already wraps the `ChannelSink` for exactly this purpose (`src/acp/mod.rs:753`); prefer extending it over a new mechanism. 3. Include **duration** on the completion update so per-tool timing becomes answerable. 4. Keep the narrative line or drop it — your call, but do not emit the same information twice in two shapes. ## Acceptance - A tecton session run through Anima produces `acp.tool_call` and `acp.tool_call_update` events, verifiable with `list_sessions` / the activity stream for the session. - Each completion update carries a duration. - A stall line during a tool call reports `last_step` as that tool, not `"narrative"`. - No double-reporting of the same tool call. ## Notes for the implementer The tree moved a lot in the last 48 hours — `#276`, `#279`, `#280`, `#281` all touched `src/acp/mod.rs`, `src/agent/agentic_chat.rs` and `src/agent/ollama.rs`. Start from current `origin/main` and read those files as they are now, not as you may remember them.
The akh emits tool activity as prose in agent_thought, not as structured ToolCall/ToolCallUpdate ACP events
All checks were successful
CI / publish-chart (pull_request) Successful in 9m21s
CI / check-seshat (pull_request) Successful in 10m51s
CI / check-seshat (push) Successful in 10m51s
CI / publish-chart (push) Successful in 3m45s
CI / docker-seshd (pull_request) Successful in 15m40s
CI / docker-seshd (push) Successful in 10m4s
bf8377aaad
Anima implementation session.
toasterson left a comment

Review verdict: BLOCK — the branch does not compile, and it does not implement the work item.

The entire diff is three lines in src/message.rs: a new duration_ms: Option<u64> field on AkhMessage::ToolCallCompleted. Adding that field without updating its match and construction sites breaks the build — cargo check --features server at bf8377aa fails with 7 errors (E0027 ×4, E0063 ×3).

More importantly, the actual bug is untouched. to_session_update() at src/acp/mod.rs:1294-1331 still converts both ToolCallStarted and ToolCallCompleted into SessionUpdate::AgentThoughtChunk prose. That stub is the work item, and this PR does not modify src/acp/mod.rs at all.

For the record, this is not duplicate work: the earlier item that emitted structured tool events landed only the internal AkhMessage variants and the ToolExecutionTracker that produces them. The ACP translation layer was never written, so the premise of this work item is correct.

CI green is not a signal here: .solstice/job.sh runs only cargo check -p seshat and never builds the root crate where src/message.rs lives.

Full remediation detail is in the work item description.

**Review verdict: BLOCK — the branch does not compile, and it does not implement the work item.** The entire diff is three lines in `src/message.rs`: a new `duration_ms: Option<u64>` field on `AkhMessage::ToolCallCompleted`. Adding that field without updating its match and construction sites breaks the build — `cargo check --features server` at `bf8377aa` fails with 7 errors (E0027 ×4, E0063 ×3). More importantly, the actual bug is untouched. `to_session_update()` at `src/acp/mod.rs:1294-1331` still converts both `ToolCallStarted` and `ToolCallCompleted` into `SessionUpdate::AgentThoughtChunk` prose. That stub *is* the work item, and this PR does not modify `src/acp/mod.rs` at all. For the record, this is not duplicate work: the earlier item that emitted structured tool events landed only the internal `AkhMessage` variants and the `ToolExecutionTracker` that produces them. The ACP translation layer was never written, so the premise of this work item is correct. CI green is not a signal here: `.solstice/job.sh` runs only `cargo check -p seshat` and never builds the root crate where `src/message.rs` lives. Full remediation detail is in the work item description.
toasterson force-pushed claude/wi-019fbe82-the-akh-emits-tool-activity-as-prose-in from bf8377aaad
All checks were successful
CI / publish-chart (pull_request) Successful in 9m21s
CI / check-seshat (pull_request) Successful in 10m51s
CI / check-seshat (push) Successful in 10m51s
CI / publish-chart (push) Successful in 3m45s
CI / docker-seshd (pull_request) Successful in 15m40s
CI / docker-seshd (push) Successful in 10m4s
to e506acf4bd
All checks were successful
CI / publish-chart (pull_request) Successful in 10m36s
CI / publish-chart (push) Successful in 20m3s
CI / check-seshat (pull_request) Successful in 22m4s
CI / check-seshat (push) Successful in 22m18s
CI / docker-seshd (pull_request) Successful in 30m24s
CI / docker-seshd (push) Successful in 30m51s
2026-08-07 22:40:38 +00:00
Compare
Emit native ACP tool lifecycle events
All checks were successful
CI / publish-chart (pull_request) Successful in 22m28s
CI / publish-chart (push) Successful in 22m33s
CI / check-seshat (push) Successful in 23m19s
CI / check-seshat (pull_request) Successful in 23m18s
CI / docker-seshd (pull_request) Successful in 38m39s
CI / docker-seshd (push) Successful in 38m50s
c879c7407f
All checks were successful
CI / publish-chart (pull_request) Successful in 22m28s
CI / publish-chart (push) Successful in 22m33s
CI / check-seshat (push) Successful in 23m19s
CI / check-seshat (pull_request) Successful in 23m18s
CI / docker-seshd (pull_request) Successful in 38m39s
CI / docker-seshd (push) Successful in 38m50s
This pull request has changes conflicting with the target branch.
  • src/acp/mod.rs
View command line instructions

Manual merge helper

Use this merge commit message when completing the merge manually.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin claude/wi-019fbe82-the-akh-emits-tool-activity-as-prose-in:claude/wi-019fbe82-the-akh-emits-tool-activity-as-prose-in
git switch claude/wi-019fbe82-the-akh-emits-tool-activity-as-prose-in

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch main
git merge --no-ff claude/wi-019fbe82-the-akh-emits-tool-activity-as-prose-in
git switch claude/wi-019fbe82-the-akh-emits-tool-activity-as-prose-in
git rebase main
git switch main
git merge --ff-only claude/wi-019fbe82-the-akh-emits-tool-activity-as-prose-in
git switch claude/wi-019fbe82-the-akh-emits-tool-activity-as-prose-in
git rebase main
git switch main
git merge --no-ff claude/wi-019fbe82-the-akh-emits-tool-activity-as-prose-in
git switch main
git merge --squash claude/wi-019fbe82-the-akh-emits-tool-activity-as-prose-in
git switch main
git merge --ff-only claude/wi-019fbe82-the-akh-emits-tool-activity-as-prose-in
git switch main
git merge claude/wi-019fbe82-the-akh-emits-tool-activity-as-prose-in
git push origin main
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
toasterson/akh-medu!295
No description provided.