Skip to content

feat(agents): opt-in terminal-only event delivery for runAgentTool - #2364

Merged
threepointone merged 5 commits into
mainfrom
feat/2298-agent-tool-terminal-only
Sep 26, 2026
Merged

threepointone merged 5 commits into
mainfrom
feat/2298-agent-tool-terminal-only

Conversation

@threepointone

@threepointone threepointone commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #2298.

Summary

Adds eventDelivery: "terminal" to runAgentTool. It is for headless parents that only need a child's result:

  • The parent forwards only lifecycle, progress and milestone events for the run, both live and on replay. Ordinary child chunks are skipped, but they still take a sequence number, so live and replay dedupe keys still match.
  • The child (Think or AIChatAgent) stops broadcasting its own stream chunks to its connections. It still stores its conversation, so getAgentToolChunks() and drill-in still work.
  • Results, summaries and structured output are unchanged.
  • Detached runs reject the option.

cf_agent_tool_runs gains an event_delivery column (schema version 12). #2305 also bumps to 12, so whichever merges second takes 13. interceptAgentToolBroadcast now returns the run id for content chunks, so the chat hosts can drop them.

Tests

packages/think/src/tests/agent-tools.test.ts, "eventDelivery: terminal (#2298)":

  • The parent's live and replayed events contain only lifecycle, progress and milestone frames.
  • Default delivery still forwards every chunk.
  • A detached run with terminal delivery is rejected.
  • A WebSocket client on the child receives chat chunks in full mode and none in terminal mode.

The three terminal-mode tests fail against main. The agents, Think and ai-chat suites pass. Docs: docs/agents/agent-tools.md.


Devin Review

@changeset-bot

changeset-bot Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d8b75dc

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
agents Minor
@cloudflare/think Minor
@cloudflare/ai-chat Minor
@cloudflare/agent-think Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@agent-think

agent-think Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

✅ agents import sizes: no significant changes (72061348 → d8b75dc7, workflow run)

devin-ai-integration[bot]

This comment was marked as resolved.

@pkg-pr-new

pkg-pr-new Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

agents

npm i https://pkg.pr.new/agents@2364

@cloudflare/ai-chat

npm i https://pkg.pr.new/@cloudflare/ai-chat@2364

@cloudflare/codemode

npm i https://pkg.pr.new/@cloudflare/codemode@2364

hono-agents

npm i https://pkg.pr.new/hono-agents@2364

@cloudflare/shell

npm i https://pkg.pr.new/@cloudflare/shell@2364

@cloudflare/think

npm i https://pkg.pr.new/@cloudflare/think@2364

@cloudflare/voice

npm i https://pkg.pr.new/@cloudflare/voice@2364

@cloudflare/worker-bundler

npm i https://pkg.pr.new/@cloudflare/worker-bundler@2364

commit: d8b75dc

@threepointone
threepointone force-pushed the feat/2298-agent-tool-terminal-only branch from 1c06f3f to 79e30d9 Compare September 25, 2026 08:25
@threepointone
threepointone changed the base branch from main to fix/2305-legacy-runfiber-completion September 25, 2026 08:25
devin-ai-integration[bot]

This comment was marked as resolved.

@threepointone

Copy link
Copy Markdown
Contributor Author

Stacked on #2363: both add a schema migration, so this one also raises CURRENT_SCHEMA_VERSION to 13. Merge #2363 first; I will then rebase this onto main.

devin-ai-integration[bot]

This comment was marked as resolved.

