@tanstack/ai 0.58.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.
Files changed (85) hide show
  1. package/dist/esm/activities/chat/agents/define-agent.d.ts +81 -0
  2. package/dist/esm/activities/chat/agents/define-agent.js +34 -0
  3. package/dist/esm/activities/chat/agents/define-agent.js.map +1 -0
  4. package/dist/esm/activities/chat/agents/route.d.ts +53 -0
  5. package/dist/esm/activities/chat/agents/route.js +59 -0
  6. package/dist/esm/activities/chat/agents/route.js.map +1 -0
  7. package/dist/esm/activities/chat/agents/spawn.d.ts +124 -0
  8. package/dist/esm/activities/chat/agents/spawn.js +490 -0
  9. package/dist/esm/activities/chat/agents/spawn.js.map +1 -0
  10. package/dist/esm/activities/chat/agents/turn.d.ts +36 -0
  11. package/dist/esm/activities/chat/agents/turn.js +78 -0
  12. package/dist/esm/activities/chat/agents/turn.js.map +1 -0
  13. package/dist/esm/activities/chat/index.d.ts +13 -3
  14. package/dist/esm/activities/chat/index.js +337 -13
  15. package/dist/esm/activities/chat/index.js.map +1 -1
  16. package/dist/esm/activities/chat/messages.d.ts +7 -1
  17. package/dist/esm/activities/chat/messages.js +94 -18
  18. package/dist/esm/activities/chat/messages.js.map +1 -1
  19. package/dist/esm/activities/chat/middleware/run-store.d.ts +43 -7
  20. package/dist/esm/activities/chat/middleware/run-store.js +8 -1
  21. package/dist/esm/activities/chat/middleware/run-store.js.map +1 -1
  22. package/dist/esm/activities/chat/middleware/types.d.ts +47 -1
  23. package/dist/esm/activities/chat/middleware/types.js.map +1 -1
  24. package/dist/esm/activities/chat/stream/processor.d.ts +46 -0
  25. package/dist/esm/activities/chat/stream/processor.js +280 -7
  26. package/dist/esm/activities/chat/stream/processor.js.map +1 -1
  27. package/dist/esm/activities/chat/tools/tool-calls.d.ts +17 -3
  28. package/dist/esm/activities/chat/tools/tool-calls.js +54 -5
  29. package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
  30. package/dist/esm/activities/generateAudio/index.js +1 -1
  31. package/dist/esm/activities/generateImage/index.js +1 -1
  32. package/dist/esm/activities/generateLiveVideo/index.js +1 -1
  33. package/dist/esm/activities/generateSpeech/index.js +1 -1
  34. package/dist/esm/activities/generateTranscription/index.js +1 -1
  35. package/dist/esm/activities/generateVoice/index.js +1 -1
  36. package/dist/esm/activities/generateWorld/index.js +1 -1
  37. package/dist/esm/activities/index.d.ts +3 -0
  38. package/dist/esm/activities/index.js +5 -3
  39. package/dist/esm/activities/summarize/index.js +1 -1
  40. package/dist/esm/client.d.ts +5 -36
  41. package/dist/esm/client.js +4 -37
  42. package/dist/esm/client.js.map +1 -1
  43. package/dist/esm/index.d.ts +5 -0
  44. package/dist/esm/index.js +6 -3
  45. package/dist/esm/middlewares/content-guard.js.map +1 -1
  46. package/dist/esm/types.d.ts +110 -88
  47. package/dist/esm/utilities/adapter-yield-chunk.d.ts +5 -1
  48. package/dist/esm/utilities/ag-ui-usage.d.ts +9 -9
  49. package/dist/esm/utilities/ag-ui-usage.js +66 -3
  50. package/dist/esm/utilities/ag-ui-usage.js.map +1 -1
  51. package/dist/esm/utilities/ag-ui-wire.js +56 -0
  52. package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
  53. package/dist/esm/utilities/normalize-stream-chunk.js +7 -2
  54. package/dist/esm/utilities/normalize-stream-chunk.js.map +1 -1
  55. package/dist/esm/utilities/spec-event-keys.js +13 -8
  56. package/dist/esm/utilities/spec-event-keys.js.map +1 -1
  57. package/dist/esm/utilities/subagent-wire.d.ts +36 -0
  58. package/dist/esm/utilities/subagent-wire.js +131 -0
  59. package/dist/esm/utilities/subagent-wire.js.map +1 -0
  60. package/package.json +2 -2
  61. package/skills/ai-core/adapter-configuration/references/grok-adapter.md +1 -1
  62. package/skills/ai-core/media-generation/SKILL.md +2 -2
  63. package/skills/ai-core/middleware/SKILL.md +7 -4
  64. package/src/activities/chat/agents/define-agent.ts +121 -0
  65. package/src/activities/chat/agents/route.ts +115 -0
  66. package/src/activities/chat/agents/spawn.ts +806 -0
  67. package/src/activities/chat/agents/turn.ts +151 -0
  68. package/src/activities/chat/index.ts +529 -11
  69. package/src/activities/chat/messages.ts +125 -15
  70. package/src/activities/chat/middleware/run-store.ts +56 -7
  71. package/src/activities/chat/middleware/types.ts +47 -0
  72. package/src/activities/chat/stream/processor.ts +428 -8
  73. package/src/activities/chat/tools/tool-calls.ts +77 -11
  74. package/src/activities/index.ts +15 -0
  75. package/src/client.ts +22 -35
  76. package/src/index.ts +23 -0
  77. package/src/middlewares/content-guard.ts +7 -5
  78. package/src/types.ts +154 -94
  79. package/src/utilities/adapter-yield-chunk.ts +10 -2
  80. package/src/utilities/ag-ui-usage.test.ts +38 -0
  81. package/src/utilities/ag-ui-usage.ts +98 -11
  82. package/src/utilities/ag-ui-wire.ts +74 -0
  83. package/src/utilities/normalize-stream-chunk.ts +10 -2
  84. package/src/utilities/spec-event-keys.ts +34 -7
  85. package/src/utilities/subagent-wire.ts +184 -0
