@tanstack/ai 0.42.0 → 0.43.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -1
- package/dist/esm/activities/chat/adapter.js +23 -16
- package/dist/esm/activities/chat/adapter.js.map +1 -1
- package/dist/esm/activities/chat/agent-loop-strategies.d.ts +5 -36
- package/dist/esm/activities/chat/agent-loop-strategies.js +75 -21
- package/dist/esm/activities/chat/agent-loop-strategies.js.map +1 -1
- package/dist/esm/activities/chat/cancel.d.ts +40 -0
- package/dist/esm/activities/chat/cancel.js +54 -0
- package/dist/esm/activities/chat/cancel.js.map +1 -0
- package/dist/esm/activities/chat/index.d.ts +28 -21
- package/dist/esm/activities/chat/index.js +2100 -1813
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/mcp/manager.d.ts +2 -2
- package/dist/esm/activities/chat/mcp/manager.js +90 -77
- package/dist/esm/activities/chat/mcp/manager.js.map +1 -1
- package/dist/esm/activities/chat/mcp/types.d.ts +2 -2
- package/dist/esm/activities/chat/messages.js +397 -346
- package/dist/esm/activities/chat/messages.js.map +1 -1
- package/dist/esm/activities/chat/middleware/builder.js +17 -15
- package/dist/esm/activities/chat/middleware/builder.js.map +1 -1
- package/dist/esm/activities/chat/middleware/capabilities.js +78 -43
- package/dist/esm/activities/chat/middleware/capabilities.js.map +1 -1
- package/dist/esm/activities/chat/middleware/compose.d.ts +94 -1
- package/dist/esm/activities/chat/middleware/compose.js +623 -531
- package/dist/esm/activities/chat/middleware/compose.js.map +1 -1
- package/dist/esm/activities/chat/middleware/define.js +12 -5
- package/dist/esm/activities/chat/middleware/define.js.map +1 -1
- package/dist/esm/activities/chat/middleware/index.d.ts +5 -1
- package/dist/esm/activities/chat/middleware/locks.d.ts +50 -0
- package/dist/esm/activities/chat/middleware/locks.js +71 -0
- package/dist/esm/activities/chat/middleware/locks.js.map +1 -0
- package/dist/esm/activities/chat/middleware/pending-turn.d.ts +15 -0
- package/dist/esm/activities/chat/middleware/pending-turn.js +35 -0
- package/dist/esm/activities/chat/middleware/pending-turn.js.map +1 -0
- package/dist/esm/activities/chat/middleware/run-disconnect.d.ts +23 -0
- package/dist/esm/activities/chat/middleware/run-disconnect.js +42 -0
- package/dist/esm/activities/chat/middleware/run-disconnect.js.map +1 -0
- package/dist/esm/activities/chat/middleware/run-store.d.ts +283 -0
- package/dist/esm/activities/chat/middleware/run-store.js +176 -0
- package/dist/esm/activities/chat/middleware/run-store.js.map +1 -0
- package/dist/esm/activities/chat/middleware/sandbox-runtime.js +14 -8
- package/dist/esm/activities/chat/middleware/sandbox-runtime.js.map +1 -1
- package/dist/esm/activities/chat/middleware/tool-cache-middleware.js +79 -70
- package/dist/esm/activities/chat/middleware/tool-cache-middleware.js.map +1 -1
- package/dist/esm/activities/chat/middleware/types.d.ts +59 -2
- package/dist/esm/activities/chat/middleware/validate.js +23 -28
- package/dist/esm/activities/chat/middleware/validate.js.map +1 -1
- package/dist/esm/activities/chat/stream/json-parser.js +39 -25
- package/dist/esm/activities/chat/stream/json-parser.js.map +1 -1
- package/dist/esm/activities/chat/stream/message-updaters.js +275 -234
- package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
- package/dist/esm/activities/chat/stream/processor.d.ts +24 -4
- package/dist/esm/activities/chat/stream/processor.js +1341 -1542
- package/dist/esm/activities/chat/stream/processor.js.map +1 -1
- package/dist/esm/activities/chat/stream/strategies.js +69 -53
- package/dist/esm/activities/chat/stream/strategies.js.map +1 -1
- package/dist/esm/activities/chat/tools/approval-schema.d.ts +19 -0
- package/dist/esm/activities/chat/tools/approval-schema.js +117 -0
- package/dist/esm/activities/chat/tools/approval-schema.js.map +1 -0
- package/dist/esm/activities/chat/tools/lazy-tool-manager.js +164 -191
- package/dist/esm/activities/chat/tools/lazy-tool-manager.js.map +1 -1
- package/dist/esm/activities/chat/tools/lazy-tools.js +24 -12
- package/dist/esm/activities/chat/tools/lazy-tools.js.map +1 -1
- package/dist/esm/activities/chat/tools/schema-converter.js +293 -146
- package/dist/esm/activities/chat/tools/schema-converter.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-calls.d.ts +18 -2
- package/dist/esm/activities/chat/tools/tool-calls.js +522 -531
- package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-definition.d.ts +75 -16
- package/dist/esm/activities/chat/tools/tool-definition.js +95 -23
- package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -1
- package/dist/esm/activities/error-payload.js +85 -47
- package/dist/esm/activities/error-payload.js.map +1 -1
- package/dist/esm/activities/generateAudio/adapter.js +22 -15
- package/dist/esm/activities/generateAudio/adapter.js.map +1 -1
- package/dist/esm/activities/generateAudio/index.d.ts +4 -0
- package/dist/esm/activities/generateAudio/index.js +141 -105
- package/dist/esm/activities/generateAudio/index.js.map +1 -1
- package/dist/esm/activities/generateImage/adapter.js +22 -15
- package/dist/esm/activities/generateImage/adapter.js.map +1 -1
- package/dist/esm/activities/generateImage/index.d.ts +4 -0
- package/dist/esm/activities/generateImage/index.js +155 -111
- package/dist/esm/activities/generateImage/index.js.map +1 -1
- package/dist/esm/activities/generateSpeech/adapter.js +22 -15
- package/dist/esm/activities/generateSpeech/adapter.js.map +1 -1
- package/dist/esm/activities/generateSpeech/index.d.ts +4 -0
- package/dist/esm/activities/generateSpeech/index.js +159 -110
- package/dist/esm/activities/generateSpeech/index.js.map +1 -1
- package/dist/esm/activities/generateTranscription/adapter.js +22 -15
- package/dist/esm/activities/generateTranscription/adapter.js.map +1 -1
- package/dist/esm/activities/generateTranscription/index.d.ts +4 -0
- package/dist/esm/activities/generateTranscription/index.js +159 -100
- package/dist/esm/activities/generateTranscription/index.js.map +1 -1
- package/dist/esm/activities/generateVideo/adapter.js +36 -29
- package/dist/esm/activities/generateVideo/adapter.js.map +1 -1
- package/dist/esm/activities/generateVideo/index.d.ts +143 -19
- package/dist/esm/activities/generateVideo/index.js +456 -279
- package/dist/esm/activities/generateVideo/index.js.map +1 -1
- package/dist/esm/activities/generateVideo/snap.js +60 -48
- package/dist/esm/activities/generateVideo/snap.js.map +1 -1
- package/dist/esm/activities/index.js +8 -34
- package/dist/esm/activities/middleware/index.d.ts +1 -1
- package/dist/esm/activities/middleware/run.d.ts +10 -0
- package/dist/esm/activities/middleware/run.js +53 -29
- package/dist/esm/activities/middleware/run.js.map +1 -1
- package/dist/esm/activities/middleware/types.d.ts +44 -6
- package/dist/esm/activities/stream-generation-result.d.ts +4 -1
- package/dist/esm/activities/stream-generation-result.js +79 -44
- package/dist/esm/activities/stream-generation-result.js.map +1 -1
- package/dist/esm/activities/summarize/adapter.js +22 -15
- package/dist/esm/activities/summarize/adapter.js.map +1 -1
- package/dist/esm/activities/summarize/chat-stream-summarize.js +252 -202
- package/dist/esm/activities/summarize/chat-stream-summarize.js.map +1 -1
- package/dist/esm/activities/summarize/index.d.ts +27 -0
- package/dist/esm/activities/summarize/index.js +268 -102
- package/dist/esm/activities/summarize/index.js.map +1 -1
- package/dist/esm/adapter-internals.d.ts +2 -1
- package/dist/esm/adapter-internals.js +4 -11
- package/dist/esm/client.d.ts +25 -3
- package/dist/esm/client.js +131 -64
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/custom-events.d.ts +76 -0
- package/dist/esm/custom-events.js +37 -0
- package/dist/esm/custom-events.js.map +1 -0
- package/dist/esm/delivery-detach.d.ts +50 -0
- package/dist/esm/delivery-detach.js +71 -0
- package/dist/esm/delivery-detach.js.map +1 -0
- package/dist/esm/delivery-disconnect.d.ts +62 -0
- package/dist/esm/delivery-disconnect.js +81 -0
- package/dist/esm/delivery-disconnect.js.map +1 -0
- package/dist/esm/extend-adapter.js +19 -17
- package/dist/esm/extend-adapter.js.map +1 -1
- package/dist/esm/index.d.ts +24 -6
- package/dist/esm/index.js +30 -98
- package/dist/esm/interrupt-resume.d.ts +71 -0
- package/dist/esm/interrupt-resume.js +438 -0
- package/dist/esm/interrupt-resume.js.map +1 -0
- package/dist/esm/interrupt-serialization.d.ts +12 -0
- package/dist/esm/interrupt-serialization.js +178 -0
- package/dist/esm/interrupt-serialization.js.map +1 -0
- package/dist/esm/interrupts.d.ts +84 -0
- package/dist/esm/interrupts.js +31 -0
- package/dist/esm/interrupts.js.map +1 -0
- package/dist/esm/locks.d.ts +10 -0
- package/dist/esm/locks.js +2 -0
- package/dist/esm/logger/console-logger.js +101 -78
- package/dist/esm/logger/console-logger.js.map +1 -1
- package/dist/esm/logger/internal-logger.js +104 -89
- package/dist/esm/logger/internal-logger.js.map +1 -1
- package/dist/esm/logger/resolve.js +54 -49
- package/dist/esm/logger/resolve.js.map +1 -1
- package/dist/esm/logger/types.d.ts +1 -1
- package/dist/esm/middlewares/content-guard.js +142 -148
- package/dist/esm/middlewares/content-guard.js.map +1 -1
- package/dist/esm/middlewares/index.js +2 -6
- package/dist/esm/middlewares/otel.d.ts +3 -1
- package/dist/esm/middlewares/otel.js +599 -732
- package/dist/esm/middlewares/otel.js.map +1 -1
- package/dist/esm/middlewares/usage-attributes.js +47 -40
- package/dist/esm/middlewares/usage-attributes.js.map +1 -1
- package/dist/esm/realtime/event-emitter.js +24 -25
- package/dist/esm/realtime/event-emitter.js.map +1 -1
- package/dist/esm/realtime/index.d.ts +5 -9
- package/dist/esm/realtime/index.js +29 -6
- package/dist/esm/realtime/index.js.map +1 -1
- package/dist/esm/scope.d.ts +47 -0
- package/dist/esm/stream-durability.d.ts +171 -0
- package/dist/esm/stream-durability.js +295 -0
- package/dist/esm/stream-durability.js.map +1 -0
- package/dist/esm/stream-to-response.d.ts +178 -13
- package/dist/esm/stream-to-response.js +663 -115
- package/dist/esm/stream-to-response.js.map +1 -1
- package/dist/esm/strip-to-spec-middleware.js +30 -16
- package/dist/esm/strip-to-spec-middleware.js.map +1 -1
- package/dist/esm/system-prompts.js +27 -21
- package/dist/esm/system-prompts.js.map +1 -1
- package/dist/esm/tool-registry.js +72 -45
- package/dist/esm/tool-registry.js.map +1 -1
- package/dist/esm/tools/provider-tool.js +14 -5
- package/dist/esm/tools/provider-tool.js.map +1 -1
- package/dist/esm/types.d.ts +321 -42
- package/dist/esm/types.js +2 -0
- package/dist/esm/utilities/ag-ui-wire.js +79 -93
- package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
- package/dist/esm/utilities/chat-params.d.ts +26 -4
- package/dist/esm/utilities/chat-params.js +218 -92
- package/dist/esm/utilities/chat-params.js.map +1 -1
- package/dist/esm/utilities/errors.js +28 -18
- package/dist/esm/utilities/errors.js.map +1 -1
- package/dist/esm/utilities/media-prompt.js +46 -41
- package/dist/esm/utilities/media-prompt.js.map +1 -1
- package/dist/esm/utilities/numbers.js +13 -10
- package/dist/esm/utilities/numbers.js.map +1 -1
- package/dist/esm/utilities/provider-executed.js +20 -11
- package/dist/esm/utilities/provider-executed.js.map +1 -1
- package/dist/esm/utilities/sampling-keys.js +31 -19
- package/dist/esm/utilities/sampling-keys.js.map +1 -1
- package/dist/esm/utilities/tool-result.js +42 -30
- package/dist/esm/utilities/tool-result.js.map +1 -1
- package/dist/esm/utilities/usage.js +27 -9
- package/dist/esm/utilities/usage.js.map +1 -1
- package/dist/esm/utils.js +26 -18
- package/dist/esm/utils.js.map +1 -1
- package/package.json +10 -6
- package/skills/ai-core/SKILL.md +69 -18
- package/skills/ai-core/adapter-configuration/SKILL.md +44 -21
- package/skills/ai-core/adapter-configuration/references/anthropic-adapter.md +1 -3
- package/skills/ai-core/adapter-configuration/references/byteplus-adapter.md +148 -0
- package/skills/ai-core/adapter-configuration/references/gemini-adapter.md +2 -6
- package/skills/ai-core/adapter-configuration/references/groq-adapter.md +2 -6
- package/skills/ai-core/adapter-configuration/references/openai-adapter.md +1 -3
- package/skills/ai-core/ag-ui-protocol/SKILL.md +1 -1
- package/skills/ai-core/chat-experience/SKILL.md +98 -11
- package/skills/ai-core/client-persistence/SKILL.md +277 -0
- package/skills/ai-core/custom-backend-integration/SKILL.md +1 -1
- package/skills/ai-core/debug-logging/SKILL.md +1 -1
- package/skills/ai-core/locks/SKILL.md +143 -0
- package/skills/ai-core/media-generation/SKILL.md +144 -12
- package/skills/ai-core/middleware/SKILL.md +258 -33
- package/skills/ai-core/structured-outputs/SKILL.md +1 -1
- package/skills/ai-core/tool-calling/SKILL.md +54 -61
- package/src/activities/chat/agent-loop-strategies.ts +5 -39
- package/src/activities/chat/cancel.ts +81 -0
- package/src/activities/chat/index.ts +1091 -200
- package/src/activities/chat/mcp/manager.ts +4 -4
- package/src/activities/chat/mcp/types.ts +2 -2
- package/src/activities/chat/messages.ts +5 -3
- package/src/activities/chat/middleware/builder.ts +1 -1
- package/src/activities/chat/middleware/compose.ts +186 -9
- package/src/activities/chat/middleware/index.ts +26 -0
- package/src/activities/chat/middleware/locks.ts +102 -0
- package/src/activities/chat/middleware/pending-turn.ts +47 -0
- package/src/activities/chat/middleware/run-disconnect.ts +62 -0
- package/src/activities/chat/middleware/run-store.ts +412 -0
- package/src/activities/chat/middleware/types.ts +62 -1
- package/src/activities/chat/stream/processor.ts +189 -5
- package/src/activities/chat/tools/approval-schema.ts +205 -0
- package/src/activities/chat/tools/tool-calls.ts +106 -13
- package/src/activities/chat/tools/tool-definition.ts +210 -39
- package/src/activities/generateAudio/index.ts +20 -3
- package/src/activities/generateImage/index.ts +20 -3
- package/src/activities/generateSpeech/index.ts +25 -3
- package/src/activities/generateTranscription/index.ts +26 -3
- package/src/activities/generateVideo/index.ts +345 -82
- package/src/activities/middleware/index.ts +2 -0
- package/src/activities/middleware/run.ts +31 -0
- package/src/activities/middleware/types.ts +49 -5
- package/src/activities/stream-generation-result.ts +30 -2
- package/src/activities/summarize/chat-stream-summarize.ts +5 -0
- package/src/activities/summarize/index.ts +200 -10
- package/src/adapter-internals.ts +10 -1
- package/src/client.ts +244 -0
- package/src/custom-events.ts +107 -0
- package/src/delivery-detach.ts +72 -0
- package/src/delivery-disconnect.ts +84 -0
- package/src/index.ts +138 -1
- package/src/interrupt-resume.ts +824 -0
- package/src/interrupt-serialization.ts +183 -0
- package/src/interrupts.ts +146 -0
- package/src/locks.ts +17 -0
- package/src/logger/types.ts +1 -1
- package/src/middlewares/otel.ts +23 -5
- package/src/realtime/index.ts +5 -9
- package/src/scope.ts +47 -0
- package/src/stream-durability.ts +598 -0
- package/src/stream-to-response.ts +1051 -95
- package/src/strip-to-spec-middleware.ts +3 -3
- package/src/types.ts +405 -45
- package/src/utilities/chat-params.ts +245 -55
- package/dist/esm/activities/index.js.map +0 -1
- package/dist/esm/adapter-internals.js.map +0 -1
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/middlewares/index.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose.js","sources":["../../../../../src/activities/chat/middleware/compose.ts"],"sourcesContent":["import { aiEventClient } from '@tanstack/ai-event-client'\nimport type { StreamChunk } from '../../../types'\nimport type { InternalLogger } from '../../../logger/internal-logger'\nimport type {\n AbortInfo,\n AfterToolCallInfo,\n BeforeToolCallDecision,\n ChatMiddleware,\n ChatMiddlewareConfig,\n ChatMiddlewareContext,\n ErrorInfo,\n FinishInfo,\n IterationInfo,\n SandboxFileHookEvent,\n StructuredOutputMiddlewareConfig,\n ToolCallHookContext,\n ToolPhaseCompleteInfo,\n UsageInfo,\n} from './types'\n\n/** Check if a middleware should be skipped for instrumentation events. */\nfunction shouldSkipInstrumentation(mw: ChatMiddleware<any>): boolean {\n return mw.name === 'devtools' || mw.name === 'strip-to-spec'\n}\n\n/** Build the base context for middleware instrumentation events. */\nfunction instrumentCtx(ctx: ChatMiddlewareContext<any>) {\n return {\n requestId: ctx.requestId,\n streamId: ctx.streamId,\n clientId: ctx.threadId,\n timestamp: Date.now(),\n }\n}\n\n/**\n * Internal middleware runner that manages composed execution of middleware hooks.\n * Created once per chat() invocation.\n */\nexport class MiddlewareRunner<TContext = unknown> {\n private readonly middlewares: ReadonlyArray<ChatMiddleware<TContext>>\n private readonly logger: InternalLogger\n\n constructor(\n middlewares: ReadonlyArray<ChatMiddleware<TContext>>,\n logger: InternalLogger,\n ) {\n this.middlewares = middlewares\n this.logger = logger\n }\n\n get hasMiddleware(): boolean {\n return this.middlewares.length > 0\n }\n\n /**\n * Pipe config through all middleware onConfig hooks in order.\n * Each middleware receives the merged config from previous middleware.\n * Partial returns are shallow-merged with the current config.\n */\n async runOnConfig(\n ctx: ChatMiddlewareContext<TContext>,\n config: ChatMiddlewareConfig,\n ): Promise<ChatMiddlewareConfig> {\n let current = config\n for (const mw of this.middlewares) {\n if (mw.onConfig) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n const result = await mw.onConfig(ctx, current)\n const hasTransform = result !== undefined && result !== null\n if (hasTransform) {\n current = { ...current, ...result }\n if (!skip) {\n this.logger.config(\n `middleware=${mw.name ?? 'unnamed'} keys=${Object.keys(result).join(',')}`,\n {\n middleware: mw.name ?? 'unnamed',\n changes: result,\n },\n )\n }\n }\n if (!skip) {\n const base = instrumentCtx(ctx)\n aiEventClient.emit('middleware:hook:executed', {\n ...base,\n middlewareName: mw.name || 'unnamed',\n hookName: 'onConfig',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform,\n })\n if (hasTransform) {\n aiEventClient.emit('middleware:config:transformed', {\n ...base,\n middlewareName: mw.name || 'unnamed',\n iteration: ctx.iteration,\n changes: result,\n })\n }\n }\n }\n }\n return current\n }\n\n /**\n * Pipe config through all middleware onStructuredOutputConfig hooks in order.\n * Each middleware receives the merged config from previous middleware.\n * Partial returns are shallow-merged with the current config.\n *\n * Called once at the structured-output boundary, before runOnConfig at the\n * same boundary (which receives a ChatMiddlewareConfig view, no outputSchema).\n */\n async runOnStructuredOutputConfig(\n ctx: ChatMiddlewareContext<TContext>,\n config: StructuredOutputMiddlewareConfig,\n ): Promise<StructuredOutputMiddlewareConfig> {\n let current = config\n for (const mw of this.middlewares) {\n if (mw.onStructuredOutputConfig) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n const result = await mw.onStructuredOutputConfig(ctx, current)\n const hasTransform = result !== undefined && result !== null\n if (hasTransform) {\n current = { ...current, ...result }\n if (!skip) {\n this.logger.config(\n `middleware=${mw.name ?? 'unnamed'} keys=${Object.keys(result).join(',')}`,\n {\n middleware: mw.name ?? 'unnamed',\n changes: result,\n },\n )\n }\n }\n if (!skip) {\n const base = instrumentCtx(ctx)\n aiEventClient.emit('middleware:hook:executed', {\n ...base,\n middlewareName: mw.name || 'unnamed',\n hookName: 'onStructuredOutputConfig',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform,\n })\n if (hasTransform) {\n aiEventClient.emit('middleware:config:transformed', {\n ...base,\n middlewareName: mw.name || 'unnamed',\n iteration: ctx.iteration,\n // `result` is `Partial<StructuredOutputMiddlewareConfig>` —\n // Object.fromEntries(Object.entries(result)) yields the\n // structural `Record<string, unknown>` the event emitter wants\n // without an `as` cast.\n changes: Object.fromEntries(Object.entries(result)),\n })\n }\n }\n }\n }\n return current\n }\n\n /**\n * Run all `setup` hooks in array order, then assert every declared `provides`\n * capability was actually provided. Wires the last-wins duplicate-provide\n * warning into the registry. Runs before init `onConfig`.\n *\n * Takes the full `ChatMiddlewareContext` — the same stable context the engine\n * threads through every other hook — because it both forwards `ctx` to each\n * `setup` hook and emits instrumentation events from it.\n */\n async runSetup(ctx: ChatMiddlewareContext<TContext>): Promise<void> {\n ctx.capabilities.setOnDuplicate((name) => {\n this.logger.warn(\n `capability \"${name}\" was provided more than once; last provider wins`,\n { capability: name },\n )\n })\n\n for (const mw of this.middlewares) {\n if (mw.setup) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n await mw.setup(ctx)\n if (!skip) {\n this.logger.middleware(\n `hook=setup middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'setup' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'setup',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: false,\n })\n }\n }\n }\n\n for (const mw of this.middlewares) {\n for (const handle of mw.provides ?? []) {\n if (!ctx.capabilities.has(handle)) {\n throw new Error(\n `Middleware \"${mw.name ?? 'unnamed'}\" declares it provides ` +\n `\"${handle.capabilityName}\" but never called provide() in setup().`,\n )\n }\n }\n }\n }\n\n /**\n * Call onStart on all middleware in order.\n */\n async runOnStart(ctx: ChatMiddlewareContext<TContext>): Promise<void> {\n for (const mw of this.middlewares) {\n if (mw.onStart) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n await mw.onStart(ctx)\n if (!skip) {\n this.logger.middleware(\n `hook=onStart middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onStart' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onStart',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: false,\n })\n }\n }\n }\n }\n\n /**\n * Pipe a single chunk through all middleware onChunk hooks in order.\n * Returns the resulting chunks (0..N) to yield to the consumer.\n *\n * - void: pass through unchanged\n * - chunk: replace with this chunk\n * - chunk[]: expand to multiple chunks\n * - null: drop the chunk entirely\n */\n async runOnChunk(\n ctx: ChatMiddlewareContext<TContext>,\n chunk: StreamChunk,\n ): Promise<Array<StreamChunk>> {\n let chunks: Array<StreamChunk> = [chunk]\n\n for (const mw of this.middlewares) {\n if (!mw.onChunk) continue\n const skip = shouldSkipInstrumentation(mw)\n\n const nextChunks: Array<StreamChunk> = []\n for (const c of chunks) {\n // Cast: @ag-ui/core Zod passthrough types prevent direct `.type` access\n const chunkType = c.type\n if (!skip) {\n this.logger.middleware(\n `hook=onChunk middleware=${mw.name ?? 'unnamed'} in=${chunkType}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onChunk', in: c },\n )\n }\n const result = await mw.onChunk(ctx, c)\n if (result === null) {\n // Drop this chunk\n if (!skip) {\n this.logger.middleware(\n `hook=onChunk middleware=${mw.name ?? 'unnamed'} in=${chunkType} out=<dropped>`,\n {\n middleware: mw.name ?? 'unnamed',\n hook: 'onChunk',\n dropped: true,\n },\n )\n aiEventClient.emit('middleware:chunk:transformed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n originalChunkType: chunkType,\n resultCount: 0,\n wasDropped: true,\n })\n }\n continue\n } else if (result === undefined) {\n // Pass through — no instrumentation for pass-throughs\n nextChunks.push(c)\n } else if (Array.isArray(result)) {\n // Expand\n nextChunks.push(...result)\n if (!skip) {\n this.logger.middleware(\n `hook=onChunk middleware=${mw.name ?? 'unnamed'} in=${chunkType} out=[${result.map((r: StreamChunk) => r.type).join(',')}]`,\n {\n middleware: mw.name ?? 'unnamed',\n hook: 'onChunk',\n in: c,\n out: result,\n },\n )\n aiEventClient.emit('middleware:chunk:transformed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n originalChunkType: chunkType,\n resultCount: result.length,\n wasDropped: false,\n })\n }\n } else {\n // Replace\n nextChunks.push(result)\n if (!skip) {\n this.logger.middleware(\n `hook=onChunk middleware=${mw.name ?? 'unnamed'} in=${chunkType} out=${result.type}`,\n {\n middleware: mw.name ?? 'unnamed',\n hook: 'onChunk',\n in: c,\n out: result,\n },\n )\n aiEventClient.emit('middleware:chunk:transformed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n originalChunkType: chunkType,\n resultCount: 1,\n wasDropped: false,\n })\n }\n }\n }\n chunks = nextChunks\n }\n\n return chunks\n }\n\n /**\n * Dispatch a sandbox file event to every middleware's `sandbox` hooks, in\n * array order: the catch-all `onFile` then the type-specific hook. Errors are\n * logged and swallowed so one bad hook can't break the run.\n */\n async runSandboxFile(\n ctx: ChatMiddlewareContext<TContext>,\n event: SandboxFileHookEvent,\n ): Promise<void> {\n const typed = (\n {\n create: 'onFileCreate',\n change: 'onFileChange',\n delete: 'onFileDelete',\n } as const\n )[event.type]\n for (const mw of this.middlewares) {\n const hooks = mw.sandbox\n if (!hooks) continue\n for (const fn of [hooks.onFile, hooks[typed]]) {\n if (!fn) continue\n try {\n await fn(ctx, event)\n } catch (error) {\n this.logger.sandbox(\n `hook=${typed} middleware=${mw.name ?? 'unnamed'} threw`,\n { middleware: mw.name ?? 'unnamed', error },\n )\n }\n }\n }\n }\n\n /**\n * Run onBeforeToolCall through middleware in order.\n * Returns the first non-void decision, or undefined to continue normally.\n */\n async runOnBeforeToolCall(\n ctx: ChatMiddlewareContext<TContext>,\n hookCtx: ToolCallHookContext,\n ): Promise<BeforeToolCallDecision> {\n for (const mw of this.middlewares) {\n if (mw.onBeforeToolCall) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n const decision = await mw.onBeforeToolCall(ctx, hookCtx)\n const hasTransform = decision !== undefined && decision !== null\n if (!skip) {\n this.logger.middleware(\n `hook=onBeforeToolCall middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onBeforeToolCall' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onBeforeToolCall',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform,\n })\n }\n if (hasTransform) {\n return decision\n }\n }\n }\n return undefined\n }\n\n /**\n * Run onAfterToolCall on all middleware in order.\n */\n async runOnAfterToolCall(\n ctx: ChatMiddlewareContext<TContext>,\n info: AfterToolCallInfo,\n ): Promise<void> {\n for (const mw of this.middlewares) {\n if (mw.onAfterToolCall) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n await mw.onAfterToolCall(ctx, info)\n if (!skip) {\n this.logger.middleware(\n `hook=onAfterToolCall middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onAfterToolCall' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onAfterToolCall',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: false,\n })\n }\n }\n }\n }\n\n /**\n * Run onUsage on all middleware in order.\n */\n async runOnUsage(\n ctx: ChatMiddlewareContext<TContext>,\n usage: UsageInfo,\n ): Promise<void> {\n for (const mw of this.middlewares) {\n if (mw.onUsage) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n await mw.onUsage(ctx, usage)\n if (!skip) {\n this.logger.middleware(\n `hook=onUsage middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onUsage' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onUsage',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: false,\n })\n }\n }\n }\n }\n\n /**\n * Run onFinish on all middleware in order.\n */\n async runOnFinish(\n ctx: ChatMiddlewareContext<TContext>,\n info: FinishInfo,\n ): Promise<void> {\n for (const mw of this.middlewares) {\n if (mw.onFinish) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n await mw.onFinish(ctx, info)\n if (!skip) {\n this.logger.middleware(\n `hook=onFinish middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onFinish' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onFinish',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: false,\n })\n }\n }\n }\n }\n\n /**\n * Run onAbort on all middleware in order.\n */\n async runOnAbort(\n ctx: ChatMiddlewareContext<TContext>,\n info: AbortInfo,\n ): Promise<void> {\n for (const mw of this.middlewares) {\n if (mw.onAbort) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n await mw.onAbort(ctx, info)\n if (!skip) {\n this.logger.middleware(\n `hook=onAbort middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onAbort' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onAbort',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: false,\n })\n }\n }\n }\n }\n\n /**\n * Run onError on all middleware in order.\n */\n async runOnError(\n ctx: ChatMiddlewareContext<TContext>,\n info: ErrorInfo,\n ): Promise<void> {\n for (const mw of this.middlewares) {\n if (mw.onError) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n await mw.onError(ctx, info)\n if (!skip) {\n this.logger.middleware(\n `hook=onError middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onError' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onError',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: false,\n })\n }\n }\n }\n }\n\n /**\n * Run onIteration on all middleware in order.\n * Called at the start of each agent loop iteration.\n */\n async runOnIteration(\n ctx: ChatMiddlewareContext<TContext>,\n info: IterationInfo,\n ): Promise<void> {\n for (const mw of this.middlewares) {\n if (mw.onIteration) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n await mw.onIteration(ctx, info)\n if (!skip) {\n this.logger.middleware(\n `hook=onIteration middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onIteration' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onIteration',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: false,\n })\n }\n }\n }\n }\n\n /**\n * Run onToolPhaseComplete on all middleware in order.\n * Called after all tool calls in an iteration have been processed.\n */\n async runOnToolPhaseComplete(\n ctx: ChatMiddlewareContext<TContext>,\n info: ToolPhaseCompleteInfo,\n ): Promise<void> {\n for (const mw of this.middlewares) {\n if (mw.onToolPhaseComplete) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n await mw.onToolPhaseComplete(ctx, info)\n if (!skip) {\n this.logger.middleware(\n `hook=onToolPhaseComplete middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onToolPhaseComplete' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onToolPhaseComplete',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: false,\n })\n }\n }\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"compose.js","names":[],"sources":["../../../../../src/activities/chat/middleware/compose.ts"],"sourcesContent":["import { aiEventClient } from '@tanstack/ai-event-client'\nimport type { AgentLoopState, StreamChunk } from '../../../types'\nimport type { InternalLogger } from '../../../logger/internal-logger'\nimport type {\n AbortInfo,\n AfterToolCallInfo,\n BeforeToolCallDecision,\n ChatMiddleware,\n ChatMiddlewareConfig,\n ChatMiddlewareContext,\n ErrorInfo,\n FinishInfo,\n IterationInfo,\n SandboxFileHookEvent,\n StructuredOutputMiddlewareConfig,\n ToolCallHookContext,\n ToolPhaseCompleteInfo,\n UsageInfo,\n} from './types'\n\n/** One middleware's terminal-hook throw, captured instead of propagated. */\ninterface HookFailure {\n middleware: string\n error: unknown\n}\n\n/** Check if a middleware should be skipped for instrumentation events. */\nfunction shouldSkipInstrumentation(mw: ChatMiddleware<any>): boolean {\n return mw.name === 'devtools' || mw.name === 'strip-to-spec'\n}\n\n/** Build the base context for middleware instrumentation events. */\nfunction instrumentCtx(ctx: ChatMiddlewareContext<any>) {\n return {\n requestId: ctx.requestId,\n streamId: ctx.streamId,\n clientId: ctx.threadId,\n timestamp: Date.now(),\n }\n}\n\n/**\n * Internal middleware runner that manages composed execution of middleware hooks.\n * Created once per chat() invocation.\n */\nexport class MiddlewareRunner<TContext = unknown> {\n private readonly middlewares: ReadonlyArray<ChatMiddleware<TContext>>\n private readonly logger: InternalLogger\n\n constructor(\n middlewares: ReadonlyArray<ChatMiddleware<TContext>>,\n logger: InternalLogger,\n ) {\n this.middlewares = middlewares\n this.logger = logger\n }\n\n get hasMiddleware(): boolean {\n return this.middlewares.length > 0\n }\n\n /**\n * Pipe config through all middleware onConfig hooks in order.\n * Each middleware receives the merged config from previous middleware.\n * Partial returns are shallow-merged with the current config.\n */\n async runOnConfig(\n ctx: ChatMiddlewareContext<TContext>,\n config: ChatMiddlewareConfig,\n ): Promise<ChatMiddlewareConfig> {\n let current = config\n for (const mw of this.middlewares) {\n if (mw.onConfig) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n const result = await mw.onConfig(ctx, current)\n const hasTransform = result !== undefined && result !== null\n if (hasTransform) {\n current = { ...current, ...result }\n if (!skip) {\n this.logger.config(\n `middleware=${mw.name ?? 'unnamed'} keys=${Object.keys(result).join(',')}`,\n {\n middleware: mw.name ?? 'unnamed',\n changes: result,\n },\n )\n }\n }\n if (!skip) {\n const base = instrumentCtx(ctx)\n aiEventClient.emit('middleware:hook:executed', {\n ...base,\n middlewareName: mw.name || 'unnamed',\n hookName: 'onConfig',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform,\n })\n if (hasTransform) {\n aiEventClient.emit('middleware:config:transformed', {\n ...base,\n middlewareName: mw.name || 'unnamed',\n iteration: ctx.iteration,\n changes: result,\n })\n }\n }\n }\n }\n return current\n }\n\n /**\n * Pipe config through all middleware onStructuredOutputConfig hooks in order.\n * Each middleware receives the merged config from previous middleware.\n * Partial returns are shallow-merged with the current config.\n *\n * Called once at the structured-output boundary, before runOnConfig at the\n * same boundary (which receives a ChatMiddlewareConfig view, no outputSchema).\n */\n async runOnStructuredOutputConfig(\n ctx: ChatMiddlewareContext<TContext>,\n config: StructuredOutputMiddlewareConfig,\n ): Promise<StructuredOutputMiddlewareConfig> {\n let current = config\n for (const mw of this.middlewares) {\n if (mw.onStructuredOutputConfig) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n const result = await mw.onStructuredOutputConfig(ctx, current)\n const hasTransform = result !== undefined && result !== null\n if (hasTransform) {\n current = { ...current, ...result }\n if (!skip) {\n this.logger.config(\n `middleware=${mw.name ?? 'unnamed'} keys=${Object.keys(result).join(',')}`,\n {\n middleware: mw.name ?? 'unnamed',\n changes: result,\n },\n )\n }\n }\n if (!skip) {\n const base = instrumentCtx(ctx)\n aiEventClient.emit('middleware:hook:executed', {\n ...base,\n middlewareName: mw.name || 'unnamed',\n hookName: 'onStructuredOutputConfig',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform,\n })\n if (hasTransform) {\n aiEventClient.emit('middleware:config:transformed', {\n ...base,\n middlewareName: mw.name || 'unnamed',\n iteration: ctx.iteration,\n // `result` is `Partial<StructuredOutputMiddlewareConfig>` —\n // Object.fromEntries(Object.entries(result)) yields the\n // structural `Record<string, unknown>` the event emitter wants\n // without an `as` cast.\n changes: Object.fromEntries(Object.entries(result)),\n })\n }\n }\n }\n }\n return current\n }\n\n /**\n * Run all `setup` hooks in array order, then assert every declared `provides`\n * capability was actually provided. Wires the last-wins duplicate-provide\n * warning into the registry. Runs before init `onConfig`.\n *\n * Takes the full `ChatMiddlewareContext` — the same stable context the engine\n * threads through every other hook — because it both forwards `ctx` to each\n * `setup` hook and emits instrumentation events from it.\n */\n async runSetup(ctx: ChatMiddlewareContext<TContext>): Promise<void> {\n ctx.capabilities.setOnDuplicate((name) => {\n this.logger.warn(\n `capability \"${name}\" was provided more than once; last provider wins`,\n { capability: name },\n )\n })\n\n for (const mw of this.middlewares) {\n if (mw.setup) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n await mw.setup(ctx)\n if (!skip) {\n this.logger.middleware(\n `hook=setup middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'setup' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'setup',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: false,\n })\n }\n }\n }\n\n for (const mw of this.middlewares) {\n for (const handle of mw.provides ?? []) {\n if (!ctx.capabilities.has(handle)) {\n throw new Error(\n `Middleware \"${mw.name ?? 'unnamed'}\" declares it provides ` +\n `\"${handle.capabilityName}\" but never called provide() in setup().`,\n )\n }\n }\n }\n }\n\n /**\n * Call onStart on all middleware in order.\n */\n async runOnStart(ctx: ChatMiddlewareContext<TContext>): Promise<void> {\n for (const mw of this.middlewares) {\n if (mw.onStart) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n await mw.onStart(ctx)\n if (!skip) {\n this.logger.middleware(\n `hook=onStart middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onStart' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onStart',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: false,\n })\n }\n }\n }\n }\n\n /**\n * Pipe a single chunk through all middleware onChunk hooks in order.\n * Returns the resulting chunks (0..N) to yield to the consumer.\n *\n * - void: pass through unchanged\n * - chunk: replace with this chunk\n * - chunk[]: expand to multiple chunks\n * - null: drop the chunk entirely\n */\n async runOnChunk(\n ctx: ChatMiddlewareContext<TContext>,\n chunk: StreamChunk,\n ): Promise<Array<StreamChunk>> {\n let chunks: Array<StreamChunk> = [chunk]\n\n for (const mw of this.middlewares) {\n if (!mw.onChunk) continue\n const skip = shouldSkipInstrumentation(mw)\n\n const nextChunks: Array<StreamChunk> = []\n for (const c of chunks) {\n // Cast: @ag-ui/core Zod passthrough types prevent direct `.type` access\n const chunkType = c.type\n if (!skip) {\n this.logger.middleware(\n `hook=onChunk middleware=${mw.name ?? 'unnamed'} in=${chunkType}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onChunk', in: c },\n )\n }\n const result = await mw.onChunk(ctx, c)\n if (result === null) {\n // Drop this chunk\n if (!skip) {\n this.logger.middleware(\n `hook=onChunk middleware=${mw.name ?? 'unnamed'} in=${chunkType} out=<dropped>`,\n {\n middleware: mw.name ?? 'unnamed',\n hook: 'onChunk',\n dropped: true,\n },\n )\n aiEventClient.emit('middleware:chunk:transformed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n originalChunkType: chunkType,\n resultCount: 0,\n wasDropped: true,\n })\n }\n continue\n } else if (result === undefined) {\n // Pass through — no instrumentation for pass-throughs\n nextChunks.push(c)\n } else if (Array.isArray(result)) {\n // Expand\n nextChunks.push(...result)\n if (!skip) {\n this.logger.middleware(\n `hook=onChunk middleware=${mw.name ?? 'unnamed'} in=${chunkType} out=[${result.map((r: StreamChunk) => r.type).join(',')}]`,\n {\n middleware: mw.name ?? 'unnamed',\n hook: 'onChunk',\n in: c,\n out: result,\n },\n )\n aiEventClient.emit('middleware:chunk:transformed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n originalChunkType: chunkType,\n resultCount: result.length,\n wasDropped: false,\n })\n }\n } else {\n // Replace\n nextChunks.push(result)\n if (!skip) {\n this.logger.middleware(\n `hook=onChunk middleware=${mw.name ?? 'unnamed'} in=${chunkType} out=${result.type}`,\n {\n middleware: mw.name ?? 'unnamed',\n hook: 'onChunk',\n in: c,\n out: result,\n },\n )\n aiEventClient.emit('middleware:chunk:transformed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n originalChunkType: chunkType,\n resultCount: 1,\n wasDropped: false,\n })\n }\n }\n }\n chunks = nextChunks\n }\n\n return chunks\n }\n\n /**\n * Dispatch a sandbox file event to every middleware's `sandbox` hooks, in\n * array order: the catch-all `onFile` then the type-specific hook. Errors are\n * logged and swallowed so one bad hook can't break the run.\n */\n async runSandboxFile(\n ctx: ChatMiddlewareContext<TContext>,\n event: SandboxFileHookEvent,\n ): Promise<void> {\n const typed = (\n {\n create: 'onFileCreate',\n change: 'onFileChange',\n delete: 'onFileDelete',\n } as const\n )[event.type]\n for (const mw of this.middlewares) {\n const hooks = mw.sandbox\n if (!hooks) continue\n for (const fn of [hooks.onFile, hooks[typed]]) {\n if (!fn) continue\n try {\n await fn(ctx, event)\n } catch (error) {\n this.logger.sandbox(\n `hook=${typed} middleware=${mw.name ?? 'unnamed'} threw`,\n { middleware: mw.name ?? 'unnamed', error },\n )\n }\n }\n }\n }\n\n /**\n * Run onBeforeToolCall through middleware in order.\n * Returns the first non-void decision, or undefined to continue normally.\n */\n async runOnBeforeToolCall(\n ctx: ChatMiddlewareContext<TContext>,\n hookCtx: ToolCallHookContext,\n ): Promise<BeforeToolCallDecision> {\n for (const mw of this.middlewares) {\n if (mw.onBeforeToolCall) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n const decision = await mw.onBeforeToolCall(ctx, hookCtx)\n const hasTransform = decision !== undefined && decision !== null\n if (!skip) {\n this.logger.middleware(\n `hook=onBeforeToolCall middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onBeforeToolCall' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onBeforeToolCall',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform,\n })\n }\n if (hasTransform) {\n return decision\n }\n }\n }\n return undefined\n }\n\n /**\n * Run onAfterToolCall on all middleware in order.\n */\n async runOnAfterToolCall(\n ctx: ChatMiddlewareContext<TContext>,\n info: AfterToolCallInfo,\n ): Promise<void> {\n for (const mw of this.middlewares) {\n if (mw.onAfterToolCall) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n await mw.onAfterToolCall(ctx, info)\n if (!skip) {\n this.logger.middleware(\n `hook=onAfterToolCall middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onAfterToolCall' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onAfterToolCall',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: false,\n })\n }\n }\n }\n }\n\n /**\n * Run onUsage on all middleware in order.\n */\n async runOnUsage(\n ctx: ChatMiddlewareContext<TContext>,\n usage: UsageInfo,\n ): Promise<void> {\n for (const mw of this.middlewares) {\n if (mw.onUsage) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n await mw.onUsage(ctx, usage)\n if (!skip) {\n this.logger.middleware(\n `hook=onUsage middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onUsage' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onUsage',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: false,\n })\n }\n }\n }\n }\n\n /**\n * Await ONE terminal hook and RETURN its throw instead of letting it escape\n * the caller's loop, logging it on the `errors` channel first so the failure\n * is never invisible. `undefined` means the hook completed.\n *\n * Capturing (rather than swallowing at this level) is what lets isolation and\n * reporting coexist: every caller gives every middleware its turn, and then\n * each decides on its own whether the collected failures are worth telling the\n * caller about. See {@link runOnFinish} vs {@link runOnAbort} /\n * {@link runOnError}.\n */\n private async captureTerminalHook(\n mw: ChatMiddleware<TContext>,\n hookName: 'onFinish' | 'onAbort' | 'onError',\n invoke: () => void | Promise<void>,\n ): Promise<HookFailure | undefined> {\n try {\n await invoke()\n return undefined\n } catch (error) {\n this.logger.errors(`middleware ${hookName} hook failed`, {\n middleware: mw.name ?? 'unnamed',\n hook: hookName,\n error,\n })\n return { middleware: mw.name ?? 'unnamed', error }\n }\n }\n\n /**\n * Run onFinish on all middleware in order.\n *\n * ISOLATED **and** REPORTED. `onFinish` is the only terminal fan-out on the\n * SUCCESS path, and it is where `withPersistence.onFinish` writes the\n * assistant turn through the store. So the two properties are needed together\n * and neither may be traded for the other:\n *\n * - ISOLATION: every middleware's hook runs even if an earlier one threw, so a\n * transient store error cannot skip a later middleware's own bookkeeping.\n * Each failure is captured by {@link captureTerminalHook}, not propagated\n * mid-loop.\n * - REPORTING: after the loop, the failures are rethrown. `chat()`'s catch\n * treats what we throw as a genuine error (it is not a\n * `MiddlewareAbortError`, and `structuralInterruptFailure` does not match\n * it) and rethrows it out of the generator.\n *\n * What that rethrow can and cannot achieve depends on the transport, because\n * this fan-out is awaited AFTER the adapter's `RUN_FINISHED` has already been\n * yielded (`chat()` yields terminal chunks while streaming, then awaits this\n * hook on its way out). The success terminal is therefore already gone; the\n * rethrow can only append to what the consumer saw, never retract it:\n *\n * - NON-DURABLE transport: the throw escapes the generator mid-response, and\n * the SSE / HTTP-stream encoder turns it into a TRAILING `RUN_ERROR` on the\n * wire carrying the store's own message and `code`. `ai-client` surfaces\n * that as an error status, so the user is not told the turn was saved when\n * it was not.\n * - DURABLE transport: the throw reaches the durability sink instead. The\n * terminal was already persisted AND forwarded, so the sink deliberately\n * does NOT append a second, contradictory terminal, and `terminalForwarded`\n * (see `stream-to-response.ts`) suppresses the rethrow to the live consumer.\n * The `RUN_FINISHED` stands and the failure is RECORDED SERVER-SIDE on the\n * sink's `errors` channel. That is the intended outcome, not a gap: the save\n * failed, not the run — the consumer did receive the complete stream, so\n * telling it the run errored would be the lie. What the rethrow buys here is\n * that the sink sees the failure at all; while this loop swallowed, the only\n * trace anywhere was {@link captureTerminalHook}'s log line.\n *\n * Either way, swallowing is the one option ruled out: a failed\n * `messages.append` would otherwise leave a `completed` run record with the\n * assistant turn missing from storage and nothing beyond a middleware log\n * line, and the client would go on to send a history the server has no record\n * of.\n *\n * A single failure is rethrown AS-IS so the store's own error — its message,\n * `cause`, `code` and `instanceof` identity — is what reaches the caller and\n * the wire; wrapping the common case would bury it. Two or more become an\n * `AggregateError` (never a `MiddlewareAbortError`, so it cannot be mistaken\n * for an abort) rather than picking a winner and dropping the rest.\n */\n async runOnFinish(\n ctx: ChatMiddlewareContext<TContext>,\n info: FinishInfo,\n ): Promise<void> {\n const failures: Array<HookFailure> = []\n let firstFailure: HookFailure | undefined\n\n for (const mw of this.middlewares) {\n const hook = mw.onFinish\n if (hook) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n const failure = await this.captureTerminalHook(mw, 'onFinish', () =>\n hook.call(mw, ctx, info),\n )\n if (failure !== undefined) {\n firstFailure ??= failure\n failures.push(failure)\n continue\n }\n if (!skip) {\n this.logger.middleware(\n `hook=onFinish middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onFinish' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onFinish',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: false,\n })\n }\n }\n }\n\n if (firstFailure !== undefined) {\n throw failures.length === 1\n ? firstFailure.error\n : new AggregateError(\n failures.map((f) => f.error),\n `${failures.length} middleware onFinish hooks failed: ` +\n failures.map((f) => f.middleware).join(', '),\n )\n }\n }\n\n /**\n * Run onAbort on all middleware in order.\n *\n * ISOLATED and DELIBERATELY SWALLOWED. `onAbort` is a pure teardown fan-out\n * released from `chat()`'s `finally`, on a path where the outcome is already\n * decided: the run stopped, and the caller is being told why. A throw here has\n * nothing better to report than the abort reason it would DISPLACE — the\n * `finally` would surface a flaky store's error in place of \"client\n * disconnected\" — so failures are logged on the `errors` channel and go no\n * further. That is not a silent failure; it is refusing to let teardown\n * rewrite an outcome it did not produce.\n *\n * Isolation matters independently: these hooks release PER-MIDDLEWARE\n * resources (`withSandbox.onAbort` detaches or destroys the sandbox and stamps\n * `detachedSince`; `withPersistence.onAbort` records the run status through the\n * store), so an unguarded loop turns one transient store error into a\n * permanently leaked sandbox for every middleware ordered after it.\n */\n async runOnAbort(\n ctx: ChatMiddlewareContext<TContext>,\n info: AbortInfo,\n ): Promise<void> {\n for (const mw of this.middlewares) {\n const hook = mw.onAbort\n if (hook) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n const failure = await this.captureTerminalHook(mw, 'onAbort', () =>\n hook.call(mw, ctx, info),\n )\n if (failure === undefined && !skip) {\n this.logger.middleware(\n `hook=onAbort middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onAbort' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onAbort',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: false,\n })\n }\n }\n }\n }\n\n /**\n * Run onError on all middleware in order.\n *\n * ISOLATED and DELIBERATELY SWALLOWED, for the same reason as\n * {@link runOnAbort} and NOT merely because it is teardown: the run has\n * already failed, `info.error` IS that failure, and `chat()` rethrows it to the\n * caller the moment this fan-out returns. A propagated hook throw could only\n * REPLACE the run's real error with a teardown artifact — strictly less\n * information for the caller, who is already learning the run failed. Reporting\n * would buy nothing and cost the diagnosis, so failures are logged on the\n * `errors` channel and stop there.\n *\n * Contrast {@link runOnFinish}, where nothing else is telling the caller\n * anything is wrong — which is why that one reports.\n */\n async runOnError(\n ctx: ChatMiddlewareContext<TContext>,\n info: ErrorInfo,\n ): Promise<void> {\n for (const mw of this.middlewares) {\n const hook = mw.onError\n if (hook) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n const failure = await this.captureTerminalHook(mw, 'onError', () =>\n hook.call(mw, ctx, info),\n )\n if (failure === undefined && !skip) {\n this.logger.middleware(\n `hook=onError middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onError' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onError',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: false,\n })\n }\n }\n }\n }\n\n /**\n * Run onIteration on all middleware in order.\n * Called at the start of each agent loop iteration.\n */\n async runOnIteration(\n ctx: ChatMiddlewareContext<TContext>,\n info: IterationInfo,\n ): Promise<void> {\n for (const mw of this.middlewares) {\n if (mw.onIteration) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n await mw.onIteration(ctx, info)\n if (!skip) {\n this.logger.middleware(\n `hook=onIteration middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onIteration' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onIteration',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: false,\n })\n }\n }\n }\n }\n\n /**\n * Run onShouldContinue through middleware in order (AND semantics).\n * Any explicit `false` stops further iterations; `true` / void / undefined pass.\n * Called after `agentLoopStrategy` has already approved continuation.\n */\n async runOnShouldContinue(\n ctx: ChatMiddlewareContext<TContext>,\n state: AgentLoopState,\n ): Promise<boolean> {\n for (const mw of this.middlewares) {\n if (mw.onShouldContinue) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n const result = await mw.onShouldContinue(ctx, state)\n if (!skip) {\n this.logger.middleware(\n `hook=onShouldContinue middleware=${mw.name ?? 'unnamed'}`,\n {\n middleware: mw.name ?? 'unnamed',\n hook: 'onShouldContinue',\n result,\n },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onShouldContinue',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: result === false,\n })\n }\n if (result === false) {\n return false\n }\n }\n }\n return true\n }\n\n /**\n * Run onToolPhaseComplete on all middleware in order.\n * Called after all tool calls in an iteration have been processed.\n */\n async runOnToolPhaseComplete(\n ctx: ChatMiddlewareContext<TContext>,\n info: ToolPhaseCompleteInfo,\n ): Promise<void> {\n for (const mw of this.middlewares) {\n if (mw.onToolPhaseComplete) {\n const skip = shouldSkipInstrumentation(mw)\n const start = Date.now()\n await mw.onToolPhaseComplete(ctx, info)\n if (!skip) {\n this.logger.middleware(\n `hook=onToolPhaseComplete middleware=${mw.name ?? 'unnamed'}`,\n { middleware: mw.name ?? 'unnamed', hook: 'onToolPhaseComplete' },\n )\n aiEventClient.emit('middleware:hook:executed', {\n ...instrumentCtx(ctx),\n middlewareName: mw.name || 'unnamed',\n hookName: 'onToolPhaseComplete',\n iteration: ctx.iteration,\n duration: Date.now() - start,\n hasTransform: false,\n })\n }\n }\n }\n }\n}\n"],"mappings":";;;AA2BA,SAAS,0BAA0B,IAAkC;CACnE,OAAO,GAAG,SAAS,cAAc,GAAG,SAAS;AAC/C;;AAGA,SAAS,cAAc,KAAiC;CACtD,OAAO;EACL,WAAW,IAAI;EACf,UAAU,IAAI;EACd,UAAU,IAAI;EACd,WAAW,KAAK,IAAI;CACtB;AACF;;;;;AAMA,IAAa,mBAAb,MAAkD;CAChD;CACA;CAEA,YACE,aACA,QACA;EACA,KAAK,cAAc;EACnB,KAAK,SAAS;CAChB;CAEA,IAAI,gBAAyB;EAC3B,OAAO,KAAK,YAAY,SAAS;CACnC;;;;;;CAOA,MAAM,YACJ,KACA,QAC+B;EAC/B,IAAI,UAAU;EACd,KAAK,MAAM,MAAM,KAAK,aACpB,IAAI,GAAG,UAAU;GACf,MAAM,OAAO,0BAA0B,EAAE;GACzC,MAAM,QAAQ,KAAK,IAAI;GACvB,MAAM,SAAS,MAAM,GAAG,SAAS,KAAK,OAAO;GAC7C,MAAM,eAAe,WAAW,KAAA,KAAa,WAAW;GACxD,IAAI,cAAc;IAChB,UAAU;KAAE,GAAG;KAAS,GAAG;IAAO;IAClC,IAAI,CAAC,MACH,KAAK,OAAO,OACV,cAAc,GAAG,QAAQ,UAAU,QAAQ,OAAO,KAAK,MAAM,CAAC,CAAC,KAAK,GAAG,KACvE;KACE,YAAY,GAAG,QAAQ;KACvB,SAAS;IACX,CACF;GAEJ;GACA,IAAI,CAAC,MAAM;IACT,MAAM,OAAO,cAAc,GAAG;IAC9B,cAAc,KAAK,4BAA4B;KAC7C,GAAG;KACH,gBAAgB,GAAG,QAAQ;KAC3B,UAAU;KACV,WAAW,IAAI;KACf,UAAU,KAAK,IAAI,IAAI;KACvB;IACF,CAAC;IACD,IAAI,cACF,cAAc,KAAK,iCAAiC;KAClD,GAAG;KACH,gBAAgB,GAAG,QAAQ;KAC3B,WAAW,IAAI;KACf,SAAS;IACX,CAAC;GAEL;EACF;EAEF,OAAO;CACT;;;;;;;;;CAUA,MAAM,4BACJ,KACA,QAC2C;EAC3C,IAAI,UAAU;EACd,KAAK,MAAM,MAAM,KAAK,aACpB,IAAI,GAAG,0BAA0B;GAC/B,MAAM,OAAO,0BAA0B,EAAE;GACzC,MAAM,QAAQ,KAAK,IAAI;GACvB,MAAM,SAAS,MAAM,GAAG,yBAAyB,KAAK,OAAO;GAC7D,MAAM,eAAe,WAAW,KAAA,KAAa,WAAW;GACxD,IAAI,cAAc;IAChB,UAAU;KAAE,GAAG;KAAS,GAAG;IAAO;IAClC,IAAI,CAAC,MACH,KAAK,OAAO,OACV,cAAc,GAAG,QAAQ,UAAU,QAAQ,OAAO,KAAK,MAAM,CAAC,CAAC,KAAK,GAAG,KACvE;KACE,YAAY,GAAG,QAAQ;KACvB,SAAS;IACX,CACF;GAEJ;GACA,IAAI,CAAC,MAAM;IACT,MAAM,OAAO,cAAc,GAAG;IAC9B,cAAc,KAAK,4BAA4B;KAC7C,GAAG;KACH,gBAAgB,GAAG,QAAQ;KAC3B,UAAU;KACV,WAAW,IAAI;KACf,UAAU,KAAK,IAAI,IAAI;KACvB;IACF,CAAC;IACD,IAAI,cACF,cAAc,KAAK,iCAAiC;KAClD,GAAG;KACH,gBAAgB,GAAG,QAAQ;KAC3B,WAAW,IAAI;KAKf,SAAS,OAAO,YAAY,OAAO,QAAQ,MAAM,CAAC;IACpD,CAAC;GAEL;EACF;EAEF,OAAO;CACT;;;;;;;;;;CAWA,MAAM,SAAS,KAAqD;EAClE,IAAI,aAAa,gBAAgB,SAAS;GACxC,KAAK,OAAO,KACV,eAAe,KAAK,oDACpB,EAAE,YAAY,KAAK,CACrB;EACF,CAAC;EAED,KAAK,MAAM,MAAM,KAAK,aACpB,IAAI,GAAG,OAAO;GACZ,MAAM,OAAO,0BAA0B,EAAE;GACzC,MAAM,QAAQ,KAAK,IAAI;GACvB,MAAM,GAAG,MAAM,GAAG;GAClB,IAAI,CAAC,MAAM;IACT,KAAK,OAAO,WACV,yBAAyB,GAAG,QAAQ,aACpC;KAAE,YAAY,GAAG,QAAQ;KAAW,MAAM;IAAQ,CACpD;IACA,cAAc,KAAK,4BAA4B;KAC7C,GAAG,cAAc,GAAG;KACpB,gBAAgB,GAAG,QAAQ;KAC3B,UAAU;KACV,WAAW,IAAI;KACf,UAAU,KAAK,IAAI,IAAI;KACvB,cAAc;IAChB,CAAC;GACH;EACF;EAGF,KAAK,MAAM,MAAM,KAAK,aACpB,KAAK,MAAM,UAAU,GAAG,YAAY,CAAC,GACnC,IAAI,CAAC,IAAI,aAAa,IAAI,MAAM,GAC9B,MAAM,IAAI,MACR,eAAe,GAAG,QAAQ,UAAU,0BAC9B,OAAO,eAAe,yCAC9B;CAIR;;;;CAKA,MAAM,WAAW,KAAqD;EACpE,KAAK,MAAM,MAAM,KAAK,aACpB,IAAI,GAAG,SAAS;GACd,MAAM,OAAO,0BAA0B,EAAE;GACzC,MAAM,QAAQ,KAAK,IAAI;GACvB,MAAM,GAAG,QAAQ,GAAG;GACpB,IAAI,CAAC,MAAM;IACT,KAAK,OAAO,WACV,2BAA2B,GAAG,QAAQ,aACtC;KAAE,YAAY,GAAG,QAAQ;KAAW,MAAM;IAAU,CACtD;IACA,cAAc,KAAK,4BAA4B;KAC7C,GAAG,cAAc,GAAG;KACpB,gBAAgB,GAAG,QAAQ;KAC3B,UAAU;KACV,WAAW,IAAI;KACf,UAAU,KAAK,IAAI,IAAI;KACvB,cAAc;IAChB,CAAC;GACH;EACF;CAEJ;;;;;;;;;;CAWA,MAAM,WACJ,KACA,OAC6B;EAC7B,IAAI,SAA6B,CAAC,KAAK;EAEvC,KAAK,MAAM,MAAM,KAAK,aAAa;GACjC,IAAI,CAAC,GAAG,SAAS;GACjB,MAAM,OAAO,0BAA0B,EAAE;GAEzC,MAAM,aAAiC,CAAC;GACxC,KAAK,MAAM,KAAK,QAAQ;IAEtB,MAAM,YAAY,EAAE;IACpB,IAAI,CAAC,MACH,KAAK,OAAO,WACV,2BAA2B,GAAG,QAAQ,UAAU,MAAM,aACtD;KAAE,YAAY,GAAG,QAAQ;KAAW,MAAM;KAAW,IAAI;IAAE,CAC7D;IAEF,MAAM,SAAS,MAAM,GAAG,QAAQ,KAAK,CAAC;IACtC,IAAI,WAAW,MAAM;KAEnB,IAAI,CAAC,MAAM;MACT,KAAK,OAAO,WACV,2BAA2B,GAAG,QAAQ,UAAU,MAAM,UAAU,iBAChE;OACE,YAAY,GAAG,QAAQ;OACvB,MAAM;OACN,SAAS;MACX,CACF;MACA,cAAc,KAAK,gCAAgC;OACjD,GAAG,cAAc,GAAG;OACpB,gBAAgB,GAAG,QAAQ;OAC3B,mBAAmB;OACnB,aAAa;OACb,YAAY;MACd,CAAC;KACH;KACA;IACF,OAAO,IAAI,WAAW,KAAA,GAEpB,WAAW,KAAK,CAAC;SACZ,IAAI,MAAM,QAAQ,MAAM,GAAG;KAEhC,WAAW,KAAK,GAAG,MAAM;KACzB,IAAI,CAAC,MAAM;MACT,KAAK,OAAO,WACV,2BAA2B,GAAG,QAAQ,UAAU,MAAM,UAAU,QAAQ,OAAO,KAAK,MAAmB,EAAE,IAAI,CAAC,CAAC,KAAK,GAAG,EAAE,IACzH;OACE,YAAY,GAAG,QAAQ;OACvB,MAAM;OACN,IAAI;OACJ,KAAK;MACP,CACF;MACA,cAAc,KAAK,gCAAgC;OACjD,GAAG,cAAc,GAAG;OACpB,gBAAgB,GAAG,QAAQ;OAC3B,mBAAmB;OACnB,aAAa,OAAO;OACpB,YAAY;MACd,CAAC;KACH;IACF,OAAO;KAEL,WAAW,KAAK,MAAM;KACtB,IAAI,CAAC,MAAM;MACT,KAAK,OAAO,WACV,2BAA2B,GAAG,QAAQ,UAAU,MAAM,UAAU,OAAO,OAAO,QAC9E;OACE,YAAY,GAAG,QAAQ;OACvB,MAAM;OACN,IAAI;OACJ,KAAK;MACP,CACF;MACA,cAAc,KAAK,gCAAgC;OACjD,GAAG,cAAc,GAAG;OACpB,gBAAgB,GAAG,QAAQ;OAC3B,mBAAmB;OACnB,aAAa;OACb,YAAY;MACd,CAAC;KACH;IACF;GACF;GACA,SAAS;EACX;EAEA,OAAO;CACT;;;;;;CAOA,MAAM,eACJ,KACA,OACe;EACf,MAAM,QACJ;GACE,QAAQ;GACR,QAAQ;GACR,QAAQ;EACV,EACA,MAAM;EACR,KAAK,MAAM,MAAM,KAAK,aAAa;GACjC,MAAM,QAAQ,GAAG;GACjB,IAAI,CAAC,OAAO;GACZ,KAAK,MAAM,MAAM,CAAC,MAAM,QAAQ,MAAM,MAAM,GAAG;IAC7C,IAAI,CAAC,IAAI;IACT,IAAI;KACF,MAAM,GAAG,KAAK,KAAK;IACrB,SAAS,OAAO;KACd,KAAK,OAAO,QACV,QAAQ,MAAM,cAAc,GAAG,QAAQ,UAAU,SACjD;MAAE,YAAY,GAAG,QAAQ;MAAW;KAAM,CAC5C;IACF;GACF;EACF;CACF;;;;;CAMA,MAAM,oBACJ,KACA,SACiC;EACjC,KAAK,MAAM,MAAM,KAAK,aACpB,IAAI,GAAG,kBAAkB;GACvB,MAAM,OAAO,0BAA0B,EAAE;GACzC,MAAM,QAAQ,KAAK,IAAI;GACvB,MAAM,WAAW,MAAM,GAAG,iBAAiB,KAAK,OAAO;GACvD,MAAM,eAAe,aAAa,KAAA,KAAa,aAAa;GAC5D,IAAI,CAAC,MAAM;IACT,KAAK,OAAO,WACV,oCAAoC,GAAG,QAAQ,aAC/C;KAAE,YAAY,GAAG,QAAQ;KAAW,MAAM;IAAmB,CAC/D;IACA,cAAc,KAAK,4BAA4B;KAC7C,GAAG,cAAc,GAAG;KACpB,gBAAgB,GAAG,QAAQ;KAC3B,UAAU;KACV,WAAW,IAAI;KACf,UAAU,KAAK,IAAI,IAAI;KACvB;IACF,CAAC;GACH;GACA,IAAI,cACF,OAAO;EAEX;CAGJ;;;;CAKA,MAAM,mBACJ,KACA,MACe;EACf,KAAK,MAAM,MAAM,KAAK,aACpB,IAAI,GAAG,iBAAiB;GACtB,MAAM,OAAO,0BAA0B,EAAE;GACzC,MAAM,QAAQ,KAAK,IAAI;GACvB,MAAM,GAAG,gBAAgB,KAAK,IAAI;GAClC,IAAI,CAAC,MAAM;IACT,KAAK,OAAO,WACV,mCAAmC,GAAG,QAAQ,aAC9C;KAAE,YAAY,GAAG,QAAQ;KAAW,MAAM;IAAkB,CAC9D;IACA,cAAc,KAAK,4BAA4B;KAC7C,GAAG,cAAc,GAAG;KACpB,gBAAgB,GAAG,QAAQ;KAC3B,UAAU;KACV,WAAW,IAAI;KACf,UAAU,KAAK,IAAI,IAAI;KACvB,cAAc;IAChB,CAAC;GACH;EACF;CAEJ;;;;CAKA,MAAM,WACJ,KACA,OACe;EACf,KAAK,MAAM,MAAM,KAAK,aACpB,IAAI,GAAG,SAAS;GACd,MAAM,OAAO,0BAA0B,EAAE;GACzC,MAAM,QAAQ,KAAK,IAAI;GACvB,MAAM,GAAG,QAAQ,KAAK,KAAK;GAC3B,IAAI,CAAC,MAAM;IACT,KAAK,OAAO,WACV,2BAA2B,GAAG,QAAQ,aACtC;KAAE,YAAY,GAAG,QAAQ;KAAW,MAAM;IAAU,CACtD;IACA,cAAc,KAAK,4BAA4B;KAC7C,GAAG,cAAc,GAAG;KACpB,gBAAgB,GAAG,QAAQ;KAC3B,UAAU;KACV,WAAW,IAAI;KACf,UAAU,KAAK,IAAI,IAAI;KACvB,cAAc;IAChB,CAAC;GACH;EACF;CAEJ;;;;;;;;;;;;CAaA,MAAc,oBACZ,IACA,UACA,QACkC;EAClC,IAAI;GACF,MAAM,OAAO;GACb;EACF,SAAS,OAAO;GACd,KAAK,OAAO,OAAO,cAAc,SAAS,eAAe;IACvD,YAAY,GAAG,QAAQ;IACvB,MAAM;IACN;GACF,CAAC;GACD,OAAO;IAAE,YAAY,GAAG,QAAQ;IAAW;GAAM;EACnD;CACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqDA,MAAM,YACJ,KACA,MACe;EACf,MAAM,WAA+B,CAAC;EACtC,IAAI;EAEJ,KAAK,MAAM,MAAM,KAAK,aAAa;GACjC,MAAM,OAAO,GAAG;GAChB,IAAI,MAAM;IACR,MAAM,OAAO,0BAA0B,EAAE;IACzC,MAAM,QAAQ,KAAK,IAAI;IACvB,MAAM,UAAU,MAAM,KAAK,oBAAoB,IAAI,kBACjD,KAAK,KAAK,IAAI,KAAK,IAAI,CACzB;IACA,IAAI,YAAY,KAAA,GAAW;KACzB,iBAAiB;KACjB,SAAS,KAAK,OAAO;KACrB;IACF;IACA,IAAI,CAAC,MAAM;KACT,KAAK,OAAO,WACV,4BAA4B,GAAG,QAAQ,aACvC;MAAE,YAAY,GAAG,QAAQ;MAAW,MAAM;KAAW,CACvD;KACA,cAAc,KAAK,4BAA4B;MAC7C,GAAG,cAAc,GAAG;MACpB,gBAAgB,GAAG,QAAQ;MAC3B,UAAU;MACV,WAAW,IAAI;MACf,UAAU,KAAK,IAAI,IAAI;MACvB,cAAc;KAChB,CAAC;IACH;GACF;EACF;EAEA,IAAI,iBAAiB,KAAA,GACnB,MAAM,SAAS,WAAW,IACtB,aAAa,QACb,IAAI,eACF,SAAS,KAAK,MAAM,EAAE,KAAK,GAC3B,GAAG,SAAS,OAAO,uCACjB,SAAS,KAAK,MAAM,EAAE,UAAU,CAAC,CAAC,KAAK,IAAI,CAC/C;CAER;;;;;;;;;;;;;;;;;;;CAoBA,MAAM,WACJ,KACA,MACe;EACf,KAAK,MAAM,MAAM,KAAK,aAAa;GACjC,MAAM,OAAO,GAAG;GAChB,IAAI,MAAM;IACR,MAAM,OAAO,0BAA0B,EAAE;IACzC,MAAM,QAAQ,KAAK,IAAI;IAIvB,IAAI,MAHkB,KAAK,oBAAoB,IAAI,iBACjD,KAAK,KAAK,IAAI,KAAK,IAAI,CACzB,MACgB,KAAA,KAAa,CAAC,MAAM;KAClC,KAAK,OAAO,WACV,2BAA2B,GAAG,QAAQ,aACtC;MAAE,YAAY,GAAG,QAAQ;MAAW,MAAM;KAAU,CACtD;KACA,cAAc,KAAK,4BAA4B;MAC7C,GAAG,cAAc,GAAG;MACpB,gBAAgB,GAAG,QAAQ;MAC3B,UAAU;MACV,WAAW,IAAI;MACf,UAAU,KAAK,IAAI,IAAI;MACvB,cAAc;KAChB,CAAC;IACH;GACF;EACF;CACF;;;;;;;;;;;;;;;;CAiBA,MAAM,WACJ,KACA,MACe;EACf,KAAK,MAAM,MAAM,KAAK,aAAa;GACjC,MAAM,OAAO,GAAG;GAChB,IAAI,MAAM;IACR,MAAM,OAAO,0BAA0B,EAAE;IACzC,MAAM,QAAQ,KAAK,IAAI;IAIvB,IAAI,MAHkB,KAAK,oBAAoB,IAAI,iBACjD,KAAK,KAAK,IAAI,KAAK,IAAI,CACzB,MACgB,KAAA,KAAa,CAAC,MAAM;KAClC,KAAK,OAAO,WACV,2BAA2B,GAAG,QAAQ,aACtC;MAAE,YAAY,GAAG,QAAQ;MAAW,MAAM;KAAU,CACtD;KACA,cAAc,KAAK,4BAA4B;MAC7C,GAAG,cAAc,GAAG;MACpB,gBAAgB,GAAG,QAAQ;MAC3B,UAAU;MACV,WAAW,IAAI;MACf,UAAU,KAAK,IAAI,IAAI;MACvB,cAAc;KAChB,CAAC;IACH;GACF;EACF;CACF;;;;;CAMA,MAAM,eACJ,KACA,MACe;EACf,KAAK,MAAM,MAAM,KAAK,aACpB,IAAI,GAAG,aAAa;GAClB,MAAM,OAAO,0BAA0B,EAAE;GACzC,MAAM,QAAQ,KAAK,IAAI;GACvB,MAAM,GAAG,YAAY,KAAK,IAAI;GAC9B,IAAI,CAAC,MAAM;IACT,KAAK,OAAO,WACV,+BAA+B,GAAG,QAAQ,aAC1C;KAAE,YAAY,GAAG,QAAQ;KAAW,MAAM;IAAc,CAC1D;IACA,cAAc,KAAK,4BAA4B;KAC7C,GAAG,cAAc,GAAG;KACpB,gBAAgB,GAAG,QAAQ;KAC3B,UAAU;KACV,WAAW,IAAI;KACf,UAAU,KAAK,IAAI,IAAI;KACvB,cAAc;IAChB,CAAC;GACH;EACF;CAEJ;;;;;;CAOA,MAAM,oBACJ,KACA,OACkB;EAClB,KAAK,MAAM,MAAM,KAAK,aACpB,IAAI,GAAG,kBAAkB;GACvB,MAAM,OAAO,0BAA0B,EAAE;GACzC,MAAM,QAAQ,KAAK,IAAI;GACvB,MAAM,SAAS,MAAM,GAAG,iBAAiB,KAAK,KAAK;GACnD,IAAI,CAAC,MAAM;IACT,KAAK,OAAO,WACV,oCAAoC,GAAG,QAAQ,aAC/C;KACE,YAAY,GAAG,QAAQ;KACvB,MAAM;KACN;IACF,CACF;IACA,cAAc,KAAK,4BAA4B;KAC7C,GAAG,cAAc,GAAG;KACpB,gBAAgB,GAAG,QAAQ;KAC3B,UAAU;KACV,WAAW,IAAI;KACf,UAAU,KAAK,IAAI,IAAI;KACvB,cAAc,WAAW;IAC3B,CAAC;GACH;GACA,IAAI,WAAW,OACb,OAAO;EAEX;EAEF,OAAO;CACT;;;;;CAMA,MAAM,uBACJ,KACA,MACe;EACf,KAAK,MAAM,MAAM,KAAK,aACpB,IAAI,GAAG,qBAAqB;GAC1B,MAAM,OAAO,0BAA0B,EAAE;GACzC,MAAM,QAAQ,KAAK,IAAI;GACvB,MAAM,GAAG,oBAAoB,KAAK,IAAI;GACtC,IAAI,CAAC,MAAM;IACT,KAAK,OAAO,WACV,uCAAuC,GAAG,QAAQ,aAClD;KAAE,YAAY,GAAG,QAAQ;KAAW,MAAM;IAAsB,CAClE;IACA,cAAc,KAAK,4BAA4B;KAC7C,GAAG,cAAc,GAAG;KACpB,gBAAgB,GAAG,QAAQ;KAC3B,UAAU;KACV,WAAW,IAAI;KACf,UAAU,KAAK,IAAI,IAAI;KACvB,cAAc;IAChB,CAAC;GACH;EACF;CAEJ;AACF"}
|
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
//#region src/activities/chat/middleware/define.ts
|
|
2
|
+
/**
|
|
3
|
+
* Identity helper for authoring middleware with precise capability inference.
|
|
4
|
+
* Returns the middleware unchanged at runtime; only sharpens its type so the
|
|
5
|
+
* `chat()` array coverage check and `createChatMiddleware` builder can read the
|
|
6
|
+
* exact `requires`/`provides`.
|
|
7
|
+
*/
|
|
1
8
|
function defineChatMiddleware(middleware) {
|
|
2
|
-
|
|
9
|
+
return middleware;
|
|
3
10
|
}
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
//# sourceMappingURL=define.js.map
|
|
11
|
+
//#endregion
|
|
12
|
+
export { defineChatMiddleware };
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=define.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define.js","sources":["../../../../../src/activities/chat/middleware/define.ts"],"sourcesContent":["import type { CapabilityHandle } from './capabilities'\nimport type { ChatMiddleware } from './types'\n\n/**\n * A middleware whose `requires`/`provides` tuple types are captured precisely\n * (via `const` inference) for the array coverage check and the builder.\n */\nexport interface DefinedChatMiddleware<\n TContext,\n TRequires extends ReadonlyArray<CapabilityHandle>,\n TProvides extends ReadonlyArray<CapabilityHandle>,\n> extends ChatMiddleware<TContext> {\n requires?: TRequires\n provides?: TProvides\n}\n\n/**\n * Identity helper for authoring middleware with precise capability inference.\n * Returns the middleware unchanged at runtime; only sharpens its type so the\n * `chat()` array coverage check and `createChatMiddleware` builder can read the\n * exact `requires`/`provides`.\n */\nexport function defineChatMiddleware<\n TContext = unknown,\n const TRequires extends ReadonlyArray<CapabilityHandle> = readonly [],\n const TProvides extends ReadonlyArray<CapabilityHandle> = readonly [],\n>(\n middleware: ChatMiddleware<TContext> & {\n requires?: TRequires\n provides?: TProvides\n },\n): DefinedChatMiddleware<TContext, TRequires, TProvides> {\n return middleware\n}\n"],"
|
|
1
|
+
{"version":3,"file":"define.js","names":[],"sources":["../../../../../src/activities/chat/middleware/define.ts"],"sourcesContent":["import type { CapabilityHandle } from './capabilities'\nimport type { ChatMiddleware } from './types'\n\n/**\n * A middleware whose `requires`/`provides` tuple types are captured precisely\n * (via `const` inference) for the array coverage check and the builder.\n */\nexport interface DefinedChatMiddleware<\n TContext,\n TRequires extends ReadonlyArray<CapabilityHandle>,\n TProvides extends ReadonlyArray<CapabilityHandle>,\n> extends ChatMiddleware<TContext> {\n requires?: TRequires\n provides?: TProvides\n}\n\n/**\n * Identity helper for authoring middleware with precise capability inference.\n * Returns the middleware unchanged at runtime; only sharpens its type so the\n * `chat()` array coverage check and `createChatMiddleware` builder can read the\n * exact `requires`/`provides`.\n */\nexport function defineChatMiddleware<\n TContext = unknown,\n const TRequires extends ReadonlyArray<CapabilityHandle> = readonly [],\n const TProvides extends ReadonlyArray<CapabilityHandle> = readonly [],\n>(\n middleware: ChatMiddleware<TContext> & {\n requires?: TRequires\n provides?: TProvides\n },\n): DefinedChatMiddleware<TContext, TRequires, TProvides> {\n return middleware\n}\n"],"mappings":";;;;;;;AAsBA,SAAgB,qBAKd,YAIuD;CACvD,OAAO;AACT"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { ChatMiddleware, ChatMiddlewareContext, ChatMiddlewarePhase, ChatMiddlewareConfig, StructuredOutputMiddlewareConfig, ToolCallHookContext, BeforeToolCallDecision, AfterToolCallInfo, IterationInfo, ToolPhaseCompleteInfo, UsageInfo, FinishInfo, AbortInfo, ErrorInfo, SandboxFileEvent, SandboxFileHookEvent, ChatSandboxHooks, } from './types.js';
|
|
1
|
+
export type { ChatMiddleware, ChatMiddlewareContext, ChatMiddlewarePhase, ChatMiddlewareConfig, ChatResumeToolState, ChatResumeGenericResolution, StructuredOutputMiddlewareConfig, ToolCallHookContext, BeforeToolCallDecision, AfterToolCallInfo, IterationInfo, ToolPhaseCompleteInfo, UsageInfo, FinishInfo, AbortInfo, ErrorInfo, SandboxFileEvent, SandboxFileHookEvent, ChatSandboxHooks, } from './types.js';
|
|
2
2
|
export { MiddlewareRunner } from './compose.js';
|
|
3
3
|
export { createCapability, CapabilityRegistry } from './capabilities.js';
|
|
4
4
|
export type { Capability, CapabilityHandle, CapabilityContext, CapabilityGetter, CapabilityProvider, CapabilityGetOptions, } from './capabilities.js';
|
|
@@ -8,3 +8,7 @@ export { createChatMiddleware } from './builder.js';
|
|
|
8
8
|
export type { ChatMiddlewareBuilder, MissingCapabilities, NamesOf, } from './builder.js';
|
|
9
9
|
export { validateCapabilities } from './validate.js';
|
|
10
10
|
export type { AnyChatMiddleware } from './types.js';
|
|
11
|
+
export { LocksCapability, getLocks, provideLocks, InMemoryLockStore, withLocks, defineLock, } from './locks.js';
|
|
12
|
+
export type { LockStore } from './locks.js';
|
|
13
|
+
export { isRunStatus, isTerminalRunStatus, defineRunStore, InMemoryRunStore, } from './run-store.js';
|
|
14
|
+
export type { RunStatus, TerminalRunStatus, RunRecord, RunError, RunStore, } from './run-store.js';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { ChatMiddleware } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Mutual exclusion around a critical section keyed by `key`. A distributed
|
|
4
|
+
* backend (e.g. a Cloudflare Durable Object) is the only kind safe across
|
|
5
|
+
* instances; the in-memory default is correct within a single process only.
|
|
6
|
+
* Lease-backed implementations abort `signal` as soon as ownership can no longer
|
|
7
|
+
* be guaranteed; the callback must stop externally visible mutations when it
|
|
8
|
+
* aborts. Callbacks that ignore `signal` (e.g. the sandbox `ensure` critical
|
|
9
|
+
* section) remain valid — a `() => Promise<T>` is assignable to the
|
|
10
|
+
* signal-taking parameter.
|
|
11
|
+
*/
|
|
12
|
+
export interface LockStore {
|
|
13
|
+
withLock: <T>(key: string, fn: (signal: AbortSignal) => Promise<T>) => Promise<T>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Type a {@link LockStore} implementation inline: pass the object and get
|
|
17
|
+
* autocomplete + contract checking, with no separate `: LockStore` annotation.
|
|
18
|
+
* Hand the result to {@link withLocks}.
|
|
19
|
+
*/
|
|
20
|
+
export declare function defineLock(lock: LockStore): LockStore;
|
|
21
|
+
/**
|
|
22
|
+
* The lock capability. Provided by {@link withLocks} or any middleware that
|
|
23
|
+
* calls {@link provideLocks}.
|
|
24
|
+
*/
|
|
25
|
+
export declare const LocksCapability: import('./capabilities.js').Capability<LockStore, "locks">;
|
|
26
|
+
/** Destructured accessors: `getLocks(ctx)` / `provideLocks(ctx, store)`. */
|
|
27
|
+
export declare const getLocks: import('./capabilities.js').CapabilityGetter<LockStore>, provideLocks: import('./capabilities.js').CapabilityProvider<LockStore>;
|
|
28
|
+
/**
|
|
29
|
+
* In-memory {@link LockStore} — a per-key promise chain. Correct within a single
|
|
30
|
+
* process; multi-instance correctness needs a distributed lock backend.
|
|
31
|
+
*/
|
|
32
|
+
export declare class InMemoryLockStore implements LockStore {
|
|
33
|
+
private readonly chains;
|
|
34
|
+
withLock<T>(key: string, fn: (signal: AbortSignal) => Promise<T>): Promise<T>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Provide a {@link LockStore} on the chat middleware capability bus.
|
|
38
|
+
*
|
|
39
|
+
* Coordination only — independent of chat state persistence. A lock provided
|
|
40
|
+
* here reaches any later middleware that reads {@link LocksCapability}
|
|
41
|
+
* (including `withSandbox`).
|
|
42
|
+
*
|
|
43
|
+
* ```ts
|
|
44
|
+
* middleware: [
|
|
45
|
+
* withLocks(distributedLocks),
|
|
46
|
+
* withSandbox(sandbox),
|
|
47
|
+
* ]
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function withLocks(locks: LockStore): ChatMiddleware;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { createCapability } from "./capabilities.js";
|
|
2
|
+
import { defineChatMiddleware } from "./define.js";
|
|
3
|
+
//#region src/activities/chat/middleware/locks.ts
|
|
4
|
+
/**
|
|
5
|
+
* Distributed-mutex primitive — the neutral home for the `'locks'` capability.
|
|
6
|
+
*
|
|
7
|
+
* Capability identity is by object reference (see `createCapability`). Any
|
|
8
|
+
* middleware may PROVIDE a {@link LockStore} via {@link withLocks} /
|
|
9
|
+
* {@link provideLocks}; consumers (notably `@tanstack/ai-sandbox` `ensure`)
|
|
10
|
+
* read it with {@link getLocks}. Coordination, not state persistence.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Type a {@link LockStore} implementation inline: pass the object and get
|
|
14
|
+
* autocomplete + contract checking, with no separate `: LockStore` annotation.
|
|
15
|
+
* Hand the result to {@link withLocks}.
|
|
16
|
+
*/
|
|
17
|
+
function defineLock(lock) {
|
|
18
|
+
return lock;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The lock capability. Provided by {@link withLocks} or any middleware that
|
|
22
|
+
* calls {@link provideLocks}.
|
|
23
|
+
*/
|
|
24
|
+
var LocksCapability = createCapability()("locks");
|
|
25
|
+
/** Destructured accessors: `getLocks(ctx)` / `provideLocks(ctx, store)`. */
|
|
26
|
+
var [getLocks, provideLocks] = LocksCapability;
|
|
27
|
+
/**
|
|
28
|
+
* In-memory {@link LockStore} — a per-key promise chain. Correct within a single
|
|
29
|
+
* process; multi-instance correctness needs a distributed lock backend.
|
|
30
|
+
*/
|
|
31
|
+
var InMemoryLockStore = class {
|
|
32
|
+
chains = /* @__PURE__ */ new Map();
|
|
33
|
+
withLock(key, fn) {
|
|
34
|
+
const prior = this.chains.get(key) ?? Promise.resolve();
|
|
35
|
+
const runCriticalSection = () => fn(new AbortController().signal);
|
|
36
|
+
const run = prior.then(runCriticalSection, runCriticalSection);
|
|
37
|
+
const settled = run.then(() => void 0, () => void 0);
|
|
38
|
+
this.chains.set(key, settled);
|
|
39
|
+
settled.then(() => {
|
|
40
|
+
if (this.chains.get(key) === settled) this.chains.delete(key);
|
|
41
|
+
});
|
|
42
|
+
return run;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Provide a {@link LockStore} on the chat middleware capability bus.
|
|
47
|
+
*
|
|
48
|
+
* Coordination only — independent of chat state persistence. A lock provided
|
|
49
|
+
* here reaches any later middleware that reads {@link LocksCapability}
|
|
50
|
+
* (including `withSandbox`).
|
|
51
|
+
*
|
|
52
|
+
* ```ts
|
|
53
|
+
* middleware: [
|
|
54
|
+
* withLocks(distributedLocks),
|
|
55
|
+
* withSandbox(sandbox),
|
|
56
|
+
* ]
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
function withLocks(locks) {
|
|
60
|
+
return defineChatMiddleware({
|
|
61
|
+
name: "locks",
|
|
62
|
+
provides: [LocksCapability],
|
|
63
|
+
setup(ctx) {
|
|
64
|
+
provideLocks(ctx, locks);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
export { InMemoryLockStore, LocksCapability, defineLock, getLocks, provideLocks, withLocks };
|
|
70
|
+
|
|
71
|
+
//# sourceMappingURL=locks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locks.js","names":[],"sources":["../../../../../src/activities/chat/middleware/locks.ts"],"sourcesContent":["/**\n * Distributed-mutex primitive — the neutral home for the `'locks'` capability.\n *\n * Capability identity is by object reference (see `createCapability`). Any\n * middleware may PROVIDE a {@link LockStore} via {@link withLocks} /\n * {@link provideLocks}; consumers (notably `@tanstack/ai-sandbox` `ensure`)\n * read it with {@link getLocks}. Coordination, not state persistence.\n */\nimport { createCapability } from './capabilities'\nimport { defineChatMiddleware } from './define'\nimport type { ChatMiddleware, ChatMiddlewareContext } from './types'\n\n/**\n * Mutual exclusion around a critical section keyed by `key`. A distributed\n * backend (e.g. a Cloudflare Durable Object) is the only kind safe across\n * instances; the in-memory default is correct within a single process only.\n * Lease-backed implementations abort `signal` as soon as ownership can no longer\n * be guaranteed; the callback must stop externally visible mutations when it\n * aborts. Callbacks that ignore `signal` (e.g. the sandbox `ensure` critical\n * section) remain valid — a `() => Promise<T>` is assignable to the\n * signal-taking parameter.\n */\nexport interface LockStore {\n withLock: <T>(\n key: string,\n fn: (signal: AbortSignal) => Promise<T>,\n ) => Promise<T>\n}\n\n/**\n * Type a {@link LockStore} implementation inline: pass the object and get\n * autocomplete + contract checking, with no separate `: LockStore` annotation.\n * Hand the result to {@link withLocks}.\n */\nexport function defineLock(lock: LockStore): LockStore {\n return lock\n}\n\n/**\n * The lock capability. Provided by {@link withLocks} or any middleware that\n * calls {@link provideLocks}.\n */\nexport const LocksCapability = createCapability<LockStore>()('locks')\n\n/** Destructured accessors: `getLocks(ctx)` / `provideLocks(ctx, store)`. */\nexport const [getLocks, provideLocks] = LocksCapability\n\n/**\n * In-memory {@link LockStore} — a per-key promise chain. Correct within a single\n * process; multi-instance correctness needs a distributed lock backend.\n */\nexport class InMemoryLockStore implements LockStore {\n private readonly chains = new Map<string, Promise<unknown>>()\n\n withLock<T>(\n key: string,\n fn: (signal: AbortSignal) => Promise<T>,\n ): Promise<T> {\n const prior = this.chains.get(key) ?? Promise.resolve()\n const runCriticalSection = () => fn(new AbortController().signal)\n // Chain after the prior holder regardless of how it settled.\n const run = prior.then(runCriticalSection, runCriticalSection)\n // Swallow rejections so one failure doesn't poison the lock, then drop the\n // chain entry once this tail is still the latest — otherwise long-lived\n // processes accumulate settled promises for every distinct key forever.\n const settled = run.then(\n () => undefined,\n () => undefined,\n )\n this.chains.set(key, settled)\n void settled.then(() => {\n if (this.chains.get(key) === settled) {\n this.chains.delete(key)\n }\n })\n return run\n }\n}\n\n/**\n * Provide a {@link LockStore} on the chat middleware capability bus.\n *\n * Coordination only — independent of chat state persistence. A lock provided\n * here reaches any later middleware that reads {@link LocksCapability}\n * (including `withSandbox`).\n *\n * ```ts\n * middleware: [\n * withLocks(distributedLocks),\n * withSandbox(sandbox),\n * ]\n * ```\n */\nexport function withLocks(locks: LockStore): ChatMiddleware {\n return defineChatMiddleware({\n name: 'locks',\n provides: [LocksCapability],\n setup(ctx: ChatMiddlewareContext) {\n provideLocks(ctx, locks)\n },\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAkCA,SAAgB,WAAW,MAA4B;CACrD,OAAO;AACT;;;;;AAMA,IAAa,kBAAkB,iBAA4B,CAAC,CAAC,OAAO;;AAGpE,IAAa,CAAC,UAAU,gBAAgB;;;;;AAMxC,IAAa,oBAAb,MAAoD;CAClD,yBAA0B,IAAI,IAA8B;CAE5D,SACE,KACA,IACY;EACZ,MAAM,QAAQ,KAAK,OAAO,IAAI,GAAG,KAAK,QAAQ,QAAQ;EACtD,MAAM,2BAA2B,GAAG,IAAI,gBAAgB,CAAC,CAAC,MAAM;EAEhE,MAAM,MAAM,MAAM,KAAK,oBAAoB,kBAAkB;EAI7D,MAAM,UAAU,IAAI,WACZ,KAAA,SACA,KAAA,CACR;EACA,KAAK,OAAO,IAAI,KAAK,OAAO;EAC5B,QAAa,WAAW;GACtB,IAAI,KAAK,OAAO,IAAI,GAAG,MAAM,SAC3B,KAAK,OAAO,OAAO,GAAG;EAE1B,CAAC;EACD,OAAO;CACT;AACF;;;;;;;;;;;;;;;AAgBA,SAAgB,UAAU,OAAkC;CAC1D,OAAO,qBAAqB;EAC1B,MAAM;EACN,UAAU,CAAC,eAAe;EAC1B,MAAM,KAA4B;GAChC,aAAa,KAAK,KAAK;EACzB;CACF,CAAC;AACH"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface PendingTurnSnapshot {
|
|
2
|
+
/**
|
|
3
|
+
* Store the user's pending turn now.
|
|
4
|
+
*
|
|
5
|
+
* Idempotent: the later `onStart` store replaces the thread with the same or a
|
|
6
|
+
* more complete list, so calling this changes what is visible EARLIER without
|
|
7
|
+
* changing what is visible at the end.
|
|
8
|
+
*
|
|
9
|
+
* Rejects only if the store itself fails. Callers treat that as non-fatal — a
|
|
10
|
+
* run that cannot pre-store its turn is still a run worth doing.
|
|
11
|
+
*/
|
|
12
|
+
snapshot: () => Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export declare const PendingTurnCapability: import('./capabilities.js').Capability<PendingTurnSnapshot, "pending-turn">;
|
|
15
|
+
export declare const getPendingTurn: import('./capabilities.js').CapabilityGetter<PendingTurnSnapshot>, providePendingTurn: import('./capabilities.js').CapabilityProvider<PendingTurnSnapshot>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { createCapability } from "./capabilities.js";
|
|
2
|
+
//#region src/activities/chat/middleware/pending-turn.ts
|
|
3
|
+
/**
|
|
4
|
+
* Internal seam that lets a SLOW middleware ask the persistence layer to store
|
|
5
|
+
* the user's pending turn NOW, before that middleware starts its slow work.
|
|
6
|
+
*
|
|
7
|
+
* WHY THIS EXISTS. Chat persistence stores the pending turn from `onStart`, which
|
|
8
|
+
* is the earliest hook that holds the merged message list. `onStart` runs after
|
|
9
|
+
* EVERY middleware `setup`, and that is normally a few milliseconds. `withSandbox`
|
|
10
|
+
* breaks the assumption: its `setup` creates a sandbox and clones a repository,
|
|
11
|
+
* which takes minutes. For that whole window the thread holds nothing, so a reload
|
|
12
|
+
* — or a second device — asks the server for the conversation and is told it is
|
|
13
|
+
* empty. The user sees no sign of the message they just sent.
|
|
14
|
+
*
|
|
15
|
+
* The provider owns the rule for WHAT to store. A caller must not rebuild that
|
|
16
|
+
* rule: `saveThread` replaces the whole thread, so a caller that stored only the
|
|
17
|
+
* newly-sent message would delete the history. Asking the owner to store the turn
|
|
18
|
+
* keeps the merge in one place.
|
|
19
|
+
*
|
|
20
|
+
* OPT-IN, so nothing changes for a fast run. Persistence offers this seam on every
|
|
21
|
+
* durable run; only a middleware that is about to be slow calls it. A run with no
|
|
22
|
+
* such middleware never calls it, and the `onStart` store stays the only one.
|
|
23
|
+
*
|
|
24
|
+
* A SEAM RATHER THAN A NEW MIDDLEWARE HOOK, deliberately. A lifecycle hook that
|
|
25
|
+
* runs before `setup` would be public API, and it would have to explain itself to
|
|
26
|
+
* every middleware author. This concern has one provider (`withPersistence`) and
|
|
27
|
+
* one caller (`withSandbox`), and it reaches across packages through the same
|
|
28
|
+
* internal channel the sandbox layer already uses for its runtime.
|
|
29
|
+
*/
|
|
30
|
+
var PendingTurnCapability = createCapability()("pending-turn");
|
|
31
|
+
var [getPendingTurn, providePendingTurn] = PendingTurnCapability;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { PendingTurnCapability, getPendingTurn, providePendingTurn };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=pending-turn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pending-turn.js","names":[],"sources":["../../../../../src/activities/chat/middleware/pending-turn.ts"],"sourcesContent":["/**\n * Internal seam that lets a SLOW middleware ask the persistence layer to store\n * the user's pending turn NOW, before that middleware starts its slow work.\n *\n * WHY THIS EXISTS. Chat persistence stores the pending turn from `onStart`, which\n * is the earliest hook that holds the merged message list. `onStart` runs after\n * EVERY middleware `setup`, and that is normally a few milliseconds. `withSandbox`\n * breaks the assumption: its `setup` creates a sandbox and clones a repository,\n * which takes minutes. For that whole window the thread holds nothing, so a reload\n * — or a second device — asks the server for the conversation and is told it is\n * empty. The user sees no sign of the message they just sent.\n *\n * The provider owns the rule for WHAT to store. A caller must not rebuild that\n * rule: `saveThread` replaces the whole thread, so a caller that stored only the\n * newly-sent message would delete the history. Asking the owner to store the turn\n * keeps the merge in one place.\n *\n * OPT-IN, so nothing changes for a fast run. Persistence offers this seam on every\n * durable run; only a middleware that is about to be slow calls it. A run with no\n * such middleware never calls it, and the `onStart` store stays the only one.\n *\n * A SEAM RATHER THAN A NEW MIDDLEWARE HOOK, deliberately. A lifecycle hook that\n * runs before `setup` would be public API, and it would have to explain itself to\n * every middleware author. This concern has one provider (`withPersistence`) and\n * one caller (`withSandbox`), and it reaches across packages through the same\n * internal channel the sandbox layer already uses for its runtime.\n */\nimport { createCapability } from './capabilities'\n\nexport interface PendingTurnSnapshot {\n /**\n * Store the user's pending turn now.\n *\n * Idempotent: the later `onStart` store replaces the thread with the same or a\n * more complete list, so calling this changes what is visible EARLIER without\n * changing what is visible at the end.\n *\n * Rejects only if the store itself fails. Callers treat that as non-fatal — a\n * run that cannot pre-store its turn is still a run worth doing.\n */\n snapshot: () => Promise<void>\n}\n\nexport const PendingTurnCapability =\n createCapability<PendingTurnSnapshot>()('pending-turn')\n\nexport const [getPendingTurn, providePendingTurn] = PendingTurnCapability\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,IAAa,wBACX,iBAAsC,CAAC,CAAC,cAAc;AAExD,IAAa,CAAC,gBAAgB,sBAAsB"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry of disconnect listeners for one run.
|
|
3
|
+
*
|
|
4
|
+
* Listeners must do BOOKKEEPING ONLY. The run is still executing, so releasing
|
|
5
|
+
* anything it depends on — stopping a file watcher, destroying a sandbox — breaks
|
|
6
|
+
* a healthy run. Teardown belongs in the terminal hooks, which still run exactly
|
|
7
|
+
* once afterwards.
|
|
8
|
+
*
|
|
9
|
+
* A listener may return a promise; the engine awaits all of them before the run
|
|
10
|
+
* finishes, so bookkeeping cannot be lost to a race with the run's own completion.
|
|
11
|
+
*/
|
|
12
|
+
export interface RunDisconnect {
|
|
13
|
+
/**
|
|
14
|
+
* Register `listener`, called at most once per run when the delivery socket
|
|
15
|
+
* closes. Registering after the socket has ALREADY closed calls `listener`
|
|
16
|
+
* immediately — otherwise a middleware whose `setup` was still running during
|
|
17
|
+
* the disconnect would silently never hear about it, which is the exact window
|
|
18
|
+
* the common disconnect lands in.
|
|
19
|
+
*/
|
|
20
|
+
subscribe: (listener: () => void | Promise<void>) => void;
|
|
21
|
+
}
|
|
22
|
+
export declare const RunDisconnectCapability: import('./capabilities.js').Capability<RunDisconnect, "run-disconnect">;
|
|
23
|
+
export declare const getRunDisconnect: import('./capabilities.js').CapabilityGetter<RunDisconnect>, provideRunDisconnect: import('./capabilities.js').CapabilityProvider<RunDisconnect>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { createCapability } from "./capabilities.js";
|
|
2
|
+
//#region src/activities/chat/middleware/run-disconnect.ts
|
|
3
|
+
/**
|
|
4
|
+
* Internal seam the chat engine PROVIDES so middleware can learn that the
|
|
5
|
+
* DELIVERY socket closed while the run is still going — and, crucially, learn it
|
|
6
|
+
* WITHOUT the run being cancelled.
|
|
7
|
+
*
|
|
8
|
+
* WHY THIS EXISTS. Before it, the only way a disconnect reached middleware was for
|
|
9
|
+
* the application to mirror `request.signal` into `chat()`'s `abortController`,
|
|
10
|
+
* which ABORTS THE RUN. For a durable run that is precisely wrong, and wrong in
|
|
11
|
+
* the most expensive direction: `chat()` returns at its `isCancelled()` check
|
|
12
|
+
* immediately after middleware `setup`, so the harness adapter's `chatStream` is
|
|
13
|
+
* never called and the agent in the sandbox that `setup` just spent minutes
|
|
14
|
+
* creating is NEVER LAUNCHED. The user switched away during "starting the
|
|
15
|
+
* sandbox", came back, and found an empty log belonging to a run that had done
|
|
16
|
+
* nothing — with no takeover able to recover it, because an agent that never
|
|
17
|
+
* started wrote no journal to replay. Applications were forced to choose between
|
|
18
|
+
* "the middleware learns about the disconnect" and "the run survives it".
|
|
19
|
+
*
|
|
20
|
+
* So a disconnect is delivered as a NOTIFICATION. `withSandbox` uses it to stamp
|
|
21
|
+
* `detachedSince`/`sandboxKey` and publish the detach verdict while the run keeps
|
|
22
|
+
* producing into its still-open durable log — which is exactly what a re-attaching
|
|
23
|
+
* client tails to catch up.
|
|
24
|
+
*
|
|
25
|
+
* A SUBSCRIPTION RATHER THAN A MIDDLEWARE HOOK, deliberately. `ChatMiddleware` is
|
|
26
|
+
* public API and a new lifecycle hook there is a permanent commitment — including
|
|
27
|
+
* the obligation to explain that it is the one hook that is NOT terminal. This
|
|
28
|
+
* concern has exactly one consumer in the tree (`withSandbox`) and it reaches it
|
|
29
|
+
* through the same internal channel the sandbox layer already uses for its runtime
|
|
30
|
+
* (`SandboxRuntimeCapability`), so it ships with no public surface at all.
|
|
31
|
+
*
|
|
32
|
+
* DISPATCHED FROM THE TRANSPORT, NOT FROM THE RUN'S UNWINDING. That is what makes
|
|
33
|
+
* it prompt. A run suspended inside a minutes-wide `setup` cannot dispatch anything
|
|
34
|
+
* from its own `finally`, because the `finally` is reached only once the generator
|
|
35
|
+
* unwinds — which is what made `detachedSince` land three minutes late.
|
|
36
|
+
*/
|
|
37
|
+
var RunDisconnectCapability = createCapability()("run-disconnect");
|
|
38
|
+
var [getRunDisconnect, provideRunDisconnect] = RunDisconnectCapability;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { RunDisconnectCapability, getRunDisconnect, provideRunDisconnect };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=run-disconnect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-disconnect.js","names":[],"sources":["../../../../../src/activities/chat/middleware/run-disconnect.ts"],"sourcesContent":["/**\n * Internal seam the chat engine PROVIDES so middleware can learn that the\n * DELIVERY socket closed while the run is still going — and, crucially, learn it\n * WITHOUT the run being cancelled.\n *\n * WHY THIS EXISTS. Before it, the only way a disconnect reached middleware was for\n * the application to mirror `request.signal` into `chat()`'s `abortController`,\n * which ABORTS THE RUN. For a durable run that is precisely wrong, and wrong in\n * the most expensive direction: `chat()` returns at its `isCancelled()` check\n * immediately after middleware `setup`, so the harness adapter's `chatStream` is\n * never called and the agent in the sandbox that `setup` just spent minutes\n * creating is NEVER LAUNCHED. The user switched away during \"starting the\n * sandbox\", came back, and found an empty log belonging to a run that had done\n * nothing — with no takeover able to recover it, because an agent that never\n * started wrote no journal to replay. Applications were forced to choose between\n * \"the middleware learns about the disconnect\" and \"the run survives it\".\n *\n * So a disconnect is delivered as a NOTIFICATION. `withSandbox` uses it to stamp\n * `detachedSince`/`sandboxKey` and publish the detach verdict while the run keeps\n * producing into its still-open durable log — which is exactly what a re-attaching\n * client tails to catch up.\n *\n * A SUBSCRIPTION RATHER THAN A MIDDLEWARE HOOK, deliberately. `ChatMiddleware` is\n * public API and a new lifecycle hook there is a permanent commitment — including\n * the obligation to explain that it is the one hook that is NOT terminal. This\n * concern has exactly one consumer in the tree (`withSandbox`) and it reaches it\n * through the same internal channel the sandbox layer already uses for its runtime\n * (`SandboxRuntimeCapability`), so it ships with no public surface at all.\n *\n * DISPATCHED FROM THE TRANSPORT, NOT FROM THE RUN'S UNWINDING. That is what makes\n * it prompt. A run suspended inside a minutes-wide `setup` cannot dispatch anything\n * from its own `finally`, because the `finally` is reached only once the generator\n * unwinds — which is what made `detachedSince` land three minutes late.\n */\nimport { createCapability } from './capabilities'\n\n/**\n * Registry of disconnect listeners for one run.\n *\n * Listeners must do BOOKKEEPING ONLY. The run is still executing, so releasing\n * anything it depends on — stopping a file watcher, destroying a sandbox — breaks\n * a healthy run. Teardown belongs in the terminal hooks, which still run exactly\n * once afterwards.\n *\n * A listener may return a promise; the engine awaits all of them before the run\n * finishes, so bookkeeping cannot be lost to a race with the run's own completion.\n */\nexport interface RunDisconnect {\n /**\n * Register `listener`, called at most once per run when the delivery socket\n * closes. Registering after the socket has ALREADY closed calls `listener`\n * immediately — otherwise a middleware whose `setup` was still running during\n * the disconnect would silently never hear about it, which is the exact window\n * the common disconnect lands in.\n */\n subscribe: (listener: () => void | Promise<void>) => void\n}\n\nexport const RunDisconnectCapability =\n createCapability<RunDisconnect>()('run-disconnect')\n\nexport const [getRunDisconnect, provideRunDisconnect] = RunDisconnectCapability\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0DA,IAAa,0BACX,iBAAgC,CAAC,CAAC,gBAAgB;AAEpD,IAAa,CAAC,kBAAkB,wBAAwB"}
|