@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
package/dist/esm/types.d.ts
CHANGED
|
@@ -4,8 +4,9 @@ import { SystemPrompt } from './system-prompts.js';
|
|
|
4
4
|
import { CapabilityContext } from './activities/chat/middleware/capabilities.js';
|
|
5
5
|
import { InterruptSubmissionError } from './interrupts.js';
|
|
6
6
|
import { BilledUsage, BillingUnit, CompletionTokensDetails, PromptTokensDetails, ProviderUsageDetails, TokenUsage, UsageCostBreakdown } from '@tanstack/ai-event-client';
|
|
7
|
-
import { BaseEvent as AGUIBaseEvent, CustomEvent as AGUICustomEvent, Interrupt as AGUIInterrupt, MessagesSnapshotEvent as AGUIMessagesSnapshotEvent, ReasoningEncryptedValueEvent as AGUIReasoningEncryptedValueEvent, ReasoningEndEvent as AGUIReasoningEndEvent, ReasoningMessageContentEvent as AGUIReasoningMessageContentEvent, ReasoningMessageEndEvent as AGUIReasoningMessageEndEvent, ReasoningMessageStartEvent as AGUIReasoningMessageStartEvent, ReasoningStartEvent as AGUIReasoningStartEvent, ResumeEntry as AGUIResumeEntry, RunErrorEvent as AGUIRunErrorEvent, RunFinishedEvent as AGUIRunFinishedEvent, RunFinishedOutcome as AGUIRunFinishedOutcome, RunStartedEvent as AGUIRunStartedEvent, StateDeltaEvent as AGUIStateDeltaEvent, StateSnapshotEvent as AGUIStateSnapshotEvent, StepFinishedEvent as AGUIStepFinishedEvent, StepStartedEvent as AGUIStepStartedEvent, TextMessageContentEvent as AGUITextMessageContentEvent, TextMessageEndEvent as AGUITextMessageEndEvent, TextMessageStartEvent as AGUITextMessageStartEvent, ToolCallArgsEvent as AGUIToolCallArgsEvent, ToolCallEndEvent as AGUIToolCallEndEvent, ToolCallResultEvent as AGUIToolCallResultEvent, ToolCallStartEvent as AGUIToolCallStartEvent, EventType } from '@ag-ui/core';
|
|
7
|
+
import { ActivityDeltaEvent as AGUIActivityDeltaEvent, ActivitySnapshotEvent as AGUIActivitySnapshotEvent, AudioPart as AGUIAudioPart, BaseEvent as AGUIBaseEvent, ContentPart as AGUIContentPart, CustomEvent as AGUICustomEvent, DataSource as AGUIDataSource, DocumentPart as AGUIDocumentPart, FileSource as AGUIFileSource, ImagePart as AGUIImagePart, Interrupt as AGUIInterrupt, MessagesSnapshotEvent as AGUIMessagesSnapshotEvent, ReasoningEncryptedValueEvent as AGUIReasoningEncryptedValueEvent, ReasoningEndEvent as AGUIReasoningEndEvent, RawEvent as AGUIRawEvent, ReasoningMessageChunkEvent as AGUIReasoningMessageChunkEvent, ReasoningMessageContentEvent as AGUIReasoningMessageContentEvent, ReasoningMessageEndEvent as AGUIReasoningMessageEndEvent, ReasoningMessageStartEvent as AGUIReasoningMessageStartEvent, ReasoningStartEvent as AGUIReasoningStartEvent, ResumeEntry as AGUIResumeEntry, RunErrorEvent as AGUIRunErrorEvent, RunFinishedEvent as AGUIRunFinishedEvent, RunFinishedOutcome as AGUIRunFinishedOutcome, RunStartedEvent as AGUIRunStartedEvent, StateDeltaEvent as AGUIStateDeltaEvent, StateSnapshotEvent as AGUIStateSnapshotEvent, StepFinishedEvent as AGUIStepFinishedEvent, StepStartedEvent as AGUIStepStartedEvent, SubagentErrorEvent as AGUISubagentErrorEvent, SubagentFinishedEvent as AGUISubagentFinishedEvent, SubagentFinishedSuspendedOutcome as AGUISubagentFinishedSuspendedOutcome, SubagentInfo as AGUISubagentInfo, SubagentRunId as AGUISubagentRunId, SubagentStartedEvent as AGUISubagentStartedEvent, TextMessageChunkEvent as AGUITextMessageChunkEvent, TextMessageContentEvent as AGUITextMessageContentEvent, TextMessageEndEvent as AGUITextMessageEndEvent, TextMessageStartEvent as AGUITextMessageStartEvent, ToolCall as AGUIToolCall, ToolCallArgsEvent as AGUIToolCallArgsEvent, ToolCallChunkEvent as AGUIToolCallChunkEvent, ToolCallEndEvent as AGUIToolCallEndEvent, ToolCallResultEvent as AGUIToolCallResultEvent, ToolCallStartEvent as AGUIToolCallStartEvent, UrlSource as AGUIUrlSource, VideoPart as AGUIVideoPart, EventType } from '@ag-ui/core';
|
|
8
8
|
import { SpecTokenUsage, TokenUsageLeftover } from './utilities/ag-ui-usage.js';
|
|
9
|
+
import { SubagentWireInfo } from './utilities/subagent-wire.js';
|
|
9
10
|
export type { ProviderTool } from './tools/provider-tool.js';
|
|
10
11
|
/**
|
|
11
12
|
* Tool call states - track the lifecycle of a tool call
|
|
@@ -87,13 +88,8 @@ export type SchemaInput = StandardJSONSchemaV1<any, any> | StandardSchemaV1<any,
|
|
|
87
88
|
* JSON Schema at compile time.
|
|
88
89
|
*/
|
|
89
90
|
export type InferSchemaType<T> = T extends StandardJSONSchemaV1<infer TInput, unknown> ? TInput : T extends StandardSchemaV1<infer TInput, unknown> ? TInput : unknown;
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
type: 'function';
|
|
93
|
-
function: {
|
|
94
|
-
name: string;
|
|
95
|
-
arguments: string;
|
|
96
|
-
};
|
|
91
|
+
/** AG-UI `ToolCall` with typed metadata. `function.arguments` is a JSON string. */
|
|
92
|
+
export interface ToolCall<TMetadata = unknown> extends Omit<AGUIToolCall, 'metadata'> {
|
|
97
93
|
/** Provider-specific metadata to carry through the tool call lifecycle.
|
|
98
94
|
* Typed per-adapter via `TToolCallMetadata`. For example,
|
|
99
95
|
* `@tanstack/ai-gemini` sets this to `{ thoughtSignature?: string }`. */
|
|
@@ -119,99 +115,60 @@ export interface ProviderExecutedToolMetadata {
|
|
|
119
115
|
[key: string]: unknown;
|
|
120
116
|
}
|
|
121
117
|
/**
|
|
122
|
-
* Supported input modality types for multimodal content
|
|
123
|
-
* -
|
|
124
|
-
* - 'image': Image content (base64 or URL)
|
|
125
|
-
* - 'audio': Audio content (base64 or URL)
|
|
126
|
-
* - 'video': Video content (base64 or URL)
|
|
127
|
-
* - 'document': Document content like PDFs (base64 or URL)
|
|
118
|
+
* Supported input modality types for multimodal content: the `type` of each
|
|
119
|
+
* AG-UI `ContentPart` (text, image, audio, video, document).
|
|
128
120
|
*/
|
|
129
|
-
export type Modality = '
|
|
121
|
+
export type Modality = AGUIContentPart['type'];
|
|
130
122
|
/**
|
|
131
|
-
*
|
|
132
|
-
* Requires a mimeType to ensure providers receive proper content type information.
|
|
123
|
+
* Inline base64 content. AG-UI `DataSource`: `mimeType` is required.
|
|
133
124
|
*/
|
|
134
|
-
export interface ContentPartDataSource {
|
|
135
|
-
/**
|
|
136
|
-
* Indicates this is inline data content.
|
|
137
|
-
*/
|
|
138
|
-
type: 'data';
|
|
139
|
-
/**
|
|
140
|
-
* The base64-encoded content value.
|
|
141
|
-
*/
|
|
142
|
-
value: string;
|
|
143
|
-
/**
|
|
144
|
-
* The MIME type of the content (e.g., 'image/png', 'audio/wav').
|
|
145
|
-
* Required for data sources to ensure proper handling by providers.
|
|
146
|
-
*/
|
|
147
|
-
mimeType: string;
|
|
125
|
+
export interface ContentPartDataSource extends AGUIDataSource {
|
|
148
126
|
}
|
|
149
127
|
/**
|
|
150
|
-
*
|
|
151
|
-
* mimeType is optional as it can often be inferred from the URL or response headers.
|
|
128
|
+
* URL-referenced content. AG-UI `UrlSource`: `mimeType` is optional.
|
|
152
129
|
*/
|
|
153
|
-
export interface ContentPartUrlSource {
|
|
154
|
-
/**
|
|
155
|
-
* Indicates this is URL-referenced content.
|
|
156
|
-
*/
|
|
157
|
-
type: 'url';
|
|
158
|
-
/**
|
|
159
|
-
* HTTP(S) URL or data URI pointing to the content.
|
|
160
|
-
*/
|
|
161
|
-
value: string;
|
|
162
|
-
/**
|
|
163
|
-
* Optional MIME type hint for cases where providers can't infer it from the URL.
|
|
164
|
-
*/
|
|
165
|
-
mimeType?: string;
|
|
130
|
+
export interface ContentPartUrlSource extends AGUIUrlSource {
|
|
166
131
|
}
|
|
167
132
|
/**
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
* - For 'data' sources: mimeType is required
|
|
171
|
-
* - For 'url' sources: mimeType is optional
|
|
133
|
+
* A provider-issued file handle (Files API). AG-UI `FileSource`: the handle
|
|
134
|
+
* is opaque, do not fetch or parse it.
|
|
172
135
|
*/
|
|
173
|
-
export
|
|
136
|
+
export interface ContentPartFileSource extends AGUIFileSource {
|
|
137
|
+
}
|
|
174
138
|
/**
|
|
175
|
-
*
|
|
139
|
+
* Where a media part's bytes come from: inline data, a URL, or a provider
|
|
140
|
+
* file handle. Same members as AG-UI `PartSource`.
|
|
141
|
+
*/
|
|
142
|
+
export type ContentPartSource = ContentPartDataSource | ContentPartUrlSource | ContentPartFileSource;
|
|
143
|
+
/**
|
|
144
|
+
* Image content part for multimodal messages. AG-UI `ImagePart` with typed metadata.
|
|
176
145
|
* @template TMetadata - Provider-specific metadata type (e.g., OpenAI's detail level)
|
|
177
146
|
*/
|
|
178
|
-
export interface ImagePart<TMetadata = unknown> {
|
|
179
|
-
type: 'image';
|
|
180
|
-
/** Source of the image content */
|
|
181
|
-
source: ContentPartSource;
|
|
147
|
+
export interface ImagePart<TMetadata = unknown> extends AGUIImagePart {
|
|
182
148
|
/** Provider-specific metadata (e.g., OpenAI's detail: 'auto' | 'low' | 'high') */
|
|
183
149
|
metadata?: TMetadata;
|
|
184
150
|
}
|
|
185
151
|
/**
|
|
186
|
-
* Audio content part for multimodal messages.
|
|
152
|
+
* Audio content part for multimodal messages. AG-UI `AudioPart` with typed metadata.
|
|
187
153
|
* @template TMetadata - Provider-specific metadata type
|
|
188
154
|
*/
|
|
189
|
-
export interface AudioPart<TMetadata = unknown> {
|
|
190
|
-
type: 'audio';
|
|
191
|
-
/** Source of the audio content */
|
|
192
|
-
source: ContentPartSource;
|
|
155
|
+
export interface AudioPart<TMetadata = unknown> extends AGUIAudioPart {
|
|
193
156
|
/** Provider-specific metadata (e.g., format, sample rate) */
|
|
194
157
|
metadata?: TMetadata;
|
|
195
158
|
}
|
|
196
159
|
/**
|
|
197
|
-
* Video content part for multimodal messages.
|
|
160
|
+
* Video content part for multimodal messages. AG-UI `VideoPart` with typed metadata.
|
|
198
161
|
* @template TMetadata - Provider-specific metadata type
|
|
199
162
|
*/
|
|
200
|
-
export interface VideoPart<TMetadata = unknown> {
|
|
201
|
-
type: 'video';
|
|
202
|
-
/** Source of the video content */
|
|
203
|
-
source: ContentPartSource;
|
|
163
|
+
export interface VideoPart<TMetadata = unknown> extends AGUIVideoPart {
|
|
204
164
|
/** Provider-specific metadata (e.g., duration, resolution) */
|
|
205
165
|
metadata?: TMetadata;
|
|
206
166
|
}
|
|
207
167
|
/**
|
|
208
|
-
* Document content part for multimodal messages (e.g., PDFs).
|
|
168
|
+
* Document content part for multimodal messages (e.g., PDFs). AG-UI `DocumentPart` with typed metadata.
|
|
209
169
|
* @template TMetadata - Provider-specific metadata type (e.g., Anthropic's media_type)
|
|
210
170
|
*/
|
|
211
|
-
export interface DocumentPart<TMetadata = unknown> {
|
|
212
|
-
type: 'document';
|
|
213
|
-
/** Source of the document content */
|
|
214
|
-
source: ContentPartSource;
|
|
171
|
+
export interface DocumentPart<TMetadata = unknown> extends AGUIDocumentPart {
|
|
215
172
|
/** Provider-specific metadata (e.g., media_type for PDFs) */
|
|
216
173
|
metadata?: TMetadata;
|
|
217
174
|
}
|
|
@@ -360,6 +317,28 @@ export interface StructuredOutputPart<TData = unknown> {
|
|
|
360
317
|
/** Populated when `status === 'error'`. */
|
|
361
318
|
errorMessage?: string;
|
|
362
319
|
}
|
|
320
|
+
export type SubagentStatus = 'running' | 'finished' | 'error' | 'suspended';
|
|
321
|
+
/**
|
|
322
|
+
* One child invocation as the client sees it. AG-UI `SubagentInfo` names the
|
|
323
|
+
* child; the other AG-UI fields come from its `SUBAGENT_STARTED`,
|
|
324
|
+
* `SUBAGENT_FINISHED` and `SUBAGENT_ERROR` events. `id` is the AG-UI
|
|
325
|
+
* `subagentRunId`. `status`, `parentRunId` and `messages` are client state the
|
|
326
|
+
* spec does not model.
|
|
327
|
+
*/
|
|
328
|
+
export interface SubagentHandleData extends AGUISubagentInfo, Pick<AGUISubagentStartedEvent, 'parentSubagentRunId' | 'parentToolCallId' | 'metadata'> {
|
|
329
|
+
id: AGUISubagentRunId;
|
|
330
|
+
status: SubagentStatus;
|
|
331
|
+
/** The parent chat run that started this child. */
|
|
332
|
+
parentRunId?: string;
|
|
333
|
+
/** Interrupts this child raised, while `status` is `'suspended'`. */
|
|
334
|
+
interruptIds?: AGUISubagentFinishedSuspendedOutcome['interruptIds'];
|
|
335
|
+
messages: Array<UIMessage>;
|
|
336
|
+
error?: Pick<AGUISubagentErrorEvent, 'message' | 'code'>;
|
|
337
|
+
}
|
|
338
|
+
export interface SubagentPart {
|
|
339
|
+
type: 'subagent';
|
|
340
|
+
subagent: SubagentHandleData;
|
|
341
|
+
}
|
|
363
342
|
export interface UIResourcePart {
|
|
364
343
|
type: 'ui-resource';
|
|
365
344
|
/** The ui:// resource object in MCP-native shape — fed straight to the renderer. */
|
|
@@ -381,7 +360,7 @@ export interface UIResourcePart {
|
|
|
381
360
|
* Currently always `undefined` — nothing populates this field yet. */
|
|
382
361
|
meta?: Record<string, unknown>;
|
|
383
362
|
}
|
|
384
|
-
export type MessagePart<TData = unknown> = TextPart | ImagePart | AudioPart | VideoPart | DocumentPart | ToolCallPart | ToolResultPart | ThinkingPart | StructuredOutputPart<TData> | UIResourcePart;
|
|
363
|
+
export type MessagePart<TData = unknown> = TextPart | ImagePart | AudioPart | VideoPart | DocumentPart | ToolCallPart | ToolResultPart | ThinkingPart | StructuredOutputPart<TData> | UIResourcePart | SubagentPart;
|
|
385
364
|
/**
|
|
386
365
|
* Shape of `metadata.tanstack` on a message.
|
|
387
366
|
* `createdAt` is an ISO-8601 string.
|
|
@@ -389,6 +368,10 @@ export type MessagePart<TData = unknown> = TextPart | ImagePart | AudioPart | Vi
|
|
|
389
368
|
export interface TanStackMessageMetadata {
|
|
390
369
|
createdAt?: string;
|
|
391
370
|
model?: string;
|
|
371
|
+
/** Parent chat run that produced this assistant message. */
|
|
372
|
+
runId?: string;
|
|
373
|
+
/** Card data on a child wire message. See `uiMessagesToWire`. */
|
|
374
|
+
subagent?: SubagentWireInfo;
|
|
392
375
|
/** Thinking signature for a `role: 'reasoning'` fan-out message. */
|
|
393
376
|
signature?: string;
|
|
394
377
|
/** Per-tool-call provider metadata keyed by tool call id (e.g. Gemini thoughtSignature). */
|
|
@@ -474,6 +457,21 @@ type RuntimeContextField<TContext> = IsUnknown<TContext> extends true ? {
|
|
|
474
457
|
*/
|
|
475
458
|
context: TContext;
|
|
476
459
|
};
|
|
460
|
+
/**
|
|
461
|
+
* Options for a single `emitCustomEvent` call, on both the tool-execution and
|
|
462
|
+
* middleware contexts.
|
|
463
|
+
*/
|
|
464
|
+
export interface EmitCustomEventOptions {
|
|
465
|
+
/**
|
|
466
|
+
* Keep this event in the durability batch with later chunks.
|
|
467
|
+
* CUSTOM events flush as soon as they are emitted, so a progress
|
|
468
|
+
* indicator can render at emit time. Pass `{ batch: true }` for a
|
|
469
|
+
* high-volume stream that should share appends with later output.
|
|
470
|
+
* `process.stdout`, `process.stderr`, `sandbox.file`, and
|
|
471
|
+
* `sandbox.file.diff` already batch.
|
|
472
|
+
*/
|
|
473
|
+
batch?: boolean;
|
|
474
|
+
}
|
|
477
475
|
/**
|
|
478
476
|
* Context passed to tool execute functions, providing capabilities like
|
|
479
477
|
* emitting custom events during execution.
|
|
@@ -493,6 +491,8 @@ export type ToolExecutionContext<TContext = unknown> = RuntimeContextField<TCont
|
|
|
493
491
|
*
|
|
494
492
|
* @param eventName - Name of the custom event
|
|
495
493
|
* @param value - Event payload value
|
|
494
|
+
* @param options - Pass `{ batch: true }` to keep this event in the
|
|
495
|
+
* durability batch instead of flushing it immediately
|
|
496
496
|
*
|
|
497
497
|
* @example
|
|
498
498
|
* ```ts
|
|
@@ -505,7 +505,7 @@ export type ToolExecutionContext<TContext = unknown> = RuntimeContextField<TCont
|
|
|
505
505
|
* })
|
|
506
506
|
* ```
|
|
507
507
|
*/
|
|
508
|
-
emitCustomEvent: (eventName: string, value: Record<string, any
|
|
508
|
+
emitCustomEvent: (eventName: string, value: Record<string, any>, options?: EmitCustomEventOptions) => void;
|
|
509
509
|
};
|
|
510
510
|
export type ToolExecuteFunction<TInput extends SchemaInput | undefined = SchemaInput, TOutput extends SchemaInput | undefined = SchemaInput, TContext = unknown> = undefined extends TContext ? (args: InferSchemaType<TInput>, context?: ToolExecutionContext<TContext>) => Promise<InferSchemaType<TOutput>> | InferSchemaType<TOutput> : (args: InferSchemaType<TInput>, context: ToolExecutionContext<TContext>) => Promise<InferSchemaType<TOutput>> | InferSchemaType<TOutput>;
|
|
511
511
|
/**
|
|
@@ -890,6 +890,12 @@ export interface TextOptions<TProviderOptionsSuperset extends Record<string, any
|
|
|
890
890
|
* Surfaced for observability/middleware; not consumed by the LLM call.
|
|
891
891
|
*/
|
|
892
892
|
parentRunId?: string;
|
|
893
|
+
/**
|
|
894
|
+
* AG-UI subagent run id when this chat runs as a child of another run.
|
|
895
|
+
* A child `chat()` passes `ctx.subagentRunId`. Middleware reads it as
|
|
896
|
+
* `ctx.subagentRunId`. Absent on a top-level run.
|
|
897
|
+
*/
|
|
898
|
+
subagentRunId?: string;
|
|
893
899
|
/** Application state mirrored in a STATE_SNAPSHOT before an interrupt terminal. */
|
|
894
900
|
state?: unknown;
|
|
895
901
|
/**
|
|
@@ -1029,13 +1035,10 @@ export interface TextMessageEndEvent extends AGUITextMessageEndEvent {
|
|
|
1029
1035
|
/**
|
|
1030
1036
|
* Emitted when a tool call starts.
|
|
1031
1037
|
*
|
|
1032
|
-
* @ag-ui/core provides: `toolCallId`, `toolCallName`, `parentMessageId
|
|
1033
|
-
*
|
|
1034
|
-
* Field shapes are taken from AG-UI via `Pick` (not `extends`) so Zod
|
|
1035
|
-
* `.passthrough()` index signatures do not pollute the StreamChunk
|
|
1036
|
-
* discriminated union — required for {@link KnownCustomEvent} narrowing.
|
|
1038
|
+
* @ag-ui/core provides: `toolCallId`, `toolCallName`, `parentMessageId?`,
|
|
1039
|
+
* `subagentRunId?`
|
|
1037
1040
|
*/
|
|
1038
|
-
export interface ToolCallStartEvent extends
|
|
1041
|
+
export interface ToolCallStartEvent extends Omit<AGUIToolCallStartEvent, 'type'> {
|
|
1039
1042
|
type: 'TOOL_CALL_START';
|
|
1040
1043
|
/** Alias of `toolCallName`. Kept so existing stream readers still compile. */
|
|
1041
1044
|
toolName?: string;
|
|
@@ -1052,11 +1055,9 @@ export interface ToolCallArgsEvent extends AGUIToolCallArgsEvent {
|
|
|
1052
1055
|
/**
|
|
1053
1056
|
* Emitted when a tool call completes.
|
|
1054
1057
|
*
|
|
1055
|
-
* @ag-ui/core provides: `toolCallId`
|
|
1056
|
-
*
|
|
1057
|
-
* Same `Pick` (not `extends`) rationale as {@link ToolCallStartEvent}.
|
|
1058
|
+
* @ag-ui/core provides: `toolCallId`, `subagentRunId?`
|
|
1058
1059
|
*/
|
|
1059
|
-
export interface ToolCallEndEvent extends
|
|
1060
|
+
export interface ToolCallEndEvent extends Omit<AGUIToolCallEndEvent, 'type'> {
|
|
1060
1061
|
type: 'TOOL_CALL_END';
|
|
1061
1062
|
/** Parsed tool arguments when the adapter already parsed them. */
|
|
1062
1063
|
input?: unknown;
|
|
@@ -1113,12 +1114,9 @@ export interface StateDeltaEvent extends AGUIStateDeltaEvent {
|
|
|
1113
1114
|
/**
|
|
1114
1115
|
* Custom event for extensibility.
|
|
1115
1116
|
*
|
|
1116
|
-
* @ag-ui/core provides: `name`, `value`
|
|
1117
|
-
*
|
|
1118
|
-
* Uses `Pick` (not `extends`) so the Zod passthrough index signature does not
|
|
1119
|
-
* erase discriminant property access on {@link KnownCustomEvent} unions.
|
|
1117
|
+
* @ag-ui/core provides: `name`, `value`, `subagentRunId?`
|
|
1120
1118
|
*/
|
|
1121
|
-
export interface CustomEvent extends
|
|
1119
|
+
export interface CustomEvent extends Omit<AGUICustomEvent, 'type'> {
|
|
1122
1120
|
type: 'CUSTOM';
|
|
1123
1121
|
metadata?: Record<string, any>;
|
|
1124
1122
|
}
|
|
@@ -1403,10 +1401,51 @@ export interface ReasoningEndEvent extends AGUIReasoningEndEvent {
|
|
|
1403
1401
|
*/
|
|
1404
1402
|
export interface ReasoningEncryptedValueEvent extends AGUIReasoningEncryptedValueEvent {
|
|
1405
1403
|
}
|
|
1404
|
+
/** AG-UI 1.0 ActivitySnapshotEvent shape. */
|
|
1405
|
+
export interface ActivitySnapshotEvent extends AGUIActivitySnapshotEvent {
|
|
1406
|
+
}
|
|
1407
|
+
/** AG-UI 1.0 ActivityDeltaEvent shape. */
|
|
1408
|
+
export interface ActivityDeltaEvent extends AGUIActivityDeltaEvent {
|
|
1409
|
+
}
|
|
1410
|
+
/** AG-UI 1.0 RawEvent shape. */
|
|
1411
|
+
export interface RawEvent extends AGUIRawEvent {
|
|
1412
|
+
}
|
|
1413
|
+
/** AG-UI 1.0 TextMessageChunkEvent shape. */
|
|
1414
|
+
export interface TextMessageChunkEvent extends AGUITextMessageChunkEvent {
|
|
1415
|
+
}
|
|
1416
|
+
/** AG-UI 1.0 ToolCallChunkEvent shape. */
|
|
1417
|
+
export interface ToolCallChunkEvent extends AGUIToolCallChunkEvent {
|
|
1418
|
+
}
|
|
1419
|
+
/** AG-UI 1.0 ReasoningMessageChunkEvent shape. */
|
|
1420
|
+
export interface ReasoningMessageChunkEvent extends AGUIReasoningMessageChunkEvent {
|
|
1421
|
+
}
|
|
1406
1422
|
/**
|
|
1407
1423
|
* Union of all AG-UI events.
|
|
1408
1424
|
*/
|
|
1409
|
-
export type AGUIEvent = RunStartedEvent | RunFinishedEvent | RunErrorEvent | TextMessageStartEvent | TextMessageContentEvent | TextMessageEndEvent | ToolCallStartEvent | ToolCallArgsEvent | ToolCallEndEvent | ToolCallResultEvent | StepStartedEvent | StepFinishedEvent | MessagesSnapshotEvent | StateSnapshotEvent | StateDeltaEvent | CustomEvent | ReasoningStartEvent | ReasoningMessageStartEvent | ReasoningMessageContentEvent | ReasoningMessageEndEvent | ReasoningEndEvent | ReasoningEncryptedValueEvent;
|
|
1425
|
+
export type AGUIEvent = ActivitySnapshotEvent | ActivityDeltaEvent | RawEvent | TextMessageChunkEvent | ToolCallChunkEvent | ReasoningMessageChunkEvent | RunStartedEvent | RunFinishedEvent | RunErrorEvent | TextMessageStartEvent | TextMessageContentEvent | TextMessageEndEvent | ToolCallStartEvent | ToolCallArgsEvent | ToolCallEndEvent | ToolCallResultEvent | StepStartedEvent | StepFinishedEvent | MessagesSnapshotEvent | StateSnapshotEvent | StateDeltaEvent | CustomEvent | ReasoningStartEvent | ReasoningMessageStartEvent | ReasoningMessageContentEvent | ReasoningMessageEndEvent | ReasoningEndEvent | ReasoningEncryptedValueEvent | SubagentStartedEvent | SubagentFinishedEvent | SubagentErrorEvent;
|
|
1426
|
+
/**
|
|
1427
|
+
* A child agent started. The later chunks for that child carry the same
|
|
1428
|
+
* `subagentRunId`.
|
|
1429
|
+
*
|
|
1430
|
+
* @ag-ui/core provides: `subagentRunId`, `name`, `description?`,
|
|
1431
|
+
* `parentSubagentRunId?`, `parentToolCallId?`, `parentMessageId?`, `metadata?`
|
|
1432
|
+
*/
|
|
1433
|
+
export interface SubagentStartedEvent extends AGUISubagentStartedEvent {
|
|
1434
|
+
}
|
|
1435
|
+
/**
|
|
1436
|
+
* A child agent's segment of this run ended.
|
|
1437
|
+
*
|
|
1438
|
+
* @ag-ui/core provides: `subagentRunId`, `result?`, `outcome?`
|
|
1439
|
+
*/
|
|
1440
|
+
export interface SubagentFinishedEvent extends AGUISubagentFinishedEvent {
|
|
1441
|
+
}
|
|
1442
|
+
/**
|
|
1443
|
+
* A child agent failed. The parent run can continue.
|
|
1444
|
+
*
|
|
1445
|
+
* @ag-ui/core provides: `subagentRunId`, `message`, `code?`
|
|
1446
|
+
*/
|
|
1447
|
+
export interface SubagentErrorEvent extends AGUISubagentErrorEvent {
|
|
1448
|
+
}
|
|
1410
1449
|
/**
|
|
1411
1450
|
* Chunk returned by the SDK during streaming chat completions.
|
|
1412
1451
|
* Uses the AG-UI protocol event format.
|
|
@@ -3,8 +3,9 @@ import { ContentPart, StreamChunk, ToolOutputState } from '../types.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* Adapter / engine yield before normalize. Public StreamChunk is spec-only.
|
|
5
5
|
* This type still allows the old extra fields.
|
|
6
|
+
* Extras never override a spec field (see WithAdapterExtras).
|
|
6
7
|
*/
|
|
7
|
-
|
|
8
|
+
type AdapterExtras = {
|
|
8
9
|
model?: string;
|
|
9
10
|
finishReason?: 'stop' | 'length' | 'content_filter' | 'tool_calls' | null;
|
|
10
11
|
usage?: any;
|
|
@@ -29,3 +30,6 @@ export type AdapterYieldChunk = StreamChunk & {
|
|
|
29
30
|
threadId?: string;
|
|
30
31
|
runId?: string;
|
|
31
32
|
};
|
|
33
|
+
type WithAdapterExtras<T> = T extends StreamChunk ? T & Omit<AdapterExtras, keyof T> : never;
|
|
34
|
+
export type AdapterYieldChunk = WithAdapterExtras<StreamChunk>;
|
|
35
|
+
export {};
|
|
@@ -1,14 +1,7 @@
|
|
|
1
|
+
import { TokenUsage as SpecTokenUsage } from '@ag-ui/core';
|
|
1
2
|
import { TokenUsage } from '../types.js';
|
|
2
3
|
/** AG-UI spec `usage[]` item (provider/model labels + token counts only). */
|
|
3
|
-
export
|
|
4
|
-
provider?: string;
|
|
5
|
-
model?: string;
|
|
6
|
-
inputTokens?: number;
|
|
7
|
-
outputTokens?: number;
|
|
8
|
-
totalTokens?: number;
|
|
9
|
-
reasoningTokens?: number;
|
|
10
|
-
cachedInputTokens?: number;
|
|
11
|
-
}
|
|
4
|
+
export type { TokenUsage as SpecTokenUsage } from '@ag-ui/core';
|
|
12
5
|
export interface ToSpecTokenUsageOptions {
|
|
13
6
|
provider?: string;
|
|
14
7
|
model?: string;
|
|
@@ -20,5 +13,12 @@ export declare function toSpecTokenUsage(usage: TokenUsage, options?: ToSpecToke
|
|
|
20
13
|
usage: Array<SpecTokenUsage>;
|
|
21
14
|
leftover?: TokenUsageLeftover;
|
|
22
15
|
};
|
|
16
|
+
/**
|
|
17
|
+
* Add two usage totals, as for a parent run and its children. Numbers add
|
|
18
|
+
* up. `billed` adds up only in the same unit. `providerUsageDetails` is
|
|
19
|
+
* opaque, so the latest one stays. `@tanstack/ai-persistence` sums per-run
|
|
20
|
+
* usage with the same rules.
|
|
21
|
+
*/
|
|
22
|
+
export declare function addTokenUsage(current: TokenUsage, next: TokenUsage): TokenUsage;
|
|
23
23
|
export declare function rebuildTokenUsage(usage: unknown, leftover?: TokenUsageLeftover): TokenUsage | undefined;
|
|
24
24
|
export declare function fromSpecTokenUsage(usage: ReadonlyArray<SpecTokenUsage> | undefined, leftover?: TokenUsageLeftover): TokenUsage | undefined;
|
|
@@ -21,6 +21,7 @@ function toSpecTokenUsage(usage, options) {
|
|
|
21
21
|
};
|
|
22
22
|
const cachedInputTokens = promptTokensDetails?.cachedTokens;
|
|
23
23
|
if (cachedInputTokens !== void 0) spec.cachedInputTokens = cachedInputTokens;
|
|
24
|
+
if (promptTokensDetails?.cacheWriteTokens !== void 0) spec.cacheWriteInputTokens = promptTokensDetails.cacheWriteTokens;
|
|
24
25
|
const reasoningTokens = completionTokensDetails?.reasoningTokens;
|
|
25
26
|
if (reasoningTokens !== void 0) spec.reasoningTokens = reasoningTokens;
|
|
26
27
|
const leftoverPrompt = promptTokensDetails ? definedDetails(withoutKey(promptTokensDetails, "cachedTokens")) : void 0;
|
|
@@ -34,17 +35,79 @@ function toSpecTokenUsage(usage, options) {
|
|
|
34
35
|
})
|
|
35
36
|
};
|
|
36
37
|
}
|
|
38
|
+
function sumNumbers(current, next) {
|
|
39
|
+
if (!current) return next;
|
|
40
|
+
if (!next) return current;
|
|
41
|
+
const result = { ...current };
|
|
42
|
+
for (const key of Object.keys(next)) {
|
|
43
|
+
const value = next[key];
|
|
44
|
+
if (typeof value !== "number") continue;
|
|
45
|
+
const previous = current[key];
|
|
46
|
+
result[key] = (typeof previous === "number" ? previous : 0) + value;
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
function sumOptional(current, next) {
|
|
51
|
+
if (current === void 0) return next;
|
|
52
|
+
if (next === void 0) return current;
|
|
53
|
+
return current + next;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Add two usage totals, as for a parent run and its children. Numbers add
|
|
57
|
+
* up. `billed` adds up only in the same unit. `providerUsageDetails` is
|
|
58
|
+
* opaque, so the latest one stays. `@tanstack/ai-persistence` sums per-run
|
|
59
|
+
* usage with the same rules.
|
|
60
|
+
*/
|
|
61
|
+
function addTokenUsage(current, next) {
|
|
62
|
+
const promptTokensDetails = sumNumbers(current.promptTokensDetails, next.promptTokensDetails);
|
|
63
|
+
const completionTokensDetails = sumNumbers(current.completionTokensDetails, next.completionTokensDetails);
|
|
64
|
+
const costDetails = sumNumbers(current.costDetails, next.costDetails);
|
|
65
|
+
const cost = sumOptional(current.cost, next.cost);
|
|
66
|
+
const durationSeconds = sumOptional(current.durationSeconds, next.durationSeconds);
|
|
67
|
+
const unitsBilled = sumOptional(current.unitsBilled, next.unitsBilled);
|
|
68
|
+
const billed = current.billed && next.billed && current.billed.unit === next.billed.unit ? {
|
|
69
|
+
quantity: current.billed.quantity + next.billed.quantity,
|
|
70
|
+
unit: current.billed.unit
|
|
71
|
+
} : next.billed ?? current.billed;
|
|
72
|
+
const providerUsageDetails = next.providerUsageDetails ?? current.providerUsageDetails;
|
|
73
|
+
return {
|
|
74
|
+
...current,
|
|
75
|
+
...next,
|
|
76
|
+
promptTokens: current.promptTokens + next.promptTokens,
|
|
77
|
+
completionTokens: current.completionTokens + next.completionTokens,
|
|
78
|
+
totalTokens: current.totalTokens + next.totalTokens,
|
|
79
|
+
...promptTokensDetails && { promptTokensDetails },
|
|
80
|
+
...completionTokensDetails && { completionTokensDetails },
|
|
81
|
+
...cost !== void 0 && { cost },
|
|
82
|
+
...costDetails && { costDetails },
|
|
83
|
+
...durationSeconds !== void 0 && { durationSeconds },
|
|
84
|
+
...unitsBilled !== void 0 && { unitsBilled },
|
|
85
|
+
...billed && { billed },
|
|
86
|
+
...providerUsageDetails && { providerUsageDetails }
|
|
87
|
+
};
|
|
88
|
+
}
|
|
37
89
|
function rebuildTokenUsage(usage, leftover) {
|
|
38
90
|
if (isTanstackUsage(usage)) return usage;
|
|
39
91
|
if (Array.isArray(usage)) return fromSpecTokenUsage(usage, leftover);
|
|
40
92
|
return fromSpecTokenUsage(void 0, leftover);
|
|
41
93
|
}
|
|
42
94
|
function fromSpecTokenUsage(usage, leftover) {
|
|
43
|
-
const spec = usage?.
|
|
44
|
-
|
|
95
|
+
const spec = usage?.reduce((total, entry) => {
|
|
96
|
+
for (const key of [
|
|
97
|
+
"inputTokens",
|
|
98
|
+
"outputTokens",
|
|
99
|
+
"totalTokens",
|
|
100
|
+
"cachedInputTokens",
|
|
101
|
+
"cacheWriteInputTokens",
|
|
102
|
+
"reasoningTokens"
|
|
103
|
+
]) if (entry[key] !== void 0) total[key] = (total[key] ?? 0) + entry[key];
|
|
104
|
+
return total;
|
|
105
|
+
}, {});
|
|
106
|
+
if ((usage === void 0 || usage.length === 0) && leftover == null) return;
|
|
45
107
|
const { promptTokensDetails: leftoverPromptDetails, completionTokensDetails: leftoverCompletionDetails, ...leftoverRest } = leftover ?? {};
|
|
46
108
|
const promptTokensDetails = definedDetails({
|
|
47
109
|
...spec?.cachedInputTokens !== void 0 ? { cachedTokens: spec.cachedInputTokens } : {},
|
|
110
|
+
...spec?.cacheWriteInputTokens !== void 0 ? { cacheWriteTokens: spec.cacheWriteInputTokens } : {},
|
|
48
111
|
...leftoverPromptDetails
|
|
49
112
|
});
|
|
50
113
|
const completionTokensDetails = definedDetails({
|
|
@@ -61,6 +124,6 @@ function fromSpecTokenUsage(usage, leftover) {
|
|
|
61
124
|
};
|
|
62
125
|
}
|
|
63
126
|
//#endregion
|
|
64
|
-
export { fromSpecTokenUsage, isTanstackUsage, rebuildTokenUsage, toSpecTokenUsage };
|
|
127
|
+
export { addTokenUsage, fromSpecTokenUsage, isTanstackUsage, rebuildTokenUsage, toSpecTokenUsage };
|
|
65
128
|
|
|
66
129
|
//# sourceMappingURL=ag-ui-usage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ag-ui-usage.js","names":[],"sources":["../../../src/utilities/ag-ui-usage.ts"],"sourcesContent":["import type { TokenUsage } from '../types'\n\n/** AG-UI spec `usage[]` item (provider/model labels + token counts only). */\nexport interface SpecTokenUsage {\n provider?: string\n model?: string\n inputTokens?: number\n outputTokens?: number\n totalTokens?: number\n reasoningTokens?: number\n cachedInputTokens?: number\n}\n\nexport interface ToSpecTokenUsageOptions {\n provider?: string\n model?: string\n}\n\n/** TokenUsage fields that have no AG-UI `usage[]` equivalent. */\nexport type TokenUsageLeftover = Omit<\n TokenUsage,\n 'promptTokens' | 'completionTokens' | 'totalTokens'\n>\n\nfunction definedDetails<T extends object>(value: T): T | undefined {\n return Object.keys(value).length > 0 ? value : undefined\n}\n\nfunction withoutKey<T extends object, K extends keyof T>(\n value: T,\n key: K,\n): Omit<T, K> {\n const next = { ...value }\n delete next[key]\n return next\n}\n\nexport function isTanstackUsage(usage: unknown): usage is TokenUsage {\n return (\n typeof usage === 'object' &&\n usage != null &&\n !Array.isArray(usage) &&\n 'promptTokens' in usage\n )\n}\n\nexport function toSpecTokenUsage(\n usage: TokenUsage,\n options?: ToSpecTokenUsageOptions,\n): { usage: Array<SpecTokenUsage>; leftover?: TokenUsageLeftover } {\n const {\n promptTokens,\n completionTokens,\n totalTokens,\n promptTokensDetails,\n completionTokensDetails,\n ...rest\n } = usage\n\n const spec: SpecTokenUsage = {\n ...(options?.provider !== undefined ? { provider: options.provider } : {}),\n ...(options?.model !== undefined ? { model: options.model } : {}),\n inputTokens: promptTokens,\n outputTokens: completionTokens,\n totalTokens,\n }\n const cachedInputTokens = promptTokensDetails?.cachedTokens\n if (cachedInputTokens !== undefined) {\n spec.cachedInputTokens = cachedInputTokens\n }\n const reasoningTokens = completionTokensDetails?.reasoningTokens\n if (reasoningTokens !== undefined) {\n spec.reasoningTokens = reasoningTokens\n }\n\n const leftoverPrompt = promptTokensDetails\n ? definedDetails(withoutKey(promptTokensDetails, 'cachedTokens'))\n : undefined\n const leftoverCompletion = completionTokensDetails\n ? definedDetails(withoutKey(completionTokensDetails, 'reasoningTokens'))\n : undefined\n\n return {\n usage: [spec],\n leftover: definedDetails({\n ...rest,\n ...(leftoverPrompt !== undefined\n ? { promptTokensDetails: leftoverPrompt }\n : {}),\n ...(leftoverCompletion !== undefined\n ? { completionTokensDetails: leftoverCompletion }\n : {}),\n }),\n }\n}\n\nexport function rebuildTokenUsage(\n usage: unknown,\n leftover?: TokenUsageLeftover,\n): TokenUsage | undefined {\n if (isTanstackUsage(usage)) {\n return usage\n }\n if (Array.isArray(usage)) {\n return fromSpecTokenUsage(usage, leftover)\n }\n return fromSpecTokenUsage(undefined, leftover)\n}\n\nexport function fromSpecTokenUsage(\n usage: ReadonlyArray<SpecTokenUsage> | undefined,\n leftover?: TokenUsageLeftover,\n): TokenUsage | undefined {\n const spec = usage?.[0]\n if (spec == null && leftover == null) {\n return undefined\n }\n\n const {\n promptTokensDetails: leftoverPromptDetails,\n completionTokensDetails: leftoverCompletionDetails,\n ...leftoverRest\n } = leftover ?? {}\n\n const promptTokensDetails = definedDetails({\n ...(spec?.cachedInputTokens !== undefined\n ? { cachedTokens: spec.cachedInputTokens }\n : {}),\n ...leftoverPromptDetails,\n })\n const completionTokensDetails = definedDetails({\n ...(spec?.reasoningTokens !== undefined\n ? { reasoningTokens: spec.reasoningTokens }\n : {}),\n ...leftoverCompletionDetails,\n })\n\n return {\n promptTokens: spec?.inputTokens ?? 0,\n completionTokens: spec?.outputTokens ?? 0,\n totalTokens: spec?.totalTokens ?? 0,\n ...leftoverRest,\n ...(promptTokensDetails !== undefined ? { promptTokensDetails } : {}),\n ...(completionTokensDetails !== undefined\n ? { completionTokensDetails }\n : {}),\n }\n}\n"],"mappings":";AAwBA,SAAS,eAAiC,OAAyB;CACjE,OAAO,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,IAAI,QAAQ,KAAA;AACjD;AAEA,SAAS,WACP,OACA,KACY;CACZ,MAAM,OAAO,EAAE,GAAG,MAAM;CACxB,OAAO,KAAK;CACZ,OAAO;AACT;AAEA,SAAgB,gBAAgB,OAAqC;CACnE,OACE,OAAO,UAAU,YACjB,SAAS,QACT,CAAC,MAAM,QAAQ,KAAK,KACpB,kBAAkB;AAEtB;AAEA,SAAgB,iBACd,OACA,SACiE;CACjE,MAAM,EACJ,cACA,kBACA,aACA,qBACA,yBACA,GAAG,SACD;CAEJ,MAAM,OAAuB;EAC3B,GAAI,SAAS,aAAa,KAAA,IAAY,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;EACxE,GAAI,SAAS,UAAU,KAAA,IAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;EAC/D,aAAa;EACb,cAAc;EACd;CACF;CACA,MAAM,oBAAoB,qBAAqB;CAC/C,IAAI,sBAAsB,KAAA,GACxB,KAAK,oBAAoB;CAE3B,MAAM,kBAAkB,yBAAyB;CACjD,IAAI,oBAAoB,KAAA,GACtB,KAAK,kBAAkB;CAGzB,MAAM,iBAAiB,sBACnB,eAAe,WAAW,qBAAqB,cAAc,CAAC,IAC9D,KAAA;CACJ,MAAM,qBAAqB,0BACvB,eAAe,WAAW,yBAAyB,iBAAiB,CAAC,IACrE,KAAA;CAEJ,OAAO;EACL,OAAO,CAAC,IAAI;EACZ,UAAU,eAAe;GACvB,GAAG;GACH,GAAI,mBAAmB,KAAA,IACnB,EAAE,qBAAqB,eAAe,IACtC,CAAC;GACL,GAAI,uBAAuB,KAAA,IACvB,EAAE,yBAAyB,mBAAmB,IAC9C,CAAC;EACP,CAAC;CACH;AACF;AAEA,SAAgB,kBACd,OACA,UACwB;CACxB,IAAI,gBAAgB,KAAK,GACvB,OAAO;CAET,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAO,mBAAmB,OAAO,QAAQ;CAE3C,OAAO,mBAAmB,KAAA,GAAW,QAAQ;AAC/C;AAEA,SAAgB,mBACd,OACA,UACwB;CACxB,MAAM,OAAO,QAAQ;CACrB,IAAI,QAAQ,QAAQ,YAAY,MAC9B;CAGF,MAAM,EACJ,qBAAqB,uBACrB,yBAAyB,2BACzB,GAAG,iBACD,YAAY,CAAC;CAEjB,MAAM,sBAAsB,eAAe;EACzC,GAAI,MAAM,sBAAsB,KAAA,IAC5B,EAAE,cAAc,KAAK,kBAAkB,IACvC,CAAC;EACL,GAAG;CACL,CAAC;CACD,MAAM,0BAA0B,eAAe;EAC7C,GAAI,MAAM,oBAAoB,KAAA,IAC1B,EAAE,iBAAiB,KAAK,gBAAgB,IACxC,CAAC;EACL,GAAG;CACL,CAAC;CAED,OAAO;EACL,cAAc,MAAM,eAAe;EACnC,kBAAkB,MAAM,gBAAgB;EACxC,aAAa,MAAM,eAAe;EAClC,GAAG;EACH,GAAI,wBAAwB,KAAA,IAAY,EAAE,oBAAoB,IAAI,CAAC;EACnE,GAAI,4BAA4B,KAAA,IAC5B,EAAE,wBAAwB,IAC1B,CAAC;CACP;AACF"}
|
|
1
|
+
{"version":3,"file":"ag-ui-usage.js","names":[],"sources":["../../../src/utilities/ag-ui-usage.ts"],"sourcesContent":["import type { TokenUsage as SpecTokenUsage } from '@ag-ui/core'\nimport type { TokenUsage } from '../types'\n\n/** AG-UI spec `usage[]` item (provider/model labels + token counts only). */\nexport type { TokenUsage as SpecTokenUsage } from '@ag-ui/core'\n\nexport interface ToSpecTokenUsageOptions {\n provider?: string\n model?: string\n}\n\n/** TokenUsage fields that have no AG-UI `usage[]` equivalent. */\nexport type TokenUsageLeftover = Omit<\n TokenUsage,\n 'promptTokens' | 'completionTokens' | 'totalTokens'\n>\n\nfunction definedDetails<T extends object>(value: T): T | undefined {\n return Object.keys(value).length > 0 ? value : undefined\n}\n\nfunction withoutKey<T extends object, K extends keyof T>(\n value: T,\n key: K,\n): Omit<T, K> {\n const next = { ...value }\n delete next[key]\n return next\n}\n\nexport function isTanstackUsage(usage: unknown): usage is TokenUsage {\n return (\n typeof usage === 'object' &&\n usage != null &&\n !Array.isArray(usage) &&\n 'promptTokens' in usage\n )\n}\n\nexport function toSpecTokenUsage(\n usage: TokenUsage,\n options?: ToSpecTokenUsageOptions,\n): { usage: Array<SpecTokenUsage>; leftover?: TokenUsageLeftover } {\n const {\n promptTokens,\n completionTokens,\n totalTokens,\n promptTokensDetails,\n completionTokensDetails,\n ...rest\n } = usage\n\n const spec: SpecTokenUsage = {\n ...(options?.provider !== undefined ? { provider: options.provider } : {}),\n ...(options?.model !== undefined ? { model: options.model } : {}),\n inputTokens: promptTokens,\n outputTokens: completionTokens,\n totalTokens,\n }\n const cachedInputTokens = promptTokensDetails?.cachedTokens\n if (cachedInputTokens !== undefined) {\n spec.cachedInputTokens = cachedInputTokens\n }\n if (promptTokensDetails?.cacheWriteTokens !== undefined) {\n spec.cacheWriteInputTokens = promptTokensDetails.cacheWriteTokens\n }\n const reasoningTokens = completionTokensDetails?.reasoningTokens\n if (reasoningTokens !== undefined) {\n spec.reasoningTokens = reasoningTokens\n }\n\n // cacheWriteTokens stays in the leftover too, so clients built before\n // cacheWriteInputTokens existed still rebuild it.\n const leftoverPrompt = promptTokensDetails\n ? definedDetails(withoutKey(promptTokensDetails, 'cachedTokens'))\n : undefined\n const leftoverCompletion = completionTokensDetails\n ? definedDetails(withoutKey(completionTokensDetails, 'reasoningTokens'))\n : undefined\n\n return {\n usage: [spec],\n leftover: definedDetails({\n ...rest,\n ...(leftoverPrompt !== undefined\n ? { promptTokensDetails: leftoverPrompt }\n : {}),\n ...(leftoverCompletion !== undefined\n ? { completionTokensDetails: leftoverCompletion }\n : {}),\n }),\n }\n}\n\nfunction sumNumbers<T extends object>(\n current: T | undefined,\n next: T | undefined,\n): T | undefined {\n if (!current) return next\n if (!next) return current\n const result = { ...current }\n for (const key of Object.keys(next) as Array<keyof T>) {\n const value = next[key]\n if (typeof value !== 'number') continue\n const previous = current[key]\n result[key] = ((typeof previous === 'number' ? previous : 0) +\n value) as T[keyof T]\n }\n return result\n}\n\nfunction sumOptional(current?: number, next?: number): number | undefined {\n if (current === undefined) return next\n if (next === undefined) return current\n return current + next\n}\n\n/**\n * Add two usage totals, as for a parent run and its children. Numbers add\n * up. `billed` adds up only in the same unit. `providerUsageDetails` is\n * opaque, so the latest one stays. `@tanstack/ai-persistence` sums per-run\n * usage with the same rules.\n */\nexport function addTokenUsage(\n current: TokenUsage,\n next: TokenUsage,\n): TokenUsage {\n const promptTokensDetails = sumNumbers(\n current.promptTokensDetails,\n next.promptTokensDetails,\n )\n const completionTokensDetails = sumNumbers(\n current.completionTokensDetails,\n next.completionTokensDetails,\n )\n const costDetails = sumNumbers(current.costDetails, next.costDetails)\n const cost = sumOptional(current.cost, next.cost)\n const durationSeconds = sumOptional(\n current.durationSeconds,\n next.durationSeconds,\n )\n const unitsBilled = sumOptional(current.unitsBilled, next.unitsBilled)\n const billed =\n current.billed && next.billed && current.billed.unit === next.billed.unit\n ? {\n quantity: current.billed.quantity + next.billed.quantity,\n unit: current.billed.unit,\n }\n : (next.billed ?? current.billed)\n const providerUsageDetails =\n next.providerUsageDetails ?? current.providerUsageDetails\n return {\n ...current,\n ...next,\n promptTokens: current.promptTokens + next.promptTokens,\n completionTokens: current.completionTokens + next.completionTokens,\n totalTokens: current.totalTokens + next.totalTokens,\n ...(promptTokensDetails && { promptTokensDetails }),\n ...(completionTokensDetails && { completionTokensDetails }),\n ...(cost !== undefined && { cost }),\n ...(costDetails && { costDetails }),\n ...(durationSeconds !== undefined && { durationSeconds }),\n ...(unitsBilled !== undefined && { unitsBilled }),\n ...(billed && { billed }),\n ...(providerUsageDetails && { providerUsageDetails }),\n }\n}\n\nexport function rebuildTokenUsage(\n usage: unknown,\n leftover?: TokenUsageLeftover,\n): TokenUsage | undefined {\n if (isTanstackUsage(usage)) {\n return usage\n }\n if (Array.isArray(usage)) {\n return fromSpecTokenUsage(usage, leftover)\n }\n return fromSpecTokenUsage(undefined, leftover)\n}\n\nexport function fromSpecTokenUsage(\n usage: ReadonlyArray<SpecTokenUsage> | undefined,\n leftover?: TokenUsageLeftover,\n): TokenUsage | undefined {\n const spec = usage?.reduce<SpecTokenUsage>((total, entry) => {\n for (const key of [\n 'inputTokens',\n 'outputTokens',\n 'totalTokens',\n 'cachedInputTokens',\n 'cacheWriteInputTokens',\n 'reasoningTokens',\n ] as const) {\n if (entry[key] !== undefined) total[key] = (total[key] ?? 0) + entry[key]\n }\n return total\n }, {})\n if ((usage === undefined || usage.length === 0) && leftover == null) {\n return undefined\n }\n\n const {\n promptTokensDetails: leftoverPromptDetails,\n completionTokensDetails: leftoverCompletionDetails,\n ...leftoverRest\n } = leftover ?? {}\n\n const promptTokensDetails = definedDetails({\n ...(spec?.cachedInputTokens !== undefined\n ? { cachedTokens: spec.cachedInputTokens }\n : {}),\n ...(spec?.cacheWriteInputTokens !== undefined\n ? { cacheWriteTokens: spec.cacheWriteInputTokens }\n : {}),\n ...leftoverPromptDetails,\n })\n const completionTokensDetails = definedDetails({\n ...(spec?.reasoningTokens !== undefined\n ? { reasoningTokens: spec.reasoningTokens }\n : {}),\n ...leftoverCompletionDetails,\n })\n\n return {\n promptTokens: spec?.inputTokens ?? 0,\n completionTokens: spec?.outputTokens ?? 0,\n totalTokens: spec?.totalTokens ?? 0,\n ...leftoverRest,\n ...(promptTokensDetails !== undefined ? { promptTokensDetails } : {}),\n ...(completionTokensDetails !== undefined\n ? { completionTokensDetails }\n : {}),\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { tanstackMetadata } from "./merge-metadata.js";
|
|
2
2
|
import { normalizeToolResult } from "./tool-result.js";
|
|
3
|
+
import { wireSubagentInfo, wireSubagentRunId } from "./subagent-wire.js";
|
|
3
4
|
import { coerceCreatedAt, modelMessageToUIMessage } from "../activities/chat/messages.js";
|
|
4
5
|
//#region src/utilities/ag-ui-wire.ts
|
|
5
6
|
function isRecord(value) {
|
|
@@ -110,6 +111,7 @@ function uiMessagesToWire(messages, options) {
|
|
|
110
111
|
metadata: rebuiltToolMetadata(void 0, void 0, void 0, result)
|
|
111
112
|
});
|
|
112
113
|
}
|
|
114
|
+
for (const part of parts) if (part.type === "subagent") wire.push(...subagentToWire(part, options));
|
|
113
115
|
}
|
|
114
116
|
return wire;
|
|
115
117
|
}
|
|
@@ -142,6 +144,7 @@ function messageMetadata(msg, parts, includeSnapshotStructuredOutput) {
|
|
|
142
144
|
const previousTanstack = tanstackMetadata(msg);
|
|
143
145
|
const tanstack = {};
|
|
144
146
|
if (previousTanstack?.model !== void 0) tanstack.model = previousTanstack.model;
|
|
147
|
+
if (previousTanstack?.runId !== void 0) tanstack.runId = previousTanstack.runId;
|
|
145
148
|
if (previousTanstack?.signature !== void 0) tanstack.signature = previousTanstack.signature;
|
|
146
149
|
const createdAt = coerceCreatedAt(msg.createdAt);
|
|
147
150
|
if (createdAt !== void 0) tanstack.createdAt = createdAt.toISOString();
|
|
@@ -175,6 +178,59 @@ function collectText(parts) {
|
|
|
175
178
|
else if (p.type === "structured-output" && p.status === "complete" && p.raw !== "") out.push(p.raw);
|
|
176
179
|
return out.join("");
|
|
177
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* A child's messages, tagged with its AG-UI `subagentRunId`. The card data
|
|
183
|
+
* rides in `metadata.tanstack.subagent`, so the other side can rebuild the
|
|
184
|
+
* card and continue a suspended child.
|
|
185
|
+
*/
|
|
186
|
+
function subagentToWire(part, options) {
|
|
187
|
+
const { subagent } = part;
|
|
188
|
+
const info = {
|
|
189
|
+
name: subagent.name,
|
|
190
|
+
status: subagent.status,
|
|
191
|
+
...subagent.description !== void 0 && { description: subagent.description },
|
|
192
|
+
...subagent.error !== void 0 && { error: subagent.error },
|
|
193
|
+
...subagent.interruptIds !== void 0 && { interruptIds: subagent.interruptIds },
|
|
194
|
+
...subagent.parentSubagentRunId !== void 0 && { parentSubagentRunId: subagent.parentSubagentRunId },
|
|
195
|
+
...subagent.parentToolCallId !== void 0 && { parentToolCallId: subagent.parentToolCallId },
|
|
196
|
+
...subagent.metadata !== void 0 && { metadata: subagent.metadata }
|
|
197
|
+
};
|
|
198
|
+
const child = uiMessagesToWire(subagent.messages, options);
|
|
199
|
+
const own = child.some((message) => wireSubagentRunId(message) === void 0);
|
|
200
|
+
return (own ? child : [{
|
|
201
|
+
id: `subagent:${subagent.id}`,
|
|
202
|
+
role: "assistant"
|
|
203
|
+
}, ...child]).map((message, index) => {
|
|
204
|
+
const nestedId = wireSubagentRunId(message);
|
|
205
|
+
if (nestedId !== void 0) {
|
|
206
|
+
const nested = wireSubagentInfo(message);
|
|
207
|
+
if (!nested || nested.parentSubagentRunId !== void 0) return message;
|
|
208
|
+
return withSubagentInfo(message, nestedId, {
|
|
209
|
+
...nested,
|
|
210
|
+
parentSubagentRunId: subagent.id
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
return withSubagentInfo(message, subagent.id, !own && index === 0 ? {
|
|
214
|
+
...info,
|
|
215
|
+
placeholder: true
|
|
216
|
+
} : info);
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
function withSubagentInfo(message, subagentRunId, info) {
|
|
220
|
+
const metadata = isRecord(message.metadata) ? message.metadata : {};
|
|
221
|
+
const tanstack = isRecord(metadata.tanstack) ? metadata.tanstack : {};
|
|
222
|
+
return {
|
|
223
|
+
...message,
|
|
224
|
+
subagentRunId,
|
|
225
|
+
metadata: {
|
|
226
|
+
...metadata,
|
|
227
|
+
tanstack: {
|
|
228
|
+
...tanstack,
|
|
229
|
+
subagent: info
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
178
234
|
function collectUserContent(parts) {
|
|
179
235
|
if (!parts.some((p) => p.type === "image" || p.type === "audio" || p.type === "video" || p.type === "document")) return collectText(parts);
|
|
180
236
|
const out = [];
|