@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/client.js
CHANGED
|
@@ -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
|
package/dist/esm/client.js.map
CHANGED
|
@@ -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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"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -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
|
@@ -5,6 +5,7 @@ import { memoryStream, replayRunStream, resolveResumeRunId } from "./stream-dura
|
|
|
5
5
|
import { EventType } from "./types.js";
|
|
6
6
|
import { fromSpecTokenUsage, toSpecTokenUsage } from "./utilities/ag-ui-usage.js";
|
|
7
7
|
import { mergeMetadata, withTanstackMetadata } from "./utilities/merge-metadata.js";
|
|
8
|
+
import { CUSTOM_EVENT, isCustomEvent } from "./custom-events.js";
|
|
8
9
|
import { normalizeStreamChunk } from "./utilities/normalize-stream-chunk.js";
|
|
9
10
|
import { ConsoleLogger } from "./logger/console-logger.js";
|
|
10
11
|
import { SkillLimitError } from "./utilities/errors.js";
|
|
@@ -17,6 +18,7 @@ import { INTERRUPT_BINDING_METADATA_KEY, InterruptResumeValidationError, interru
|
|
|
17
18
|
import { INTERRUPT_PAYLOAD_METADATA_KEY, createInterruptBinding, defineInterrupt } from "./interrupt-definition.js";
|
|
18
19
|
import { INTERRUPT_CONTINUATION_METADATA_KEY, INTERRUPT_CONTINUATION_VERSION, genericInterruptContinuationFromDescriptor, readGenericInterruptContinuation, wrapGenericInterruptContinuation } from "./generic-interrupt-continuation.js";
|
|
19
20
|
import { isContentPart, isContentPartArray, normalizeToolResult } from "./utilities/tool-result.js";
|
|
21
|
+
import { subagentHostMessageId, wireSubagentInfo } from "./utilities/subagent-wire.js";
|
|
20
22
|
import { getProviderExecutedMetadata, isProviderExecutedToolCall } from "./utilities/provider-executed.js";
|
|
21
23
|
import { convertMessagesToModelMessages, generateMessageId, modelMessageToUIMessage, modelMessagesToUIMessages, normalizeToUIMessage, uiMessageToModelMessages } from "./activities/chat/messages.js";
|
|
22
24
|
import { uiMessagesToWire } from "./utilities/ag-ui-wire.js";
|
|
@@ -27,11 +29,13 @@ import { ToolCallManager } from "./activities/chat/tools/tool-calls.js";
|
|
|
27
29
|
import { combineStrategies, maxIterations, untilFinishReason } from "./activities/chat/agent-loop-strategies.js";
|
|
28
30
|
import { MCPDuplicateToolNameError } from "./activities/chat/mcp/manager.js";
|
|
29
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";
|
|
30
36
|
import { createSummarizeOptions, summarize } from "./activities/summarize/index.js";
|
|
31
37
|
import { BaseRerankAdapter } from "./activities/rerank/adapter.js";
|
|
32
38
|
import { createRerankOptions, rerank } from "./activities/rerank/index.js";
|
|
33
|
-
import { BaseEvaluateAdapter } from "./activities/evaluate/adapter.js";
|
|
34
|
-
import { boolean, choice, decide, score } from "./activities/evaluate/index.js";
|
|
35
39
|
import { resolveMediaPrompt } from "./utilities/media-prompt.js";
|
|
36
40
|
import { createImageOptions, generateImage } from "./activities/generateImage/index.js";
|
|
37
41
|
import { createAudioOptions, generateAudio } from "./activities/generateAudio/index.js";
|
|
@@ -52,7 +56,6 @@ import { INTERRUPT_BOUNDARY_PHASES, INTERRUPT_TOOL_RESUMES } from "./activities/
|
|
|
52
56
|
import { defineChatMiddleware } from "./activities/chat/middleware/define.js";
|
|
53
57
|
import { createChatMiddleware } from "./activities/chat/middleware/builder.js";
|
|
54
58
|
import { MetadataCapability, getMetadata, provideMetadata } from "./activities/chat/middleware/metadata.js";
|
|
55
|
-
import { CUSTOM_EVENT, isCustomEvent } from "./custom-events.js";
|
|
56
59
|
import { buildBaseUsage } from "./utilities/usage.js";
|
|
57
60
|
import { normalizeSystemPrompts } from "./system-prompts.js";
|
|
58
61
|
import { detectImageMimeType } from "./utils.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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"}
|
|
@@ -5,6 +5,7 @@ import { wasRunDetached } from "./delivery-detach.js";
|
|
|
5
5
|
import { notifyRunDisconnected } from "./delivery-disconnect.js";
|
|
6
6
|
import { resolveResumeRunId } from "./stream-durability.js";
|
|
7
7
|
import { EventType } from "./types.js";
|
|
8
|
+
import { isDurabilityBatchedCustom, stripDurabilityBatchHint } from "./utilities/durability-batch.js";
|
|
8
9
|
import { toWireChunk } from "./strip-to-spec-middleware.js";
|
|
9
10
|
import { resolveDebugOption } from "./logger/resolve.js";
|
|
10
11
|
import { runErrorEventToError } from "./utilities/errors.js";
|
|
@@ -191,19 +192,24 @@ function resolveBatchSize(batch) {
|
|
|
191
192
|
}
|
|
192
193
|
/**
|
|
193
194
|
* Boundaries at which the batching producer flushes early, regardless of the
|
|
194
|
-
* batch size
|
|
195
|
-
*
|
|
196
|
-
* meaningful points.
|
|
195
|
+
* batch size: run-start, terminals, tool-call ends, and CUSTOM events that
|
|
196
|
+
* are not high-volume adapter output.
|
|
197
197
|
*
|
|
198
198
|
* `RUN_STARTED` matters especially for one-shot activities (image, speech,
|
|
199
199
|
* transcription, summarize): they emit `RUN_STARTED`, then await the provider
|
|
200
200
|
* for seconds, then a terminal. Without flushing `RUN_STARTED` the log stays
|
|
201
201
|
* empty for the whole run, so a mount-time `joinRun` finds nothing and its
|
|
202
|
-
* empty-log deadline fast-fails as "run gone"
|
|
202
|
+
* empty-log deadline fast-fails as "run gone" even though the run is alive.
|
|
203
203
|
* Flushing it immediately makes the run resumable from the instant it starts.
|
|
204
|
+
*
|
|
205
|
+
* CUSTOM progress events (compaction, tool progress, middleware) flush at
|
|
206
|
+
* emit time so a live indicator can render. `process.stdout`,
|
|
207
|
+
* `process.stderr`, `sandbox.file`, and `sandbox.file.diff` stay batched.
|
|
208
|
+
* `emitCustomEvent(name, value, { batch: true })` opts a single event into
|
|
209
|
+
* that same batch.
|
|
204
210
|
*/
|
|
205
211
|
function isDurabilityFlushBoundary(chunk) {
|
|
206
|
-
return chunk.type === "RUN_STARTED" || chunk.type === "RUN_FINISHED" || chunk.type === "RUN_ERROR" || chunk.type === "TOOL_CALL_END";
|
|
212
|
+
return chunk.type === "RUN_STARTED" || chunk.type === "RUN_FINISHED" || chunk.type === "RUN_ERROR" || chunk.type === "TOOL_CALL_END" || chunk.type === "CUSTOM" && !isDurabilityBatchedCustom(chunk);
|
|
207
213
|
}
|
|
208
214
|
/**
|
|
209
215
|
* Name of the synthetic `CUSTOM` chunk a fresh durable producer appends to its
|
|
@@ -265,7 +271,7 @@ function durableStreamSource(stream, durability, options) {
|
|
|
265
271
|
};
|
|
266
272
|
async function* flush() {
|
|
267
273
|
if (batch.length === 0) return;
|
|
268
|
-
const toForward = batch;
|
|
274
|
+
const toForward = batch.map(stripDurabilityBatchHint);
|
|
269
275
|
batch = [];
|
|
270
276
|
const offsets = await durability.append(toForward);
|
|
271
277
|
if (offsets.length !== toForward.length) throw new Error(`Durability append returned ${offsets.length} offsets for ${toForward.length} chunks`);
|