Skip to content

fix(ai-orchestration): observe agentStream output before draining#986

Open
tombeckenham wants to merge 1 commit into
TanStack:taren/workflow-orchestration-rfcfrom
tombeckenham:tom/fix-agentstream-unhandled-rejection
Open

fix(ai-orchestration): observe agentStream output before draining#986
tombeckenham wants to merge 1 commit into
TanStack:taren/workflow-orchestration-rfcfrom
tombeckenham:tom/fix-agentstream-unhandled-rejection

Conversation

@tombeckenham

Copy link
Copy Markdown
Contributor

🎯 Changes

Targets #979's branch, not main.

executeAgent awaited drainAgentStream() before result.output. When the stream fails, drain throws and the already-in-flight output promise is never observed — leaving a rejected promise unhandled. Under Node's default --unhandled-rejections=throw that terminates the worker, so an ordinary model error took down the process in addition to correctly failing the step.

Reproduced against the real workflow-core runtime before fixing:

unhandled rejections: 1 [ 'Error: output never observed' ]
events: [ 'RUN_STARTED', 'STEP_STARTED', 'STEP_FAILED', 'RUN_ERRORED' ]

The fix attaches a no-op catch to output as soon as the result is recognized, then awaits it after draining. Behaviour on the success path is unchanged.

Also adds the first test coverage for agentStream() — it was exported from index.ts but had no unit or E2E exercise, which is why this path went unnoticed. The test asserts both halves: the step fails with AgentStreamError, and no unhandled rejection escapes. Verified it fails without the source change.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm run test:pr.

🚀 Release Impact

  • This change is docs/CI/dev-only (no release).

@tanstack/ai-orchestration is still unreleased (0.0.0) and #979 already carries a minor changeset introducing the package. This fixes code from that same unreleased changeset, so a second changeset would only add noise. Happy to add one if you'd rather it be itemised.

`executeAgent` awaited `drainAgentStream()` before `result.output`. When the
stream failed, drain threw and the already-in-flight `output` promise was
never observed, leaving a rejected promise unhandled. Under Node's default
`--unhandled-rejections=throw` that terminates the worker — so an ordinary
model error took down the process in addition to failing the step.

Attach a no-op catch to `output` as soon as the result is recognized, then
await it after draining.

Adds the first coverage for `agentStream()`, asserting both that the step
fails with `AgentStreamError` and that no unhandled rejection escapes.
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a86acdaf-962f-44d0-84d8-5e16ad8f6dc2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@tombeckenham tombeckenham added the waiting-on: maintainer The ball is in the maintainers’ court label Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting-on: maintainer The ball is in the maintainers’ court

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants