Commit 98979f7
feat: streaming structured output across openai/openrouter/grok/groq + summarize fix (TanStack#527)
* feat(ai): streaming structured output (chat outputSchema + stream:true)
Adds an optional `structuredOutputStream` method to the `TextAdapter` interface
plus the activity-layer wiring so `chat({ outputSchema, stream: true })` returns
a typed `StructuredOutputStream<T>`. The stream yields raw JSON deltas via the
existing TEXT_MESSAGE_* lifecycle and terminates with a CUSTOM
`structured-output.complete` event whose `value` is `{ object, raw, reasoning? }`.
Adapters that don't implement `structuredOutputStream` natively fall back to
`fallbackStructuredOutputStream`, which wraps the non-streaming
`structuredOutput()` call so consumers see a consistent lifecycle on every
adapter. With tools, the activity layer runs the agent loop, drops its
RUN_STARTED/RUN_FINISHED, and lets the structured stream bracket the run.
`TextActivityResult` uses `[TStream] extends [true]` (not bare `TStream extends true`)
so the default `boolean` value of `TStream` does *not* match the streaming branch.
This fixes TanStack#526 where `chat({ outputSchema })` typed as a stream while the
runtime returned a Promise.
Native streaming structured output for each provider lands in follow-up
commits via a centralised lift into @tanstack/openai-base.
* feat(openai-base): centralised structuredOutputStream + isAbortError hook
Adds `structuredOutputStream` to both `OpenAICompatibleChatCompletionsTextAdapter`
and `OpenAICompatibleResponsesTextAdapter`. Chat Completions issues a single
request with `response_format: json_schema` + `stream: true`; Responses uses
`text.format: json_schema` + `stream: true`. Subclasses inherit the method β
reasoning lifecycle flows through the existing `extractReasoning` hook (Chat
Completions) or Responses-API event-type discrimination (Responses), and the
final parsed JSON runs through the existing `transformStructuredOutput` hook.
Subclass changes:
- ai-groq: new `extractReasoning` override reading `delta.reasoning` /
`delta.reasoning_content` so Groq reasoning models stream reasoning under
the centralised path. (ai-groq's existing `processStreamChunks` override
only fires on the chatStream path; the new structuredOutputStream
independently captures usage from `chunk.x_groq?.usage` outside the
`choices[0]` guard.)
- ai-grok: new `extractReasoning` override for xAI's `reasoning_content` /
`reasoning` convention.
- ai-openrouter: new `isAbortError` override mapping `RequestAbortedError`
from `@openrouter/sdk` to `RUN_ERROR { code: 'aborted' }`. Existing
`extractReasoning` (`_reasoningText` on adapted chunks) and
`transformStructuredOutput` (identity, preserves nulls) overrides apply
to the new path unchanged.
Net deletion: ~1k LOC of per-adapter structuredOutputStream implementations
(landed in prior commit but never reached production) collapse into ~330 LOC
in the chat-completions base + ~340 LOC in the responses base.
* fix(openai-base): tighten structuredOutputStream conditionals for eslint
Drop dead `hasEmittedTextMessageEnd` flag (only set, never read), unwrap
unneeded `?.` on `chunk.choices[0]` (type already nullable), and remove
`?? 0` fallbacks on SDK-typed numeric usage fields.
* refactor: drop \`as unknown as\` from streaming structured-output paths
Replace \`as unknown as StreamChunk\` casts in fallbackStructuredOutputStream
and runStreamingStructuredOutputImpl with \`satisfies StreamChunk\` on
EventType-enum-tagged event literals (the AG-UI types tag \`.type\` with
\`EventType.*\` enum values, not string literals β so import \`EventType\`
and use it).
The custom-event narrow now uses the existing \`isStructuredOutputCompleteEvent\`
type guard instead of an inline shape check + cast, which lets the inner
\`value\` reference drop its \`as { object; raw; reasoning? }\` cast.
In openai-base, the request-cleanup destructures now operate on the SDK's
typed params directly (the OpenAI SDK types are well-formed enough to
spread without coercing to \`Record<string, unknown>\` first).
* fix(openai-base): align structuredOutputStream with TanStack#545 asChunk cleanup
chatStream path. The structuredOutputStream lift on this branch was emitting
those events without \`threadId\`; the new \`satisfies StreamChunk\` checks now
catch it. Plumb \`threadId\` through structuredOutputStream's aguiState in
both bases.
Also drop the residual \`asChunk()\` wrappers in my structuredOutputStream
yields and use \`type: EventType.X, ... } satisfies StreamChunk\` directly,
matching TanStack#545's new convention.
While we're here: the chat-completions \`processStreamChunks\` finalisation
forwards the SDK's \`finish_reason\` directly into \`RUN_FINISHED.finishReason\`,
but the SDK type still includes the legacy \`function_call\` value that AG-UI
doesn't accept. TanStack#545's \`satisfies\` cleanup exposed the mismatch β collapse
\`function_call\` to \`stop\` alongside the existing orphan \`tool_calls\` collapse.
* ci: apply automated fixes
* fix: align structured streaming with 543 openai-base + port to ai-openrouter
After rebasing onto TanStack#543 (openai-base adopts the openai SDK directly and
decouples ai-openrouter), wire the structured-output stream to the SDK
client and re-implement it inside ai-openrouter:
- openai-base: call `this.client.chat.completions.create` /
`this.client.responses.create` directly instead of the removed
`callChatCompletion*` / `callResponse*` abstract hooks; drop the
defensive cast on `response.completed` now that `chunk.response`
narrows via the SDK's `ResponseStreamEvent` union.
- ai-openrouter: add `structuredOutputStream` mirroring the openai-base
implementation, adapted to OpenRouter's camelCase wire shape
(`responseFormat` / `streamOptions: { includeUsage: true }`) and SDK
call surface (`orClient.chat.send({ chatRequest })`). Maps both DOM
`AbortError` and SDK `RequestAbortedError` to `RUN_ERROR { code: 'aborted' }`.
- ai-grok / ai-groq: switch to the canonical
`OpenAI.Chat.Completions.ChatCompletionChunk` namespace form (ai-grok
was importing a non-existent re-export from `@tanstack/openai-base`).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(ai-openrouter): structuredOutputStream for Responses (beta) adapter
Adds streaming structured output to `OpenRouterResponsesTextAdapter` for
parity with the chat-completions variant and the openai-base Responses
adapter. Single call to `beta.responses.send` with
`text.format: { type: 'json_schema', strict: true }` + `stream: true`;
events flow through the existing `normalizeStreamEvent` so the canonical
shape matches `processStreamChunks` (including the Speakeasy
UNKNOWN-with-`raw` fallback for events that fail strict per-variant
validation upstream).
Adaptations vs the openai-base port: camelCase usage shape
(`inputTokens`/`outputTokens`/`totalTokens`) on `response.completed`,
both `response.failed` and `response.incomplete` treated as terminal
RUN_ERROR (matching `processStreamChunks`), SSE-level `error` event also
surfaced as RUN_ERROR, and inline abort detection for
`RequestAbortedError` / `AbortError` β `code: 'aborted'`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat: openai Chat Completions adapter + summarize streaming fix + example wiring
Packages
- ai-openai: add openaiChatCompletions / OpenAIChatCompletionsTextAdapter
sibling to the existing Responses adapter. Thin subclass of
OpenAIBaseChatCompletionsTextAdapter so callers can pick the older
/v1/chat/completions wire format against the OpenAI SDK.
- ai: ChatStreamSummarizeAdapter.summarizeStream now accumulates summary
text and emits a terminal CUSTOM { name: 'generation:result' } event
before passing RUN_FINISHED through. Fixes useSummarize never populating
result in connection/server-fn streaming modes β GenerationClient only
sets result on that specific CUSTOM event.
ts-react-chat example
- Structured Output menu: drop the misleading '(OpenRouter)' suffix from
the sidebar entry; relabel the OpenAI option as 'OpenAI (Responses)';
add 'OpenAI (Chat Completions)' and 'OpenRouter (Responses beta)' so
the page exposes all four wire-format combinations end-to-end.
- Summarize page: add a model picker (gpt-4o-mini through gpt-5.2) wired
through to the API route and both server-fns. Drop the hard-coded
maxLength: 200 which on Responses-API reasoning models gets the whole
max_output_tokens budget consumed by hidden reasoning; the style
instruction in the prompt already drives length. Live-render
TEXT_MESSAGE_CONTENT deltas via onChunk so streaming mode is visibly
streaming rather than appearing identical to direct.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ci: apply automated fixes
* refactor(ai-openrouter): drop casts and `satisfies StreamChunk` from structured-output streams
Address PR TanStack#527 review feedback from @AlemTuzlak (3 comments on
responses-text.ts, 1 on text.ts, 2 on activities/chat/index.ts):
- ai-openrouter/responses-text.ts (`structuredOutputStream`):
- Drop `(await this.orClient.beta.responses.send(...)) as AsyncIterable<StreamEvents>` β
`EventStream<T>` already extends `AsyncIterable<T>`.
- Drop `as ResponsesRequest['text']` on the inner `text` object β the SDK's
request type accepts the literal shape directly.
- Drop inline `(chunk as { ... }).delta` / `(chunk.response ?? {}) as {...}` casts.
`NormalizedStreamEvent` already types `delta` and `response`; the existing
`processStreamChunks` reads the same fields without casts.
- Drop redundant `satisfies StreamChunk` (20Γ). The `AsyncIterable<StreamChunk>` /
`Generator<StreamChunk>` return types already validate every yield site via
contextual typing.
- ai-openrouter/text.ts (`structuredOutputStream`):
- Drop `(await this.orClient.chat.send(...)) as AsyncIterable<ChatStreamChunk>`.
- Drop redundant `satisfies StreamChunk` (17Γ).
- ai/activities/chat/index.ts:
- Replace `{ chatOptions: TextOptions<any, any>; outputSchema: any }` parameter
on `fallbackStructuredOutputStream` with `StructuredOutputOptions<Record<string,
unknown>>` β the adapter-side type already exists.
- Drop `(adapter as { provider?: string }).provider ?? adapter.name` in the
structured-stream logger. `provider` is not a `TextAdapter` field; `adapter.name`
is the canonical provider identifier.
- Drop redundant `satisfies StreamChunk` / `satisfies StructuredOutputCompleteEvent`
(8Γ) in `fallbackStructuredOutputStream` and `runStreamingStructuredOutputImpl`.
- ai/tests/chat-result-types.test.ts (new):
- Add type-only regression test for `TextActivityResult`. Pins each
`(outputSchema?, stream?)` combination so TanStack#526's streaming-structured-output
branch can't silently regress to a Promise (or vice versa).
* Removed satisfies StreamChunk
* refactor(ai): drop `as unknown as` casts in chat() dispatch
Use narrowed locals (`outputSchema`, `stream`) and explicit `outputSchema: undefined` overrides instead of double-casting `options` through `unknown`. The trailing `as TextActivityResult<TSchema, TStream>` stays β TS narrows value types from runtime guards but not generic type parameters, so the conditional return type can't be reduced from inside a branch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ci: apply automated fixes
* docs(ai): document streaming structured output in skill + chat docs
Cover chat({ outputSchema, stream: true }) in docs/chat/structured-outputs.md
and the ai-core/structured-outputs skill: StructuredOutputStream<T> return
type, isStructuredOutputCompleteEvent example, structured-output.complete
event shape, per-adapter coverage (native vs. fallback), and a HIGH common
mistake against parsing partial JSON deltas. Adds a cross-ref from the skill
to ai-core/chat-experience.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* ci: apply automated fixes
* feat(ai): tag custom events in StructuredOutputStream + debug-log chunks in structuredOutputStream
Public `StructuredOutputStream<T>` is now a discriminated union over three
tagged CUSTOM variants: `structured-output.complete<T>`, `approval-requested`,
and `tool-input-available`. Each has a literal `name` and typed `value`, so
`chunk.type === 'CUSTOM' && chunk.name === '<literal>'` narrows directly to
the exact shape β no `isStructuredOutputCompleteEvent` helper or cast needed.
The bare CustomEvent is excluded from the union (its `value: any` would
collapse the narrow to `any`); user-emitted events via the `emitCustomEvent`
API still flow at runtime as a documented residual gap.
New exports from @tanstack/ai: `ApprovalRequestedEvent`,
`ToolInputAvailableEvent`. The `isStructuredOutputCompleteEvent` helper is
removed (this overload is new in this PR β no shipped consumers).
Per-chunk `logger.provider(...)` debug logging added inside
`structuredOutputStream` for the four affected adapters (openai-base
chat-completions + responses, ai-openrouter text + responses-text), matching
the existing pattern in `chatStream` for end-to-end introspection in debug
mode. ai-openrouter uses `finishReason` (camelCase) consistent with the SDK
and the sibling chatStream logger; openai-base uses `finish_reason` per the
openai SDK shape.
Docs (`docs/chat/structured-outputs.md`) and the AI-core
`structured-outputs` SKILL.md updated to use the direct discriminated
narrow.
* chore: consolidate streaming-structured-output changesets into one
Merge the 10 changesets covering this PR (streaming structured output
across chat/grok/groq/openai/openai-base/openrouter, the openrouter
decoupling + narrowing, and the summarize subsystem unification) into a
single `.changeset/streaming-structured-output.md` with the union of
version bumps. The body retains every meaningful section from the
originals (core, openai-base, provider adapters, openrouter decoupling,
summarize) and adds the tagged-CustomEvent type design from the previous
commit.
* chore: scaffold .agent/self-learning pile with build-before-examples lesson
Initial scaffold of `.agent/self-learning/` for the self-improve plugin
(INDEX.md, config.yml, curation-state.yml, coupling.json, .gitignore,
`lessons/promoted/`). Captures the first repo-scoped lesson:
`2026-05-14-build-before-running-examples.md` β run
`pnpm -w run build:all` before starting any example dev server so the
workspace packages have `dist/` outputs vite can resolve.
* ci: apply automated fixes
* docs: streaming structured output with tools + OpenAI Chat Completions adapter
docs/chat/structured-outputs.md
Add "Streaming with tools that may pause" subsection covering the
approval-requested / tool-input-available tagged variants the agent
loop can emit before structured-output.complete. Code example shows
the narrowing pattern for all three CUSTOM variants. Cross-links the
Tool Approval Flow and Client Tools pages.
docs/adapters/openai.md
Add "Chat Completions API" section after Basic Usage covering the new
openaiChatCompletions / createOpenaiChatCompletions factories β when
to pick Chat Completions vs. Responses (reasoning-summary streaming,
wire-format compatibility), code example, and a link to the Structured
Outputs page for the streaming case. API Reference at the bottom now
includes both factories.
* docs(chat/structured-outputs): lead with client+server flow, demote manual iteration to advanced
The previous streaming section opened with \`for await (const chunk of stream)\`
β that's the advanced/server-side-only path. The typical use case is a UI
streaming JSON deltas through SSE from a server endpoint, and the docs should
lead with it.
- New "Server endpoint" subsection: \`chat({outputSchema, stream: true})\` +
\`toServerSentEventsResponse(stream)\`. One short example, no ceremony.
- New "Client with useChat" subsection: \`useChat\` + \`fetchServerSentEvents\`
+ \`onChunk\`, with \`parsePartialJSON\` driving progressive UI. Shows where
the validated object lives (the terminal \`structured-output.complete\` event,
typed as \`T\` via the schema). Notes Vue/Solid/Svelte share the shape.
- "What the stream contains" + "Adapter coverage" tables retained verbatim.
- Old standalone \`for await\` example moved to a new "Advanced: iterating the
stream directly" subsection at the end, framed as the path for Node scripts,
CLIs, server-only flows, and tests.
- "Streaming with tools that may pause" reframed to use the \`onChunk\` signature
(matching the new primary path); a note points back to the advanced section
for callers iterating the stream directly.
* feat(ai-react): useChat managed partial/final for structured-output streaming
Pass the same schema you give chat() on the server to useChat() on the
client, and the hook tracks the progressive object and the validated
terminal payload for you β no external useState, no onChunk ceremony, no
parsePartialJSON calls in user code.
API:
const { sendMessage, isLoading, partial, final } = useChat({
connection: fetchServerSentEvents("/api/extract"),
outputSchema: PersonSchema,
})
// partial: DeepPartial<Person> β updates per TEXT_MESSAGE_CONTENT delta
// final: Person | null β snaps on structured-output.complete
Implementation:
- New generic param TSchema extends SchemaInput | undefined = undefined on
UseChatOptions / UseChatReturn / useChat.
- UseChatReturn is conditional on TSchema: when supplied, adds typed
partial/final; when undefined (default), return is unchanged. Inferred
automatically from outputSchema option.
- Internal onChunk handler tracks raw JSON buffer via ref, runs
parsePartialJSON on each TEXT_MESSAGE_CONTENT delta, snaps final on the
terminal CUSTOM structured-output.complete event, resets all three on
RUN_STARTED. User's own onChunk callback still fires after internal
processing β both compose.
- DeepPartial<T> exported for handlers that need to annotate.
The schema is used purely for client-side type inference; server-side
validation still runs against the schema passed to chat({ outputSchema })
on the server route. Works identically for non-streaming endpoints β for
those, partial stays {} and final populates when the single terminal
event arrives.
Type-level tests (tests/use-chat-types.test.ts) pin both branches of the
discriminated return type β useChat() without outputSchema rejects access
to partial/final via @ts-expect-error, useChat() with outputSchema asserts
typed DeepPartial<Person> / Person | null.
* ci: apply automated fixes
* feat(ai-vue, ai-solid, ai-svelte): mirror useChat outputSchema/partial/final
Apply the same schema-driven structured-output API that landed in
@tanstack/ai-react to the other three framework hooks. Same options shape
(`outputSchema?: TSchema`), same discriminated return type, identical
runtime behavior β only the reactivity primitive differs per framework.
Reactivity primitives:
Vue β `Readonly<ShallowRef<DeepPartial<T>>>` / `Readonly<ShallowRef<T | null>>`
Solid β `Accessor<DeepPartial<T>>` / `Accessor<T | null>`
Svelte β `readonly partial: DeepPartial<T>` / `readonly final: T | null`
(rune-backed getters)
Each hook is now generic on `TSchema extends SchemaInput | undefined`,
inferred from the `outputSchema` option. When omitted (default), the
return type is byte-identical to before; when supplied, `partial`/`final`
are added via a conditional `UseChatReturn<TTools, TSchema>` /
`CreateChatReturn<TTools, TSchema>`. The internal onChunk handler is the
same in all four β RUN_STARTED resets, TEXT_MESSAGE_CONTENT accumulates +
parses, CUSTOM structured-output.complete snaps final. User onChunk is
still invoked after the internal pass.
DeepPartial<T> is exported from each framework package.
Type-level tests in each package pin both branches of the discriminated
return type, mirroring the React variant β pure types, no renderer
required. Existing test suites pass on all three packages:
ai-vue: 93 tests pass
ai-solid: 103 tests pass
ai-svelte: 56 tests pass
* docs: structured-outputs cross-framework + rendering reasoning/tool-calls
- structured-outputs.md "Client with useChat" section: add a "Rendering
reasoning and tool calls" subsection explaining that those land on
messages[β¦].parts (ThinkingPart, ToolCallPart, ToolResultPart) just
like normal chat β no separate hook fields. Includes a render snippet
showing how to hide the raw-JSON TextPart and let the structured view
(partial/final) replace it.
- Note that useChat (React/Vue/Solid) and createChat (Svelte) all accept
the same outputSchema option with the same semantics β only the
reactivity primitive differs.
- Changeset: bump @tanstack/ai-vue, @tanstack/ai-solid, @tanstack/ai-svelte
to minor alongside @tanstack/ai-react. Replaced the "React" section with
a unified "Framework hooks" section covering all four packages and
documenting the per-framework reactivity types.
* ci: apply automated fixes
* docs(structured-outputs): fix 'with tools that may pause' to use real APIs
The previous draft of the streaming-with-tools-that-may-pause subsection
invented showApprovalPrompt / runClientTool / resumeWithToolResult
helpers. The actual flow uses the standard chat APIs, identical to a
non-structured chat:
- Server tools with needsApproval:true land on messages[...].parts as
ToolCallPart with state === 'approval-requested'. Render approval UI
from messages, respond via addToolApprovalResponse({ id, approved })
from the hook return (see docs/tools/tool-approval).
- Client tools with execute() set run automatically via the
ChatClient's onToolCall handler (chat-client.ts:198-233). For manual
handling, use addToolResult({ toolCallId, tool, output, state }) β
see docs/tools/client-tools.
Replaced the made-up code with a real example showing an approval-
gated tool inside a structured-output run, using addToolApprovalResponse
and rendering the prompt from messages.parts. The structured stream
layers on top of standard chat β no special pause-handling logic.
* test: cover useChat({outputSchema}) runtime + runStreamingStructuredOutput orchestrator
Two runtime test files closing the highest-value gaps in the PR's
test coverage:
packages/typescript/ai-react/tests/use-chat-structured-output.test.ts (4 tests)
- partial updates progressively from TEXT_MESSAGE_CONTENT deltas, final
snaps on the terminal CUSTOM structured-output.complete event
- state resets between runs via the stateful mock adapter (RUN_STARTED
clears partial/final before the second run's deltas land)
- user-supplied onChunk callback fires after internal tracking, with
full visibility of the same chunks
- useChat() without outputSchema doesn't track structured state β the
internal handler's outputSchema-gate is a no-op
packages/typescript/ai/tests/chat-structured-output-stream.test.ts (6 tests)
- native adapter.structuredOutputStream path: validated structured-
output.complete event forwarded with parsed object, schema validation
failure β RUN_ERROR { code: 'schema-validation' } and NO complete
event is emitted, reasoning carries through validation onto the
terminal event, TEXT_MESSAGE_CONTENT deltas pass through
- fallbackStructuredOutputStream path (adapter lacks native streaming):
synthesizes RUN_STARTED β TEXT_MESSAGE_* β structured-output.complete
β RUN_FINISHED around the non-streaming structuredOutput call;
schema validation failure on the fallback path also emits RUN_ERROR
Together: ai package 769 tests, ai-react 110, ai-vue 93, ai-solid 103,
ai-svelte 56 β all green.
* ci: apply automated fixes
* test(openai-base): cover structuredOutputStream on both base adapters
The server-side adapter implementations of structuredOutputStream (shared
by ai-openai, ai-grok, ai-groq via inheritance) had zero unit coverage β
only the e2e suite exercised them. Two new focused test files close that
gap by stubbing the openai SDK client and verifying the AG-UI lifecycle,
request shape, error paths, and per-chunk debug logging.
tests/chat-completions-structured-output-stream.test.ts (6 tests)
- happy path: RUN_STARTED β TEXT_MESSAGE_* β CUSTOM
structured-output.complete (typed object + raw JSON) β RUN_FINISHED
- request shape: stream: true + response_format: { type: 'json_schema',
json_schema: { strict: true } }; tools are stripped
- delta accumulation across multiple chunks produces exactly one
structured-output.complete with the fully-parsed object
- empty content β RUN_ERROR { code: 'empty-response' }, no
structured-output.complete is emitted
- malformed JSON β RUN_ERROR { code: 'parse-error' }
- per-chunk logger.provider is called once per SDK chunk (verified via
a spy logger threaded through resolveDebugOption)
tests/responses-structured-output-stream.test.ts (7 tests)
- same matrix against the Responses API event shape
(response.created / response.output_text.delta / response.completed)
- request shape: stream: true + text.format: { type: 'json_schema',
strict: true }; tools stripped
- usage promoted from response.completed onto RUN_FINISHED
- empty content / parse-error β RUN_ERROR with the correct code
- response.refusal.delta β RUN_ERROR { code: 'refusal' } (Responses-
only failure surface)
- per-chunk logger.provider invocation
Stub adapters extend the base directly and pass a fake OpenAI client
whose chat.completions.create / responses.create routes into a per-test
mock β same pattern as the existing chat-completions-text.test.ts and
responses-text.test.ts suites.
openai-base test count: 70 β 83 (all passing). Types + lint clean.
* ci: apply automated fixes
* fix(ci): list @standard-schema/spec as devDep on framework packages
Two failures from the previous push, both stemming from the type-test
files I added: knip flagged @standard-schema/spec as an unlisted import
across ai-react, ai-vue, ai-solid, and ai-svelte test files, and
@tanstack/ai-vue:test:types failed because β unlike the other three β
its tsconfig included tests/, so tsc strictly resolved the import (which
isn't a direct dep, only transitively via @tanstack/ai).
Fixes:
- Add \`@standard-schema/spec: ^1.1.0\` to devDependencies on all four
framework packages. The import is purely for type-level construction
in the type tests (StandardJSONSchemaV1<Person, Person> β a phantom
branded type that simulates what a Zod schema's inferred type would
look like). devDep is the right scope.
- Align ai-vue's tsconfig with ai-react/ai-solid/ai-svelte by dropping
tests/ from the tsc include block. Tests are still type-checked by
vitest at runtime; tsc now only checks src/.
Verified locally: pnpm test:knip, pnpm test:sherif, and test:types on
all four framework packages pass.
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Alem Tuzlak <t.zlak@hotmail.com>1 parent 02527c2 commit 98979f7
69 files changed
Lines changed: 5647 additions & 426 deletions
File tree
- .agent/self-learning
- lessons
- promoted
- .changeset
- docs
- adapters
- chat
- examples/ts-react-chat/src
- components
- lib
- routes
- packages/typescript
- ai-grok/src/adapters
- ai-groq/src/adapters
- ai-openai/src
- adapters
- ai-openrouter/src/adapters
- ai-react
- src
- tests
- ai-solid
- src
- tests
- ai-svelte
- src
- tests
- ai-vue
- src
- tests
- ai
- skills/ai-core/structured-outputs
- src
- activities
- chat
- summarize
- tests
- openai-base
- src/adapters
- tests
- testing/e2e
- fixtures
- abort
- structured-output-stream
- src
- components
- lib
- routes
- $provider
- tests
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
Lines changed: 19 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
Whitespace-only changes.
Lines changed: 0 additions & 35 deletions
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
0 commit comments