Base automatically changed from fix/2305-legacy-runfiber-completion to main September 26, 2026 07:01
threepointone and others added 5 commits September 26, 2026 08:02
…ld restarts (#2298)

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
… chunk reads fail

Co-authored-by: Cursor <cursoragent@cursor.com>

@devin-ai-integration devin-ai-integration Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

Newer findings are available below. Devin Review posted a newer report on this PR, in addition to the findings presented here.

Devin Review found 1 new potential issue.

Devin Review

Comment on lines +6968 to +6975
body: JSON.stringify({
type: AGENT_TOOL_MILESTONE_PART,
data: {
name: milestone.name,
sequence: milestone.sequence,
at: milestone.at,
...(milestone.data !== undefined ? { data: milestone.data } : {})
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Replayed milestones lose progress details

When a milestone reports a fraction, phase, or message, _broadcastAgentToolMilestones replays it without those fields. Fresh clients show an incomplete progress snapshot after reconnect.

Learn more

AgentToolProgressEmitter.report sends fraction, message, and phase with a live milestone. The child milestone ledger stores name, sequence, time, and optional custom data only. Synthesizing a replay frame from that ledger therefore discards the live progress fields; applyToRun reconstructs progress from fields in the frame.

Example: A child reports { milestone: 'indexed', fraction: 0.7, phase: 'indexing' }. The live parent shows 70% and 'indexing', but a new client replaying the milestone only sees its name.

Recommended fix: Persist the milestone's progress fields alongside its durable record and include them in replay frames, or restore the latest child progress snapshot separately when replaying.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

@threepointone
threepointone force-pushed the feat/2298-agent-tool-terminal-only branch from cf94a0e to d8b75dc Compare September 26, 2026 07:04

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Devin Review

Comment on lines +463 to +483
### Deliver only progress and the final result

By default, the parent forwards every chunk of the child's stream to its
clients, and the child broadcasts the same chunks to its own connections. When
nobody watches the child's text as it streams (for example, a server-side
pipeline that only reads the result), pass `eventDelivery: "terminal"`:

```ts
const result = await this.runAgentTool(ResearchAgent, {
input: { query: "Durable Objects" },
eventDelivery: "terminal"
});
```

The run still produces `started`, progress, milestone, and terminal
(`finished`, `error`, `aborted`, or `interrupted`) events, and the result,
summary, and output are unchanged. Ordinary child chunks are not forwarded to the
parent's clients, are not replayed on reconnect, and are not broadcast by the
child. The child still stores its own conversation, so `getAgentToolChunks()`
and drill-in continue to work. Detached runs do not support
`eventDelivery: "terminal"` and reject it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Sync the agent-tools guide upstream

The docs rules require a matching update in cloudflare-docs. Confirm its agent-tools page receives this new option and its delivery semantics.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

@threepointone
threepointone merged commit 5e0507e into main Sep 26, 2026
17 checks passed
@threepointone
threepointone deleted the feat/2298-agent-tool-terminal-only branch September 26, 2026 07:18
@github-actions github-actions Bot mentioned this pull request Sep 26, 2026
brandhaug added a commit to brandhaug/b2b-saas-starter that referenced this pull request Oct 5, 2026
## pnpm-workspace.yaml (default)

## Dependency Updates

| Package | From | To | Type |
| --- | --- | --- | --- |
| `agents` | 0.24.0 | 0.25.0 | minor |

## Release Notes

<details>
<summary><b>agents</b> (0.24.0 → 0.25.0)</summary>

### Minor Changes

- [#2005](cloudflare/agents#2005)
[`c2f7672`](cloudflare/agents@c2f7672)
Thanks [@<!---->cjol](https://github.com/cjol)! - Native RPC calls to
async Agent and Think methods now start lifecycle initialization first;
address Agents by name because raw IDs from `newUniqueId()` and
`idFromString()` now fail their first async RPC. See
[Lifecycle](https://github.com/cloudflare/agents/blob/main/docs/agents/lifecycle.md).

### Patch Changes

- [#2390](cloudflare/agents#2390)
[`c55ec80`](cloudflare/agents@c55ec80)
Thanks [@<!---->threepointone](https://github.com/threepointone)! -
Report a failed agent-tool child as failed even when it was evicted
before recording the failure. See [Agent
tools](https://github.com/cloudflare/agents/blob/main/docs/agents/agent-tools.md).

- [#2384](cloudflare/agents#2384)
[`f904999`](cloudflare/agents@f904999)
Thanks [@<!---->threepointone](https://github.com/threepointone)! - Fix
agent-tool chunks being duplicated or dropped on reconnect, child
re-attach, and fiber recovery. See [Agent
tools](https://github.com/cloudflare/agents/blob/main/docs/agents/agent-tools.md).

- [#2364](cloudflare/agents#2364)
[`5e0507e`](cloudflare/agents@5e0507e)
Thanks [@<!---->threepointone](https://github.com/threepointone)! - Add
`eventDelivery: "terminal"` to `runAgentTool` to forward only lifecycle,
progress, and milestone events for a run. See [Agent
tools](https://github.com/cloudflare/agents/blob/main/docs/agents/agent-tools.md).

- [#2448](cloudflare/agents#2448)
[`54f9ca7`](cloudflare/agents@54f9ca7)
Thanks [@<!---->aron-cf](https://github.com/aron-cf)!

…[full
notes](https://github.com/cloudflare/agents/releases/tag/agents%400.25.0)

</details>

---
*This PR was auto-generated by
[catalog-update-action](https://github.com/brandhaug/catalog-update-action).*

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
brandhaug added a commit to brandhaug/b2b-saas-starter that referenced this pull request Oct 5, 2026
## pnpm-workspace.yaml (default)

## Dependency Updates

| Package | From | To | Type |
| --- | --- | --- | --- |
| `@cloudflare/ai-chat` | 0.12.0 | 0.12.1 | patch |

## Release Notes

<details>
<summary><b>@<!---->cloudflare/ai-chat</b> (0.12.0 → 0.12.1)</summary>

### Patch Changes

- [#2390](cloudflare/agents#2390)
[`c55ec80`](cloudflare/agents@c55ec80)
Thanks [@<!---->threepointone](https://github.com/threepointone)! -
Report a failed agent-tool child as failed even when it was evicted
before recording the failure. See [Agent
tools](https://github.com/cloudflare/agents/blob/main/docs/agents/agent-tools.md).

- [#2384](cloudflare/agents#2384)
[`f904999`](cloudflare/agents@f904999)
Thanks [@<!---->threepointone](https://github.com/threepointone)! - Fix
agent-tool chunks being duplicated or dropped on reconnect, child
re-attach, and fiber recovery. See [Agent
tools](https://github.com/cloudflare/agents/blob/main/docs/agents/agent-tools.md).

- [#2364](cloudflare/agents#2364)
[`5e0507e`](cloudflare/agents@5e0507e)
Thanks [@<!---->threepointone](https://github.com/threepointone)! - Add
`eventDelivery: "terminal"` to `runAgentTool` to forward only lifecycle,
progress, and milestone events for a run. See [Agent
tools](https://github.com/cloudflare/agents/blob/main/docs/agents/agent-tools.md).

- [#2334](cloudflare/agents#2334)
[`7f564e7`](cloudflare/agents@7f564e7)
Thanks [@<!---->threepointone](https://github.com/threepointone)! - AI
Chat and Think send the terminal `done` frame after persisting and
broadcasting the assistant reply, so later sends are not overwritten.
See [Chat
agents](https://github.com/cloudflare/agents/blob/main/docs/agents/chat-agents.md).

- [#2352](cloudflare/agents#2352)
[`449ac27`](cloudflare/agents@449ac27)
Thanks [@<!---->threepointone](https://github.com/threepointone)! - Do
not start an automatic continuation after an

…[full
notes](https://github.com/cloudflare/agents/releases/tag/%40cloudflare/ai-chat%400.12.1)

</details>

---
*This PR was auto-generated by
[catalog-update-action](https://github.com/brandhaug/catalog-update-action).*

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
tombeckenham added a commit to tombeckenham/agents-tom that referenced this pull request Oct 7, 2026
Ports three upstream changes to the legacy AIChatAgent's agent-tool child
adapter onto AGUIChatAgent:

- cloudflare#2364: opt-in terminal-only event delivery. Runs started with
  eventDelivery: "terminal" are tracked (and persisted on the run row) so
  their chunks are stored but not broadcast, including after a restart.
- cloudflare#2384: seed a cold live sequence from the stored backlog before a tail
  attaches (replacing the post-drain realign), and
  inspectAgentToolRun(runId, { reconcile: false }).
- cloudflare#2390: record a run's stream error on its open row so a stale-row
  reconcile after eviction reports error. The engine sends no error frame
  for an in-band RUN_ERROR, so that path records it directly.

The test worker's unported() casts for _agentToolTerminalOnlyRuns and the
inspectAgentToolRun options are replaced with the real members, and its
finalize gate moves to _saveAGUIMessages, which is what the engine's
agent-tool lifecycle calls.
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.

runAgentTool: opt-in terminal-only event delivery so a headless parent does not rebroadcast every child chunk

2 participants