@tanstack/ai 0.27.0 → 0.29.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.d.ts +7 -0
- package/dist/esm/activities/chat/index.js +86 -20
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/mcp/manager.d.ts +25 -0
- package/dist/esm/activities/chat/mcp/manager.js +71 -0
- package/dist/esm/activities/chat/mcp/manager.js.map +1 -0
- package/dist/esm/activities/chat/mcp/types.d.ts +56 -0
- package/dist/esm/activities/chat/messages.js +1 -1
- package/dist/esm/activities/chat/messages.js.map +1 -1
- package/dist/esm/activities/chat/stream/message-updaters.js +20 -8
- package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
- package/dist/esm/activities/chat/stream/processor.d.ts +6 -0
- package/dist/esm/activities/chat/stream/processor.js +18 -3
- package/dist/esm/activities/chat/stream/processor.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-calls.d.ts +1 -1
- package/dist/esm/activities/chat/tools/tool-calls.js +2 -1
- package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
- package/dist/esm/activities/generateVideo/index.d.ts +2 -1
- package/dist/esm/activities/generateVideo/index.js +12 -2
- package/dist/esm/activities/generateVideo/index.js.map +1 -1
- package/dist/esm/extend-adapter.d.ts +22 -6
- package/dist/esm/extend-adapter.js.map +1 -1
- 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/logger/console-logger.d.ts +18 -0
- package/dist/esm/logger/console-logger.js +64 -8
- package/dist/esm/logger/console-logger.js.map +1 -1
- package/dist/esm/logger/types.d.ts +4 -4
- package/dist/esm/realtime/index.d.ts +1 -3
- package/dist/esm/realtime/index.js.map +1 -1
- package/dist/esm/types.d.ts +13 -1
- package/package.json +2 -2
- package/skills/ai-core/adapter-configuration/references/gemini-adapter.md +2 -2
- package/skills/ai-core/chat-experience/SKILL.md +71 -0
- package/skills/ai-core/media-generation/SKILL.md +29 -1
- package/skills/ai-core/tool-calling/SKILL.md +287 -0
- package/src/activities/chat/index.ts +109 -25
- package/src/activities/chat/mcp/manager.ts +85 -0
- package/src/activities/chat/mcp/types.ts +66 -0
- package/src/activities/chat/messages.ts +1 -0
- package/src/activities/chat/stream/message-updaters.ts +22 -9
- package/src/activities/chat/stream/processor.ts +30 -3
- package/src/activities/chat/tools/tool-calls.ts +2 -0
- package/src/activities/generateVideo/index.ts +12 -0
- package/src/extend-adapter.ts +42 -24
- package/src/index.ts +10 -0
- package/src/logger/console-logger.ts +112 -17
- package/src/logger/types.ts +4 -4
- package/src/realtime/index.ts +1 -3
- package/src/types.ts +13 -0
package/src/extend-adapter.ts
CHANGED
|
@@ -144,6 +144,14 @@ type ExtractCustomModelNames<TDefs extends ReadonlyArray<ExtendedModelDef>> =
|
|
|
144
144
|
// Factory Type Inference
|
|
145
145
|
// ===========================
|
|
146
146
|
|
|
147
|
+
/**
|
|
148
|
+
* The widest factory shape `extendAdapter` accepts: any function taking a
|
|
149
|
+
* model as its first parameter. Parameters are contravariant, so `never`
|
|
150
|
+
* params and an `unknown` return accept every factory without resorting
|
|
151
|
+
* to `any`.
|
|
152
|
+
*/
|
|
153
|
+
type AnyAdapterFactory = (model: never, ...args: Array<never>) => unknown
|
|
154
|
+
|
|
147
155
|
/**
|
|
148
156
|
* Infer the model parameter type from an adapter factory function.
|
|
149
157
|
* For generic functions like `<T extends Union>(model: T)`, this gets `T` which
|
|
@@ -151,32 +159,44 @@ type ExtractCustomModelNames<TDefs extends ReadonlyArray<ExtendedModelDef>> =
|
|
|
151
159
|
*/
|
|
152
160
|
type InferFactoryModels<TFactory> = TFactory extends (
|
|
153
161
|
model: infer TModel,
|
|
154
|
-
...args: Array<
|
|
155
|
-
) =>
|
|
162
|
+
...args: Array<never>
|
|
163
|
+
) => unknown
|
|
156
164
|
? TModel extends string
|
|
157
165
|
? TModel
|
|
158
166
|
: string
|
|
159
167
|
: string
|
|
160
168
|
|
|
161
|
-
/**
|
|
162
|
-
* Infer the config parameter type from an adapter factory function.
|
|
163
|
-
*/
|
|
164
|
-
type InferConfig<TFactory> = TFactory extends (
|
|
165
|
-
model: any,
|
|
166
|
-
config?: infer TConfig,
|
|
167
|
-
) => any
|
|
168
|
-
? TConfig
|
|
169
|
-
: undefined
|
|
170
|
-
|
|
171
169
|
/**
|
|
172
170
|
* Infer the adapter return type from a factory function.
|
|
173
171
|
*/
|
|
174
172
|
type InferAdapterReturn<TFactory> = TFactory extends (
|
|
175
|
-
...args: Array<
|
|
173
|
+
...args: Array<never>
|
|
176
174
|
) => infer TReturn
|
|
177
175
|
? TReturn
|
|
178
176
|
: never
|
|
179
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Extracts all parameter types after the model parameter from a factory,
|
|
180
|
+
* preserving labels and optionality (e.g. `[apiKey: string, config?: C]`).
|
|
181
|
+
* Note: overloaded factories resolve against their last overload (a
|
|
182
|
+
* `Parameters` limitation).
|
|
183
|
+
*/
|
|
184
|
+
type InferRestArgs<TFactory extends AnyAdapterFactory> =
|
|
185
|
+
Parameters<TFactory> extends [unknown?, ...infer TRest] ? TRest : []
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* The factory signature produced by `extendAdapter`: accepts both original
|
|
189
|
+
* and custom model names while preserving all remaining parameters and the
|
|
190
|
+
* return type of the original factory.
|
|
191
|
+
*/
|
|
192
|
+
type ExtendedFactory<
|
|
193
|
+
TFactory extends AnyAdapterFactory,
|
|
194
|
+
TDefs extends ReadonlyArray<ExtendedModelDef>,
|
|
195
|
+
> = (
|
|
196
|
+
model: InferFactoryModels<TFactory> | ExtractCustomModelNames<TDefs>,
|
|
197
|
+
...args: InferRestArgs<TFactory>
|
|
198
|
+
) => InferAdapterReturn<TFactory>
|
|
199
|
+
|
|
180
200
|
// ===========================
|
|
181
201
|
// extendAdapter Function
|
|
182
202
|
// ===========================
|
|
@@ -225,19 +245,17 @@ type InferAdapterReturn<TFactory> = TFactory extends (
|
|
|
225
245
|
* ```
|
|
226
246
|
*/
|
|
227
247
|
export function extendAdapter<
|
|
228
|
-
TFactory extends
|
|
248
|
+
TFactory extends AnyAdapterFactory,
|
|
229
249
|
const TDefs extends ReadonlyArray<ExtendedModelDef>,
|
|
230
|
-
>(
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
: [config?: InferConfig<TFactory>]
|
|
238
|
-
) => InferAdapterReturn<TFactory> {
|
|
250
|
+
>(factory: TFactory, _customModels: TDefs): ExtendedFactory<TFactory, TDefs>
|
|
251
|
+
// The implementation signature stays at the honest `AnyAdapterFactory` width;
|
|
252
|
+
// the overload above performs the deliberate model-union widening.
|
|
253
|
+
export function extendAdapter(
|
|
254
|
+
factory: AnyAdapterFactory,
|
|
255
|
+
_customModels: ReadonlyArray<ExtendedModelDef>,
|
|
256
|
+
): AnyAdapterFactory {
|
|
239
257
|
// At runtime, we simply pass through to the original factory.
|
|
240
258
|
// The _customModels parameter is only used for type inference.
|
|
241
259
|
// No runtime validation - users are trusted to pass valid model names.
|
|
242
|
-
return factory
|
|
260
|
+
return factory
|
|
243
261
|
}
|
package/src/index.ts
CHANGED
|
@@ -52,6 +52,16 @@ export {
|
|
|
52
52
|
type InferToolOutput,
|
|
53
53
|
} from './activities/chat/tools/tool-definition'
|
|
54
54
|
|
|
55
|
+
// MCP chat option types
|
|
56
|
+
export type {
|
|
57
|
+
MCPToolSource,
|
|
58
|
+
ChatMCPOptions,
|
|
59
|
+
MCPConnectionPolicy,
|
|
60
|
+
} from './activities/chat/mcp/types'
|
|
61
|
+
|
|
62
|
+
// MCP error classes (value exports — usable with instanceof)
|
|
63
|
+
export { MCPDuplicateToolNameError } from './activities/chat/mcp/manager'
|
|
64
|
+
|
|
55
65
|
// Schema conversion (Standard JSON Schema compliant)
|
|
56
66
|
export {
|
|
57
67
|
convertSchemaToJsonSchema,
|
|
@@ -1,5 +1,86 @@
|
|
|
1
1
|
import type { Logger } from './types'
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* `util.inspect` options used with `console.dir` on Node so deeply nested
|
|
5
|
+
* structures (e.g. provider chunk payloads with `usage`, `output`,
|
|
6
|
+
* `reasoning`, `tools`) render in full instead of truncating to
|
|
7
|
+
* `[Object]` / `[Array]`.
|
|
8
|
+
*/
|
|
9
|
+
const DIR_OPTIONS = { depth: null, colors: true } as const
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* How `meta` should be rendered on the current runtime:
|
|
13
|
+
*
|
|
14
|
+
* - `dir` — Node. `console.dir(meta, { depth: null, colors: true })` gives a
|
|
15
|
+
* depth-unlimited, colored inspect dump.
|
|
16
|
+
* - `json` — Cloudflare Workers / workerd. workerd never forwards
|
|
17
|
+
* `console.dir` output to the terminal (with or without options), and its
|
|
18
|
+
* own inspect of extra console arguments truncates nested objects, so the
|
|
19
|
+
* payload is appended as circular-safe pretty-printed JSON instead.
|
|
20
|
+
* - `arg` — everything else (browsers, Deno, Bun). `meta` is passed as an
|
|
21
|
+
* extra console argument: devtools keep collapsible object trees and the
|
|
22
|
+
* runtime's inspect handles circular references natively.
|
|
23
|
+
*/
|
|
24
|
+
type MetaStrategy = 'dir' | 'json' | 'arg'
|
|
25
|
+
|
|
26
|
+
function resolveMetaStrategy(): MetaStrategy {
|
|
27
|
+
// workerd must be detected before the Node check: under the `nodejs_compat`
|
|
28
|
+
// flag it emulates `process.versions.node`, but still drops `console.dir`.
|
|
29
|
+
try {
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- navigator is missing on Node < 21 despite the DOM lib typing it as always present
|
|
31
|
+
if (globalThis.navigator?.userAgent === 'Cloudflare-Workers') return 'json'
|
|
32
|
+
} catch {
|
|
33
|
+
// A locked-down runtime with a throwing `userAgent` getter is not workerd;
|
|
34
|
+
// fall through to the remaining checks rather than crash the log call.
|
|
35
|
+
}
|
|
36
|
+
if (
|
|
37
|
+
typeof process !== 'undefined' &&
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- a partial process global (bundler shims) may lack versions
|
|
39
|
+
typeof process.versions?.node === 'string'
|
|
40
|
+
) {
|
|
41
|
+
return 'dir'
|
|
42
|
+
}
|
|
43
|
+
return 'arg'
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* `JSON.stringify` hardened for debug payloads: circular references collapse
|
|
48
|
+
* to `"[Circular]"`, `Error` instances expand to `name`/`message`/`stack`
|
|
49
|
+
* (they would otherwise stringify to `{}`), and `bigint` values become
|
|
50
|
+
* strings (they would otherwise throw). Never throws — falls back to
|
|
51
|
+
* `String(value)` and, if even that coercion throws, a placeholder.
|
|
52
|
+
*/
|
|
53
|
+
function stringifyMetaSafely(value: unknown): string {
|
|
54
|
+
const seen = new WeakSet<object>()
|
|
55
|
+
try {
|
|
56
|
+
return JSON.stringify(
|
|
57
|
+
value,
|
|
58
|
+
(_key, entry: unknown) => {
|
|
59
|
+
if (typeof entry === 'bigint') return entry.toString()
|
|
60
|
+
if (entry instanceof Error) {
|
|
61
|
+
return {
|
|
62
|
+
name: entry.name,
|
|
63
|
+
message: entry.message,
|
|
64
|
+
stack: entry.stack,
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (typeof entry === 'object' && entry !== null) {
|
|
68
|
+
if (seen.has(entry)) return '[Circular]'
|
|
69
|
+
seen.add(entry)
|
|
70
|
+
}
|
|
71
|
+
return entry
|
|
72
|
+
},
|
|
73
|
+
2,
|
|
74
|
+
)
|
|
75
|
+
} catch {
|
|
76
|
+
try {
|
|
77
|
+
return String(value)
|
|
78
|
+
} catch {
|
|
79
|
+
return '[Unserializable meta]'
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
3
84
|
/**
|
|
4
85
|
* Default `Logger` implementation that routes each level to the matching
|
|
5
86
|
* `console` method:
|
|
@@ -9,41 +90,55 @@ import type { Logger } from './types'
|
|
|
9
90
|
* - `warn` → `console.warn`
|
|
10
91
|
* - `error` → `console.error`
|
|
11
92
|
*
|
|
12
|
-
* When a `meta` object is supplied
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* `[Object]` / `[Array]`. On Node this produces a depth-unlimited inspect
|
|
17
|
-
* dump; browsers present the object as an interactive tree (extra options
|
|
18
|
-
* are ignored).
|
|
93
|
+
* When a `meta` object is supplied it is rendered with the strategy that
|
|
94
|
+
* actually surfaces it on the current runtime (see {@link MetaStrategy}):
|
|
95
|
+
* depth-unlimited `console.dir` on Node, circular-safe JSON on Cloudflare
|
|
96
|
+
* Workers, and an extra console argument everywhere else.
|
|
19
97
|
*
|
|
20
98
|
* This is the logger used when `debug` is enabled on any activity and no
|
|
21
99
|
* custom `logger` is supplied via `debug: { logger }`.
|
|
22
100
|
*/
|
|
23
|
-
const DIR_OPTIONS = { depth: null, colors: true } as const
|
|
24
|
-
|
|
25
101
|
export class ConsoleLogger implements Logger {
|
|
26
102
|
/** Log a debug-level message; forwards to `console.debug`. */
|
|
27
103
|
debug(message: string, meta?: Record<string, unknown>): void {
|
|
28
|
-
|
|
29
|
-
if (meta !== undefined) console.dir(meta, DIR_OPTIONS)
|
|
104
|
+
this.emit('debug', message, meta)
|
|
30
105
|
}
|
|
31
106
|
|
|
32
107
|
/** Log an info-level message; forwards to `console.info`. */
|
|
33
108
|
info(message: string, meta?: Record<string, unknown>): void {
|
|
34
|
-
|
|
35
|
-
if (meta !== undefined) console.dir(meta, DIR_OPTIONS)
|
|
109
|
+
this.emit('info', message, meta)
|
|
36
110
|
}
|
|
37
111
|
|
|
38
112
|
/** Log a warning-level message; forwards to `console.warn`. */
|
|
39
113
|
warn(message: string, meta?: Record<string, unknown>): void {
|
|
40
|
-
|
|
41
|
-
if (meta !== undefined) console.dir(meta, DIR_OPTIONS)
|
|
114
|
+
this.emit('warn', message, meta)
|
|
42
115
|
}
|
|
43
116
|
|
|
44
117
|
/** Log an error-level message; forwards to `console.error`. */
|
|
45
118
|
error(message: string, meta?: Record<string, unknown>): void {
|
|
46
|
-
|
|
47
|
-
|
|
119
|
+
this.emit('error', message, meta)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private emit(
|
|
123
|
+
level: 'debug' | 'info' | 'warn' | 'error',
|
|
124
|
+
message: string,
|
|
125
|
+
meta?: Record<string, unknown>,
|
|
126
|
+
): void {
|
|
127
|
+
if (meta === undefined) {
|
|
128
|
+
console[level](message)
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
switch (resolveMetaStrategy()) {
|
|
132
|
+
case 'dir':
|
|
133
|
+
console[level](message)
|
|
134
|
+
console.dir(meta, DIR_OPTIONS)
|
|
135
|
+
break
|
|
136
|
+
case 'json':
|
|
137
|
+
console[level](`${message}\n${stringifyMetaSafely(meta)}`)
|
|
138
|
+
break
|
|
139
|
+
case 'arg':
|
|
140
|
+
console[level](message, meta)
|
|
141
|
+
break
|
|
142
|
+
}
|
|
48
143
|
}
|
|
49
144
|
}
|
package/src/logger/types.ts
CHANGED
|
@@ -4,22 +4,22 @@
|
|
|
4
4
|
export interface Logger {
|
|
5
5
|
/**
|
|
6
6
|
* Called for chunk-level diagnostic output (raw provider chunks, per-chunk output, agent-loop iteration markers).
|
|
7
|
-
* @param meta Structured data forwarded to the underlying logger. Loggers like pino will preserve this as a structured record;
|
|
7
|
+
* @param meta Structured data forwarded to the underlying logger. Loggers like pino will preserve this as a structured record; the default `ConsoleLogger` renders it with a runtime-appropriate strategy (depth-unlimited `console.dir` on Node, JSON appended to the message on Cloudflare Workers, a second `console.<level>` argument elsewhere).
|
|
8
8
|
*/
|
|
9
9
|
debug: (message: string, meta?: Record<string, unknown>) => void
|
|
10
10
|
/**
|
|
11
11
|
* Called for notable informational events (outgoing requests, tool invocations, middleware transitions).
|
|
12
|
-
* @param meta Structured data forwarded to the underlying logger. Loggers like pino will preserve this as a structured record;
|
|
12
|
+
* @param meta Structured data forwarded to the underlying logger. Loggers like pino will preserve this as a structured record; the default `ConsoleLogger` renders it with a runtime-appropriate strategy (depth-unlimited `console.dir` on Node, JSON appended to the message on Cloudflare Workers, a second `console.<level>` argument elsewhere).
|
|
13
13
|
*/
|
|
14
14
|
info: (message: string, meta?: Record<string, unknown>) => void
|
|
15
15
|
/**
|
|
16
16
|
* Called for notable warnings that don't halt execution (deprecations, recoverable anomalies).
|
|
17
|
-
* @param meta Structured data forwarded to the underlying logger. Loggers like pino will preserve this as a structured record;
|
|
17
|
+
* @param meta Structured data forwarded to the underlying logger. Loggers like pino will preserve this as a structured record; the default `ConsoleLogger` renders it with a runtime-appropriate strategy (depth-unlimited `console.dir` on Node, JSON appended to the message on Cloudflare Workers, a second `console.<level>` argument elsewhere).
|
|
18
18
|
*/
|
|
19
19
|
warn: (message: string, meta?: Record<string, unknown>) => void
|
|
20
20
|
/**
|
|
21
21
|
* Called for caught exceptions throughout the pipeline.
|
|
22
|
-
* @param meta Structured data forwarded to the underlying logger. Loggers like pino will preserve this as a structured record;
|
|
22
|
+
* @param meta Structured data forwarded to the underlying logger. Loggers like pino will preserve this as a structured record; the default `ConsoleLogger` renders it with a runtime-appropriate strategy (depth-unlimited `console.dir` on Node, JSON appended to the message on Cloudflare Workers, a second `console.<level>` argument elsewhere).
|
|
23
23
|
*/
|
|
24
24
|
error: (message: string, meta?: Record<string, unknown>) => void
|
|
25
25
|
}
|
package/src/realtime/index.ts
CHANGED
|
@@ -22,9 +22,7 @@ export type * from './types'
|
|
|
22
22
|
* .handler(async () => {
|
|
23
23
|
* return realtimeToken({
|
|
24
24
|
* adapter: openaiRealtimeToken({
|
|
25
|
-
* model: 'gpt-
|
|
26
|
-
* voice: 'alloy',
|
|
27
|
-
* instructions: 'You are a helpful assistant...',
|
|
25
|
+
* model: 'gpt-realtime',
|
|
28
26
|
* }),
|
|
29
27
|
* })
|
|
30
28
|
* })
|
package/src/types.ts
CHANGED
|
@@ -51,6 +51,7 @@ export type ToolCallState =
|
|
|
51
51
|
| 'approval-requested' // Waiting for user approval
|
|
52
52
|
| 'approval-responded' // User has approved/denied
|
|
53
53
|
| 'complete' // Result is complete
|
|
54
|
+
| 'error' // Tool execution failed (terminal)
|
|
54
55
|
|
|
55
56
|
/**
|
|
56
57
|
* Tool result states - track the lifecycle of a tool result
|
|
@@ -490,6 +491,12 @@ export type ToolExecutionContext<TContext = unknown> =
|
|
|
490
491
|
RuntimeContextField<TContext> & {
|
|
491
492
|
/** The ID of the tool call being executed */
|
|
492
493
|
toolCallId?: string
|
|
494
|
+
/**
|
|
495
|
+
* Abort signal for the current chat run. Aborts when the run's
|
|
496
|
+
* `abortController` fires (or middleware aborts). Long-running tools —
|
|
497
|
+
* e.g. MCP `callTool` — should forward this to cancel in-flight work.
|
|
498
|
+
*/
|
|
499
|
+
abortSignal?: AbortSignal
|
|
493
500
|
/**
|
|
494
501
|
* Emit a custom event during tool execution.
|
|
495
502
|
* Events are streamed to the client in real-time as AG-UI CUSTOM events.
|
|
@@ -1650,6 +1657,12 @@ export interface VideoUrlResult {
|
|
|
1650
1657
|
url: string
|
|
1651
1658
|
/** When the URL expires, if applicable */
|
|
1652
1659
|
expiresAt?: Date
|
|
1660
|
+
/**
|
|
1661
|
+
* Usage information for the completed generation, when the adapter can report
|
|
1662
|
+
* it. For usage-based providers (e.g. fal) this carries `unitsBilled` — the
|
|
1663
|
+
* real billed quantity — so consumers can compute exact cost.
|
|
1664
|
+
*/
|
|
1665
|
+
usage?: TokenUsage
|
|
1653
1666
|
}
|
|
1654
1667
|
|
|
1655
1668
|
// ============================================================================
|