Skip to content

Stream agent investigate turn by turn - #39

Merged
shipmill-romamo[bot] merged 3 commits into
mainfrom
feat/agent-stream
Oct 9, 2026
Merged

shipmill-romamo[bot] merged 3 commits into
mainfrom
feat/agent-stream

Conversation

@romamo

@romamo romamo commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator

What

  • investigation_events() is the loop as a generator of Turn (the model's words, how many tools it called) and Called (the step and the tool's result); investigate() drains it, unchanged for callers
  • agent investigate is a treaty streaming command: one line per turn, one per call (effect: created when it wrote a decision), the saved record last (kind: investigation), then the end line with meta.effects. --no-stream gives every event in one envelope; failures still end the stream with exit 92 or 93, after the saved record

Why

The hosted hackathon demo shows the agent working as it happens. It also makes the CLI watchable.

Contract change

agent investigate is unreleased, so its output changes before anyone depends on it: the record moved from data.investigation to the kind: investigation event.

Checks

  • uv run pytest: 396 passed (CLI tests read the stream; a new test checks the order turn, call, turn, investigation and the end line)
  • uv run ruff check ., uv run mypy: clean
  • Live: Super against the replayed disk-full incident streamed 12 events over about 7 seconds

🤖 Generated with Claude Code

https://claude.ai/code/session_01APTdZZw8Jw9PQF4TD55wMv

The loop is now a generator of turns and tool calls; investigate()
drains it. The command streams one event per turn and per call, then the
saved record, so a watcher sees the agent work as it happens. --no-stream
returns all events in one envelope.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01APTdZZw8Jw9PQF4TD55wMv
shipmill-romamo Bot and others added 2 commits October 8, 2026 23:53
The error line of a streamed agent investigate holds no data: the record
is the event of kind investigation just before it. The exit code's
description and suggestion still sent the reader to data.investigation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep both Unreleased entries; the stream's entry names rc38's line shape.
The tests read bare event lines with _seq and the _summary end line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@shipmill-romamo

Copy link
Copy Markdown
Contributor

@romamo Decision needed: the stream can lose the investigation record. Should #39 merge before that's fixed?

Review result: MERGE AFTER SMALL FIX, with one regression left open. Pushed to the branch as fast-forwards, with no rewrite:

  • 9347341: the exit 93 description and suggestion said "read data.investigation.spec.steps". The error line has no data now, because the record is on the line before it (kind: investigation). This commit fixes that and adds the first CLI test of the exit 93 path
  • ea0c0a3: merges main after Require a person at a terminal to approve a decision #37 (treaty rc38). The tests read rc38's bare lines with _seq and the _summary end line, and the CHANGELOG entry describes that shape. The handler needed no change. 405 tests pass locally

The regression. Start cloudfall agent investigate ... and close its stdout mid-run, for example piping into a reader that exits early. The decision already proposed stays on disk, but no investigation record is saved, and the command exits 0. On main the same run keeps the record. This was reproduced on the branch and on main. A proper fix has two parts: the generator returns its record when it's closed, and the record gets a new status (say stopped) in the schema. The status is a stored-state change.

  1. Merge now and file the regression as its own issue (recommended): agent investigate hasn't been released, the demo needs the stream, and the record status gets designed on the issue
  2. Hold Stream agent investigate turn by turn #39 until it's fixed in this PR, with a stopped status in the investigation record schema
  3. Hold Stream agent investigate turn by turn #39 and fix it without a schema change: when the reader goes away, save the record with its current status and exit non-zero

Reply here with a number or your own answer; shipmill takes this up on the tick after your reply.

@shipmill-romamo shipmill-romamo Bot added the needs-decision A shipmill session asked a question here; waits for a reply label Oct 8, 2026
@romamo

romamo commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

Decision by @romamo, given in chat; posted by Claude on his behalf.

Merge #39 now, before the regression is fixed. The lost investigation record when stdout closes mid-run is fixed in a follow-up.

@shipmill-romamo shipmill-romamo Bot removed the needs-decision A shipmill session asked a question here; waits for a reply label Oct 9, 2026
@shipmill-romamo
shipmill-romamo Bot merged commit ef7b4b5 into main Oct 9, 2026
1 check passed
@shipmill-romamo
shipmill-romamo Bot deleted the feat/agent-stream branch October 9, 2026 08:13
shipmill-romamo Bot added a commit that referenced this pull request Oct 9, 2026
Since agent investigate streams (PR #39), a reader closing stdout mid-run
left the decisions the model proposed without the investigation that made
them, and the command exited 0: treaty closes the handler's generator on
a broken pipe and ends a stream that delivered an event with exit 0.

investigation_events now returns the investigation so far, ended with the
new status stopped, when it is closed, and the handler saves it before
re-raising GeneratorExit, so nothing more reaches the dead stdout. treaty
gives the handler no say in the exit code of a closed output, so the
handler sets cloudfall.app.stream_stopped and cloudfall.cli turns treaty's
0 or 141 into 94 INVESTIGATION_STOPPED. A signal or a timeout keeps its
own exit code; --no-stream is unchanged.

Fixes #44

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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