@tanstack/ai 0.10.0 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,82 @@
1
+ # Ollama Adapter Reference
2
+
3
+ ## Package
4
+
5
+ ```
6
+ @tanstack/ai-ollama
7
+ ```
8
+
9
+ ## Adapter Factories
10
+
11
+ | Factory | Type | Description |
12
+ | ----------------- | --------- | ------------------ |
13
+ | `ollamaText` | Text/Chat | Chat completions |
14
+ | `ollamaSummarize` | Summarize | Text summarization |
15
+
16
+ ## Import
17
+
18
+ ```typescript
19
+ import { ollamaText } from '@tanstack/ai-ollama'
20
+ ```
21
+
22
+ ## Key Models (Local)
23
+
24
+ Ollama runs models locally. The adapter supports a large catalog of models.
25
+ Key families include:
26
+
27
+ | Model Family | Example Names | Notes |
28
+ | ------------ | -------------------------------- | ----------------------- |
29
+ | Llama 4 | `llama4`, `llama4:scout` | Latest Meta models |
30
+ | Llama 3.3 | `llama3.3`, `llama3.3:70b` | Strong general purpose |
31
+ | Qwen 3 | `qwen3`, `qwen3:32b` | Reasoning capable |
32
+ | DeepSeek R1 | `deepseek-r1`, `deepseek-r1:70b` | Reasoning focused |
33
+ | Gemma 3 | `gemma3`, `gemma3:27b` | Google's open model |
34
+ | Phi 4 | `phi4`, `phi4:14b` | Microsoft's small model |
35
+ | Mistral | `mistral`, `mistral-large` | Mistral AI models |
36
+
37
+ Models must be pulled first: `ollama pull llama3.3`
38
+
39
+ ## Provider-Specific modelOptions
40
+
41
+ Ollama models use a generic options type. Provider options vary by the
42
+ underlying model. The adapter passes options through to the Ollama API.
43
+
44
+ ```typescript
45
+ import { chat } from '@tanstack/ai'
46
+ import { ollamaText } from '@tanstack/ai-ollama'
47
+
48
+ const stream = chat({
49
+ adapter: ollamaText('llama3.3'),
50
+ messages,
51
+ temperature: 0.7,
52
+ // Ollama-specific options are limited compared to cloud providers
53
+ })
54
+ ```
55
+
56
+ ## Configuration
57
+
58
+ ```typescript
59
+ // With explicit host
60
+ const adapter = ollamaText('llama3.3', {
61
+ host: 'http://my-server:11434',
62
+ })
63
+ ```
64
+
65
+ ## Environment Variable
66
+
67
+ ```
68
+ OLLAMA_HOST (default: http://localhost:11434)
69
+ ```
70
+
71
+ No API key is needed. Ollama runs locally by default.
72
+
73
+ ## Gotchas
74
+
75
+ - **System prompts:** Pass system prompts via the `systemPrompts` option in `chat()`.
76
+ - Ollama requires models to be downloaded first (`ollama pull <model>`).
77
+ The adapter does not auto-download models.
78
+ - The model catalog is very large (60+ model families). Model names follow
79
+ Ollama's naming: `family:variant` (e.g., `llama3.3:70b`).
80
+ - Vision models (e.g., `llama3.2-vision`, `llava`, `gemma3`) support
81
+ image input. Text-only models do not.
82
+ - No image generation, TTS, or transcription adapters for Ollama.
@@ -0,0 +1,95 @@
1
+ # OpenAI Adapter Reference
2
+
3
+ ## Package
4
+
5
+ ```
6
+ @tanstack/ai-openai
7
+ ```
8
+
9
+ ## Adapter Factories
10
+
11
+ | Factory | Type | Description |
12
+ | --------------------- | -------------- | ------------------------------------ |
13
+ | `openaiText` | Text/Chat | Chat completions (Responses API) |
14
+ | `openaiImage` | Image | Image generation (DALL-E, GPT Image) |
15
+ | `openaiSpeech` | TTS | Text-to-speech |
16
+ | `openaiTranscription` | Transcription | Speech-to-text |
17
+ | `openaiVideo` | Video | Video generation (experimental) |
18
+ | `openaiSummarize` | Summarize | Text summarization |
19
+ | `openaiRealtime` | Realtime/Voice | Realtime voice conversations |
20
+
21
+ ## Import
22
+
23
+ ```typescript
24
+ import { openaiText } from '@tanstack/ai-openai'
25
+ import { openaiImage } from '@tanstack/ai-openai'
26
+ import { openaiSpeech } from '@tanstack/ai-openai'
27
+ ```
28
+
29
+ ## Key Chat Models
30
+
31
+ | Model | Context Window | Max Output | Notes |
32
+ | --------------------- | -------------- | ---------- | -------------------------------------- |
33
+ | `gpt-5.4` | 400K | 128K | Flagship, reasoning, image input |
34
+ | `gpt-5.4-pro` | 400K | 128K | Higher reasoning, no structured output |
35
+ | `gpt-5.4-chat-latest` | 128K | 16K | Chat-optimized variant |
36
+ | `gpt-5.1` | 400K | 128K | Previous flagship, image I/O |
37
+ | `gpt-5` | 400K | 128K | Previous gen flagship |
38
+ | `gpt-5-mini` | 400K | 128K | Cost-efficient |
39
+
40
+ ## Provider-Specific modelOptions
41
+
42
+ ```typescript
43
+ chat({
44
+ adapter: openaiText('gpt-5.4'),
45
+ messages,
46
+ modelOptions: {
47
+ // Reasoning (effort levels: none, minimal, low, medium, high)
48
+ reasoning: {
49
+ effort: 'high',
50
+ summary: 'auto', // 'auto' | 'detailed'
51
+ },
52
+ // Service tier
53
+ service_tier: 'auto', // 'auto' | 'default' | 'flex' | 'priority'
54
+ // Response storage
55
+ store: true,
56
+ // Truncation strategy
57
+ truncation: 'auto', // 'auto' | 'disabled'
58
+ // Tool calling
59
+ max_tool_calls: 10,
60
+ parallel_tool_calls: true,
61
+ tool_choice: 'auto', // 'auto' | 'none' | 'required'
62
+ // Structured output
63
+ text: {
64
+ /* ResponseTextConfig */
65
+ },
66
+ // Metadata (max 16 key-value pairs)
67
+ metadata: { session_id: 'abc' },
68
+ // Streaming
69
+ stream_options: { include_obfuscation: true },
70
+ // Verbosity
71
+ verbosity: 'medium', // 'low' | 'medium' | 'high'
72
+ // Prompt caching
73
+ prompt_cache_key: 'my-cache',
74
+ prompt_cache_retention: '24h',
75
+ // Conversations API
76
+ conversation: { id: 'conv-123' },
77
+ // Background processing
78
+ background: false,
79
+ },
80
+ })
81
+ ```
82
+
83
+ ## Environment Variable
84
+
85
+ ```
86
+ OPENAI_API_KEY
87
+ ```
88
+
89
+ ## Gotchas
90
+
91
+ - Uses the **Responses API** (not Chat Completions) by default.
92
+ - `gpt-5.1` defaults reasoning effort to `none`; you must explicitly set
93
+ `effort: 'low'` or higher to enable reasoning.
94
+ - `o3-pro` only supports `high` reasoning effort.
95
+ - `conversation` and `previous_response_id` cannot be used together.
@@ -0,0 +1,99 @@
1
+ # OpenRouter Adapter Reference
2
+
3
+ ## Package
4
+
5
+ ```
6
+ @tanstack/ai-openrouter
7
+ ```
8
+
9
+ ## Adapter Factories
10
+
11
+ | Factory | Type | Description |
12
+ | --------------------- | --------- | ------------------ |
13
+ | `openRouterText` | Text/Chat | Chat completions |
14
+ | `openRouterImage` | Image | Image generation |
15
+ | `openRouterSummarize` | Summarize | Text summarization |
16
+
17
+ ## Import
18
+
19
+ ```typescript
20
+ import { openRouterText } from '@tanstack/ai-openrouter'
21
+ ```
22
+
23
+ ## Key Models
24
+
25
+ OpenRouter routes to hundreds of models across providers. Model IDs use
26
+ the format `provider/model-name`:
27
+
28
+ | Model ID | Notes |
29
+ | ----------------------------- | -------------------------- |
30
+ | `anthropic/claude-sonnet-4` | Claude via OpenRouter |
31
+ | `openai/gpt-5.2` | GPT-5.2 via OpenRouter |
32
+ | `google/gemini-2.5-pro` | Gemini via OpenRouter |
33
+ | `meta-llama/llama-4-maverick` | Open-source via OpenRouter |
34
+ | `deepseek/deepseek-r1` | Reasoning model |
35
+
36
+ ## Provider-Specific modelOptions
37
+
38
+ OpenRouter has unique routing and provider selection options:
39
+
40
+ ```typescript
41
+ chat({
42
+ adapter: openRouterText('anthropic/claude-sonnet-4'),
43
+ messages,
44
+ modelOptions: {
45
+ // Reasoning
46
+ reasoning: {
47
+ effort: 'high', // 'none' | 'minimal' | 'low' | 'medium' | 'high'
48
+ max_tokens: 4096,
49
+ exclude: false,
50
+ },
51
+ // Sampling
52
+ temperature: 0.7,
53
+ topP: 0.9,
54
+ topK: 40,
55
+ frequencyPenalty: 0.5,
56
+ presencePenalty: 0.5,
57
+ repetitionPenalty: 1.1,
58
+ minP: 0.05,
59
+ seed: 42,
60
+ // Token limits
61
+ maxCompletionTokens: 8192,
62
+ // Stop sequences
63
+ stop: ['\n\n'],
64
+ // Tool calling
65
+ toolChoice: 'auto',
66
+ parallelToolCalls: true,
67
+ // Response format
68
+ responseFormat: { type: 'json_object' },
69
+ // Web search
70
+ webSearchOptions: {
71
+ search_context_size: 'medium', // 'low' | 'medium' | 'high'
72
+ },
73
+ // Verbosity
74
+ verbosity: 'medium',
75
+ // Logprobs
76
+ logprobs: true,
77
+ topLogprobs: 5,
78
+ },
79
+ })
80
+ ```
81
+
82
+ ## Environment Variable
83
+
84
+ ```
85
+ OPENROUTER_API_KEY
86
+ ```
87
+
88
+ ## Gotchas
89
+
90
+ - Model IDs are `provider/model-name` format (e.g., `openai/gpt-5.2`).
91
+ - OpenRouter has unique features not found in direct provider adapters:
92
+ - `variant` option: `'free'`, `'nitro'`, `'online'`, `'thinking'`, etc.
93
+ - `provider` routing preferences (order, fallbacks, data collection policies)
94
+ - `transforms: ['middle-out']` for context compression
95
+ - `prediction` for latency reduction
96
+ - `plugins: [{ id: 'web' }]` for web search
97
+ - Uses `camelCase` for option names (e.g., `topP`, `frequencyPenalty`),
98
+ unlike OpenAI's `snake_case`.
99
+ - `route: 'fallback'` with `models` array tries models in order.
@@ -0,0 +1,232 @@
1
+ ---
2
+ name: ai-core/ag-ui-protocol
3
+ description: >
4
+ Server-side AG-UI streaming protocol implementation: StreamChunk event
5
+ types (RUN_STARTED, TEXT_MESSAGE_START/CONTENT/END, TOOL_CALL_START/ARGS/END,
6
+ RUN_FINISHED, RUN_ERROR, STEP_STARTED/STEP_FINISHED, STATE_SNAPSHOT/DELTA,
7
+ CUSTOM), toServerSentEventsStream() for SSE format, toHttpStream() for
8
+ NDJSON format. For backends serving AG-UI events without client packages.
9
+ type: sub-skill
10
+ library: tanstack-ai
11
+ library_version: '0.10.0'
12
+ sources:
13
+ - 'TanStack/ai:docs/protocol/chunk-definitions.md'
14
+ - 'TanStack/ai:docs/protocol/sse-protocol.md'
15
+ - 'TanStack/ai:docs/protocol/http-stream-protocol.md'
16
+ ---
17
+
18
+ # AG-UI Protocol
19
+
20
+ This skill builds on ai-core. Read it first for critical rules.
21
+
22
+ ## Setup — Server Endpoint Producing AG-UI Events via SSE
23
+
24
+ ```typescript
25
+ import { chat, toServerSentEventsResponse } from '@tanstack/ai'
26
+ import { openaiText } from '@tanstack/ai-openai'
27
+
28
+ export async function POST(request: Request) {
29
+ const { messages } = await request.json()
30
+ const stream = chat({
31
+ adapter: openaiText('gpt-5.2'),
32
+ messages,
33
+ })
34
+ return toServerSentEventsResponse(stream)
35
+ }
36
+ ```
37
+
38
+ `chat()` returns an `AsyncIterable<StreamChunk>`. Each `StreamChunk` is a
39
+ typed AG-UI event (discriminated union on `type`). The `toServerSentEventsResponse()`
40
+ helper encodes that iterable into an SSE-formatted `Response` with correct headers.
41
+
42
+ ## Core Patterns
43
+
44
+ ### 1. SSE Format — toServerSentEventsStream / toServerSentEventsResponse
45
+
46
+ **Wire format:** Each event is `data: <JSON>\n\n`. Stream ends with `data: [DONE]\n\n`.
47
+
48
+ ```typescript
49
+ import {
50
+ chat,
51
+ toServerSentEventsStream,
52
+ toServerSentEventsResponse,
53
+ } from '@tanstack/ai'
54
+ import { openaiText } from '@tanstack/ai-openai'
55
+
56
+ // Option A: Get a ReadableStream (manual Response construction)
57
+ const abortController = new AbortController()
58
+ const stream = chat({
59
+ adapter: openaiText('gpt-5.2'),
60
+ messages,
61
+ abortController,
62
+ })
63
+ const sseStream = toServerSentEventsStream(stream, abortController)
64
+
65
+ const response = new Response(sseStream, {
66
+ headers: {
67
+ 'Content-Type': 'text/event-stream',
68
+ 'Cache-Control': 'no-cache',
69
+ Connection: 'keep-alive',
70
+ },
71
+ })
72
+
73
+ // Option B: Use the helper (sets headers automatically)
74
+ const response2 = toServerSentEventsResponse(stream, { abortController })
75
+ // Default headers: Content-Type: text/event-stream, Cache-Control: no-cache, Connection: keep-alive
76
+ ```
77
+
78
+ **Default response headers set by `toServerSentEventsResponse()`:**
79
+
80
+ | Header | Value |
81
+ | --------------- | ------------------- |
82
+ | `Content-Type` | `text/event-stream` |
83
+ | `Cache-Control` | `no-cache` |
84
+ | `Connection` | `keep-alive` |
85
+
86
+ Custom headers merge on top (user headers override defaults):
87
+
88
+ ```typescript
89
+ toServerSentEventsResponse(stream, {
90
+ headers: {
91
+ 'X-Accel-Buffering': 'no', // Disable nginx buffering
92
+ 'Cache-Control': 'no-store', // Override default
93
+ },
94
+ abortController,
95
+ })
96
+ ```
97
+
98
+ **Error handling:** If the stream throws, a `RUN_ERROR` event is emitted
99
+ automatically before the stream closes. If the `abortController` is already
100
+ aborted, the error event is suppressed and the stream closes silently.
101
+
102
+ ### 2. HTTP Stream (NDJSON) — toHttpStream / toHttpResponse
103
+
104
+ **Wire format:** Each event is `<JSON>\n` (newline-delimited JSON, no SSE prefix, no `[DONE]` marker).
105
+
106
+ ```typescript
107
+ import { chat, toHttpStream, toHttpResponse } from '@tanstack/ai'
108
+ import { openaiText } from '@tanstack/ai-openai'
109
+
110
+ // Option A: Get a ReadableStream
111
+ const abortController = new AbortController()
112
+ const stream = chat({
113
+ adapter: openaiText('gpt-5.2'),
114
+ messages,
115
+ abortController,
116
+ })
117
+ const ndjsonStream = toHttpStream(stream, abortController)
118
+
119
+ const response = new Response(ndjsonStream, {
120
+ headers: {
121
+ 'Content-Type': 'application/x-ndjson',
122
+ },
123
+ })
124
+
125
+ // Option B: Use the helper (does NOT set headers automatically)
126
+ const response2 = toHttpResponse(stream, { abortController })
127
+ // Note: toHttpResponse does NOT set Content-Type automatically.
128
+ // You should pass headers explicitly:
129
+ const response3 = toHttpResponse(stream, {
130
+ headers: { 'Content-Type': 'application/x-ndjson' },
131
+ abortController,
132
+ })
133
+ ```
134
+
135
+ **Client-side pairing:** SSE endpoints are consumed by `fetchServerSentEvents()`.
136
+ HTTP stream endpoints are consumed by `fetchHttpStream()`. Both are connection
137
+ adapters from `@tanstack/ai-react` (or the framework-specific package).
138
+
139
+ ### 3. AG-UI Event Types Reference
140
+
141
+ All events extend `BaseAGUIEvent` which carries `type`, `timestamp`, optional
142
+ `model`, and optional `rawEvent`.
143
+
144
+ | Event Type | Description |
145
+ | ---------------------- | --------------------------------------------------------------------------------------------------------------------------- |
146
+ | `RUN_STARTED` | First event in a stream. Carries `runId` and optional `threadId`. |
147
+ | `TEXT_MESSAGE_START` | New text message begins. Carries `messageId` and `role`. |
148
+ | `TEXT_MESSAGE_CONTENT` | Incremental text token. Carries `messageId` and `delta` (the new text). |
149
+ | `TEXT_MESSAGE_END` | Text message complete. Carries `messageId`. |
150
+ | `TOOL_CALL_START` | Tool invocation begins. Carries `toolCallId`, `toolName`, and `index`. |
151
+ | `TOOL_CALL_ARGS` | Incremental tool arguments JSON. Carries `toolCallId` and `delta`. |
152
+ | `TOOL_CALL_END` | Tool call arguments complete. Carries `toolCallId` and `toolName`. |
153
+ | `STEP_STARTED` | Thinking/reasoning step begins. Carries `stepId` and optional `stepType`. |
154
+ | `STEP_FINISHED` | Thinking step complete. Carries `stepId`, `delta`, and optional `content`. |
155
+ | `MESSAGES_SNAPSHOT` | Full conversation transcript snapshot. Carries `messages: Array<UIMessage>`. |
156
+ | `STATE_SNAPSHOT` | Full application state snapshot. Carries `state: Record<string, unknown>`. |
157
+ | `STATE_DELTA` | Incremental state update. Carries `delta: Record<string, unknown>`. |
158
+ | `CUSTOM` | Extension point. Carries `name` (string) and optional `value` (unknown). |
159
+ | `RUN_FINISHED` | Stream complete. Carries `runId` and `finishReason` (`'stop'` / `'length'` / `'content_filter'` / `'tool_calls'` / `null`). |
160
+ | `RUN_ERROR` | Error during stream. Carries optional `runId` and `error: { message, code? }`. |
161
+
162
+ **Typical event sequence for a text-only response:**
163
+
164
+ ```
165
+ RUN_STARTED -> TEXT_MESSAGE_START -> TEXT_MESSAGE_CONTENT (repeated) -> TEXT_MESSAGE_END -> RUN_FINISHED
166
+ ```
167
+
168
+ **Typical event sequence with tool calls:**
169
+
170
+ ```
171
+ RUN_STARTED -> TEXT_MESSAGE_START -> TEXT_MESSAGE_CONTENT* -> TEXT_MESSAGE_END
172
+ -> TOOL_CALL_START -> TOOL_CALL_ARGS* -> TOOL_CALL_END
173
+ -> RUN_FINISHED (finishReason: 'tool_calls')
174
+ ```
175
+
176
+ **Type aliases:** `StreamChunk` is an alias for `AGUIEvent` (the discriminated
177
+ union of all event interfaces). `StreamChunkType` is an alias for `AGUIEventType`
178
+ (the string union of all event type literals).
179
+
180
+ ## Common Mistakes
181
+
182
+ ### MEDIUM: Proxy buffering breaks SSE streaming
183
+
184
+ Reverse proxies (nginx, Cloudflare, AWS ALB) buffer SSE responses by default,
185
+ causing events to arrive in batches instead of streaming token-by-token.
186
+
187
+ Fix: Set proxy-bypass headers on the response.
188
+
189
+ ```typescript
190
+ toServerSentEventsResponse(stream, {
191
+ headers: {
192
+ 'X-Accel-Buffering': 'no', // nginx
193
+ 'X-Content-Type-Options': 'nosniff', // Some CDNs
194
+ },
195
+ abortController,
196
+ })
197
+ ```
198
+
199
+ For Cloudflare Workers, SSE streams automatically. For Cloudflare proxied
200
+ origins, ensure "Response Buffering" is disabled in the dashboard.
201
+
202
+ Source: docs/protocol/sse-protocol.md
203
+
204
+ ### MEDIUM: Assuming all AG-UI events arrive in every response
205
+
206
+ Not all event types appear in every stream:
207
+
208
+ - `STEP_STARTED` / `STEP_FINISHED` only appear with thinking-enabled models
209
+ (e.g., `o3`, `claude-sonnet-4-5` with extended thinking). Standard models
210
+ skip these entirely.
211
+ - `TOOL_CALL_START` / `TOOL_CALL_ARGS` / `TOOL_CALL_END` only appear when
212
+ the model invokes tools. A text-only response has none.
213
+ - `STATE_SNAPSHOT` / `STATE_DELTA` only appear when server code explicitly
214
+ emits them for stateful agent workflows.
215
+ - `MESSAGES_SNAPSHOT` only appears when the server explicitly sends a
216
+ full transcript snapshot.
217
+ - `CUSTOM` events are application-defined and never emitted by default.
218
+
219
+ Code that expects a fixed sequence (e.g., always waiting for `STEP_FINISHED`
220
+ before processing text) will hang or break on models that don't emit those events.
221
+
222
+ Source: docs/protocol/chunk-definitions.md
223
+
224
+ ## Tension
225
+
226
+ HIGH Tension: AG-UI protocol compliance vs. internal message format -- TanStack
227
+ AI's `UIMessage` format (parts-based) diverges from AG-UI spec (content-based).
228
+ Full compliance would require a different message structure.
229
+
230
+ ## Cross-References
231
+
232
+ - See also: `ai-core/custom-backend-integration/SKILL.md` -- Custom backends must implement SSE or HTTP stream format to work with TanStack AI client connection adapters.