Skip to content

[BUG]: A built agent streams under the id it began with, and a second stream starts cancelled #790

Description

@justintime4tea

Summary

Since PR #719 (#628), an Agent is one run of a PreparedAgent: begin_run creates the run's RunContext, with its id and cancel token, before anything streams. StreamingAgent::stream on that Agent then misbehaves in two ways.

  • It ignores the id it is given. The run keeps the id begin_run gave it, and a different request_id passed to stream is only logged at debug. build_streaming_agent begins the run with config.request_id, which defaults to "". Built without one and streamed under "req_123", as the streaming.rs usage example does, the hook key, MCP in-flight tracking and approvals are all keyed by "". cancel_and_close_mcp("req_123") matches nothing, and two agents built that way share "" and can release each other's approvals.
  • A second stream reuses the run. The first AgentRun's drop guard cancels the run's token, so the second stream stops at its first hook. It also has no observer, since the event receiver went to the first stream, and it inherits whatever ids are left in the run's tool-call queue. Two concurrent calls on one Arc<dyn StreamingAgent> mix up tool_call_ids.

Before PR #719, each stream call made its own RunContext under the id it was given. No server path hits either case today: chat completions (and the standalone CLI through it), A2A and Slack all build per request with the id they stream under, and stream once. This is library API behavior.

Reported in the review of PR #719: #719 (comment) (items 1 and 2).

Reproduction

  1. Build with build_streaming_agent(&config, None), with config.request_id unset.
  2. Call agent.stream(query, vec![], RunOptions::default(), "req_123").await.
  3. The run's id is "": an approval it raises carries request_id: "", and agent.cancel_and_close_mcp("req_123", …) cancels nothing.
  4. Drop that AgentRun and call stream again on the same agent: the new stream ends at once, cancelled, and its events reach no observer.

Additional Context

Proposed fix, in crates/aura/src/builder.rs (impl StreamingAgent for Agent):

  • A request_id other than the run's returns a run whose stream yields one StreamError naming both ids, and runs nothing. The streaming.rs module example builds with the id it streams under.
  • A second StreamingAgent::stream on the same Agent fails the same way, tracked by a flag on Agent.
  • Only the trait method. The orchestrator re-streams one coordinator Agent through the inherent stream_chat_with_depth on transient retries (planning_stream_with_transient_retry). Park-mode workers use stream_chat_with_timeout with RunOptions::default(), which makes its own token. Neither is refused.
  • Tests in builder.rs's prepared_runs:
    • a mismatched id yields the error and runs nothing;
    • a second stream yields the error and leaves the first untouched;
    • the coordinator retry path still streams twice.

This is a stopgap. Dropping request_id from stream belongs to #780, whose runtime mints the run's id once and hands it to begin_run. #780 also makes the second-stream case moot for server paths, since the runtime streams each run once.

Searched Issues

  • No similar issues found

Code of Conduct

  • I agree to follow this project's Code of Conduct

Activity

  1. added a commit that references this issue on Oct 8, 2026
    aa3e3ba
  2. justintime4tea commented on Oct 8, 2026

    @justintime4tea
    CollaboratorAuthor

    Fixed in #797 (layer 3 of the #778 stack: #794, then #796, then #797), which closes this issue when it merges. It covers both halves here, plus the orchestration factory, which the run-id layer (#796) had given the same id mismatch, and adds StreamingAgent::run_id() so a caller can stream an agent built without an id. The "" default in the summary no longer applies once #796 lands: an agent built without a run id mints one, so two agents can't share "".

  3. added 6 commits that reference this issue on Oct 8, 2026
    4f5f612
    b063bad
    c339c83
    a42a20e
    c020de9
    a417f91
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions