@tanstack/ai 0.32.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/activities/chat/index.js +24 -3
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/middleware/types.d.ts +7 -0
- package/dist/esm/activities/chat/tools/lazy-tool-manager.d.ts +25 -1
- package/dist/esm/activities/chat/tools/lazy-tool-manager.js +26 -2
- package/dist/esm/activities/chat/tools/lazy-tool-manager.js.map +1 -1
- package/dist/esm/activities/generateAudio/index.d.ts +7 -0
- package/dist/esm/activities/generateAudio/index.js +26 -1
- package/dist/esm/activities/generateAudio/index.js.map +1 -1
- package/dist/esm/activities/generateImage/index.d.ts +7 -0
- package/dist/esm/activities/generateImage/index.js +26 -1
- package/dist/esm/activities/generateImage/index.js.map +1 -1
- package/dist/esm/activities/generateSpeech/index.d.ts +7 -0
- package/dist/esm/activities/generateSpeech/index.js +26 -1
- package/dist/esm/activities/generateSpeech/index.js.map +1 -1
- package/dist/esm/activities/generateTranscription/index.d.ts +7 -0
- package/dist/esm/activities/generateTranscription/index.js +26 -1
- package/dist/esm/activities/generateTranscription/index.js.map +1 -1
- package/dist/esm/activities/generateVideo/index.d.ts +9 -0
- package/dist/esm/activities/generateVideo/index.js +52 -2
- package/dist/esm/activities/generateVideo/index.js.map +1 -1
- package/dist/esm/activities/middleware/index.d.ts +2 -0
- package/dist/esm/activities/middleware/run.d.ts +20 -0
- package/dist/esm/activities/middleware/run.js +42 -0
- package/dist/esm/activities/middleware/run.js.map +1 -0
- package/dist/esm/activities/middleware/types.d.ts +118 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/middlewares/otel.d.ts +8 -2
- package/dist/esm/middlewares/otel.js +145 -95
- package/dist/esm/middlewares/otel.js.map +1 -1
- package/dist/esm/middlewares/usage-attributes.d.ts +24 -0
- package/dist/esm/middlewares/usage-attributes.js +43 -0
- package/dist/esm/middlewares/usage-attributes.js.map +1 -0
- package/dist/esm/types.d.ts +7 -7
- package/dist/esm/utilities/errors.d.ts +13 -0
- package/dist/esm/utilities/errors.js +22 -0
- package/dist/esm/utilities/errors.js.map +1 -0
- package/dist/esm/utilities/numbers.d.ts +8 -0
- package/dist/esm/utilities/numbers.js +12 -0
- package/dist/esm/utilities/numbers.js.map +1 -0
- package/package.json +2 -2
- package/src/activities/chat/index.ts +32 -4
- package/src/activities/chat/middleware/types.ts +7 -0
- package/src/activities/chat/tools/lazy-tool-manager.ts +46 -4
- package/src/activities/generateAudio/index.ts +42 -1
- package/src/activities/generateImage/index.ts +42 -1
- package/src/activities/generateSpeech/index.ts +42 -1
- package/src/activities/generateTranscription/index.ts +42 -1
- package/src/activities/generateVideo/index.ts +88 -2
- package/src/activities/middleware/index.ts +20 -0
- package/src/activities/middleware/run.ts +88 -0
- package/src/activities/middleware/types.ts +173 -0
- package/src/index.ts +19 -0
- package/src/middlewares/otel.ts +195 -120
- package/src/middlewares/usage-attributes.ts +65 -0
- package/src/types.ts +7 -7
- package/src/utilities/errors.ts +29 -0
- package/src/utilities/numbers.ts +15 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import type { TokenUsage } from '../../types'
|
|
2
|
+
|
|
3
|
+
// ===========================
|
|
4
|
+
// Generation middleware
|
|
5
|
+
// ===========================
|
|
6
|
+
//
|
|
7
|
+
// The base, activity-agnostic middleware contract. Every activity — chat and
|
|
8
|
+
// the media activities — runs middleware that satisfies this shape. `chat()`
|
|
9
|
+
// accepts the richer `ChatMiddleware` superset (it adds config/chunk/tool
|
|
10
|
+
// hooks and capability primitives on top of these lifecycle hooks); media
|
|
11
|
+
// activities accept `GenerationMiddleware` directly.
|
|
12
|
+
//
|
|
13
|
+
// The relationship is intentionally STRUCTURAL, not nominal: `ChatMiddleware`
|
|
14
|
+
// does not `extends GenerationMiddleware`. Chat hooks use function-property
|
|
15
|
+
// syntax, so under `strictFunctionTypes` a narrowed-context subtype would be
|
|
16
|
+
// rejected; declaring it via inheritance would force method syntax and reopen
|
|
17
|
+
// a bivariance hole (a chat hook reading `ctx.messages` slotted where only a
|
|
18
|
+
// base context exists). Instead, the base context/info types are SUPERTYPES
|
|
19
|
+
// (fewer fields) and the chat context/info types are SUBTYPES (more fields),
|
|
20
|
+
// so a single value whose lifecycle hooks are authored against the base — like
|
|
21
|
+
// `otelMiddleware()` — satisfies `GenerationMiddleware & ChatMiddleware` by
|
|
22
|
+
// contravariance, while an arbitrary `ChatMiddleware` is NOT assignable to
|
|
23
|
+
// `GenerationMiddleware`.
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The activity an observability event describes.
|
|
27
|
+
*
|
|
28
|
+
* Mirrors the public surface a caller reaches for: `'chat'` for `chat()`, and
|
|
29
|
+
* the media kinds for the `generate*` activities. `'tts'` matches the speech
|
|
30
|
+
* adapter's kind (the public discriminator avoids inventing a parallel
|
|
31
|
+
* `'speech'`/`'text'` vocabulary). `otelMiddleware` maps each to its
|
|
32
|
+
* `gen_ai.operation.name`.
|
|
33
|
+
*/
|
|
34
|
+
export type GenerationActivity =
|
|
35
|
+
| 'chat'
|
|
36
|
+
| 'image'
|
|
37
|
+
| 'video'
|
|
38
|
+
| 'audio'
|
|
39
|
+
| 'tts'
|
|
40
|
+
| 'transcription'
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Stable context passed to every {@link GenerationMiddleware} hook. Created
|
|
44
|
+
* once per activity call and shared across the hooks of that call.
|
|
45
|
+
*
|
|
46
|
+
* Carries only fields every activity can honor. `ChatMiddlewareContext`
|
|
47
|
+
* structurally includes all of these plus chat-only state (messages,
|
|
48
|
+
* iteration, capabilities, …), which is why a chat middleware that reads those
|
|
49
|
+
* extra fields is not assignable to `GenerationMiddleware`.
|
|
50
|
+
*/
|
|
51
|
+
export interface GenerationMiddlewareContext<TContext = unknown> {
|
|
52
|
+
/**
|
|
53
|
+
* Stable id correlating the `onStart` / `onFinish` / `onError` / `onAbort`
|
|
54
|
+
* hooks of a single activity call.
|
|
55
|
+
*/
|
|
56
|
+
requestId: string
|
|
57
|
+
/** Which activity this call is. Discriminates media from chat. */
|
|
58
|
+
activity: GenerationActivity
|
|
59
|
+
/** Provider/adapter name (e.g. `"openai"`). Emitted as `gen_ai.system`. */
|
|
60
|
+
provider: string
|
|
61
|
+
/** Model id. Emitted as `gen_ai.request.model`. */
|
|
62
|
+
model: string
|
|
63
|
+
/**
|
|
64
|
+
* Provider-specific options passed to the activity, if any. Typed `unknown`
|
|
65
|
+
* because each activity's options are strongly typed per model; a supertype
|
|
66
|
+
* of `ChatMiddlewareContext`'s `modelOptions`.
|
|
67
|
+
*/
|
|
68
|
+
modelOptions?: unknown
|
|
69
|
+
/** Where the call originates. Always `'server'` for media activities. */
|
|
70
|
+
source: 'client' | 'server'
|
|
71
|
+
/** Generate a unique id with the given prefix. */
|
|
72
|
+
createId: (prefix: string) => string
|
|
73
|
+
/** Runtime context provided by the activity options, if any. */
|
|
74
|
+
context: TContext
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ===========================
|
|
78
|
+
// Hook payloads
|
|
79
|
+
// ===========================
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Token usage passed to {@link GenerationMiddleware.onUsage}. Kept as an
|
|
83
|
+
* interface extending `TokenUsage` to preserve declaration merging for this
|
|
84
|
+
* publicly exported type.
|
|
85
|
+
*/
|
|
86
|
+
export interface GenerationUsageInfo extends TokenUsage {}
|
|
87
|
+
|
|
88
|
+
/** Information passed to {@link GenerationMiddleware.onFinish}. */
|
|
89
|
+
export interface GenerationFinishInfo {
|
|
90
|
+
/** Wall-clock duration of the activity call, in milliseconds. */
|
|
91
|
+
duration: number
|
|
92
|
+
/** Unified usage, when the provider reported it. */
|
|
93
|
+
usage?: TokenUsage | undefined
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Information passed to {@link GenerationMiddleware.onAbort}. */
|
|
97
|
+
export interface GenerationAbortInfo {
|
|
98
|
+
/** The reason for the abort, if provided. */
|
|
99
|
+
reason?: string
|
|
100
|
+
/** Wall-clock duration until the abort, in milliseconds. */
|
|
101
|
+
duration: number
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Information passed to {@link GenerationMiddleware.onError}. */
|
|
105
|
+
export interface GenerationErrorInfo {
|
|
106
|
+
/** The thrown value (typically an `Error`). */
|
|
107
|
+
error: unknown
|
|
108
|
+
/** Wall-clock duration until the failure, in milliseconds. */
|
|
109
|
+
duration: number
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ===========================
|
|
113
|
+
// Middleware interface
|
|
114
|
+
// ===========================
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Activity-agnostic, observe-only middleware.
|
|
118
|
+
*
|
|
119
|
+
* A thin lifecycle observer registerable on any activity via its `middleware`
|
|
120
|
+
* option. Unlike `ChatMiddleware` (which can also rewrite config, chunks, and
|
|
121
|
+
* tool calls), these hooks only observe — the right fit for the single
|
|
122
|
+
* request → response shape of media activities. Pass `otelMiddleware()` for
|
|
123
|
+
* OpenTelemetry, or implement the hooks directly for a custom backend.
|
|
124
|
+
*
|
|
125
|
+
* Hooks are awaited in registration order. A hook that throws PROPAGATES and
|
|
126
|
+
* fails the activity — matching `chat()` middleware semantics. Keep them cheap;
|
|
127
|
+
* they run inline with the request.
|
|
128
|
+
*
|
|
129
|
+
* Exactly one of `onFinish` / `onAbort` / `onError` fires per call.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```ts
|
|
133
|
+
* import { generateImage } from '@tanstack/ai'
|
|
134
|
+
* import { otelMiddleware } from '@tanstack/ai/middlewares/otel'
|
|
135
|
+
* import { openaiImage } from '@tanstack/ai-openai'
|
|
136
|
+
* import { trace } from '@opentelemetry/api'
|
|
137
|
+
*
|
|
138
|
+
* await generateImage({
|
|
139
|
+
* adapter: openaiImage('gpt-image-1'),
|
|
140
|
+
* prompt: 'A serene mountain landscape at sunset',
|
|
141
|
+
* middleware: [otelMiddleware({ tracer: trace.getTracer('my-app') })],
|
|
142
|
+
* })
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
export interface GenerationMiddleware<TContext = unknown> {
|
|
146
|
+
/** Optional name, surfaced in diagnostics. */
|
|
147
|
+
name?: string
|
|
148
|
+
/** Called before the adapter request begins. */
|
|
149
|
+
onStart?: (ctx: GenerationMiddlewareContext<TContext>) => void | Promise<void>
|
|
150
|
+
/** Called when the provider reports usage, before `onFinish`. */
|
|
151
|
+
onUsage?: (
|
|
152
|
+
ctx: GenerationMiddlewareContext<TContext>,
|
|
153
|
+
usage: GenerationUsageInfo,
|
|
154
|
+
) => void | Promise<void>
|
|
155
|
+
/** Called after the activity completes successfully. */
|
|
156
|
+
onFinish?: (
|
|
157
|
+
ctx: GenerationMiddlewareContext<TContext>,
|
|
158
|
+
info: GenerationFinishInfo,
|
|
159
|
+
) => void | Promise<void>
|
|
160
|
+
/** Called when the activity is aborted (e.g. an abandoned stream). */
|
|
161
|
+
onAbort?: (
|
|
162
|
+
ctx: GenerationMiddlewareContext<TContext>,
|
|
163
|
+
info: GenerationAbortInfo,
|
|
164
|
+
) => void | Promise<void>
|
|
165
|
+
/** Called when the activity throws before completing. */
|
|
166
|
+
onError?: (
|
|
167
|
+
ctx: GenerationMiddlewareContext<TContext>,
|
|
168
|
+
info: GenerationErrorInfo,
|
|
169
|
+
) => void | Promise<void>
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** A `GenerationMiddleware` with a permissive context — for use as a constraint. */
|
|
173
|
+
export type AnyGenerationMiddleware = GenerationMiddleware<any>
|
package/src/index.ts
CHANGED
|
@@ -82,6 +82,10 @@ export {
|
|
|
82
82
|
// Tool call management
|
|
83
83
|
export { ToolCallManager } from './activities/chat/tools/tool-calls'
|
|
84
84
|
|
|
85
|
+
// Lazy tool discovery (name of the synthetic discovery tool, for custom
|
|
86
|
+
// message-compaction logic that needs to reference it)
|
|
87
|
+
export { DISCOVERY_TOOL_NAME } from './activities/chat/tools/lazy-tool-manager'
|
|
88
|
+
|
|
85
89
|
// Provider tool type
|
|
86
90
|
export type { ProviderTool } from './tools/provider-tool'
|
|
87
91
|
export { brandProviderTool } from './tools/provider-tool'
|
|
@@ -118,6 +122,21 @@ export type {
|
|
|
118
122
|
ErrorInfo,
|
|
119
123
|
} from './activities/chat/middleware/index'
|
|
120
124
|
|
|
125
|
+
// Base, activity-agnostic middleware. The observe-only superset that media
|
|
126
|
+
// activities accept via their `middleware` option; `ChatMiddleware` adds the
|
|
127
|
+
// chat-only hooks on top. Pure types only — the `otelMiddleware` value lives at
|
|
128
|
+
// `@tanstack/ai/middlewares/otel` so the root barrel never requires the
|
|
129
|
+
// optional `@opentelemetry/api` peer dependency.
|
|
130
|
+
export type {
|
|
131
|
+
GenerationMiddleware,
|
|
132
|
+
GenerationMiddlewareContext,
|
|
133
|
+
GenerationActivity,
|
|
134
|
+
GenerationUsageInfo,
|
|
135
|
+
GenerationFinishInfo,
|
|
136
|
+
GenerationAbortInfo,
|
|
137
|
+
GenerationErrorInfo,
|
|
138
|
+
AnyGenerationMiddleware,
|
|
139
|
+
} from './activities/middleware/index'
|
|
121
140
|
// Capability primitives + middleware builder
|
|
122
141
|
export {
|
|
123
142
|
createCapability,
|