@@ -11,11 +11,14 @@ import { INTERRUPT_CONTINUATION_METADATA_KEY, INTERRUPT_CONTINUATION_VERSION, ge
11
11
  import { convertMessagesToModelMessages, generateMessageId, modelMessageToUIMessage, modelMessagesToUIMessages, normalizeToUIMessage, uiMessageToModelMessages } from "./activities/chat/messages.js";
12
12
  import { uiMessagesToWire } from "./utilities/ag-ui-wire.js";
13
13
  import { restoreInboundChunk } from "./utilities/restore-inbound-chunk.js";
14
+ import { defineAgent } from "./activities/chat/agents/define-agent.js";
15
+ import { subagentRoute } from "./activities/chat/agents/route.js";
14
16
  import { toolDefinition } from "./activities/chat/tools/tool-definition.js";
15
17
  import { getChunkRunId, getChunkThreadId } from "./utilities/chunk-ids.js";
16
18
  import { PartialJSONParser, defaultJSONParser, parsePartialJSON } from "./activities/chat/stream/json-parser.js";
17
19
  import { BatchStrategy, CompositeStrategy, ImmediateStrategy, PunctuationStrategy, WordBoundaryStrategy } from "./activities/chat/stream/strategies.js";
18
20
  import { StreamProcessor } from "./activities/chat/stream/processor.js";
21
+ import { EventType } from "@ag-ui/core";
19
22
  //#region src/client.ts
20
23
  var generationKinds = [
21
24
  "image",
@@ -119,43 +122,7 @@ async function generationParamsFromRequest(kind, request) {
119
122
  if (!isRecord(body)) throw new Error("Generation request body must be a JSON object.");
120
123
  return generationParamsFromBody(kind, body);
121
124
  }
122
- var EventType = /* @__PURE__ */ function(EventType) {
123
- EventType["TEXT_MESSAGE_START"] = "TEXT_MESSAGE_START";
124
- EventType["TEXT_MESSAGE_CONTENT"] = "TEXT_MESSAGE_CONTENT";
125
- EventType["TEXT_MESSAGE_END"] = "TEXT_MESSAGE_END";
126
- EventType["TEXT_MESSAGE_CHUNK"] = "TEXT_MESSAGE_CHUNK";
127
- EventType["TOOL_CALL_START"] = "TOOL_CALL_START";
128
- EventType["TOOL_CALL_ARGS"] = "TOOL_CALL_ARGS";
129
- EventType["TOOL_CALL_END"] = "TOOL_CALL_END";
130
- EventType["TOOL_CALL_CHUNK"] = "TOOL_CALL_CHUNK";
131
- EventType["TOOL_CALL_RESULT"] = "TOOL_CALL_RESULT";
132
- EventType["THINKING_START"] = "THINKING_START";
133
- EventType["THINKING_END"] = "THINKING_END";
134
- EventType["THINKING_TEXT_MESSAGE_START"] = "THINKING_TEXT_MESSAGE_START";
135
- EventType["THINKING_TEXT_MESSAGE_CONTENT"] = "THINKING_TEXT_MESSAGE_CONTENT";
136
- EventType["THINKING_TEXT_MESSAGE_END"] = "THINKING_TEXT_MESSAGE_END";
137
- EventType["STATE_SNAPSHOT"] = "STATE_SNAPSHOT";
138
- EventType["STATE_DELTA"] = "STATE_DELTA";
139
- EventType["MESSAGES_SNAPSHOT"] = "MESSAGES_SNAPSHOT";
140
- EventType["ACTIVITY_SNAPSHOT"] = "ACTIVITY_SNAPSHOT";
141
- EventType["ACTIVITY_DELTA"] = "ACTIVITY_DELTA";
142
- EventType["RAW"] = "RAW";
143
- EventType["CUSTOM"] = "CUSTOM";
144
- EventType["RUN_STARTED"] = "RUN_STARTED";
145
- EventType["RUN_FINISHED"] = "RUN_FINISHED";
146
- EventType["RUN_ERROR"] = "RUN_ERROR";
147
- EventType["STEP_STARTED"] = "STEP_STARTED";
148
- EventType["STEP_FINISHED"] = "STEP_FINISHED";
149
- EventType["REASONING_START"] = "REASONING_START";
150
- EventType["REASONING_MESSAGE_START"] = "REASONING_MESSAGE_START";
151
- EventType["REASONING_MESSAGE_CONTENT"] = "REASONING_MESSAGE_CONTENT";
152
- EventType["REASONING_MESSAGE_END"] = "REASONING_MESSAGE_END";
153
- EventType["REASONING_MESSAGE_CHUNK"] = "REASONING_MESSAGE_CHUNK";
154
- EventType["REASONING_END"] = "REASONING_END";
155
- EventType["REASONING_ENCRYPTED_VALUE"] = "REASONING_ENCRYPTED_VALUE";
156
- return EventType;
157
- }({});
158
125
  //#endregion
159
- export { BatchStrategy, CompositeStrategy, EventType, INTERRUPT_BINDING_METADATA_KEY, INTERRUPT_BINDING_VERSION, INTERRUPT_CONTINUATION_METADATA_KEY, INTERRUPT_CONTINUATION_VERSION, INTERRUPT_PAYLOAD_METADATA_KEY, ImmediateStrategy, PartialJSONParser, PunctuationStrategy, StreamProcessor, WordBoundaryStrategy, canonicalInterruptJson, canonicalizeInterruptResolutions, cloneAndDeepFreezeJson, convertMessagesToModelMessages, convertSchemaToJsonSchema, defaultJSONParser, defineInterrupt, digestInterruptJson, fromSpecTokenUsage, generateMessageId, generationParamsFromBody, generationParamsFromRequest, genericInterruptContinuationFromDescriptor, getChunkRunId, getChunkThreadId, hashInterruptDefinitionSchema, hashSchemaInput, isStandardSchema, mergeMetadata, modelMessageToUIMessage, modelMessagesToUIMessages, normalizeApprovalSchema, normalizeStreamChunk, normalizeToUIMessage, parsePartialJSON, parseWithStandardSchema, readGenericInterruptContinuation, readInterruptBinding, readUnopenedInterruptBinding, restoreInboundChunk, tanstackMetadata, toSpecTokenUsage, toolDefinition, uiMessageToModelMessages, uiMessagesToWire, validateWithStandardSchema, withInterruptBinding, withTanstackMetadata, withoutInterruptBinding, wrapGenericInterruptContinuation };
126
+ export { BatchStrategy, CompositeStrategy, EventType, INTERRUPT_BINDING_METADATA_KEY, INTERRUPT_BINDING_VERSION, INTERRUPT_CONTINUATION_METADATA_KEY, INTERRUPT_CONTINUATION_VERSION, INTERRUPT_PAYLOAD_METADATA_KEY, ImmediateStrategy, PartialJSONParser, PunctuationStrategy, StreamProcessor, WordBoundaryStrategy, canonicalInterruptJson, canonicalizeInterruptResolutions, cloneAndDeepFreezeJson, convertMessagesToModelMessages, convertSchemaToJsonSchema, defaultJSONParser, defineAgent, defineInterrupt, digestInterruptJson, fromSpecTokenUsage, generateMessageId, generationParamsFromBody, generationParamsFromRequest, genericInterruptContinuationFromDescriptor, getChunkRunId, getChunkThreadId, hashInterruptDefinitionSchema, hashSchemaInput, isStandardSchema, mergeMetadata, modelMessageToUIMessage, modelMessagesToUIMessages, normalizeApprovalSchema, normalizeStreamChunk, normalizeToUIMessage, parsePartialJSON, parseWithStandardSchema, readGenericInterruptContinuation, readInterruptBinding, readUnopenedInterruptBinding, restoreInboundChunk, subagentRoute, tanstackMetadata, toSpecTokenUsage, toolDefinition, uiMessageToModelMessages, uiMessagesToWire, validateWithStandardSchema, withInterruptBinding, withTanstackMetadata, withoutInterruptBinding, wrapGenericInterruptContinuation };
160
127
 
161
128
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":[],"sources":["../../src/client.ts"],"sourcesContent":["import type {\n AudioGenerationOptions,\n ImageGenerationOptions,\n TTSOptions,\n TranscriptionOptions,\n VoiceGenerationOptions,\n VideoGenerationOptions,\n WorldGenerationOptions,\n LiveVideoGenerationOptions,\n} from './types'\n\nexport type GenerationKind =\n | 'image'\n | 'audio'\n | 'tts'\n | 'voice'\n | 'video'\n | 'transcription'\n | 'world'\n | 'liveVideo'\n\ntype GenerationInputByKind = {\n image: Omit<ImageGenerationOptions, 'logger' | 'model'>\n audio: Omit<AudioGenerationOptions, 'logger' | 'model'>\n tts: Omit<TTSOptions, 'logger' | 'model'>\n voice: Omit<VoiceGenerationOptions, 'logger' | 'model'>\n video: Omit<VideoGenerationOptions, 'logger' | 'model'>\n transcription: Omit<TranscriptionOptions, 'logger' | 'model'>\n world: Omit<WorldGenerationOptions, 'logger' | 'model'>\n liveVideo: Omit<LiveVideoGenerationOptions, 'logger' | 'model'>\n}\n\nexport interface GenerationParams<TKind extends GenerationKind> {\n input: GenerationInputByKind[TKind]\n forwardedProps: Record<string, unknown>\n threadId?: string\n runId?: string\n}\n\nconst generationKinds = [\n 'image',\n 'audio',\n 'tts',\n 'voice',\n 'video',\n 'transcription',\n 'world',\n 'liveVideo',\n] as const satisfies ReadonlyArray<GenerationKind>\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction hasOwnKey(value: Record<string, unknown>, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(value, key)\n}\n\nfunction isGenerationEnvelope(body: unknown): body is Record<string, unknown> {\n return (\n isRecord(body) &&\n (hasOwnKey(body, 'data') || hasOwnKey(body, 'forwardedProps'))\n )\n}\n\nfunction assertGenerationKind(kind: unknown): asserts kind is GenerationKind {\n if (!generationKinds.includes(kind as GenerationKind)) {\n throw new Error(\n `Unsupported generation kind: ${String(\n kind,\n )}. Expected one of ${generationKinds.join(', ')}.`,\n )\n }\n}\n\n/**\n * The input field(s) that identify a generation body for a kind. Most kinds\n * have exactly one; `voice` accepts either of its two creation modes, so any\n * one of its keys is enough.\n */\nfunction requiredKeysForKind(kind: GenerationKind): Array<string> {\n // Enumerated rather than defaulted so a new generation kind has to declare\n // the field that identifies its body instead of silently inheriting\n // `prompt`.\n switch (kind) {\n case 'tts':\n return ['text']\n case 'transcription':\n return ['audio']\n case 'voice':\n return ['prompt', 'referenceAudio']\n case 'image':\n case 'audio':\n case 'video':\n case 'world':\n case 'liveVideo':\n return ['prompt']\n }\n}\n\nfunction assertInputForKind(\n kind: GenerationKind,\n input: unknown,\n): asserts input is GenerationInputByKind[GenerationKind] {\n if (!isRecord(input)) {\n throw new Error(`Generation ${kind} input must be an object.`)\n }\n\n const requiredKeys = requiredKeysForKind(kind)\n\n if (!requiredKeys.some((key) => hasOwnKey(input, key))) {\n throw new Error(\n `Generation ${kind} input must include ${requiredKeys.join(' or ')}.`,\n )\n }\n}\n\nfunction isInputForKind(kind: GenerationKind, input: unknown): boolean {\n if (!isRecord(input)) return false\n\n return requiredKeysForKind(kind).some((key) => hasOwnKey(input, key))\n}\n\nfunction forwardedPropsFromEnvelope(\n envelope: Record<string, unknown>,\n): Record<string, unknown> {\n if (!hasOwnKey(envelope, 'forwardedProps')) {\n return {}\n }\n\n if (!isRecord(envelope.forwardedProps)) {\n throw new Error('Generation envelope forwardedProps must be an object.')\n }\n\n return envelope.forwardedProps\n}\n\nfunction optionalStringField(\n envelope: Record<string, unknown>,\n key: 'threadId' | 'runId',\n): string | undefined {\n if (!hasOwnKey(envelope, key)) {\n return undefined\n }\n\n const value = envelope[key]\n if (typeof value !== 'string') {\n throw new Error(`Generation envelope ${key} must be a string.`)\n }\n\n return value\n}\n\nfunction generationIdentityFields(envelope: Record<string, unknown>): {\n threadId?: string\n runId?: string\n} {\n const identity: {\n threadId?: string\n runId?: string\n } = {}\n const threadId = optionalStringField(envelope, 'threadId')\n const runId = optionalStringField(envelope, 'runId')\n\n if (threadId !== undefined) identity.threadId = threadId\n if (runId !== undefined) identity.runId = runId\n\n return identity\n}\n\nexport function generationParamsFromBody<TKind extends GenerationKind>(\n kind: TKind,\n body: unknown,\n): GenerationParams<TKind> {\n assertGenerationKind(kind)\n\n if (isInputForKind(kind, body)) {\n assertInputForKind(kind, body)\n return {\n input: body as GenerationInputByKind[TKind],\n forwardedProps: {},\n }\n }\n\n if (!isGenerationEnvelope(body)) {\n assertInputForKind(kind, body)\n return {\n input: body as GenerationInputByKind[TKind],\n forwardedProps: {},\n }\n }\n\n if (!hasOwnKey(body, 'data')) {\n throw new Error(`Generation ${kind} envelope must include data.`)\n }\n\n const input = body.data\n assertInputForKind(kind, input)\n\n const forwardedProps = forwardedPropsFromEnvelope(body)\n\n return {\n input: input as GenerationInputByKind[TKind],\n forwardedProps,\n ...generationIdentityFields(body),\n }\n}\n\nexport async function generationParamsFromRequest<TKind extends GenerationKind>(\n kind: TKind,\n request: Request,\n): Promise<GenerationParams<TKind>> {\n let body: unknown\n try {\n body = await request.json()\n } catch (error) {\n throw new Error('Invalid JSON request body.', { cause: error })\n }\n\n if (!isRecord(body)) {\n throw new Error('Generation request body must be a JSON object.')\n }\n\n return generationParamsFromBody(kind, body)\n}\n\nexport enum EventType {\n TEXT_MESSAGE_START = 'TEXT_MESSAGE_START',\n TEXT_MESSAGE_CONTENT = 'TEXT_MESSAGE_CONTENT',\n TEXT_MESSAGE_END = 'TEXT_MESSAGE_END',\n TEXT_MESSAGE_CHUNK = 'TEXT_MESSAGE_CHUNK',\n TOOL_CALL_START = 'TOOL_CALL_START',\n TOOL_CALL_ARGS = 'TOOL_CALL_ARGS',\n TOOL_CALL_END = 'TOOL_CALL_END',\n TOOL_CALL_CHUNK = 'TOOL_CALL_CHUNK',\n TOOL_CALL_RESULT = 'TOOL_CALL_RESULT',\n THINKING_START = 'THINKING_START',\n THINKING_END = 'THINKING_END',\n THINKING_TEXT_MESSAGE_START = 'THINKING_TEXT_MESSAGE_START',\n THINKING_TEXT_MESSAGE_CONTENT = 'THINKING_TEXT_MESSAGE_CONTENT',\n THINKING_TEXT_MESSAGE_END = 'THINKING_TEXT_MESSAGE_END',\n STATE_SNAPSHOT = 'STATE_SNAPSHOT',\n STATE_DELTA = 'STATE_DELTA',\n MESSAGES_SNAPSHOT = 'MESSAGES_SNAPSHOT',\n ACTIVITY_SNAPSHOT = 'ACTIVITY_SNAPSHOT',\n ACTIVITY_DELTA = 'ACTIVITY_DELTA',\n RAW = 'RAW',\n CUSTOM = 'CUSTOM',\n RUN_STARTED = 'RUN_STARTED',\n RUN_FINISHED = 'RUN_FINISHED',\n RUN_ERROR = 'RUN_ERROR',\n STEP_STARTED = 'STEP_STARTED',\n STEP_FINISHED = 'STEP_FINISHED',\n REASONING_START = 'REASONING_START',\n REASONING_MESSAGE_START = 'REASONING_MESSAGE_START',\n REASONING_MESSAGE_CONTENT = 'REASONING_MESSAGE_CONTENT',\n REASONING_MESSAGE_END = 'REASONING_MESSAGE_END',\n REASONING_MESSAGE_CHUNK = 'REASONING_MESSAGE_CHUNK',\n REASONING_END = 'REASONING_END',\n REASONING_ENCRYPTED_VALUE = 'REASONING_ENCRYPTED_VALUE',\n}\n\nexport {\n toolDefinition,\n type AnyClientTool,\n type ClientTool,\n type InferToolInput,\n type InferToolName,\n type InferToolOutput,\n type ApprovalCapabilityOf,\n type ApprovalSchemaConfig,\n type ApprovalSchemaOf,\n type InputSchemaOf,\n type OutputSchemaOf,\n type NoSchema,\n type ToolDefinition,\n type ToolDefinitionConfig,\n type ToolDefinitionInstance,\n} from './activities/chat/tools/tool-definition'\n\nexport {\n hashSchemaInput,\n normalizeApprovalSchema,\n type NormalizedApprovalSchema,\n type NormalizedSchemaInput,\n} from './activities/chat/tools/approval-schema'\n\nexport {\n canonicalInterruptJson,\n cloneAndDeepFreezeJson,\n digestInterruptJson,\n} from './interrupt-serialization'\n\nexport {\n convertSchemaToJsonSchema,\n isStandardSchema,\n parseWithStandardSchema,\n validateWithStandardSchema,\n} from './activities/chat/tools/schema-converter'\n\nexport {\n convertMessagesToModelMessages,\n generateMessageId,\n modelMessageToUIMessage,\n modelMessagesToUIMessages,\n normalizeToUIMessage,\n uiMessageToModelMessages,\n} from './activities/chat/messages'\n\nexport {\n BatchStrategy,\n CompositeStrategy,\n defaultJSONParser,\n ImmediateStrategy,\n parsePartialJSON,\n PartialJSONParser,\n PunctuationStrategy,\n StreamProcessor,\n WordBoundaryStrategy,\n} from './activities/chat/stream/index'\nexport type {\n ChunkRecording,\n ChunkStrategy,\n InternalToolCallState,\n JSONParser,\n ProcessorResult,\n ProcessorState,\n StreamProcessorEvents,\n StreamProcessorOptions,\n ToolCallState,\n ToolResultState,\n} from './activities/chat/stream/index'\n\nexport { uiMessagesToWire } from './utilities/ag-ui-wire'\nexport {\n mergeMetadata,\n tanstackMetadata,\n withTanstackMetadata,\n} from './utilities/merge-metadata'\nexport { fromSpecTokenUsage, toSpecTokenUsage } from './utilities/ag-ui-usage'\nexport type { SpecTokenUsage } from './utilities/ag-ui-usage'\nexport { normalizeStreamChunk } from './utilities/normalize-stream-chunk'\nexport { restoreInboundChunk } from './utilities/restore-inbound-chunk'\nexport type { AdapterYieldChunk } from './utilities/adapter-yield-chunk'\nexport { getChunkRunId, getChunkThreadId } from './utilities/chunk-ids'\nexport type { WireMessage } from './utilities/ag-ui-wire'\n\nexport type {\n AudioPart,\n ContentPart,\n ContentPartDataSource,\n ContentPartSource,\n ContentPartUrlSource,\n CustomEvent,\n DocumentPart,\n ImagePart,\n MediaInputMetadata,\n MediaInputRole,\n MediaPrompt,\n MediaPromptPart,\n MessagePart,\n ModelMessage,\n PersistedArtifactActivity,\n PersistedArtifactRef,\n PersistedArtifactRole,\n Interrupt,\n RunAgentResumeItem,\n RunErrorEvent,\n RunFinishedEvent,\n RunFinishedOutcome,\n SchemaInput,\n StreamChunk,\n StructuredOutputPart,\n TextPart,\n TanStackMessageMetadata,\n TanStackRunMetadata,\n ThinkingPart,\n ToolCall,\n ToolCallPart,\n ToolResultPart,\n UIMessage,\n UIResourcePart,\n VideoPart,\n InferSchemaType,\n} from './types'\n\n// Enumerated, not `export *` — see the matching note in `index.ts`. The\n// interrupt protocol surface is a commitment, so it is published field by\n// field.\nexport {\n INTERRUPT_BINDING_VERSION,\n canonicalizeInterruptResolutions,\n} from './interrupts'\nexport {\n defineInterrupt,\n hashInterruptDefinitionSchema,\n INTERRUPT_PAYLOAD_METADATA_KEY,\n} from './interrupt-definition'\nexport {\n INTERRUPT_CONTINUATION_METADATA_KEY,\n INTERRUPT_CONTINUATION_VERSION,\n genericInterruptContinuationFromDescriptor,\n readGenericInterruptContinuation,\n wrapGenericInterruptContinuation,\n} from './generic-interrupt-continuation'\nexport type {\n GenericInterruptContinuation,\n GenericInterruptContinuationReadResult,\n} from './generic-interrupt-continuation'\nexport type {\n GenericInterruptRequest,\n InterruptDefinition,\n} from './interrupt-definition'\nexport type {\n BatchInterruptError,\n BatchInterruptErrorCode,\n InterruptBinding,\n InterruptCorrelation,\n InterruptSubmissionError,\n ItemInterruptError,\n ItemInterruptErrorCode,\n ToolApprovalResolution,\n UnopenedInterruptBinding,\n} from './interrupts'\n\nexport {\n INTERRUPT_BINDING_METADATA_KEY,\n readInterruptBinding,\n readUnopenedInterruptBinding,\n withInterruptBinding,\n withoutInterruptBinding,\n} from './interrupt-resume'\n\nexport type {\n AudioVisualization,\n RealtimeAdapter,\n RealtimeConnection,\n RealtimeError,\n RealtimeErrorCode,\n RealtimeEvent,\n RealtimeEventHandler,\n RealtimeEventPayloads,\n RealtimeMessage,\n RealtimeMessagePart,\n RealtimeMode,\n RealtimeSessionConfig,\n RealtimeStatus,\n RealtimeToken,\n RealtimeAudioPart,\n RealtimeImagePart,\n RealtimeTextPart,\n RealtimeToolCallPart,\n RealtimeToolResultPart,\n VADConfig,\n} from './realtime/types'\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":[],"sources":["../../src/client.ts"],"sourcesContent":["import type {\n AudioGenerationOptions,\n ImageGenerationOptions,\n TTSOptions,\n TranscriptionOptions,\n VoiceGenerationOptions,\n VideoGenerationOptions,\n WorldGenerationOptions,\n LiveVideoGenerationOptions,\n} from './types'\n\nexport type GenerationKind =\n | 'image'\n | 'audio'\n | 'tts'\n | 'voice'\n | 'video'\n | 'transcription'\n | 'world'\n | 'liveVideo'\n\ntype GenerationInputByKind = {\n image: Omit<ImageGenerationOptions, 'logger' | 'model'>\n audio: Omit<AudioGenerationOptions, 'logger' | 'model'>\n tts: Omit<TTSOptions, 'logger' | 'model'>\n voice: Omit<VoiceGenerationOptions, 'logger' | 'model'>\n video: Omit<VideoGenerationOptions, 'logger' | 'model'>\n transcription: Omit<TranscriptionOptions, 'logger' | 'model'>\n world: Omit<WorldGenerationOptions, 'logger' | 'model'>\n liveVideo: Omit<LiveVideoGenerationOptions, 'logger' | 'model'>\n}\n\nexport interface GenerationParams<TKind extends GenerationKind> {\n input: GenerationInputByKind[TKind]\n forwardedProps: Record<string, unknown>\n threadId?: string\n runId?: string\n}\n\nconst generationKinds = [\n 'image',\n 'audio',\n 'tts',\n 'voice',\n 'video',\n 'transcription',\n 'world',\n 'liveVideo',\n] as const satisfies ReadonlyArray<GenerationKind>\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction hasOwnKey(value: Record<string, unknown>, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(value, key)\n}\n\nfunction isGenerationEnvelope(body: unknown): body is Record<string, unknown> {\n return (\n isRecord(body) &&\n (hasOwnKey(body, 'data') || hasOwnKey(body, 'forwardedProps'))\n )\n}\n\nfunction assertGenerationKind(kind: unknown): asserts kind is GenerationKind {\n if (!generationKinds.includes(kind as GenerationKind)) {\n throw new Error(\n `Unsupported generation kind: ${String(\n kind,\n )}. Expected one of ${generationKinds.join(', ')}.`,\n )\n }\n}\n\n/**\n * The input field(s) that identify a generation body for a kind. Most kinds\n * have exactly one; `voice` accepts either of its two creation modes, so any\n * one of its keys is enough.\n */\nfunction requiredKeysForKind(kind: GenerationKind): Array<string> {\n // Enumerated rather than defaulted so a new generation kind has to declare\n // the field that identifies its body instead of silently inheriting\n // `prompt`.\n switch (kind) {\n case 'tts':\n return ['text']\n case 'transcription':\n return ['audio']\n case 'voice':\n return ['prompt', 'referenceAudio']\n case 'image':\n case 'audio':\n case 'video':\n case 'world':\n case 'liveVideo':\n return ['prompt']\n }\n}\n\nfunction assertInputForKind(\n kind: GenerationKind,\n input: unknown,\n): asserts input is GenerationInputByKind[GenerationKind] {\n if (!isRecord(input)) {\n throw new Error(`Generation ${kind} input must be an object.`)\n }\n\n const requiredKeys = requiredKeysForKind(kind)\n\n if (!requiredKeys.some((key) => hasOwnKey(input, key))) {\n throw new Error(\n `Generation ${kind} input must include ${requiredKeys.join(' or ')}.`,\n )\n }\n}\n\nfunction isInputForKind(kind: GenerationKind, input: unknown): boolean {\n if (!isRecord(input)) return false\n\n return requiredKeysForKind(kind).some((key) => hasOwnKey(input, key))\n}\n\nfunction forwardedPropsFromEnvelope(\n envelope: Record<string, unknown>,\n): Record<string, unknown> {\n if (!hasOwnKey(envelope, 'forwardedProps')) {\n return {}\n }\n\n if (!isRecord(envelope.forwardedProps)) {\n throw new Error('Generation envelope forwardedProps must be an object.')\n }\n\n return envelope.forwardedProps\n}\n\nfunction optionalStringField(\n envelope: Record<string, unknown>,\n key: 'threadId' | 'runId',\n): string | undefined {\n if (!hasOwnKey(envelope, key)) {\n return undefined\n }\n\n const value = envelope[key]\n if (typeof value !== 'string') {\n throw new Error(`Generation envelope ${key} must be a string.`)\n }\n\n return value\n}\n\nfunction generationIdentityFields(envelope: Record<string, unknown>): {\n threadId?: string\n runId?: string\n} {\n const identity: {\n threadId?: string\n runId?: string\n } = {}\n const threadId = optionalStringField(envelope, 'threadId')\n const runId = optionalStringField(envelope, 'runId')\n\n if (threadId !== undefined) identity.threadId = threadId\n if (runId !== undefined) identity.runId = runId\n\n return identity\n}\n\nexport function generationParamsFromBody<TKind extends GenerationKind>(\n kind: TKind,\n body: unknown,\n): GenerationParams<TKind> {\n assertGenerationKind(kind)\n\n if (isInputForKind(kind, body)) {\n assertInputForKind(kind, body)\n return {\n input: body as GenerationInputByKind[TKind],\n forwardedProps: {},\n }\n }\n\n if (!isGenerationEnvelope(body)) {\n assertInputForKind(kind, body)\n return {\n input: body as GenerationInputByKind[TKind],\n forwardedProps: {},\n }\n }\n\n if (!hasOwnKey(body, 'data')) {\n throw new Error(`Generation ${kind} envelope must include data.`)\n }\n\n const input = body.data\n assertInputForKind(kind, input)\n\n const forwardedProps = forwardedPropsFromEnvelope(body)\n\n return {\n input: input as GenerationInputByKind[TKind],\n forwardedProps,\n ...generationIdentityFields(body),\n }\n}\n\nexport async function generationParamsFromRequest<TKind extends GenerationKind>(\n kind: TKind,\n request: Request,\n): Promise<GenerationParams<TKind>> {\n let body: unknown\n try {\n body = await request.json()\n } catch (error) {\n throw new Error('Invalid JSON request body.', { cause: error })\n }\n\n if (!isRecord(body)) {\n throw new Error('Generation request body must be a JSON object.')\n }\n\n return generationParamsFromBody(kind, body)\n}\n\nexport { EventType } from '@ag-ui/core'\n\nexport {\n defineAgent,\n type DefinedAgent,\n type SubagentChoiceOptions,\n type SubagentRunContext,\n} from './activities/chat/agents/define-agent'\nexport {\n subagentRoute,\n type SubagentRouteOptions,\n} from './activities/chat/agents/route'\nexport type {\n SubagentOrder,\n SubagentRouterPick,\n SubagentRouterPlan,\n SubagentStep,\n SubagentStepsPlan,\n} from './activities/chat/agents/spawn'\n\nexport {\n toolDefinition,\n type AnyClientTool,\n type ClientTool,\n type InferToolInput,\n type InferToolName,\n type InferToolOutput,\n type ApprovalCapabilityOf,\n type ApprovalSchemaConfig,\n type ApprovalSchemaOf,\n type InputSchemaOf,\n type OutputSchemaOf,\n type NoSchema,\n type ToolDefinition,\n type ToolDefinitionConfig,\n type ToolDefinitionInstance,\n} from './activities/chat/tools/tool-definition'\n\nexport {\n hashSchemaInput,\n normalizeApprovalSchema,\n type NormalizedApprovalSchema,\n type NormalizedSchemaInput,\n} from './activities/chat/tools/approval-schema'\n\nexport {\n canonicalInterruptJson,\n cloneAndDeepFreezeJson,\n digestInterruptJson,\n} from './interrupt-serialization'\n\nexport {\n convertSchemaToJsonSchema,\n isStandardSchema,\n parseWithStandardSchema,\n validateWithStandardSchema,\n} from './activities/chat/tools/schema-converter'\n\nexport {\n convertMessagesToModelMessages,\n generateMessageId,\n modelMessageToUIMessage,\n modelMessagesToUIMessages,\n normalizeToUIMessage,\n uiMessageToModelMessages,\n} from './activities/chat/messages'\n\nexport {\n BatchStrategy,\n CompositeStrategy,\n defaultJSONParser,\n ImmediateStrategy,\n parsePartialJSON,\n PartialJSONParser,\n PunctuationStrategy,\n StreamProcessor,\n WordBoundaryStrategy,\n} from './activities/chat/stream/index'\nexport type {\n ChunkRecording,\n ChunkStrategy,\n InternalToolCallState,\n JSONParser,\n ProcessorResult,\n ProcessorState,\n StreamProcessorEvents,\n StreamProcessorOptions,\n ToolCallState,\n ToolResultState,\n} from './activities/chat/stream/index'\n\nexport { uiMessagesToWire } from './utilities/ag-ui-wire'\nexport {\n mergeMetadata,\n tanstackMetadata,\n withTanstackMetadata,\n} from './utilities/merge-metadata'\nexport { fromSpecTokenUsage, toSpecTokenUsage } from './utilities/ag-ui-usage'\nexport type { SpecTokenUsage } from './utilities/ag-ui-usage'\nexport { normalizeStreamChunk } from './utilities/normalize-stream-chunk'\nexport { restoreInboundChunk } from './utilities/restore-inbound-chunk'\nexport type { AdapterYieldChunk } from './utilities/adapter-yield-chunk'\nexport { getChunkRunId, getChunkThreadId } from './utilities/chunk-ids'\nexport type { WireMessage } from './utilities/ag-ui-wire'\n\nexport type {\n AudioPart,\n ContentPart,\n ContentPartDataSource,\n ContentPartFileSource,\n SubagentHandleData,\n SubagentStatus,\n ContentPartSource,\n ContentPartUrlSource,\n CustomEvent,\n DocumentPart,\n ImagePart,\n MediaInputMetadata,\n MediaInputRole,\n MediaPrompt,\n MediaPromptPart,\n MessagePart,\n ModelMessage,\n PersistedArtifactActivity,\n PersistedArtifactRef,\n PersistedArtifactRole,\n Interrupt,\n RunAgentResumeItem,\n RunErrorEvent,\n RunFinishedEvent,\n RunFinishedOutcome,\n SchemaInput,\n StreamChunk,\n StructuredOutputPart,\n TextPart,\n TanStackMessageMetadata,\n TanStackRunMetadata,\n ThinkingPart,\n ToolCall,\n ToolCallPart,\n ToolResultPart,\n UIMessage,\n UIResourcePart,\n VideoPart,\n InferSchemaType,\n} from './types'\n\n// Enumerated, not `export *` — see the matching note in `index.ts`. The\n// interrupt protocol surface is a commitment, so it is published field by\n// field.\nexport {\n INTERRUPT_BINDING_VERSION,\n canonicalizeInterruptResolutions,\n} from './interrupts'\nexport {\n defineInterrupt,\n hashInterruptDefinitionSchema,\n INTERRUPT_PAYLOAD_METADATA_KEY,\n} from './interrupt-definition'\nexport {\n INTERRUPT_CONTINUATION_METADATA_KEY,\n INTERRUPT_CONTINUATION_VERSION,\n genericInterruptContinuationFromDescriptor,\n readGenericInterruptContinuation,\n wrapGenericInterruptContinuation,\n} from './generic-interrupt-continuation'\nexport type {\n GenericInterruptContinuation,\n GenericInterruptContinuationReadResult,\n} from './generic-interrupt-continuation'\nexport type {\n GenericInterruptRequest,\n InterruptDefinition,\n} from './interrupt-definition'\nexport type {\n BatchInterruptError,\n BatchInterruptErrorCode,\n InterruptBinding,\n InterruptCorrelation,\n InterruptSubmissionError,\n ItemInterruptError,\n ItemInterruptErrorCode,\n ToolApprovalResolution,\n UnopenedInterruptBinding,\n} from './interrupts'\n\nexport {\n INTERRUPT_BINDING_METADATA_KEY,\n readInterruptBinding,\n readUnopenedInterruptBinding,\n withInterruptBinding,\n withoutInterruptBinding,\n} from './interrupt-resume'\n\nexport type {\n AudioVisualization,\n RealtimeAdapter,\n RealtimeConnection,\n RealtimeError,\n RealtimeErrorCode,\n RealtimeEvent,\n RealtimeEventHandler,\n RealtimeEventPayloads,\n RealtimeMessage,\n RealtimeMessagePart,\n RealtimeMode,\n RealtimeSessionConfig,\n RealtimeStatus,\n RealtimeToken,\n RealtimeAudioPart,\n RealtimeImagePart,\n RealtimeTextPart,\n RealtimeToolCallPart,\n RealtimeToolResultPart,\n VADConfig,\n} from './realtime/types'\n"],"mappings":"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"}
@@ -14,6 +14,9 @@ export { createLiveVideoOptions } from './activities/generateLiveVideo/index.js'
14
14
  export type { AIAdapter, ImageAdapter, AnyImageAdapter, TextAdapter, AnyTextAdapter, AnySummarizeAdapter, SummarizeAdapter, AnyAudioAdapter, AudioAdapter, AnyTTSAdapter, TTSAdapter, TTSCapabilities, AnyVoiceAdapter, VoiceAdapter, AnyTranscriptionAdapter, TranscriptionAdapter, AnyVideoAdapter, VideoAdapter, AnyEmbeddingAdapter, EmbeddingAdapter, AnyRerankAdapter, RerankAdapter, AnyEvaluateAdapter, EvaluateAdapter, ChoiceAnswer, ScoreAnswer, BooleanAnswer, EvaluateResult, WireQuestion, WireAnswer, AnyWorldAdapter, WorldAdapter, AnyLiveVideoAdapter, LiveVideoAdapter, } from './activities/index.js';
15
15
  export { BaseRerankAdapter } from './activities/rerank/adapter.js';
16
16
  export { BaseEvaluateAdapter } from './activities/evaluate/adapter.js';
17
+ export { defineAgent, type DefinedAgent, type SubagentChoiceOptions, type SubagentRunContext, } from './activities/chat/agents/define-agent.js';
18
+ export { subagentRoute, type SubagentRouteOptions, } from './activities/chat/agents/route.js';
19
+ export type { SubagentOrder, SubagentRouterPick, SubagentRouterPlan, SubagentStep, SubagentStepsPlan, } from './activities/chat/agents/spawn.js';
17
20
  export { toolDefinition, type ToolDefinition, type ToolDefinitionInstance, type ToolDefinitionConfig, type ServerTool, type AnyServerTool, type ClientTool, type AnyClientTool, type InferToolName, type InferToolInput, type InferToolOutput, type ApprovalCapabilityOf, type ApprovalSchemaConfig, type ApprovalSchemaOf, type InputSchemaOf, type OutputSchemaOf, type NoSchema, } from './activities/chat/tools/tool-definition.js';
18
21
  export { hashSchemaInput, normalizeApprovalSchema, type NormalizedApprovalSchema, type NormalizedSchemaInput, } from './activities/chat/tools/approval-schema.js';
19
22
  export { canonicalInterruptJson, cloneAndDeepFreezeJson, digestInterruptJson, } from './interrupt-serialization.js';
@@ -74,6 +77,8 @@ export { chatParamsFromRequest, chatParamsFromRequestBody, mergeAgentTools, } fr
74
77
  export type { ClientToolDeclaration, MergedAgentTools, } from './utilities/chat-params.js';
75
78
  export { generationParamsFromBody, generationParamsFromRequest } from './client.js';
76
79
  export { uiMessagesToWire } from './utilities/ag-ui-wire.js';
80
+ export type { SubagentWireInfo } from './utilities/subagent-wire.js';
81
+ export { subagentHostMessageId, wireSubagentInfo, } from './utilities/subagent-wire.js';
77
82
  export { mergeMetadata, withTanstackMetadata } from './utilities/merge-metadata.js';
78
83
  export { fromSpecTokenUsage, toSpecTokenUsage } from './utilities/ag-ui-usage.js';
79
84
  export type { SpecTokenUsage } from './utilities/ag-ui-usage.js';
package/dist/esm/index.js CHANGED
@@ -18,6 +18,7 @@ import { INTERRUPT_BINDING_METADATA_KEY, InterruptResumeValidationError, interru
18
18
  import { INTERRUPT_PAYLOAD_METADATA_KEY, createInterruptBinding, defineInterrupt } from "./interrupt-definition.js";
19
19
  import { INTERRUPT_CONTINUATION_METADATA_KEY, INTERRUPT_CONTINUATION_VERSION, genericInterruptContinuationFromDescriptor, readGenericInterruptContinuation, wrapGenericInterruptContinuation } from "./generic-interrupt-continuation.js";
20
20
  import { isContentPart, isContentPartArray, normalizeToolResult } from "./utilities/tool-result.js";
21
+ import { subagentHostMessageId, wireSubagentInfo } from "./utilities/subagent-wire.js";
21
22
  import { getProviderExecutedMetadata, isProviderExecutedToolCall } from "./utilities/provider-executed.js";
22
23
  import { convertMessagesToModelMessages, generateMessageId, modelMessageToUIMessage, modelMessagesToUIMessages, normalizeToUIMessage, uiMessageToModelMessages } from "./activities/chat/messages.js";
23
24
  import { uiMessagesToWire } from "./utilities/ag-ui-wire.js";
@@ -28,11 +29,13 @@ import { ToolCallManager } from "./activities/chat/tools/tool-calls.js";
28
29
  import { combineStrategies, maxIterations, untilFinishReason } from "./activities/chat/agent-loop-strategies.js";
29
30
  import { MCPDuplicateToolNameError } from "./activities/chat/mcp/manager.js";
30
31
  import { chat, createChatOptions } from "./activities/chat/index.js";
32
+ import { defineAgent } from "./activities/chat/agents/define-agent.js";
33
+ import { BaseEvaluateAdapter } from "./activities/evaluate/adapter.js";
34
+ import { boolean, choice, decide, score } from "./activities/evaluate/index.js";
35
+ import { subagentRoute } from "./activities/chat/agents/route.js";
31
36
  import { createSummarizeOptions, summarize } from "./activities/summarize/index.js";
32
37
  import { BaseRerankAdapter } from "./activities/rerank/adapter.js";
33
38
  import { createRerankOptions, rerank } from "./activities/rerank/index.js";
34
- import { BaseEvaluateAdapter } from "./activities/evaluate/adapter.js";
35
- import { boolean, choice, decide, score } from "./activities/evaluate/index.js";
36
39
  import { resolveMediaPrompt } from "./utilities/media-prompt.js";
37
40
  import { createImageOptions, generateImage } from "./activities/generateImage/index.js";
38
41
  import { createAudioOptions, generateAudio } from "./activities/generateAudio/index.js";
@@ -64,4 +67,4 @@ import { BatchStrategy, CompositeStrategy, ImmediateStrategy, PunctuationStrateg
64
67
  import { StreamProcessor, createReplayStream } from "./activities/chat/stream/processor.js";
65
68
  import { generationParamsFromBody, generationParamsFromRequest } from "./client.js";
66
69
  import { createModel, extendAdapter } from "./extend-adapter.js";
67
- export { BaseEvaluateAdapter, BaseRerankAdapter, BatchStrategy, CUSTOM_EVENT, CompositeStrategy, ConsoleLogger, DISCOVERY_TOOL_NAME, DetachableRunCapability, DuplicateToolNameError, EventType, INTERRUPT_BINDING_METADATA_KEY, INTERRUPT_BINDING_VERSION, INTERRUPT_BOUNDARY_PHASES, INTERRUPT_CONTINUATION_METADATA_KEY, INTERRUPT_CONTINUATION_VERSION, INTERRUPT_PAYLOAD_METADATA_KEY, INTERRUPT_TOOL_RESUMES, ImmediateStrategy, InMemoryRunStore, InterruptResumeValidationError, MCPDuplicateToolNameError, MetadataCapability, PartialJSONParser, PunctuationStrategy, RUN_ACCEPTED_EVENT, RUN_CANCEL_REASON, RunDetachedCapability, SkillLimitError, StandardSchemaValidationError, StreamProcessor, ToolCallManager, WordBoundaryStrategy, boolean, brandProviderTool, buildBaseUsage, canonicalInterruptJson, canonicalizeInterruptResolutions, chat, chatParamsFromRequest, chatParamsFromRequestBody, choice, cloneAndDeepFreezeJson, combineStrategies, convertMessagesToModelMessages, convertSchemaToJsonSchema, countEmbeddingInputModalities, createAudioOptions, createCapability, createChatMiddleware, createChatOptions, createEmbedOptions, createFrozenRegistry, createImageOptions, createInterruptBinding, createLiveVideoOptions, createModel, createRealtimeEventEmitter, createReplayStream, createRerankOptions, createSpeechOptions, createSummarizeOptions, createToolRegistry, createTranscriptionOptions, createVideoOptions, createVoiceOptions, createWorldOptions, decide, decodeWsFrame, defaultJSONParser, defineChatMiddleware, defineInterrupt, defineRunStore, detectImageMimeType, digestInterruptJson, embed, encodeWsFrame, extendAdapter, firstSentence, fromSpecTokenUsage, generateAudio, generateImage, generateLiveVideo, generateMessageId, generateSpeech, generateTranscription, generateVideo, generateVoice, generateWorld, generationParamsFromBody, generationParamsFromRequest, genericInterruptContinuationFromDescriptor, getChunkRunId, getChunkThreadId, getDetachableRun, getMetadata, getProviderExecutedMetadata, getRunDetached, getVideoJobStatus, hashSchemaInput, interruptItemError, isCancelRequestedReason, isContentPart, isContentPartArray, isCustomEvent, isProviderExecutedToolCall, isRunStatus, isStandardSchema, isTerminalRunStatus, listVoices, maxIterations, memoryStream, mergeAgentTools, mergeMetadata, modelMessageToUIMessage, modelMessagesToUIMessages, normalizeApprovalSchema, normalizeStreamChunk, normalizeSystemPrompts, normalizeToUIMessage, normalizeToolResult, parsePartialJSON, parseWithStandardSchema, provideDetachableRun, provideMetadata, provideRunDetached, readGenericInterruptContinuation, readInterruptBinding, readUnopenedInterruptBinding, realtimeToken, renderLazyCatalogEntry, replayRunStream, requestRunCancel, requireTextOnlyEmbeddingInput, rerank, resolveEmbeddingInput, resolveMediaPrompt, resolveResumeRunId, resumeHttpResponse, resumeServerSentEventsResponse, resumeWebSocketResponse, resumeWebSocketStream, score, streamToText, summarize, toHttpResponse, toHttpStream, toServerSentEventsResponse, toServerSentEventsStream, toSpecTokenUsage, toWebSocketResponse, toWebSocketStream, toolDefinition, uiMessageToModelMessages, uiMessagesToWire, untilFinishReason, validateInterruptResumeBatch, validateWithStandardSchema, wasCancelRequested, withInterruptBinding, withTanstackMetadata, withoutInterruptBinding, wrapGenericInterruptContinuation };
70
+ export { BaseEvaluateAdapter, BaseRerankAdapter, BatchStrategy, CUSTOM_EVENT, CompositeStrategy, ConsoleLogger, DISCOVERY_TOOL_NAME, DetachableRunCapability, DuplicateToolNameError, EventType, INTERRUPT_BINDING_METADATA_KEY, INTERRUPT_BINDING_VERSION, INTERRUPT_BOUNDARY_PHASES, INTERRUPT_CONTINUATION_METADATA_KEY, INTERRUPT_CONTINUATION_VERSION, INTERRUPT_PAYLOAD_METADATA_KEY, INTERRUPT_TOOL_RESUMES, ImmediateStrategy, InMemoryRunStore, InterruptResumeValidationError, MCPDuplicateToolNameError, MetadataCapability, PartialJSONParser, PunctuationStrategy, RUN_ACCEPTED_EVENT, RUN_CANCEL_REASON, RunDetachedCapability, SkillLimitError, StandardSchemaValidationError, StreamProcessor, ToolCallManager, WordBoundaryStrategy, boolean, brandProviderTool, buildBaseUsage, canonicalInterruptJson, canonicalizeInterruptResolutions, chat, chatParamsFromRequest, chatParamsFromRequestBody, choice, cloneAndDeepFreezeJson, combineStrategies, convertMessagesToModelMessages, convertSchemaToJsonSchema, countEmbeddingInputModalities, createAudioOptions, createCapability, createChatMiddleware, createChatOptions, createEmbedOptions, createFrozenRegistry, createImageOptions, createInterruptBinding, createLiveVideoOptions, createModel, createRealtimeEventEmitter, createReplayStream, createRerankOptions, createSpeechOptions, createSummarizeOptions, createToolRegistry, createTranscriptionOptions, createVideoOptions, createVoiceOptions, createWorldOptions, decide, decodeWsFrame, defaultJSONParser, defineAgent, defineChatMiddleware, defineInterrupt, defineRunStore, detectImageMimeType, digestInterruptJson, embed, encodeWsFrame, extendAdapter, firstSentence, fromSpecTokenUsage, generateAudio, generateImage, generateLiveVideo, generateMessageId, generateSpeech, generateTranscription, generateVideo, generateVoice, generateWorld, generationParamsFromBody, generationParamsFromRequest, genericInterruptContinuationFromDescriptor, getChunkRunId, getChunkThreadId, getDetachableRun, getMetadata, getProviderExecutedMetadata, getRunDetached, getVideoJobStatus, hashSchemaInput, interruptItemError, isCancelRequestedReason, isContentPart, isContentPartArray, isCustomEvent, isProviderExecutedToolCall, isRunStatus, isStandardSchema, isTerminalRunStatus, listVoices, maxIterations, memoryStream, mergeAgentTools, mergeMetadata, modelMessageToUIMessage, modelMessagesToUIMessages, normalizeApprovalSchema, normalizeStreamChunk, normalizeSystemPrompts, normalizeToUIMessage, normalizeToolResult, parsePartialJSON, parseWithStandardSchema, provideDetachableRun, provideMetadata, provideRunDetached, readGenericInterruptContinuation, readInterruptBinding, readUnopenedInterruptBinding, realtimeToken, renderLazyCatalogEntry, replayRunStream, requestRunCancel, requireTextOnlyEmbeddingInput, rerank, resolveEmbeddingInput, resolveMediaPrompt, resolveResumeRunId, resumeHttpResponse, resumeServerSentEventsResponse, resumeWebSocketResponse, resumeWebSocketStream, score, streamToText, subagentHostMessageId, subagentRoute, summarize, toHttpResponse, toHttpStream, toServerSentEventsResponse, toServerSentEventsStream, toSpecTokenUsage, toWebSocketResponse, toWebSocketStream, toolDefinition, uiMessageToModelMessages, uiMessagesToWire, untilFinishReason, validateInterruptResumeBatch, validateWithStandardSchema, wasCancelRequested, wireSubagentInfo, withInterruptBinding, withTanstackMetadata, withoutInterruptBinding, wrapGenericInterruptContinuation };
@@ -1 +1 @@
1
- {"version":3,"file":"content-guard.js","names":[],"sources":["../../../src/middlewares/content-guard.ts"],"sourcesContent":["import type {\n ChatMiddleware,\n ChatMiddlewareContext,\n} from '../activities/chat/middleware/types'\nimport type { StreamChunk } from '../types'\n\n/**\n * A content guard rule — either a regex pattern with replacement, or a transform function.\n */\nexport type ContentGuardRule =\n | { pattern: RegExp; replacement: string }\n | { fn: (text: string) => string }\n\n/**\n * Information passed to the onFiltered callback.\n */\nexport interface ContentFilteredInfo {\n /** The message ID being filtered */\n messageId: string\n /** The original text before filtering */\n original: string\n /** The filtered text after rules applied */\n filtered: string\n /** Which strategy was used */\n strategy: 'delta' | 'buffered'\n}\n\n/**\n * Options for the content guard middleware.\n */\nexport interface ContentGuardMiddlewareOptions {\n /**\n * Rules to apply to text content. Each rule is either a regex pattern\n * with a replacement string, or a custom transform function.\n * Rules are applied in order. Each rule receives the output of the previous.\n */\n rules: Array<ContentGuardRule>\n\n /**\n * Matching strategy:\n * - 'delta': Apply rules to each delta as it arrives. Fast, real-time,\n * but patterns spanning chunk boundaries may be missed.\n * - 'buffered': Accumulate content and apply rules to settled portions,\n * holding back a look-behind buffer to catch cross-boundary patterns.\n *\n * @default 'buffered'\n */\n strategy?: 'delta' | 'buffered'\n\n /**\n * Number of characters to hold back before emitting (buffered strategy only).\n * Should be at least as long as the longest pattern you expect to match.\n * Buffer is flushed when the stream ends.\n *\n * @default 50\n */\n bufferSize?: number\n\n /**\n * If true, drop the entire chunk when any rule changes the content.\n * @default false\n */\n blockOnMatch?: boolean\n\n /**\n * Callback when content is filtered by any rule.\n */\n onFiltered?: (info: ContentFilteredInfo) => void\n}\n\n/**\n * Apply all rules to a string, returning the transformed result.\n */\nfunction applyRules(text: string, rules: Array<ContentGuardRule>): string {\n let result = text\n for (const rule of rules) {\n if ('pattern' in rule) {\n result = result.replace(rule.pattern, rule.replacement)\n } else {\n result = rule.fn(result)\n }\n }\n return result\n}\n\n/**\n * Creates a middleware that filters or transforms streamed text content.\n *\n * @example\n * ```ts\n * import { contentGuardMiddleware } from '@tanstack/ai/middlewares'\n *\n * const guard = contentGuardMiddleware({\n * rules: [\n * { pattern: /\\b\\d{3}-\\d{2}-\\d{4}\\b/g, replacement: '[SSN REDACTED]' },\n * ],\n * strategy: 'buffered',\n * })\n * ```\n */\nexport function contentGuardMiddleware(\n options: ContentGuardMiddlewareOptions,\n): ChatMiddleware {\n const {\n rules,\n strategy = 'buffered',\n bufferSize = 50,\n blockOnMatch = false,\n onFiltered,\n } = options\n\n if (strategy === 'delta') {\n return createDeltaStrategy(rules, blockOnMatch, onFiltered)\n }\n return createBufferedStrategy(rules, bufferSize, blockOnMatch, onFiltered)\n}\n\nfunction createDeltaStrategy(\n rules: Array<ContentGuardRule>,\n blockOnMatch: boolean,\n onFiltered?: (info: ContentFilteredInfo) => void,\n): ChatMiddleware {\n return {\n name: 'content-guard',\n\n onChunk(_ctx: ChatMiddlewareContext, chunk: StreamChunk) {\n if (chunk.type !== 'TEXT_MESSAGE_CONTENT') return\n\n const original = chunk.delta\n const filtered = applyRules(original, rules)\n\n if (filtered === original) return // unchanged, pass through\n\n if (onFiltered) {\n onFiltered({\n messageId: chunk.messageId,\n original,\n filtered,\n strategy: 'delta',\n })\n }\n\n if (blockOnMatch) return null // drop chunk\n\n // Strip out the previous `content` field by destructuring it away — with\n // `exactOptionalPropertyTypes` we can't assign `content: undefined`\n // against `content?: string`. The replacement event carries only the\n // filtered delta.\n const { content: _strippedContent, ...rest } = chunk\n void _strippedContent\n return {\n ...rest,\n delta: filtered,\n }\n },\n }\n}\n\nfunction createBufferedStrategy(\n rules: Array<ContentGuardRule>,\n bufferSize: number,\n blockOnMatch: boolean,\n onFiltered?: (info: ContentFilteredInfo) => void,\n): ChatMiddleware {\n let rawAccumulated = ''\n let emittedFilteredLength = 0\n let lastMessageId = ''\n\n function resetState() {\n rawAccumulated = ''\n emittedFilteredLength = 0\n lastMessageId = ''\n }\n\n function flushBuffer(): StreamChunk | null {\n if (rawAccumulated.length === 0) return null\n\n const filtered = applyRules(rawAccumulated, rules)\n\n if (blockOnMatch && filtered !== rawAccumulated) {\n if (onFiltered) {\n onFiltered({\n messageId: lastMessageId,\n original: rawAccumulated,\n filtered,\n strategy: 'buffered',\n })\n }\n resetState()\n return null\n }\n\n const remaining = filtered.slice(emittedFilteredLength)\n if (remaining.length > 0) {\n if (filtered !== rawAccumulated && onFiltered) {\n onFiltered({\n messageId: lastMessageId,\n original: rawAccumulated,\n filtered,\n strategy: 'buffered',\n })\n }\n\n const flushed = {\n type: 'TEXT_MESSAGE_CONTENT',\n messageId: lastMessageId,\n delta: remaining,\n content: filtered,\n timestamp: Date.now(),\n } as StreamChunk\n\n resetState()\n return flushed\n }\n\n resetState()\n return null\n }\n\n return {\n name: 'content-guard',\n\n onStart() {\n resetState()\n },\n\n onChunk(_ctx: ChatMiddlewareContext, chunk: StreamChunk) {\n // Flush buffer on stream end events\n if (chunk.type === 'TEXT_MESSAGE_END' || chunk.type === 'RUN_FINISHED') {\n const flushed = flushBuffer()\n if (flushed) return [flushed, chunk]\n return // pass through end event\n }\n\n if (chunk.type !== 'TEXT_MESSAGE_CONTENT') return // pass through\n\n // Flush buffer on message boundary change\n const pending: Array<StreamChunk> = []\n if (lastMessageId && chunk.messageId !== lastMessageId) {\n const flushed = flushBuffer()\n if (flushed) pending.push(flushed)\n }\n\n rawAccumulated += chunk.delta\n lastMessageId = chunk.messageId\n\n // Apply rules to full accumulated text, buffer in filtered space\n const filtered = applyRules(rawAccumulated, rules)\n const safeFilteredEnd = Math.max(0, filtered.length - bufferSize)\n\n if (safeFilteredEnd <= emittedFilteredLength) {\n return pending.length > 0 ? pending : null\n }\n\n if (blockOnMatch && filtered !== rawAccumulated) {\n if (onFiltered) {\n onFiltered({\n messageId: chunk.messageId,\n original: rawAccumulated,\n filtered,\n strategy: 'buffered',\n })\n }\n return pending.length > 0 ? pending : null\n }\n\n const newDelta = filtered.slice(emittedFilteredLength, safeFilteredEnd)\n\n if (filtered !== rawAccumulated && onFiltered) {\n onFiltered({\n messageId: chunk.messageId,\n original: rawAccumulated,\n filtered,\n strategy: 'buffered',\n })\n }\n\n emittedFilteredLength = safeFilteredEnd\n\n const emitChunk = {\n ...chunk,\n delta: newDelta,\n content: filtered.slice(0, safeFilteredEnd),\n } as StreamChunk\n\n // `pending` was empty before this push iff `emitChunk` is now the only\n // entry — return it directly without re-indexing through `pending[0]`.\n const wasEmpty = pending.length === 0\n pending.push(emitChunk)\n return wasEmpty ? emitChunk : pending\n },\n }\n}\n"],"mappings":";;;;AAyEA,SAAS,WAAW,MAAc,OAAwC;CACxE,IAAI,SAAS;CACb,KAAK,MAAM,QAAQ,OACjB,IAAI,aAAa,MACf,SAAS,OAAO,QAAQ,KAAK,SAAS,KAAK,WAAW;MAEtD,SAAS,KAAK,GAAG,MAAM;CAG3B,OAAO;AACT;;;;;;;;;;;;;;;;AAiBA,SAAgB,uBACd,SACgB;CAChB,MAAM,EACJ,OACA,WAAW,YACX,aAAa,IACb,eAAe,OACf,eACE;CAEJ,IAAI,aAAa,SACf,OAAO,oBAAoB,OAAO,cAAc,UAAU;CAE5D,OAAO,uBAAuB,OAAO,YAAY,cAAc,UAAU;AAC3E;AAEA,SAAS,oBACP,OACA,cACA,YACgB;CAChB,OAAO;EACL,MAAM;EAEN,QAAQ,MAA6B,OAAoB;GACvD,IAAI,MAAM,SAAS,wBAAwB;GAE3C,MAAM,WAAW,MAAM;GACvB,MAAM,WAAW,WAAW,UAAU,KAAK;GAE3C,IAAI,aAAa,UAAU;GAE3B,IAAI,YACF,WAAW;IACT,WAAW,MAAM;IACjB;IACA;IACA,UAAU;GACZ,CAAC;GAGH,IAAI,cAAc,OAAO;GAMzB,MAAM,EAAE,SAAS,kBAAkB,GAAG,SAAS;GAE/C,OAAO;IACL,GAAG;IACH,OAAO;GACT;EACF;CACF;AACF;AAEA,SAAS,uBACP,OACA,YACA,cACA,YACgB;CAChB,IAAI,iBAAiB;CACrB,IAAI,wBAAwB;CAC5B,IAAI,gBAAgB;CAEpB,SAAS,aAAa;EACpB,iBAAiB;EACjB,wBAAwB;EACxB,gBAAgB;CAClB;CAEA,SAAS,cAAkC;EACzC,IAAI,eAAe,WAAW,GAAG,OAAO;EAExC,MAAM,WAAW,WAAW,gBAAgB,KAAK;EAEjD,IAAI,gBAAgB,aAAa,gBAAgB;GAC/C,IAAI,YACF,WAAW;IACT,WAAW;IACX,UAAU;IACV;IACA,UAAU;GACZ,CAAC;GAEH,WAAW;GACX,OAAO;EACT;EAEA,MAAM,YAAY,SAAS,MAAM,qBAAqB;EACtD,IAAI,UAAU,SAAS,GAAG;GACxB,IAAI,aAAa,kBAAkB,YACjC,WAAW;IACT,WAAW;IACX,UAAU;IACV;IACA,UAAU;GACZ,CAAC;GAGH,MAAM,UAAU;IACd,MAAM;IACN,WAAW;IACX,OAAO;IACP,SAAS;IACT,WAAW,KAAK,IAAI;GACtB;GAEA,WAAW;GACX,OAAO;EACT;EAEA,WAAW;EACX,OAAO;CACT;CAEA,OAAO;EACL,MAAM;EAEN,UAAU;GACR,WAAW;EACb;EAEA,QAAQ,MAA6B,OAAoB;GAEvD,IAAI,MAAM,SAAS,sBAAsB,MAAM,SAAS,gBAAgB;IACtE,MAAM,UAAU,YAAY;IAC5B,IAAI,SAAS,OAAO,CAAC,SAAS,KAAK;IACnC;GACF;GAEA,IAAI,MAAM,SAAS,wBAAwB;GAG3C,MAAM,UAA8B,CAAC;GACrC,IAAI,iBAAiB,MAAM,cAAc,eAAe;IACtD,MAAM,UAAU,YAAY;IAC5B,IAAI,SAAS,QAAQ,KAAK,OAAO;GACnC;GAEA,kBAAkB,MAAM;GACxB,gBAAgB,MAAM;GAGtB,MAAM,WAAW,WAAW,gBAAgB,KAAK;GACjD,MAAM,kBAAkB,KAAK,IAAI,GAAG,SAAS,SAAS,UAAU;GAEhE,IAAI,mBAAmB,uBACrB,OAAO,QAAQ,SAAS,IAAI,UAAU;GAGxC,IAAI,gBAAgB,aAAa,gBAAgB;IAC/C,IAAI,YACF,WAAW;KACT,WAAW,MAAM;KACjB,UAAU;KACV;KACA,UAAU;IACZ,CAAC;IAEH,OAAO,QAAQ,SAAS,IAAI,UAAU;GACxC;GAEA,MAAM,WAAW,SAAS,MAAM,uBAAuB,eAAe;GAEtE,IAAI,aAAa,kBAAkB,YACjC,WAAW;IACT,WAAW,MAAM;IACjB,UAAU;IACV;IACA,UAAU;GACZ,CAAC;GAGH,wBAAwB;GAExB,MAAM,YAAY;IAChB,GAAG;IACH,OAAO;IACP,SAAS,SAAS,MAAM,GAAG,eAAe;GAC5C;GAIA,MAAM,WAAW,QAAQ,WAAW;GACpC,QAAQ,KAAK,SAAS;GACtB,OAAO,WAAW,YAAY;EAChC;CACF;AACF"}
1
+ {"version":3,"file":"content-guard.js","names":[],"sources":["../../../src/middlewares/content-guard.ts"],"sourcesContent":["import type {\n ChatMiddleware,\n ChatMiddlewareContext,\n} from '../activities/chat/middleware/types'\nimport type { StreamChunk } from '../types'\nimport type { AdapterYieldChunk } from '../utilities/adapter-yield-chunk'\n\n/**\n * A content guard rule — either a regex pattern with replacement, or a transform function.\n */\nexport type ContentGuardRule =\n | { pattern: RegExp; replacement: string }\n | { fn: (text: string) => string }\n\n/**\n * Information passed to the onFiltered callback.\n */\nexport interface ContentFilteredInfo {\n /** The message ID being filtered */\n messageId: string\n /** The original text before filtering */\n original: string\n /** The filtered text after rules applied */\n filtered: string\n /** Which strategy was used */\n strategy: 'delta' | 'buffered'\n}\n\n/**\n * Options for the content guard middleware.\n */\nexport interface ContentGuardMiddlewareOptions {\n /**\n * Rules to apply to text content. Each rule is either a regex pattern\n * with a replacement string, or a custom transform function.\n * Rules are applied in order. Each rule receives the output of the previous.\n */\n rules: Array<ContentGuardRule>\n\n /**\n * Matching strategy:\n * - 'delta': Apply rules to each delta as it arrives. Fast, real-time,\n * but patterns spanning chunk boundaries may be missed.\n * - 'buffered': Accumulate content and apply rules to settled portions,\n * holding back a look-behind buffer to catch cross-boundary patterns.\n *\n * @default 'buffered'\n */\n strategy?: 'delta' | 'buffered'\n\n /**\n * Number of characters to hold back before emitting (buffered strategy only).\n * Should be at least as long as the longest pattern you expect to match.\n * Buffer is flushed when the stream ends.\n *\n * @default 50\n */\n bufferSize?: number\n\n /**\n * If true, drop the entire chunk when any rule changes the content.\n * @default false\n */\n blockOnMatch?: boolean\n\n /**\n * Callback when content is filtered by any rule.\n */\n onFiltered?: (info: ContentFilteredInfo) => void\n}\n\n/**\n * Apply all rules to a string, returning the transformed result.\n */\nfunction applyRules(text: string, rules: Array<ContentGuardRule>): string {\n let result = text\n for (const rule of rules) {\n if ('pattern' in rule) {\n result = result.replace(rule.pattern, rule.replacement)\n } else {\n result = rule.fn(result)\n }\n }\n return result\n}\n\n/**\n * Creates a middleware that filters or transforms streamed text content.\n *\n * @example\n * ```ts\n * import { contentGuardMiddleware } from '@tanstack/ai/middlewares'\n *\n * const guard = contentGuardMiddleware({\n * rules: [\n * { pattern: /\\b\\d{3}-\\d{2}-\\d{4}\\b/g, replacement: '[SSN REDACTED]' },\n * ],\n * strategy: 'buffered',\n * })\n * ```\n */\nexport function contentGuardMiddleware(\n options: ContentGuardMiddlewareOptions,\n): ChatMiddleware {\n const {\n rules,\n strategy = 'buffered',\n bufferSize = 50,\n blockOnMatch = false,\n onFiltered,\n } = options\n\n if (strategy === 'delta') {\n return createDeltaStrategy(rules, blockOnMatch, onFiltered)\n }\n return createBufferedStrategy(rules, bufferSize, blockOnMatch, onFiltered)\n}\n\nfunction createDeltaStrategy(\n rules: Array<ContentGuardRule>,\n blockOnMatch: boolean,\n onFiltered?: (info: ContentFilteredInfo) => void,\n): ChatMiddleware {\n return {\n name: 'content-guard',\n\n onChunk(_ctx: ChatMiddlewareContext, chunk: StreamChunk) {\n if (chunk.type !== 'TEXT_MESSAGE_CONTENT') return\n\n const original = chunk.delta\n const filtered = applyRules(original, rules)\n\n if (filtered === original) return // unchanged, pass through\n\n if (onFiltered) {\n onFiltered({\n messageId: chunk.messageId,\n original,\n filtered,\n strategy: 'delta',\n })\n }\n\n if (blockOnMatch) return null // drop chunk\n\n // Drop the adapter-era content field; the replacement event carries only\n // the filtered delta.\n const { content: _strippedContent, ...rest } = chunk as Extract<\n AdapterYieldChunk,\n { type: 'TEXT_MESSAGE_CONTENT' }\n >\n void _strippedContent\n return {\n ...rest,\n delta: filtered,\n }\n },\n }\n}\n\nfunction createBufferedStrategy(\n rules: Array<ContentGuardRule>,\n bufferSize: number,\n blockOnMatch: boolean,\n onFiltered?: (info: ContentFilteredInfo) => void,\n): ChatMiddleware {\n let rawAccumulated = ''\n let emittedFilteredLength = 0\n let lastMessageId = ''\n\n function resetState() {\n rawAccumulated = ''\n emittedFilteredLength = 0\n lastMessageId = ''\n }\n\n function flushBuffer(): StreamChunk | null {\n if (rawAccumulated.length === 0) return null\n\n const filtered = applyRules(rawAccumulated, rules)\n\n if (blockOnMatch && filtered !== rawAccumulated) {\n if (onFiltered) {\n onFiltered({\n messageId: lastMessageId,\n original: rawAccumulated,\n filtered,\n strategy: 'buffered',\n })\n }\n resetState()\n return null\n }\n\n const remaining = filtered.slice(emittedFilteredLength)\n if (remaining.length > 0) {\n if (filtered !== rawAccumulated && onFiltered) {\n onFiltered({\n messageId: lastMessageId,\n original: rawAccumulated,\n filtered,\n strategy: 'buffered',\n })\n }\n\n const flushed = {\n type: 'TEXT_MESSAGE_CONTENT',\n messageId: lastMessageId,\n delta: remaining,\n content: filtered,\n timestamp: Date.now(),\n } as StreamChunk\n\n resetState()\n return flushed\n }\n\n resetState()\n return null\n }\n\n return {\n name: 'content-guard',\n\n onStart() {\n resetState()\n },\n\n onChunk(_ctx: ChatMiddlewareContext, chunk: StreamChunk) {\n // Flush buffer on stream end events\n if (chunk.type === 'TEXT_MESSAGE_END' || chunk.type === 'RUN_FINISHED') {\n const flushed = flushBuffer()\n if (flushed) return [flushed, chunk]\n return // pass through end event\n }\n\n if (chunk.type !== 'TEXT_MESSAGE_CONTENT') return // pass through\n\n // Flush buffer on message boundary change\n const pending: Array<StreamChunk> = []\n if (lastMessageId && chunk.messageId !== lastMessageId) {\n const flushed = flushBuffer()\n if (flushed) pending.push(flushed)\n }\n\n rawAccumulated += chunk.delta\n lastMessageId = chunk.messageId\n\n // Apply rules to full accumulated text, buffer in filtered space\n const filtered = applyRules(rawAccumulated, rules)\n const safeFilteredEnd = Math.max(0, filtered.length - bufferSize)\n\n if (safeFilteredEnd <= emittedFilteredLength) {\n return pending.length > 0 ? pending : null\n }\n\n if (blockOnMatch && filtered !== rawAccumulated) {\n if (onFiltered) {\n onFiltered({\n messageId: chunk.messageId,\n original: rawAccumulated,\n filtered,\n strategy: 'buffered',\n })\n }\n return pending.length > 0 ? pending : null\n }\n\n const newDelta = filtered.slice(emittedFilteredLength, safeFilteredEnd)\n\n if (filtered !== rawAccumulated && onFiltered) {\n onFiltered({\n messageId: chunk.messageId,\n original: rawAccumulated,\n filtered,\n strategy: 'buffered',\n })\n }\n\n emittedFilteredLength = safeFilteredEnd\n\n const emitChunk = {\n ...chunk,\n delta: newDelta,\n content: filtered.slice(0, safeFilteredEnd),\n } as StreamChunk\n\n // `pending` was empty before this push iff `emitChunk` is now the only\n // entry — return it directly without re-indexing through `pending[0]`.\n const wasEmpty = pending.length === 0\n pending.push(emitChunk)\n return wasEmpty ? emitChunk : pending\n },\n }\n}\n"],"mappings":"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"}
@@ -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
- export interface ToolCall<TMetadata = unknown> {
91
- id: string;
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
- * - 'text': Plain text content
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 = 'text' | 'image' | 'audio' | 'video' | 'document';
121
+ export type Modality = AGUIContentPart['type'];
130
122
  /**
131
- * Source specification for inline data content (base64).
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
- * Source specification for URL-based content.
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 {
131
+ }
132
+ /**
133
+ * A provider-issued file handle (Files API). AG-UI `FileSource`: the handle
134
+ * is opaque, do not fetch or parse it.
135
+ */
136
+ export interface ContentPartFileSource extends AGUIFileSource {
166
137
  }
167
138
  /**
168
- * Source specification for multimodal content.
169
- * Discriminated union supporting both inline data (base64) and URL-based content.
170
- * - For 'data' sources: mimeType is required
171
- * - For 'url' sources: mimeType is optional
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`.
172
141
  */
173
- export type ContentPartSource = ContentPartDataSource | ContentPartUrlSource;
142
+ export type ContentPartSource = ContentPartDataSource | ContentPartUrlSource | ContentPartFileSource;
174
143
  /**
175
- * Image content part for multimodal messages.
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). */
@@ -907,6 +890,12 @@ export interface TextOptions<TProviderOptionsSuperset extends Record<string, any
907
890
  * Surfaced for observability/middleware; not consumed by the LLM call.
908
891
  */
909
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;
910
899
  /** Application state mirrored in a STATE_SNAPSHOT before an interrupt terminal. */
911
900
  state?: unknown;
912
901
  /**
@@ -1046,13 +1035,10 @@ export interface TextMessageEndEvent extends AGUITextMessageEndEvent {
1046
1035
  /**
1047
1036
  * Emitted when a tool call starts.
1048
1037
  *
1049
- * @ag-ui/core provides: `toolCallId`, `toolCallName`, `parentMessageId?`
1050
- *
1051
- * Field shapes are taken from AG-UI via `Pick` (not `extends`) so Zod
1052
- * `.passthrough()` index signatures do not pollute the StreamChunk
1053
- * discriminated union — required for {@link KnownCustomEvent} narrowing.
1038
+ * @ag-ui/core provides: `toolCallId`, `toolCallName`, `parentMessageId?`,
1039
+ * `subagentRunId?`
1054
1040
  */
1055
- export interface ToolCallStartEvent extends Pick<AGUIToolCallStartEvent, 'toolCallId' | 'toolCallName' | 'parentMessageId' | 'timestamp' | 'rawEvent'> {
1041
+ export interface ToolCallStartEvent extends Omit<AGUIToolCallStartEvent, 'type'> {
1056
1042
  type: 'TOOL_CALL_START';
1057
1043
  /** Alias of `toolCallName`. Kept so existing stream readers still compile. */
1058
1044
  toolName?: string;
@@ -1069,11 +1055,9 @@ export interface ToolCallArgsEvent extends AGUIToolCallArgsEvent {
1069
1055
  /**
1070
1056
  * Emitted when a tool call completes.
1071
1057
  *
1072
- * @ag-ui/core provides: `toolCallId`
1073
- *
1074
- * Same `Pick` (not `extends`) rationale as {@link ToolCallStartEvent}.
1058
+ * @ag-ui/core provides: `toolCallId`, `subagentRunId?`
1075
1059
  */
1076
- export interface ToolCallEndEvent extends Pick<AGUIToolCallEndEvent, 'toolCallId' | 'timestamp' | 'rawEvent'> {
1060
+ export interface ToolCallEndEvent extends Omit<AGUIToolCallEndEvent, 'type'> {
1077
1061
  type: 'TOOL_CALL_END';
1078
1062
  /** Parsed tool arguments when the adapter already parsed them. */
1079
1063
  input?: unknown;
@@ -1130,12 +1114,9 @@ export interface StateDeltaEvent extends AGUIStateDeltaEvent {
1130
1114
  /**
1131
1115
  * Custom event for extensibility.
1132
1116
  *
1133
- * @ag-ui/core provides: `name`, `value`
1134
- *
1135
- * Uses `Pick` (not `extends`) so the Zod passthrough index signature does not
1136
- * erase discriminant property access on {@link KnownCustomEvent} unions.
1117
+ * @ag-ui/core provides: `name`, `value`, `subagentRunId?`
1137
1118
  */
1138
- export interface CustomEvent extends Pick<AGUICustomEvent, 'name' | 'value' | 'timestamp' | 'rawEvent'> {
1119
+ export interface CustomEvent extends Omit<AGUICustomEvent, 'type'> {
1139
1120
  type: 'CUSTOM';
1140
1121
  metadata?: Record<string, any>;
1141
1122
  }
@@ -1420,10 +1401,51 @@ export interface ReasoningEndEvent extends AGUIReasoningEndEvent {
1420
1401
  */
1421
1402
  export interface ReasoningEncryptedValueEvent extends AGUIReasoningEncryptedValueEvent {
1422
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
+ }
1423
1422
  /**
1424
1423
  * Union of all AG-UI events.
1425
1424
  */
1426
- 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
+ }
1427
1449
  /**
1428
1450
  * Chunk returned by the SDK during streaming chat completions.
1429
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
- export type AdapterYieldChunk = StreamChunk & {
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 interface SpecTokenUsage {
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;