@tanstack/ai 0.42.0 → 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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.js +598 -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 +1 -0
- 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
|
@@ -25,11 +25,14 @@ import type { TokenUsage } from '../../types'
|
|
|
25
25
|
/**
|
|
26
26
|
* The activity an observability event describes.
|
|
27
27
|
*
|
|
28
|
-
* Mirrors the public surface a caller reaches for: `'chat'` for `chat()`,
|
|
29
|
-
* the media kinds for the `generate*`
|
|
30
|
-
* adapter's kind (the public
|
|
31
|
-
* `'speech'`/`'text'` vocabulary).
|
|
32
|
-
* `gen_ai.operation.name`.
|
|
28
|
+
* Mirrors the public surface a caller reaches for: `'chat'` for `chat()`,
|
|
29
|
+
* `'summarize'` for `summarize()`, and the media kinds for the `generate*`
|
|
30
|
+
* activities. `'tts'` matches the speech adapter's kind (the public
|
|
31
|
+
* discriminator avoids inventing a parallel `'speech'`/`'text'` vocabulary).
|
|
32
|
+
* `otelMiddleware` maps each to its `gen_ai.operation.name`.
|
|
33
|
+
*
|
|
34
|
+
* `'summarize'` produces text, not media, so it has no artifacts — a
|
|
35
|
+
* persistence middleware stores its run record and result and nothing else.
|
|
33
36
|
*/
|
|
34
37
|
export type GenerationActivity =
|
|
35
38
|
| 'chat'
|
|
@@ -38,6 +41,7 @@ export type GenerationActivity =
|
|
|
38
41
|
| 'audio'
|
|
39
42
|
| 'tts'
|
|
40
43
|
| 'transcription'
|
|
44
|
+
| 'summarize'
|
|
41
45
|
|
|
42
46
|
/**
|
|
43
47
|
* Stable context passed to every {@link GenerationMiddleware} hook. Created
|
|
@@ -60,6 +64,10 @@ export interface GenerationMiddlewareContext<TContext = unknown> {
|
|
|
60
64
|
provider: string
|
|
61
65
|
/** Model id. Emitted as `gen_ai.request.model`. */
|
|
62
66
|
model: string
|
|
67
|
+
/** Stable conversation/thread id, when supplied by the caller. */
|
|
68
|
+
threadId?: string
|
|
69
|
+
/** Stable run id, when supplied by the caller. */
|
|
70
|
+
runId?: string
|
|
63
71
|
/**
|
|
64
72
|
* Provider-specific options passed to the activity, if any. Typed `unknown`
|
|
65
73
|
* because each activity's options are strongly typed per model; a supertype
|
|
@@ -72,8 +80,44 @@ export interface GenerationMiddlewareContext<TContext = unknown> {
|
|
|
72
80
|
createId: (prefix: string) => string
|
|
73
81
|
/** Runtime context provided by the activity options, if any. */
|
|
74
82
|
context: TContext
|
|
83
|
+
/**
|
|
84
|
+
* Result transforms registered by middleware during this activity call.
|
|
85
|
+
* Transforms run after the raw adapter result exists and before the final
|
|
86
|
+
* result is returned or streamed. Push multiple transforms to run them in
|
|
87
|
+
* registration order.
|
|
88
|
+
*
|
|
89
|
+
* REQUIRED (always an array, empty when nothing registered): middleware
|
|
90
|
+
* registers by pushing onto it, so an optional array would let a host that
|
|
91
|
+
* builds its own context omit it and silently no-op every registration —
|
|
92
|
+
* generation persistence would then mark a run completed with neither its
|
|
93
|
+
* result nor its artifacts written, with nothing to observe but the missing
|
|
94
|
+
* data. Every context the library builds comes from
|
|
95
|
+
* `createGenerationContext`, which always sets `[]`.
|
|
96
|
+
*/
|
|
97
|
+
resultTransforms: Array<GenerationResultTransform<any, TContext>>
|
|
98
|
+
/**
|
|
99
|
+
* Activity inputs captured for middleware that needs to transform or persist
|
|
100
|
+
* the result together with reconstructable request metadata.
|
|
101
|
+
*/
|
|
102
|
+
artifactInputs?: unknown
|
|
75
103
|
}
|
|
76
104
|
|
|
105
|
+
/** Stable context handed to each {@link GenerationResultTransform}. */
|
|
106
|
+
export interface GenerationResultTransformContext<TContext = unknown> {
|
|
107
|
+
/** The activity call being transformed. */
|
|
108
|
+
middleware: GenerationMiddlewareContext<TContext>
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* A transform middleware registers on `ctx.resultTransforms` to rewrite the raw
|
|
113
|
+
* adapter result before it is returned or streamed. Return a new result to
|
|
114
|
+
* replace it, or `undefined` to leave it unchanged.
|
|
115
|
+
*/
|
|
116
|
+
export type GenerationResultTransform<TResult = unknown, TContext = unknown> = (
|
|
117
|
+
result: TResult,
|
|
118
|
+
ctx: GenerationResultTransformContext<TContext>,
|
|
119
|
+
) => TResult | undefined | Promise<TResult | undefined>
|
|
120
|
+
|
|
77
121
|
// ===========================
|
|
78
122
|
// Hook payloads
|
|
79
123
|
// ===========================
|
|
@@ -12,6 +12,19 @@ function createId(prefix: string): string {
|
|
|
12
12
|
return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Persisted artifact refs a middleware may have attached to the result. Read
|
|
17
|
+
* defensively: the result shape is activity-specific and `artifacts` is only
|
|
18
|
+
* present when generation persistence is wired with an artifact + blob store.
|
|
19
|
+
*/
|
|
20
|
+
function artifactsFromResult(result: unknown): Array<unknown> | undefined {
|
|
21
|
+
if (typeof result !== 'object' || result === null) return undefined
|
|
22
|
+
const artifacts = (result as { artifacts?: unknown }).artifacts
|
|
23
|
+
return Array.isArray(artifacts) && artifacts.length > 0
|
|
24
|
+
? artifacts
|
|
25
|
+
: undefined
|
|
26
|
+
}
|
|
27
|
+
|
|
15
28
|
/**
|
|
16
29
|
* Wrap a one-shot generation result as a StreamChunk async iterable.
|
|
17
30
|
*
|
|
@@ -23,7 +36,10 @@ function createId(prefix: string): string {
|
|
|
23
36
|
* @returns An AsyncIterable of StreamChunks with RUN_STARTED, CUSTOM(generation:result), and RUN_FINISHED events on success, or RUN_STARTED and RUN_ERROR on failure
|
|
24
37
|
*/
|
|
25
38
|
export async function* streamGenerationResult<TResult>(
|
|
26
|
-
generator: (
|
|
39
|
+
generator: (resolved: {
|
|
40
|
+
runId: string
|
|
41
|
+
threadId: string
|
|
42
|
+
}) => Promise<TResult>,
|
|
27
43
|
options?: { runId?: string; threadId?: string },
|
|
28
44
|
): AsyncIterable<StreamChunk> {
|
|
29
45
|
const runId = options?.runId ?? createId('run')
|
|
@@ -37,7 +53,19 @@ export async function* streamGenerationResult<TResult>(
|
|
|
37
53
|
}
|
|
38
54
|
|
|
39
55
|
try {
|
|
40
|
-
const result = await generator()
|
|
56
|
+
const result = await generator({ runId, threadId })
|
|
57
|
+
|
|
58
|
+
// Emit persisted artifact refs (if a middleware attached any) before the
|
|
59
|
+
// result, so the client records them as the run streams.
|
|
60
|
+
const artifacts = artifactsFromResult(result)
|
|
61
|
+
if (artifacts) {
|
|
62
|
+
yield {
|
|
63
|
+
type: EventType.CUSTOM,
|
|
64
|
+
name: 'generation:artifacts',
|
|
65
|
+
value: artifacts,
|
|
66
|
+
timestamp: Date.now(),
|
|
67
|
+
}
|
|
68
|
+
}
|
|
41
69
|
|
|
42
70
|
yield {
|
|
43
71
|
type: EventType.CUSTOM,
|
|
@@ -362,6 +362,11 @@ export class ChatStreamSummarizeAdapter<
|
|
|
362
362
|
systemPrompts: [systemPrompt],
|
|
363
363
|
modelOptions,
|
|
364
364
|
logger: options.logger,
|
|
365
|
+
// Forward the run identity so the wrapped chat stamps it onto RUN_STARTED
|
|
366
|
+
// (chat uses `runId` as its `runIdOverride`). Conditional spreads keep the
|
|
367
|
+
// fields absent when unset, under `exactOptionalPropertyTypes`.
|
|
368
|
+
...(options.runId !== undefined ? { runId: options.runId } : {}),
|
|
369
|
+
...(options.threadId !== undefined ? { threadId: options.threadId } : {}),
|
|
365
370
|
}
|
|
366
371
|
}
|
|
367
372
|
|
|
@@ -8,8 +8,18 @@
|
|
|
8
8
|
import { aiEventClient } from '@tanstack/ai-event-client'
|
|
9
9
|
import { streamGenerationResult } from '../stream-generation-result.js'
|
|
10
10
|
import { resolveDebugOption } from '../../logger/resolve'
|
|
11
|
+
import {
|
|
12
|
+
applyGenerationResultTransforms,
|
|
13
|
+
createGenerationContext,
|
|
14
|
+
runGenerationAbort,
|
|
15
|
+
runGenerationError,
|
|
16
|
+
runGenerationFinish,
|
|
17
|
+
runGenerationStart,
|
|
18
|
+
runGenerationUsage,
|
|
19
|
+
} from '../middleware/run'
|
|
11
20
|
import type { InternalLogger } from '../../logger/internal-logger'
|
|
12
21
|
import type { DebugOption } from '../../logger/types'
|
|
22
|
+
import type { GenerationMiddleware } from '../middleware/types'
|
|
13
23
|
import type { SummarizeAdapter } from './adapter'
|
|
14
24
|
import type { StreamChunk, SummarizationResult } from '../../types'
|
|
15
25
|
|
|
@@ -57,6 +67,32 @@ export interface SummarizeActivityOptions<
|
|
|
57
67
|
focus?: Array<string>
|
|
58
68
|
/** Provider-specific options */
|
|
59
69
|
modelOptions?: SummarizeProviderOptions<TAdapter>
|
|
70
|
+
/**
|
|
71
|
+
* Optional run identity. When set on a streaming summarize, it is stamped
|
|
72
|
+
* onto the emitted `RUN_STARTED` so a delivery-durable route keys the run's
|
|
73
|
+
* log by the same id the client rejoins with — making a mid-run reload
|
|
74
|
+
* resumable. Filed under `threadId` when persistence is wired.
|
|
75
|
+
*/
|
|
76
|
+
runId?: string
|
|
77
|
+
/**
|
|
78
|
+
* Stable conversation/thread id for correlating this run when persisted — the
|
|
79
|
+
* slot a reloading client hydrates the last summary by. Pass it whenever
|
|
80
|
+
* persistence is on; `withGenerationPersistence` refuses a run without one.
|
|
81
|
+
*/
|
|
82
|
+
threadId?: string
|
|
83
|
+
/**
|
|
84
|
+
* Observe-only middleware notified on start, usage, success, and error. Pass
|
|
85
|
+
* `otelMiddleware()` for OpenTelemetry, `withGenerationPersistence()` to
|
|
86
|
+
* record the run (summaries are text, so the run record holds the result and
|
|
87
|
+
* there are no artifacts to store), or implement the `GenerationMiddleware`
|
|
88
|
+
* contract for a custom backend.
|
|
89
|
+
*
|
|
90
|
+
* Streaming and non-streaming behave the same way: one `onStart`, then a
|
|
91
|
+
* terminal `onFinish` / `onError`, with the result transforms applied to the
|
|
92
|
+
* `SummarizationResult` in between. A streaming consumer that disconnects
|
|
93
|
+
* mid-summary fires `onAbort`.
|
|
94
|
+
*/
|
|
95
|
+
middleware?: Array<GenerationMiddleware>
|
|
60
96
|
/**
|
|
61
97
|
* Whether to stream the summarization result.
|
|
62
98
|
* When true, returns an AsyncIterable<StreamChunk> for streaming output.
|
|
@@ -180,13 +216,27 @@ export function summarize<
|
|
|
180
216
|
async function runSummarize(
|
|
181
217
|
options: SummarizeActivityOptions<SummarizeAdapter<string, object>, false>,
|
|
182
218
|
): Promise<SummarizationResult> {
|
|
183
|
-
const { adapter, text, maxLength, style, focus, modelOptions } =
|
|
219
|
+
const { adapter, text, maxLength, style, focus, modelOptions, middleware } =
|
|
220
|
+
options
|
|
184
221
|
const model = adapter.model
|
|
185
222
|
const requestId = createId('summarize')
|
|
186
223
|
const inputLength = text.length
|
|
187
224
|
const startTime = Date.now()
|
|
188
225
|
const logger: InternalLogger = resolveDebugOption(options.debug)
|
|
189
226
|
|
|
227
|
+
const mwCtx = createGenerationContext({
|
|
228
|
+
requestId,
|
|
229
|
+
activity: 'summarize',
|
|
230
|
+
provider: adapter.name,
|
|
231
|
+
model,
|
|
232
|
+
modelOptions,
|
|
233
|
+
threadId: options.threadId,
|
|
234
|
+
runId: options.runId,
|
|
235
|
+
createId,
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
await runGenerationStart(middleware, mwCtx)
|
|
239
|
+
|
|
190
240
|
aiEventClient.emit('summarize:request:started', {
|
|
191
241
|
requestId,
|
|
192
242
|
provider: adapter.name,
|
|
@@ -212,7 +262,11 @@ async function runSummarize(
|
|
|
212
262
|
}
|
|
213
263
|
|
|
214
264
|
try {
|
|
215
|
-
const
|
|
265
|
+
const rawResult = await adapter.summarize(summarizeOptions)
|
|
266
|
+
// Transforms run before anything observes the result — the same order every
|
|
267
|
+
// media activity uses — so the run record and the returned value are the
|
|
268
|
+
// same object.
|
|
269
|
+
const result = await applyGenerationResultTransforms(mwCtx, rawResult)
|
|
216
270
|
|
|
217
271
|
const duration = Date.now() - startTime
|
|
218
272
|
const outputLength = result.summary.length
|
|
@@ -232,8 +286,18 @@ async function runSummarize(
|
|
|
232
286
|
outputLength,
|
|
233
287
|
})
|
|
234
288
|
|
|
289
|
+
if (result.usage) await runGenerationUsage(middleware, mwCtx, result.usage)
|
|
290
|
+
await runGenerationFinish(middleware, mwCtx, {
|
|
291
|
+
duration,
|
|
292
|
+
usage: result.usage,
|
|
293
|
+
})
|
|
294
|
+
|
|
235
295
|
return result
|
|
236
296
|
} catch (error) {
|
|
297
|
+
await runGenerationError(middleware, mwCtx, {
|
|
298
|
+
error,
|
|
299
|
+
duration: Date.now() - startTime,
|
|
300
|
+
})
|
|
237
301
|
logger.errors('summarize activity failed', {
|
|
238
302
|
error,
|
|
239
303
|
source: 'summarize',
|
|
@@ -242,6 +306,15 @@ async function runSummarize(
|
|
|
242
306
|
}
|
|
243
307
|
}
|
|
244
308
|
|
|
309
|
+
/** Read a `usage` off a transformed result without asserting its shape. */
|
|
310
|
+
function usageOf(result: unknown): SummarizationResult['usage'] | undefined {
|
|
311
|
+
if (typeof result !== 'object' || result === null) return undefined
|
|
312
|
+
const usage = (result as { usage?: unknown }).usage
|
|
313
|
+
return typeof usage === 'object' && usage !== null
|
|
314
|
+
? (usage as SummarizationResult['usage'])
|
|
315
|
+
: undefined
|
|
316
|
+
}
|
|
317
|
+
|
|
245
318
|
/**
|
|
246
319
|
* Run streaming summarization
|
|
247
320
|
* Uses the adapter's native streaming if available, otherwise falls back
|
|
@@ -250,7 +323,16 @@ async function runSummarize(
|
|
|
250
323
|
async function* runStreamingSummarize(
|
|
251
324
|
options: SummarizeActivityOptions<SummarizeAdapter<string, object>, true>,
|
|
252
325
|
): AsyncIterable<StreamChunk> {
|
|
253
|
-
const {
|
|
326
|
+
const {
|
|
327
|
+
adapter,
|
|
328
|
+
text,
|
|
329
|
+
maxLength,
|
|
330
|
+
style,
|
|
331
|
+
focus,
|
|
332
|
+
modelOptions,
|
|
333
|
+
runId,
|
|
334
|
+
threadId,
|
|
335
|
+
} = options
|
|
254
336
|
const model = adapter.model
|
|
255
337
|
const logger: InternalLogger = resolveDebugOption(options.debug)
|
|
256
338
|
|
|
@@ -260,6 +342,10 @@ async function* runStreamingSummarize(
|
|
|
260
342
|
stream: true,
|
|
261
343
|
})
|
|
262
344
|
|
|
345
|
+
// Thread the caller's run identity through so the emitted `RUN_STARTED`
|
|
346
|
+
// carries it — keeps a delivery-durable route's log keyed by the id the
|
|
347
|
+
// client rejoins with (mid-run reload resumability). Conditional spreads keep
|
|
348
|
+
// the fields off the object entirely under `exactOptionalPropertyTypes`.
|
|
263
349
|
const summarizeOptions = {
|
|
264
350
|
model,
|
|
265
351
|
text,
|
|
@@ -268,23 +354,127 @@ async function* runStreamingSummarize(
|
|
|
268
354
|
focus,
|
|
269
355
|
modelOptions,
|
|
270
356
|
logger,
|
|
357
|
+
...(runId !== undefined ? { runId } : {}),
|
|
358
|
+
...(threadId !== undefined ? { threadId } : {}),
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Use real streaming if the adapter supports it
|
|
362
|
+
if (adapter.summarizeStream) {
|
|
363
|
+
yield* runNativeSummarizeStream(
|
|
364
|
+
options,
|
|
365
|
+
adapter.summarizeStream(summarizeOptions),
|
|
366
|
+
logger,
|
|
367
|
+
)
|
|
368
|
+
return
|
|
271
369
|
}
|
|
272
370
|
|
|
273
371
|
try {
|
|
274
|
-
//
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
372
|
+
// Fall back to non-streaming — wrap the result with streamGenerationResult,
|
|
373
|
+
// forwarding the run identity so its RUN_STARTED matches too. The generation
|
|
374
|
+
// itself goes through `runSummarize`, so middleware (and its result
|
|
375
|
+
// transforms) run exactly as they do for a non-streaming call. Only `runId`
|
|
376
|
+
// is taken from the resolved wire identity — `threadId` stays the CALLER's,
|
|
377
|
+
// since a minted one would file the run in a slot no client can hydrate.
|
|
378
|
+
yield* streamGenerationResult(
|
|
379
|
+
(resolved) =>
|
|
380
|
+
runSummarize({ ...options, stream: false, runId: resolved.runId }),
|
|
381
|
+
{
|
|
382
|
+
...(runId !== undefined ? { runId } : {}),
|
|
383
|
+
...(threadId !== undefined ? { threadId } : {}),
|
|
384
|
+
},
|
|
385
|
+
)
|
|
386
|
+
} catch (error) {
|
|
387
|
+
logger.errors('summarize activity failed', {
|
|
388
|
+
error,
|
|
389
|
+
source: 'summarize',
|
|
390
|
+
})
|
|
391
|
+
throw error
|
|
392
|
+
}
|
|
393
|
+
}
|
|
279
394
|
|
|
280
|
-
|
|
281
|
-
|
|
395
|
+
/**
|
|
396
|
+
* Drive an adapter's native `summarizeStream`, wiring the generation middleware
|
|
397
|
+
* around it.
|
|
398
|
+
*
|
|
399
|
+
* The adapter emits a terminal `generation:result` CUSTOM chunk carrying the
|
|
400
|
+
* assembled {@link SummarizationResult}; that is the one point where a result
|
|
401
|
+
* exists, so the transforms run there and the REWRITTEN result is what gets
|
|
402
|
+
* yielded — the client and the persisted run record then hold the same object.
|
|
403
|
+
* An adapter whose stream never emits one still finishes the run, just with no
|
|
404
|
+
* result recorded.
|
|
405
|
+
*/
|
|
406
|
+
async function* runNativeSummarizeStream(
|
|
407
|
+
options: SummarizeActivityOptions<SummarizeAdapter<string, object>, true>,
|
|
408
|
+
stream: AsyncIterable<StreamChunk>,
|
|
409
|
+
logger: InternalLogger,
|
|
410
|
+
): AsyncIterable<StreamChunk> {
|
|
411
|
+
const { adapter, middleware, modelOptions } = options
|
|
412
|
+
const mwCtx = createGenerationContext({
|
|
413
|
+
requestId: createId('summarize'),
|
|
414
|
+
activity: 'summarize',
|
|
415
|
+
provider: adapter.name,
|
|
416
|
+
model: adapter.model,
|
|
417
|
+
modelOptions,
|
|
418
|
+
threadId: options.threadId,
|
|
419
|
+
runId: options.runId,
|
|
420
|
+
createId,
|
|
421
|
+
})
|
|
422
|
+
|
|
423
|
+
await runGenerationStart(middleware, mwCtx)
|
|
424
|
+
|
|
425
|
+
const startTime = Date.now()
|
|
426
|
+
// Tracks whether a terminal hook already fired, so the `finally` can report an
|
|
427
|
+
// abandoned stream without double-firing. Mirrors the streaming video path.
|
|
428
|
+
let settled = false
|
|
429
|
+
try {
|
|
430
|
+
for await (const chunk of stream) {
|
|
431
|
+
if (chunk.type === 'CUSTOM' && chunk.name === 'generation:result') {
|
|
432
|
+
const result = await applyGenerationResultTransforms<unknown>(
|
|
433
|
+
mwCtx,
|
|
434
|
+
chunk.value,
|
|
435
|
+
)
|
|
436
|
+
const usage = usageOf(result)
|
|
437
|
+
// Finish before yielding the terminal chunks: a consumer that stops
|
|
438
|
+
// reading once it has the result must not trip the abandonment path.
|
|
439
|
+
if (usage) await runGenerationUsage(middleware, mwCtx, usage)
|
|
440
|
+
await runGenerationFinish(middleware, mwCtx, {
|
|
441
|
+
duration: Date.now() - startTime,
|
|
442
|
+
usage,
|
|
443
|
+
})
|
|
444
|
+
settled = true
|
|
445
|
+
yield { ...chunk, value: result }
|
|
446
|
+
continue
|
|
447
|
+
}
|
|
448
|
+
yield chunk
|
|
449
|
+
}
|
|
450
|
+
if (!settled) {
|
|
451
|
+
await runGenerationFinish(middleware, mwCtx, {
|
|
452
|
+
duration: Date.now() - startTime,
|
|
453
|
+
})
|
|
454
|
+
settled = true
|
|
455
|
+
}
|
|
282
456
|
} catch (error) {
|
|
457
|
+
settled = true
|
|
458
|
+
await runGenerationError(middleware, mwCtx, {
|
|
459
|
+
error,
|
|
460
|
+
duration: Date.now() - startTime,
|
|
461
|
+
})
|
|
283
462
|
logger.errors('summarize activity failed', {
|
|
284
463
|
error,
|
|
285
464
|
source: 'summarize',
|
|
286
465
|
})
|
|
287
466
|
throw error
|
|
467
|
+
} finally {
|
|
468
|
+
if (!settled) {
|
|
469
|
+
// The consumer abandoned the stream mid-summary, so the generator is being
|
|
470
|
+
// unwound at a `yield`. Report a cancel, not an error, so an observer ends
|
|
471
|
+
// its span (and persistence marks the run interrupted) instead of leaving
|
|
472
|
+
// the run open forever.
|
|
473
|
+
await runGenerationAbort(middleware, mwCtx, {
|
|
474
|
+
reason: 'Summarize stream abandoned before completion',
|
|
475
|
+
duration: Date.now() - startTime,
|
|
476
|
+
})
|
|
477
|
+
}
|
|
288
478
|
}
|
|
289
479
|
}
|
|
290
480
|
|
package/src/adapter-internals.ts
CHANGED
|
@@ -15,4 +15,13 @@ export {
|
|
|
15
15
|
provideSandboxRuntime,
|
|
16
16
|
SandboxRuntimeCapability,
|
|
17
17
|
} from './activities/chat/middleware/sandbox-runtime'
|
|
18
|
-
export
|
|
18
|
+
export {
|
|
19
|
+
getRunDisconnect,
|
|
20
|
+
provideRunDisconnect,
|
|
21
|
+
RunDisconnectCapability,
|
|
22
|
+
} from './activities/chat/middleware/run-disconnect'
|
|
23
|
+
export {
|
|
24
|
+
getPendingTurn,
|
|
25
|
+
PendingTurnCapability,
|
|
26
|
+
providePendingTurn,
|
|
27
|
+
} from './activities/chat/middleware/pending-turn'
|