@tanstack/ai 0.57.0 → 0.59.0
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/agents/define-agent.d.ts +81 -0
- package/dist/esm/activities/chat/agents/define-agent.js +34 -0
- package/dist/esm/activities/chat/agents/define-agent.js.map +1 -0
- package/dist/esm/activities/chat/agents/route.d.ts +53 -0
- package/dist/esm/activities/chat/agents/route.js +59 -0
- package/dist/esm/activities/chat/agents/route.js.map +1 -0
- package/dist/esm/activities/chat/agents/spawn.d.ts +124 -0
- package/dist/esm/activities/chat/agents/spawn.js +490 -0
- package/dist/esm/activities/chat/agents/spawn.js.map +1 -0
- package/dist/esm/activities/chat/agents/turn.d.ts +36 -0
- package/dist/esm/activities/chat/agents/turn.js +78 -0
- package/dist/esm/activities/chat/agents/turn.js.map +1 -0
- package/dist/esm/activities/chat/index.d.ts +13 -3
- package/dist/esm/activities/chat/index.js +345 -19
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/messages.d.ts +7 -1
- package/dist/esm/activities/chat/messages.js +94 -18
- package/dist/esm/activities/chat/messages.js.map +1 -1
- package/dist/esm/activities/chat/middleware/run-store.d.ts +43 -7
- package/dist/esm/activities/chat/middleware/run-store.js +8 -1
- package/dist/esm/activities/chat/middleware/run-store.js.map +1 -1
- package/dist/esm/activities/chat/middleware/types.d.ts +50 -3
- package/dist/esm/activities/chat/middleware/types.js.map +1 -1
- package/dist/esm/activities/chat/stream/processor.d.ts +46 -0
- package/dist/esm/activities/chat/stream/processor.js +280 -7
- package/dist/esm/activities/chat/stream/processor.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-calls.d.ts +17 -3
- package/dist/esm/activities/chat/tools/tool-calls.js +56 -7
- package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
- package/dist/esm/activities/generateAudio/index.js +1 -1
- package/dist/esm/activities/generateImage/index.js +1 -1
- package/dist/esm/activities/generateLiveVideo/index.js +1 -1
- package/dist/esm/activities/generateSpeech/index.js +1 -1
- package/dist/esm/activities/generateTranscription/index.js +1 -1
- package/dist/esm/activities/generateVoice/index.js +1 -1
- package/dist/esm/activities/generateWorld/index.js +1 -1
- package/dist/esm/activities/index.d.ts +3 -0
- package/dist/esm/activities/index.js +5 -3
- package/dist/esm/activities/summarize/index.js +1 -1
- package/dist/esm/client.d.ts +5 -36
- package/dist/esm/client.js +4 -37
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.js +7 -4
- package/dist/esm/middlewares/content-guard.js.map +1 -1
- package/dist/esm/stream-to-response.js +12 -6
- package/dist/esm/stream-to-response.js.map +1 -1
- package/dist/esm/strip-to-spec-middleware.js +2 -1
- package/dist/esm/strip-to-spec-middleware.js.map +1 -1
- package/dist/esm/types.d.ts +128 -89
- package/dist/esm/utilities/adapter-yield-chunk.d.ts +5 -1
- package/dist/esm/utilities/ag-ui-usage.d.ts +9 -9
- package/dist/esm/utilities/ag-ui-usage.js +66 -3
- package/dist/esm/utilities/ag-ui-usage.js.map +1 -1
- package/dist/esm/utilities/ag-ui-wire.js +56 -0
- package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
- package/dist/esm/utilities/durability-batch.d.ts +8 -0
- package/dist/esm/utilities/durability-batch.js +45 -0
- package/dist/esm/utilities/durability-batch.js.map +1 -0
- package/dist/esm/utilities/normalize-stream-chunk.js +7 -2
- package/dist/esm/utilities/normalize-stream-chunk.js.map +1 -1
- package/dist/esm/utilities/spec-event-keys.js +13 -8
- package/dist/esm/utilities/spec-event-keys.js.map +1 -1
- package/dist/esm/utilities/subagent-wire.d.ts +36 -0
- package/dist/esm/utilities/subagent-wire.js +131 -0
- package/dist/esm/utilities/subagent-wire.js.map +1 -0
- package/package.json +4 -4
- package/skills/ai-core/adapter-configuration/references/grok-adapter.md +1 -1
- package/skills/ai-core/media-generation/SKILL.md +2 -2
- package/skills/ai-core/middleware/SKILL.md +7 -4
- package/src/activities/chat/agents/define-agent.ts +121 -0
- package/src/activities/chat/agents/route.ts +115 -0
- package/src/activities/chat/agents/spawn.ts +806 -0
- package/src/activities/chat/agents/turn.ts +151 -0
- package/src/activities/chat/index.ts +540 -16
- package/src/activities/chat/messages.ts +125 -15
- package/src/activities/chat/middleware/run-store.ts +56 -7
- package/src/activities/chat/middleware/types.ts +55 -2
- package/src/activities/chat/stream/processor.ts +428 -8
- package/src/activities/chat/tools/tool-calls.ts +92 -16
- package/src/activities/index.ts +15 -0
- package/src/client.ts +22 -35
- package/src/index.ts +23 -0
- package/src/middlewares/content-guard.ts +7 -5
- package/src/stream-to-response.ts +16 -6
- package/src/strip-to-spec-middleware.ts +2 -1
- package/src/types.ts +177 -95
- package/src/utilities/adapter-yield-chunk.ts +10 -2
- package/src/utilities/ag-ui-usage.test.ts +38 -0
- package/src/utilities/ag-ui-usage.ts +98 -11
- package/src/utilities/ag-ui-wire.ts +74 -0
- package/src/utilities/durability-batch.ts +48 -0
- package/src/utilities/normalize-stream-chunk.ts +10 -2
- package/src/utilities/spec-event-keys.ts +34 -7
- package/src/utilities/subagent-wire.ts +184 -0
|
@@ -4,6 +4,10 @@ import {
|
|
|
4
4
|
normalizeToolResult,
|
|
5
5
|
} from '../../utilities/tool-result'
|
|
6
6
|
import { tanstackMetadata } from '../../utilities/merge-metadata'
|
|
7
|
+
import {
|
|
8
|
+
splitSubagentWire,
|
|
9
|
+
subagentWireText,
|
|
10
|
+
} from '../../utilities/subagent-wire'
|
|
7
11
|
import type { Message as AGUIMessage } from '@ag-ui/core'
|
|
8
12
|
import type {
|
|
9
13
|
ContentPart,
|
|
@@ -14,6 +18,7 @@ import type {
|
|
|
14
18
|
TextPart,
|
|
15
19
|
ToolCall,
|
|
16
20
|
ToolCallPart,
|
|
21
|
+
SubagentPart,
|
|
17
22
|
UIMessage,
|
|
18
23
|
UIResourcePart,
|
|
19
24
|
} from '../../types'
|
|
@@ -124,6 +129,37 @@ function getTextContent(
|
|
|
124
129
|
.join('')
|
|
125
130
|
}
|
|
126
131
|
|
|
132
|
+
function historyTextFromParts(parts: ReadonlyArray<MessagePart>): string {
|
|
133
|
+
const blocks: Array<string> = []
|
|
134
|
+
for (const part of parts) {
|
|
135
|
+
if (part.type === 'text' && part.content !== '') {
|
|
136
|
+
blocks.push(part.content)
|
|
137
|
+
} else if (
|
|
138
|
+
part.type === 'structured-output' &&
|
|
139
|
+
part.status === 'complete' &&
|
|
140
|
+
part.raw !== ''
|
|
141
|
+
) {
|
|
142
|
+
blocks.push(part.raw)
|
|
143
|
+
} else if (part.type === 'subagent') {
|
|
144
|
+
const nested = subagentHistoryText(part)
|
|
145
|
+
if (nested !== '') blocks.push(nested)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return blocks.join('\n\n')
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Child text for a later turn. The name stays so the next agent can tell the notes apart. */
|
|
152
|
+
export function subagentHistoryText(part: SubagentPart): string {
|
|
153
|
+
const blocks: Array<string> = []
|
|
154
|
+
for (const message of part.subagent.messages) {
|
|
155
|
+
if (!('parts' in message)) continue
|
|
156
|
+
const text = historyTextFromParts(message.parts).trim()
|
|
157
|
+
if (text !== '') blocks.push(text)
|
|
158
|
+
}
|
|
159
|
+
if (blocks.length === 0) return ''
|
|
160
|
+
return `${part.subagent.name}:\n${blocks.join('\n\n')}`
|
|
161
|
+
}
|
|
162
|
+
|
|
127
163
|
function toolResultContent(
|
|
128
164
|
content: string | null | undefined | Array<ContentPart>,
|
|
129
165
|
): string | Array<ContentPart> {
|
|
@@ -135,6 +171,57 @@ function toolResultContent(
|
|
|
135
171
|
*/
|
|
136
172
|
export function convertMessagesToModelMessages(
|
|
137
173
|
messages: Array<UIMessage | ModelMessage>,
|
|
174
|
+
): Array<ModelMessage> {
|
|
175
|
+
const { top, groups } = splitSubagentWire(messages)
|
|
176
|
+
if (groups.length === 0) return convertOwnMessages(messages)
|
|
177
|
+
|
|
178
|
+
// Child wire messages leave the parent history. The parent model reads each
|
|
179
|
+
// child's text on the assistant message before it, the same as for a UI
|
|
180
|
+
// subagent part. A child that a tool call started reports through the tool
|
|
181
|
+
// result instead.
|
|
182
|
+
const blocks = new Map<string | undefined, Array<string>>()
|
|
183
|
+
for (const group of groups) {
|
|
184
|
+
if (group.info.parentToolCallId !== undefined) continue
|
|
185
|
+
const text = subagentWireText(group.messages)
|
|
186
|
+
if (text === '') continue
|
|
187
|
+
const host = top
|
|
188
|
+
.slice(0, group.hostIndex + 1)
|
|
189
|
+
.findLast((message) => message.role === 'assistant')
|
|
190
|
+
const hostId = host && 'id' in host ? host.id : undefined
|
|
191
|
+
blocks.set(hostId, [
|
|
192
|
+
...(blocks.get(hostId) ?? []),
|
|
193
|
+
`${group.info.name}:\n${text}`,
|
|
194
|
+
])
|
|
195
|
+
}
|
|
196
|
+
const converted = convertOwnMessages(top)
|
|
197
|
+
for (const [hostId, texts] of blocks) {
|
|
198
|
+
const block = texts.join('\n\n')
|
|
199
|
+
const index =
|
|
200
|
+
hostId === undefined
|
|
201
|
+
? -1
|
|
202
|
+
: converted.findIndex(
|
|
203
|
+
(message) => message.role === 'assistant' && message.id === hostId,
|
|
204
|
+
)
|
|
205
|
+
const host = converted[index]
|
|
206
|
+
if (!host) {
|
|
207
|
+
converted.push({ role: 'assistant', content: block })
|
|
208
|
+
continue
|
|
209
|
+
}
|
|
210
|
+
converted[index] = {
|
|
211
|
+
...host,
|
|
212
|
+
content:
|
|
213
|
+
typeof host.content === 'string' && host.content !== ''
|
|
214
|
+
? `${host.content}\n\n${block}`
|
|
215
|
+
: Array.isArray(host.content)
|
|
216
|
+
? [...host.content, { type: 'text', content: block }]
|
|
217
|
+
: block,
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return converted
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function convertOwnMessages(
|
|
224
|
+
messages: Array<UIMessage | ModelMessage>,
|
|
138
225
|
): Array<ModelMessage> {
|
|
139
226
|
// Pre-pass: collect toolCallIds already represented in anchor UIMessage parts.
|
|
140
227
|
// Fan-out tool messages whose toolCallId matches an anchored ToolResultPart
|
|
@@ -455,6 +542,7 @@ function assistantMetadata(
|
|
|
455
542
|
const previous = tanstackMetadata(uiMessage)
|
|
456
543
|
const tanstack: TanStackMessageMetadata = {}
|
|
457
544
|
if (previous?.model !== undefined) tanstack.model = previous.model
|
|
545
|
+
if (previous?.runId !== undefined) tanstack.runId = previous.runId
|
|
458
546
|
if (previous?.signature !== undefined) tanstack.signature = previous.signature
|
|
459
547
|
if (fromParts.length > 0) tanstack.uiResources = fromParts
|
|
460
548
|
const result = { ...current }
|
|
@@ -690,6 +778,22 @@ function buildAssistantMessages(uiMessage: UIMessage): Array<ModelMessage> {
|
|
|
690
778
|
// model input, so it is intentionally dropped from the model message.
|
|
691
779
|
break
|
|
692
780
|
|
|
781
|
+
case 'subagent': {
|
|
782
|
+
// A child that a tool call started reports through the tool result.
|
|
783
|
+
const block =
|
|
784
|
+
part.subagent.parentToolCallId === undefined
|
|
785
|
+
? subagentHistoryText(part)
|
|
786
|
+
: ''
|
|
787
|
+
if (block !== '') {
|
|
788
|
+
const prefix = current.contentParts.length > 0 ? '\n\n' : ''
|
|
789
|
+
current.contentParts.push({
|
|
790
|
+
type: 'text',
|
|
791
|
+
content: `${prefix}${block}`,
|
|
792
|
+
})
|
|
793
|
+
}
|
|
794
|
+
break
|
|
795
|
+
}
|
|
796
|
+
|
|
693
797
|
default:
|
|
694
798
|
break
|
|
695
799
|
}
|
|
@@ -947,7 +1051,9 @@ export function aguiSnapshotMessageToUIMessage(
|
|
|
947
1051
|
modelMessageToUIMessage(
|
|
948
1052
|
{
|
|
949
1053
|
role: 'tool',
|
|
950
|
-
content: message.content
|
|
1054
|
+
content: isContentPartArray(message.content)
|
|
1055
|
+
? message.content
|
|
1056
|
+
: aguiContentToContentParts(message.content),
|
|
951
1057
|
toolCallId: message.toolCallId,
|
|
952
1058
|
...('name' in message && typeof message.name === 'string'
|
|
953
1059
|
? { name: message.name }
|
|
@@ -1071,25 +1177,29 @@ function snapshotStructuredOutput(
|
|
|
1071
1177
|
* AG-UI user content is either a plain string or a multimodal array whose text
|
|
1072
1178
|
* entries use `{ type: 'text', text }` (vs. TanStack's `{ type: 'text', content }`).
|
|
1073
1179
|
* Text entries are rewritten to the TanStack shape; image/audio/video/document
|
|
1074
|
-
* entries already match `ContentPart` and pass through.
|
|
1075
|
-
* TanStack equivalent and are dropped.
|
|
1180
|
+
* entries already match `ContentPart` and pass through.
|
|
1076
1181
|
*/
|
|
1077
1182
|
function aguiUserContentToParts(
|
|
1078
1183
|
content: Extract<AGUIMessage, { role: 'user' }>['content'],
|
|
1079
1184
|
): Array<MessagePart> {
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1185
|
+
const converted = aguiContentToContentParts(content)
|
|
1186
|
+
return typeof converted === 'string'
|
|
1187
|
+
? converted
|
|
1188
|
+
? [{ type: 'text', content: converted }]
|
|
1189
|
+
: []
|
|
1190
|
+
: converted
|
|
1191
|
+
}
|
|
1083
1192
|
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1193
|
+
/** Convert wire content parts. Data, url, and file sources pass through. */
|
|
1194
|
+
export function aguiContentToContentParts(
|
|
1195
|
+
content: Extract<AGUIMessage, { role: 'user' }>['content'],
|
|
1196
|
+
): string | Array<ContentPart> {
|
|
1197
|
+
if (typeof content === 'string') return content
|
|
1198
|
+
return content.map((part) => {
|
|
1199
|
+
if (part.type !== 'text') return part
|
|
1200
|
+
const { text, ...rest } = part
|
|
1201
|
+
return { ...rest, content: text }
|
|
1202
|
+
})
|
|
1093
1203
|
}
|
|
1094
1204
|
|
|
1095
1205
|
/**
|
|
@@ -112,8 +112,25 @@ export interface RunRecord {
|
|
|
112
112
|
* reuse this record by faking `threadId = requestId`; they need a separate
|
|
113
113
|
* job store. `withGenerationPersistence` currently does exactly that and
|
|
114
114
|
* labels itself a stopgap — do not copy it.
|
|
115
|
+
*
|
|
116
|
+
* A subagent child record stores `subagent:<subagentRunId>` here, the key of
|
|
117
|
+
* its own transcript, so `findActiveRun` and `listByThread` on the
|
|
118
|
+
* conversation never return children. Use `listByParentRun`.
|
|
115
119
|
*/
|
|
116
120
|
threadId: string
|
|
121
|
+
/**
|
|
122
|
+
* Parent chat run that started this child, when this record is a subagent.
|
|
123
|
+
* Absent on the parent run itself.
|
|
124
|
+
*/
|
|
125
|
+
parentRunId?: string
|
|
126
|
+
/**
|
|
127
|
+
* The child's AG-UI subagentRunId, the id on its `SUBAGENT_*` chunks and on
|
|
128
|
+
* every chunk it streams. On a child record this equals `runId`. Absent on
|
|
129
|
+
* the parent run.
|
|
130
|
+
*/
|
|
131
|
+
subagentRunId?: string
|
|
132
|
+
/** Agent name (`researcher`, `writer`) when this record is a subagent. */
|
|
133
|
+
name?: string
|
|
117
134
|
status: RunStatus
|
|
118
135
|
startedAt: number
|
|
119
136
|
finishedAt?: number
|
|
@@ -172,9 +189,10 @@ export interface RunRecord {
|
|
|
172
189
|
* instead of failing at build time. It was optional for exactly one release
|
|
173
190
|
* cycle and cost precisely that.
|
|
174
191
|
*
|
|
175
|
-
* OPTIONAL: `listByThread`, `listReclaimable`. Each serves
|
|
176
|
-
* feature (thread history,
|
|
177
|
-
* degrading
|
|
192
|
+
* OPTIONAL: `listByThread`, `listByParentRun`, `listReclaimable`. Each serves
|
|
193
|
+
* one higher-level feature (thread history, subagent card reload, reclaim
|
|
194
|
+
* reaping) and callers feature-detect them, degrading when a backend omits
|
|
195
|
+
* them.
|
|
178
196
|
*/
|
|
179
197
|
export interface RunStore {
|
|
180
198
|
/**
|
|
@@ -182,12 +200,17 @@ export interface RunStore {
|
|
|
182
200
|
* already present.
|
|
183
201
|
*
|
|
184
202
|
* INVARIANT (idempotency): an existing record is returned **unchanged** and
|
|
185
|
-
* the passed `threadId
|
|
186
|
-
*
|
|
203
|
+
* the passed `threadId`, `startedAt`, `status`, `parentRunId`,
|
|
204
|
+
* `subagentRunId`, and `name` are ignored. This is what makes resuming a
|
|
205
|
+
* run safe. `status` defaults to `'running'` on first creation. The three
|
|
206
|
+
* link fields are copied only on the first insert.
|
|
187
207
|
*/
|
|
188
208
|
createOrResume: (
|
|
189
209
|
input: Pick<RunRecord, 'runId' | 'threadId' | 'startedAt'> & {
|
|
190
210
|
status?: RunStatus
|
|
211
|
+
parentRunId?: string
|
|
212
|
+
subagentRunId?: string
|
|
213
|
+
name?: string
|
|
191
214
|
},
|
|
192
215
|
) => Promise<RunRecord>
|
|
193
216
|
/**
|
|
@@ -215,10 +238,19 @@ export interface RunStore {
|
|
|
215
238
|
/** Current record, or null when unknown. */
|
|
216
239
|
get: (runId: string) => Promise<RunRecord | null>
|
|
217
240
|
/**
|
|
218
|
-
* Every run in a conversation, ascending by `startedAt`. OPTIONAL
|
|
219
|
-
*
|
|
241
|
+
* Every run in a conversation, ascending by `startedAt`. OPTIONAL.
|
|
242
|
+
* `reconstructChat` calls it to find the parent runs of children that a
|
|
243
|
+
* tool call started. Without it those cards stay absent on reload.
|
|
244
|
+
* Consumers feature-detect.
|
|
220
245
|
*/
|
|
221
246
|
listByThread?: (threadId: string) => Promise<Array<RunRecord>>
|
|
247
|
+
/**
|
|
248
|
+
* Child runs started by `parentRunId`, ascending by `startedAt`.
|
|
249
|
+
* OPTIONAL. `reconstructChat` uses this to put subagent cards back
|
|
250
|
+
* on the parent assistant message. A store that omits it reloads the
|
|
251
|
+
* text and not the cards.
|
|
252
|
+
*/
|
|
253
|
+
listByParentRun?: (parentRunId: string) => Promise<Array<RunRecord>>
|
|
222
254
|
/**
|
|
223
255
|
* Runs that may be reclaimed: ALL THREE of `status === 'running'`,
|
|
224
256
|
* `detachedSince` is set, and `detachedSince <= now - ttlMs`. The cutoff is
|
|
@@ -341,6 +373,9 @@ export class InMemoryRunStore implements RunStore {
|
|
|
341
373
|
createOrResume(
|
|
342
374
|
input: Pick<RunRecord, 'runId' | 'threadId' | 'startedAt'> & {
|
|
343
375
|
status?: RunStatus
|
|
376
|
+
parentRunId?: string
|
|
377
|
+
subagentRunId?: string
|
|
378
|
+
name?: string
|
|
344
379
|
},
|
|
345
380
|
): Promise<RunRecord> {
|
|
346
381
|
const existing = this.runs.get(input.runId)
|
|
@@ -350,6 +385,13 @@ export class InMemoryRunStore implements RunStore {
|
|
|
350
385
|
threadId: input.threadId,
|
|
351
386
|
status: input.status ?? 'running',
|
|
352
387
|
startedAt: input.startedAt,
|
|
388
|
+
...(input.parentRunId !== undefined
|
|
389
|
+
? { parentRunId: input.parentRunId }
|
|
390
|
+
: {}),
|
|
391
|
+
...(input.subagentRunId !== undefined
|
|
392
|
+
? { subagentRunId: input.subagentRunId }
|
|
393
|
+
: {}),
|
|
394
|
+
...(input.name !== undefined ? { name: input.name } : {}),
|
|
353
395
|
}
|
|
354
396
|
this.runs.set(record.runId, record)
|
|
355
397
|
return Promise.resolve(record)
|
|
@@ -387,6 +429,13 @@ export class InMemoryRunStore implements RunStore {
|
|
|
387
429
|
return Promise.resolve(matching)
|
|
388
430
|
}
|
|
389
431
|
|
|
432
|
+
listByParentRun(parentRunId: string): Promise<Array<RunRecord>> {
|
|
433
|
+
const matching = [...this.runs.values()]
|
|
434
|
+
.filter((run) => run.parentRunId === parentRunId)
|
|
435
|
+
.sort((a, b) => a.startedAt - b.startedAt)
|
|
436
|
+
return Promise.resolve(matching)
|
|
437
|
+
}
|
|
438
|
+
|
|
390
439
|
listReclaimable(opts: {
|
|
391
440
|
now: number
|
|
392
441
|
ttlMs: number
|
|
@@ -4,8 +4,11 @@ import type {
|
|
|
4
4
|
} from '@standard-schema/spec'
|
|
5
5
|
import type {
|
|
6
6
|
AgentLoopState,
|
|
7
|
+
EmitCustomEventOptions,
|
|
8
|
+
Interrupt,
|
|
7
9
|
JSONSchema,
|
|
8
10
|
ModelMessage,
|
|
11
|
+
UIMessage,
|
|
9
12
|
RunAgentResumeItem,
|
|
10
13
|
StreamChunk,
|
|
11
14
|
TokenUsage,
|
|
@@ -190,6 +193,11 @@ export interface ChatMiddlewareContext<TContext = unknown> {
|
|
|
190
193
|
runId: string
|
|
191
194
|
/** Interrupted or parent run correlated with this continuation. */
|
|
192
195
|
parentRunId?: string
|
|
196
|
+
/**
|
|
197
|
+
* Set when this run is a subagent. The id on the child's `SUBAGENT_STARTED`
|
|
198
|
+
* and on every chunk it streams. Absent on a top-level run.
|
|
199
|
+
*/
|
|
200
|
+
subagentRunId?: string
|
|
193
201
|
/**
|
|
194
202
|
* AG-UI thread identifier — a stable per-conversation ID used to
|
|
195
203
|
* correlate client and server devtools events. Resolves to the
|
|
@@ -216,9 +224,14 @@ export interface ChatMiddlewareContext<TContext = unknown> {
|
|
|
216
224
|
/**
|
|
217
225
|
* Push a `CUSTOM` chunk onto the chat stream immediately.
|
|
218
226
|
* The engine yields it as soon as it can (including while `onConfig`
|
|
219
|
-
* is still awaiting work such as a summarize call).
|
|
227
|
+
* is still awaiting work such as a summarize call). Durability then
|
|
228
|
+
* flushes the event on its own, unless you pass `{ batch: true }`.
|
|
220
229
|
*/
|
|
221
|
-
emitCustomEvent: (
|
|
230
|
+
emitCustomEvent: (
|
|
231
|
+
name: string,
|
|
232
|
+
value: Record<string, any>,
|
|
233
|
+
options?: EmitCustomEventOptions,
|
|
234
|
+
) => void
|
|
222
235
|
/** Runtime context provided by chat() options */
|
|
223
236
|
context: TContext
|
|
224
237
|
/**
|
|
@@ -538,6 +551,40 @@ export interface ErrorInfo {
|
|
|
538
551
|
duration: number
|
|
539
552
|
}
|
|
540
553
|
|
|
554
|
+
/**
|
|
555
|
+
* Saves subagent runs while a router owns the turn.
|
|
556
|
+
* `withPersistence` sets this. `chat()` calls it. Apps do not.
|
|
557
|
+
*/
|
|
558
|
+
export interface RoutedSubagentPersistence {
|
|
559
|
+
start: (input: {
|
|
560
|
+
threadId: string
|
|
561
|
+
runId: string
|
|
562
|
+
messages: ReadonlyArray<UIMessage | ModelMessage>
|
|
563
|
+
/**
|
|
564
|
+
* The run's resume entries: answers to earlier child interrupts, plus any
|
|
565
|
+
* the parent answers itself.
|
|
566
|
+
*/
|
|
567
|
+
resume?: ReadonlyArray<RunAgentResumeItem>
|
|
568
|
+
}) => Promise<void>
|
|
569
|
+
chunk: (input: {
|
|
570
|
+
threadId: string
|
|
571
|
+
runId: string
|
|
572
|
+
chunk: StreamChunk
|
|
573
|
+
}) => Promise<void>
|
|
574
|
+
finish: (input: { threadId: string; runId: string }) => Promise<void>
|
|
575
|
+
/** The run stopped because a child waits for outside input. */
|
|
576
|
+
suspend?: (input: {
|
|
577
|
+
threadId: string
|
|
578
|
+
runId: string
|
|
579
|
+
interrupts: ReadonlyArray<Interrupt>
|
|
580
|
+
}) => Promise<void>
|
|
581
|
+
abort: (input: {
|
|
582
|
+
threadId: string
|
|
583
|
+
runId: string
|
|
584
|
+
error?: unknown
|
|
585
|
+
}) => Promise<void>
|
|
586
|
+
}
|
|
587
|
+
|
|
541
588
|
// ===========================
|
|
542
589
|
// Middleware Interface
|
|
543
590
|
// ===========================
|
|
@@ -578,6 +625,12 @@ export interface ChatMiddleware<
|
|
|
578
625
|
/** Optional name for debugging and identification */
|
|
579
626
|
name?: string
|
|
580
627
|
|
|
628
|
+
/**
|
|
629
|
+
* Present when this middleware stores subagent runs.
|
|
630
|
+
* The router calls it. An app does not set it.
|
|
631
|
+
*/
|
|
632
|
+
routedSubagentPersistence?: RoutedSubagentPersistence
|
|
633
|
+
|
|
581
634
|
/**
|
|
582
635
|
* Called at a lifecycle boundary. Return interrupt requests to pause the run.
|
|
583
636
|
* Requests from every middleware in the same boundary form one batch.
|