feat(ai-sdk): stream tool outputs for async generator handlers - #1981
Merged
dinwwwh merged 1 commit intoSep 4, 2026
Merged
Conversation
Add isAsyncGeneratorFunction to @orpc/shared and use it in createToolFactory as a fallback when the output schema is not an asyncIteratorObject, so async function* handlers stream preliminary results even without a schema.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Contributor
More templates
@orpc/ai-sdk
@orpc/arktype
@orpc/bun
@orpc/client
@orpc/cloudflare
@orpc/contract
@orpc/experimental-effect
@orpc/evlog
@orpc/hibernation
@orpc/json-schema
@orpc/experimental-msw
@orpc/nest
@orpc/next
@orpc/node
@orpc/openapi
@orpc/opentelemetry
@orpc/pinia-colada
@orpc/pino
@orpc/publisher
@orpc/ratelimit
@orpc/server
@orpc/shared
@orpc/swr
@orpc/tanstack-query
@orpc/trpc
@orpc/valibot
@orpc/zod
commit: |
Contributor
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — Reviewed the full single-commit diff of feat(ai-sdk): stream tool outputs for async generator handlers (features, tests, type tests, and docs).
isAsyncGeneratorFunctionin@orpc/shared— detects nativeasync function*handlers via the built-in constructor; correctly handles bound functions and async generator methods, and excludes sync generators, plain async functions, and iterator values (the(async function* () {})()case).createToolFactorystreaming fallback —isIteratorOutputnow also fires when the procedure handler is an async generator, so schema-less (andtype<AsyncIteratorObject<...>>()-schematized) async generator handlers stream each event through the existingyield* await call(...)path instead of returning the raw iterator. Contract-basedimplementToolFactoryis untouched.- Tests — streaming tests genuinely fail without the fix (
for awaitover the old Promise-returningexecutethrows "not async iterable", verified empirically), and the non-generator test guards against over-broad detection. ThegetIteratorYieldSchemas(...)branch and the handler fallback are independently exercised. - Type test — pins
InferToolOutputto the yield type for a schema-less async generator handler, matching the new runtime behavior. - Docs — the Streaming Tool Outputs sentence now names the
async function*path.
Verified: affected unit tests pass, tsc -b (incl. .test-d.ts) passes, and eslint on the changed files is clean.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

createToolFactorynow streams tool outputs whenever the procedure handler is anasync function*, not only when the output schema is built withasyncIteratorObject. Previously a schema-less async generator handler (or one paired with atype<AsyncIteratorObject<...>>()schema) returned the iterator object as the tool result instead of streaming preliminary results, even though the inferred tool output type was already the yield type.The detection lives in
@orpc/sharedasisAsyncGeneratorFunction, so other packages can reuse it.Fixes
asyncIteratorObjectoutput schema. Runtime behavior now matches the inferredInferToolOutputtype.asynchandlers that happen to return an iterator are unchanged.Testing
isAsyncGeneratorFunction(bound functions and async generator methods included, sync generators and plain async functions excluded).asyncIteratorObjectschema, and no streaming for a non-generator handler returning an iterator. Type test covers the schema-less yield type inference.async function*path.