@tanstack/ai 0.9.2 → 0.10.1
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.
- package/dist/esm/activities/chat/stream/processor.js +3 -0
- package/dist/esm/activities/chat/stream/processor.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/tool-registry.d.ts +81 -0
- package/dist/esm/tool-registry.js +49 -0
- package/dist/esm/tool-registry.js.map +1 -0
- package/package.json +6 -4
- package/skills/ai-core/SKILL.md +59 -0
- package/skills/ai-core/adapter-configuration/SKILL.md +283 -0
- package/skills/ai-core/adapter-configuration/references/anthropic-adapter.md +97 -0
- package/skills/ai-core/adapter-configuration/references/gemini-adapter.md +102 -0
- package/skills/ai-core/adapter-configuration/references/grok-adapter.md +77 -0
- package/skills/ai-core/adapter-configuration/references/groq-adapter.md +106 -0
- package/skills/ai-core/adapter-configuration/references/ollama-adapter.md +82 -0
- package/skills/ai-core/adapter-configuration/references/openai-adapter.md +95 -0
- package/skills/ai-core/adapter-configuration/references/openrouter-adapter.md +99 -0
- package/skills/ai-core/ag-ui-protocol/SKILL.md +232 -0
- package/skills/ai-core/chat-experience/SKILL.md +506 -0
- package/skills/ai-core/custom-backend-integration/SKILL.md +463 -0
- package/skills/ai-core/media-generation/SKILL.md +471 -0
- package/skills/ai-core/middleware/SKILL.md +336 -0
- package/skills/ai-core/structured-outputs/SKILL.md +203 -0
- package/skills/ai-core/tool-calling/SKILL.md +411 -0
- package/src/activities/chat/stream/processor.ts +7 -0
- package/src/index.ts +7 -0
- package/src/tool-registry.ts +150 -0
|
@@ -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.
|