@tanstack/ai 0.43.1 → 0.44.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/messages.js +21 -8
- package/dist/esm/activities/chat/messages.js.map +1 -1
- package/dist/esm/activities/embed/adapter.d.ts +69 -0
- package/dist/esm/activities/embed/adapter.js +23 -0
- package/dist/esm/activities/embed/adapter.js.map +1 -0
- package/dist/esm/activities/embed/index.d.ts +117 -0
- package/dist/esm/activities/embed/index.js +166 -0
- package/dist/esm/activities/embed/index.js.map +1 -0
- package/dist/esm/activities/error-payload.d.ts +8 -0
- package/dist/esm/activities/error-payload.js +29 -17
- package/dist/esm/activities/error-payload.js.map +1 -1
- package/dist/esm/activities/generateAudio/index.d.ts +12 -0
- package/dist/esm/activities/generateAudio/index.js +19 -6
- package/dist/esm/activities/generateAudio/index.js.map +1 -1
- package/dist/esm/activities/generateImage/index.d.ts +12 -0
- package/dist/esm/activities/generateImage/index.js +21 -7
- package/dist/esm/activities/generateImage/index.js.map +1 -1
- package/dist/esm/activities/generateSpeech/index.d.ts +17 -1
- package/dist/esm/activities/generateSpeech/index.js +19 -6
- package/dist/esm/activities/generateSpeech/index.js.map +1 -1
- package/dist/esm/activities/generateTranscription/index.d.ts +17 -1
- package/dist/esm/activities/generateTranscription/index.js +19 -6
- package/dist/esm/activities/generateTranscription/index.js.map +1 -1
- package/dist/esm/activities/generateVideo/index.d.ts +18 -0
- package/dist/esm/activities/generateVideo/index.js +54 -15
- package/dist/esm/activities/generateVideo/index.js.map +1 -1
- package/dist/esm/activities/index.d.ts +8 -2
- package/dist/esm/activities/index.js +11 -7
- package/dist/esm/activities/middleware/types.d.ts +1 -1
- package/dist/esm/activities/rerank/adapter.d.ts +63 -0
- package/dist/esm/activities/rerank/adapter.js +23 -0
- package/dist/esm/activities/rerank/adapter.js.map +1 -0
- package/dist/esm/activities/rerank/index.d.ts +92 -0
- package/dist/esm/activities/rerank/index.js +163 -0
- package/dist/esm/activities/rerank/index.js.map +1 -0
- package/dist/esm/activities/summarize/index.d.ts +17 -1
- package/dist/esm/activities/summarize/index.js +19 -5
- package/dist/esm/activities/summarize/index.js.map +1 -1
- package/dist/esm/index.d.ts +7 -2
- package/dist/esm/index.js +5 -1
- package/dist/esm/middlewares/otel.js +20 -2
- package/dist/esm/middlewares/otel.js.map +1 -1
- package/dist/esm/types.d.ts +195 -0
- package/dist/esm/utilities/activity-abort.d.ts +53 -0
- package/dist/esm/utilities/activity-abort.js +150 -0
- package/dist/esm/utilities/activity-abort.js.map +1 -0
- package/dist/esm/utilities/embedding-input.d.ts +32 -0
- package/dist/esm/utilities/embedding-input.js +61 -0
- package/dist/esm/utilities/embedding-input.js.map +1 -0
- package/package.json +3 -3
- package/src/activities/chat/messages.ts +30 -1
- package/src/activities/embed/adapter.ts +112 -0
- package/src/activities/embed/index.ts +318 -0
- package/src/activities/error-payload.ts +41 -9
- package/src/activities/generateAudio/index.ts +47 -5
- package/src/activities/generateImage/index.ts +48 -5
- package/src/activities/generateSpeech/index.ts +52 -9
- package/src/activities/generateTranscription/index.ts +52 -9
- package/src/activities/generateVideo/index.ts +131 -33
- package/src/activities/index.ts +44 -0
- package/src/activities/middleware/types.ts +2 -0
- package/src/activities/rerank/adapter.ts +90 -0
- package/src/activities/rerank/index.ts +302 -0
- package/src/activities/summarize/index.ts +59 -19
- package/src/index.ts +19 -0
- package/src/middlewares/otel.ts +38 -3
- package/src/types.ts +219 -0
- package/src/utilities/activity-abort.ts +197 -0
- package/src/utilities/embedding-input.ts +83 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared abort/timeout composition for media (and summarize) activities.
|
|
3
|
+
*
|
|
4
|
+
* Callers pass optional `timeout` and/or `abortSignal` on activity options.
|
|
5
|
+
* Core composes them into one effective signal, races the adapter call so a
|
|
6
|
+
* hung provider still rejects, clears timeout resources on settle, and
|
|
7
|
+
* classifies aborts so lifecycle middleware gets `onAbort` rather than
|
|
8
|
+
* `onError`.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Combine two optional AbortSignals into one that aborts when either does.
|
|
12
|
+
* Returns the other signal directly when one is absent or already aborted.
|
|
13
|
+
* First abort wins and preserves its reason.
|
|
14
|
+
*
|
|
15
|
+
* Manual implementation — `AbortSignal.any` requires Node >= 20.3.
|
|
16
|
+
*/
|
|
17
|
+
export declare function combineAbortSignals(a: AbortSignal | undefined, b: AbortSignal | undefined): AbortSignal | undefined;
|
|
18
|
+
/** Normalize an abort reason into an Error the activity can reject with. */
|
|
19
|
+
export declare function toAbortError(reason: unknown): Error;
|
|
20
|
+
export interface ActivityAbortControls {
|
|
21
|
+
/** Effective signal, or `undefined` when neither timeout nor caller signal. */
|
|
22
|
+
signal: AbortSignal | undefined;
|
|
23
|
+
/** Clear the timeout timer if one was set. Idempotent. */
|
|
24
|
+
clear: () => void;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Compose an activity-level timeout with a caller AbortSignal.
|
|
28
|
+
*
|
|
29
|
+
* - No SDK-wide default timeout; omit both for unlimited wait.
|
|
30
|
+
* - First of caller cancellation or timeout wins and keeps its reason.
|
|
31
|
+
* - Call `clear()` when the activity settles (success or failure) so timers
|
|
32
|
+
* do not leak.
|
|
33
|
+
*/
|
|
34
|
+
export declare function createActivityAbortControls(options: {
|
|
35
|
+
abortSignal?: AbortSignal;
|
|
36
|
+
timeout?: number;
|
|
37
|
+
}): ActivityAbortControls;
|
|
38
|
+
/**
|
|
39
|
+
* Reject when `signal` aborts, even if the underlying promise ignores it.
|
|
40
|
+
* Ensures activity-level timeouts work for adapters that do not yet forward
|
|
41
|
+
* the signal to the provider SDK.
|
|
42
|
+
*
|
|
43
|
+
* When the signal wins, the adapter promise is observed with an empty handler
|
|
44
|
+
* so a later settle cannot surface as an unhandled rejection.
|
|
45
|
+
*/
|
|
46
|
+
export declare function raceWithAbort<T>(promise: Promise<T>, signal: AbortSignal | undefined): Promise<T>;
|
|
47
|
+
/**
|
|
48
|
+
* Whether a thrown value (and optional effective signal) should route to
|
|
49
|
+
* middleware `onAbort` instead of `onError`.
|
|
50
|
+
*/
|
|
51
|
+
export declare function isActivityAbortError(error: unknown, signal?: AbortSignal): boolean;
|
|
52
|
+
/** Best-effort string reason for {@link GenerationAbortInfo}. */
|
|
53
|
+
export declare function abortReasonMessage(error: unknown, signal?: AbortSignal): string | undefined;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
//#region src/utilities/activity-abort.ts
|
|
2
|
+
/**
|
|
3
|
+
* Shared abort/timeout composition for media (and summarize) activities.
|
|
4
|
+
*
|
|
5
|
+
* Callers pass optional `timeout` and/or `abortSignal` on activity options.
|
|
6
|
+
* Core composes them into one effective signal, races the adapter call so a
|
|
7
|
+
* hung provider still rejects, clears timeout resources on settle, and
|
|
8
|
+
* classifies aborts so lifecycle middleware gets `onAbort` rather than
|
|
9
|
+
* `onError`.
|
|
10
|
+
*/
|
|
11
|
+
var ABORT_ERROR_NAMES = /* @__PURE__ */ new Set([
|
|
12
|
+
"AbortError",
|
|
13
|
+
"TimeoutError",
|
|
14
|
+
"APIUserAbortError",
|
|
15
|
+
"RequestAbortedError"
|
|
16
|
+
]);
|
|
17
|
+
/**
|
|
18
|
+
* Combine two optional AbortSignals into one that aborts when either does.
|
|
19
|
+
* Returns the other signal directly when one is absent or already aborted.
|
|
20
|
+
* First abort wins and preserves its reason.
|
|
21
|
+
*
|
|
22
|
+
* Manual implementation — `AbortSignal.any` requires Node >= 20.3.
|
|
23
|
+
*/
|
|
24
|
+
function combineAbortSignals(a, b) {
|
|
25
|
+
if (!a) return b;
|
|
26
|
+
if (!b) return a;
|
|
27
|
+
if (a.aborted) return a;
|
|
28
|
+
if (b.aborted) return b;
|
|
29
|
+
const controller = new AbortController();
|
|
30
|
+
const onAbort = (source) => () => {
|
|
31
|
+
controller.abort(source.reason);
|
|
32
|
+
};
|
|
33
|
+
a.addEventListener("abort", onAbort(a), { once: true });
|
|
34
|
+
b.addEventListener("abort", onAbort(b), { once: true });
|
|
35
|
+
return controller.signal;
|
|
36
|
+
}
|
|
37
|
+
function createTimeoutReason(ms) {
|
|
38
|
+
if (typeof DOMException !== "undefined") return new DOMException(`Activity timed out after ${ms}ms`, "TimeoutError");
|
|
39
|
+
const err = /* @__PURE__ */ new Error(`Activity timed out after ${ms}ms`);
|
|
40
|
+
err.name = "TimeoutError";
|
|
41
|
+
return err;
|
|
42
|
+
}
|
|
43
|
+
/** Normalize an abort reason into an Error the activity can reject with. */
|
|
44
|
+
function toAbortError(reason) {
|
|
45
|
+
if (reason instanceof Error) return reason;
|
|
46
|
+
if (typeof reason === "string" && reason.length > 0) {
|
|
47
|
+
const err = new Error(reason);
|
|
48
|
+
err.name = "AbortError";
|
|
49
|
+
return err;
|
|
50
|
+
}
|
|
51
|
+
const err = /* @__PURE__ */ new Error("The operation was aborted");
|
|
52
|
+
err.name = "AbortError";
|
|
53
|
+
return err;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Compose an activity-level timeout with a caller AbortSignal.
|
|
57
|
+
*
|
|
58
|
+
* - No SDK-wide default timeout; omit both for unlimited wait.
|
|
59
|
+
* - First of caller cancellation or timeout wins and keeps its reason.
|
|
60
|
+
* - Call `clear()` when the activity settles (success or failure) so timers
|
|
61
|
+
* do not leak.
|
|
62
|
+
*/
|
|
63
|
+
function createActivityAbortControls(options) {
|
|
64
|
+
let timeoutId;
|
|
65
|
+
let timeoutSignal;
|
|
66
|
+
if (options.timeout !== void 0) {
|
|
67
|
+
if (!Number.isFinite(options.timeout) || options.timeout < 0) throw new Error(`Invalid activity timeout: expected a non-negative finite number, got ${String(options.timeout)}`);
|
|
68
|
+
const controller = new AbortController();
|
|
69
|
+
timeoutSignal = controller.signal;
|
|
70
|
+
const ms = options.timeout;
|
|
71
|
+
timeoutId = setTimeout(() => {
|
|
72
|
+
controller.abort(createTimeoutReason(ms));
|
|
73
|
+
}, ms);
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
signal: combineAbortSignals(options.abortSignal, timeoutSignal),
|
|
77
|
+
clear: () => {
|
|
78
|
+
if (timeoutId !== void 0) {
|
|
79
|
+
clearTimeout(timeoutId);
|
|
80
|
+
timeoutId = void 0;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Reject when `signal` aborts, even if the underlying promise ignores it.
|
|
87
|
+
* Ensures activity-level timeouts work for adapters that do not yet forward
|
|
88
|
+
* the signal to the provider SDK.
|
|
89
|
+
*
|
|
90
|
+
* When the signal wins, the adapter promise is observed with an empty handler
|
|
91
|
+
* so a later settle cannot surface as an unhandled rejection.
|
|
92
|
+
*/
|
|
93
|
+
function raceWithAbort(promise, signal) {
|
|
94
|
+
if (!signal) return promise;
|
|
95
|
+
const swallow = () => {
|
|
96
|
+
promise.then(() => void 0, () => void 0);
|
|
97
|
+
};
|
|
98
|
+
if (signal.aborted) {
|
|
99
|
+
swallow();
|
|
100
|
+
return Promise.reject(toAbortError(signal.reason));
|
|
101
|
+
}
|
|
102
|
+
return new Promise((resolve, reject) => {
|
|
103
|
+
let settled = false;
|
|
104
|
+
const onAbort = () => {
|
|
105
|
+
if (settled) return;
|
|
106
|
+
settled = true;
|
|
107
|
+
cleanup();
|
|
108
|
+
swallow();
|
|
109
|
+
reject(toAbortError(signal.reason));
|
|
110
|
+
};
|
|
111
|
+
const cleanup = () => {
|
|
112
|
+
signal.removeEventListener("abort", onAbort);
|
|
113
|
+
};
|
|
114
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
115
|
+
promise.then((value) => {
|
|
116
|
+
if (settled) return;
|
|
117
|
+
settled = true;
|
|
118
|
+
cleanup();
|
|
119
|
+
resolve(value);
|
|
120
|
+
}, (error) => {
|
|
121
|
+
if (settled) return;
|
|
122
|
+
settled = true;
|
|
123
|
+
cleanup();
|
|
124
|
+
reject(error);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Whether a thrown value (and optional effective signal) should route to
|
|
130
|
+
* middleware `onAbort` instead of `onError`.
|
|
131
|
+
*/
|
|
132
|
+
function isActivityAbortError(error, signal) {
|
|
133
|
+
if (signal?.aborted) return true;
|
|
134
|
+
if (!error || typeof error !== "object") return false;
|
|
135
|
+
const name = error.name;
|
|
136
|
+
return typeof name === "string" && ABORT_ERROR_NAMES.has(name);
|
|
137
|
+
}
|
|
138
|
+
/** Best-effort string reason for {@link GenerationAbortInfo}. */
|
|
139
|
+
function abortReasonMessage(error, signal) {
|
|
140
|
+
if (signal?.reason !== void 0) {
|
|
141
|
+
if (typeof signal.reason === "string") return signal.reason;
|
|
142
|
+
if (signal.reason instanceof Error) return signal.reason.message;
|
|
143
|
+
}
|
|
144
|
+
if (error instanceof Error) return error.message;
|
|
145
|
+
if (typeof error === "string") return error;
|
|
146
|
+
}
|
|
147
|
+
//#endregion
|
|
148
|
+
export { abortReasonMessage, combineAbortSignals, createActivityAbortControls, isActivityAbortError, raceWithAbort, toAbortError };
|
|
149
|
+
|
|
150
|
+
//# sourceMappingURL=activity-abort.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity-abort.js","names":[],"sources":["../../../src/utilities/activity-abort.ts"],"sourcesContent":["/**\n * Shared abort/timeout composition for media (and summarize) activities.\n *\n * Callers pass optional `timeout` and/or `abortSignal` on activity options.\n * Core composes them into one effective signal, races the adapter call so a\n * hung provider still rejects, clears timeout resources on settle, and\n * classifies aborts so lifecycle middleware gets `onAbort` rather than\n * `onError`.\n */\n\nconst ABORT_ERROR_NAMES = new Set([\n 'AbortError',\n 'TimeoutError',\n 'APIUserAbortError',\n 'RequestAbortedError',\n])\n\n/**\n * Combine two optional AbortSignals into one that aborts when either does.\n * Returns the other signal directly when one is absent or already aborted.\n * First abort wins and preserves its reason.\n *\n * Manual implementation — `AbortSignal.any` requires Node >= 20.3.\n */\nexport function combineAbortSignals(\n a: AbortSignal | undefined,\n b: AbortSignal | undefined,\n): AbortSignal | undefined {\n if (!a) return b\n if (!b) return a\n if (a.aborted) return a\n if (b.aborted) return b\n const controller = new AbortController()\n const onAbort = (source: AbortSignal) => () => {\n controller.abort(source.reason)\n }\n a.addEventListener('abort', onAbort(a), { once: true })\n b.addEventListener('abort', onAbort(b), { once: true })\n return controller.signal\n}\n\nfunction createTimeoutReason(ms: number): Error {\n if (typeof DOMException !== 'undefined') {\n return new DOMException(`Activity timed out after ${ms}ms`, 'TimeoutError')\n }\n const err = new Error(`Activity timed out after ${ms}ms`)\n err.name = 'TimeoutError'\n return err\n}\n\n/** Normalize an abort reason into an Error the activity can reject with. */\nexport function toAbortError(reason: unknown): Error {\n if (reason instanceof Error) return reason\n if (typeof reason === 'string' && reason.length > 0) {\n const err = new Error(reason)\n err.name = 'AbortError'\n return err\n }\n const err = new Error('The operation was aborted')\n err.name = 'AbortError'\n return err\n}\n\nexport interface ActivityAbortControls {\n /** Effective signal, or `undefined` when neither timeout nor caller signal. */\n signal: AbortSignal | undefined\n /** Clear the timeout timer if one was set. Idempotent. */\n clear: () => void\n}\n\n/**\n * Compose an activity-level timeout with a caller AbortSignal.\n *\n * - No SDK-wide default timeout; omit both for unlimited wait.\n * - First of caller cancellation or timeout wins and keeps its reason.\n * - Call `clear()` when the activity settles (success or failure) so timers\n * do not leak.\n */\nexport function createActivityAbortControls(options: {\n abortSignal?: AbortSignal\n timeout?: number\n}): ActivityAbortControls {\n let timeoutId: ReturnType<typeof setTimeout> | undefined\n let timeoutSignal: AbortSignal | undefined\n\n if (options.timeout !== undefined) {\n if (!Number.isFinite(options.timeout) || options.timeout < 0) {\n throw new Error(\n `Invalid activity timeout: expected a non-negative finite number, got ${String(options.timeout)}`,\n )\n }\n const controller = new AbortController()\n timeoutSignal = controller.signal\n const ms = options.timeout\n timeoutId = setTimeout(() => {\n controller.abort(createTimeoutReason(ms))\n }, ms)\n }\n\n const signal = combineAbortSignals(options.abortSignal, timeoutSignal)\n\n return {\n signal,\n clear: () => {\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId)\n timeoutId = undefined\n }\n },\n }\n}\n\n/**\n * Reject when `signal` aborts, even if the underlying promise ignores it.\n * Ensures activity-level timeouts work for adapters that do not yet forward\n * the signal to the provider SDK.\n *\n * When the signal wins, the adapter promise is observed with an empty handler\n * so a later settle cannot surface as an unhandled rejection.\n */\nexport function raceWithAbort<T>(\n promise: Promise<T>,\n signal: AbortSignal | undefined,\n): Promise<T> {\n if (!signal) return promise\n\n const swallow = () => {\n // Observe the adapter promise without acting on its outcome so a late\n // reject after we already aborted cannot become an unhandled rejection.\n promise.then(\n () => undefined,\n () => undefined,\n )\n }\n\n if (signal.aborted) {\n swallow()\n return Promise.reject(toAbortError(signal.reason))\n }\n\n return new Promise<T>((resolve, reject) => {\n let settled = false\n const onAbort = () => {\n if (settled) return\n settled = true\n cleanup()\n swallow()\n reject(toAbortError(signal.reason))\n }\n const cleanup = () => {\n signal.removeEventListener('abort', onAbort)\n }\n signal.addEventListener('abort', onAbort, { once: true })\n promise.then(\n (value) => {\n if (settled) return\n settled = true\n cleanup()\n resolve(value)\n },\n (error: unknown) => {\n if (settled) return\n settled = true\n cleanup()\n reject(error)\n },\n )\n })\n}\n\n/**\n * Whether a thrown value (and optional effective signal) should route to\n * middleware `onAbort` instead of `onError`.\n */\nexport function isActivityAbortError(\n error: unknown,\n signal?: AbortSignal,\n): boolean {\n if (signal?.aborted) return true\n if (!error || typeof error !== 'object') return false\n const name = (error as { name?: unknown }).name\n return typeof name === 'string' && ABORT_ERROR_NAMES.has(name)\n}\n\n/** Best-effort string reason for {@link GenerationAbortInfo}. */\nexport function abortReasonMessage(\n error: unknown,\n signal?: AbortSignal,\n): string | undefined {\n if (signal?.reason !== undefined) {\n if (typeof signal.reason === 'string') return signal.reason\n if (signal.reason instanceof Error) return signal.reason.message\n }\n if (error instanceof Error) return error.message\n if (typeof error === 'string') return error\n return undefined\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { EmbeddingInputItem, ImagePart } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* One embedding input item resolved into its text and image constituents.
|
|
4
|
+
* Produced by {@link resolveEmbeddingInput}; adapters map each entry onto
|
|
5
|
+
* one provider-native input (one vector per entry).
|
|
6
|
+
*/
|
|
7
|
+
export interface ResolvedEmbeddingItem {
|
|
8
|
+
/** Text contents of the item, in order (empty for image-only items) */
|
|
9
|
+
texts: Array<string>;
|
|
10
|
+
/** Image parts of the item, in order (empty for text-only items) */
|
|
11
|
+
images: Array<ImagePart>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Resolve each embedding input item into its text and image constituents,
|
|
15
|
+
* preserving input order (result[i] corresponds to input[i] and to the
|
|
16
|
+
* vector at index i).
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolveEmbeddingInput(input: Array<EmbeddingInputItem>): Array<ResolvedEmbeddingItem>;
|
|
19
|
+
/**
|
|
20
|
+
* Extract plain text inputs for a text-only embedding model, throwing a
|
|
21
|
+
* uniform error if any item carries an image. The per-model modality typing
|
|
22
|
+
* rejects these at compile time; this guard covers untyped/dynamic callers.
|
|
23
|
+
*/
|
|
24
|
+
export declare function requireTextOnlyEmbeddingInput(input: Array<EmbeddingInputItem>, provider: string, model: string): Array<string>;
|
|
25
|
+
/**
|
|
26
|
+
* Count text-only and image-carrying items for observability events. Never
|
|
27
|
+
* exposes input content.
|
|
28
|
+
*/
|
|
29
|
+
export declare function countEmbeddingInputModalities(input: Array<EmbeddingInputItem>): {
|
|
30
|
+
textInputCount: number;
|
|
31
|
+
imageInputCount: number;
|
|
32
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
//#region src/utilities/embedding-input.ts
|
|
2
|
+
function resolveItem(item) {
|
|
3
|
+
if (typeof item === "string") return {
|
|
4
|
+
texts: [item],
|
|
5
|
+
images: []
|
|
6
|
+
};
|
|
7
|
+
if (Array.isArray(item)) {
|
|
8
|
+
const resolved = {
|
|
9
|
+
texts: [],
|
|
10
|
+
images: []
|
|
11
|
+
};
|
|
12
|
+
for (const part of item) if (part.type === "text") resolved.texts.push(part.content);
|
|
13
|
+
else resolved.images.push(part);
|
|
14
|
+
return resolved;
|
|
15
|
+
}
|
|
16
|
+
if (item.type === "text") return {
|
|
17
|
+
texts: [item.content],
|
|
18
|
+
images: []
|
|
19
|
+
};
|
|
20
|
+
return {
|
|
21
|
+
texts: [],
|
|
22
|
+
images: [item]
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Resolve each embedding input item into its text and image constituents,
|
|
27
|
+
* preserving input order (result[i] corresponds to input[i] and to the
|
|
28
|
+
* vector at index i).
|
|
29
|
+
*/
|
|
30
|
+
function resolveEmbeddingInput(input) {
|
|
31
|
+
return input.map(resolveItem);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Extract plain text inputs for a text-only embedding model, throwing a
|
|
35
|
+
* uniform error if any item carries an image. The per-model modality typing
|
|
36
|
+
* rejects these at compile time; this guard covers untyped/dynamic callers.
|
|
37
|
+
*/
|
|
38
|
+
function requireTextOnlyEmbeddingInput(input, provider, model) {
|
|
39
|
+
return resolveEmbeddingInput(input).map((item, index) => {
|
|
40
|
+
if (item.images.length > 0) throw new Error(`${provider} model "${model}" only supports text embedding inputs; input item at index ${index} contains an image part`);
|
|
41
|
+
return item.texts.join("\n");
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Count text-only and image-carrying items for observability events. Never
|
|
46
|
+
* exposes input content.
|
|
47
|
+
*/
|
|
48
|
+
function countEmbeddingInputModalities(input) {
|
|
49
|
+
let textInputCount = 0;
|
|
50
|
+
let imageInputCount = 0;
|
|
51
|
+
for (const item of resolveEmbeddingInput(input)) if (item.images.length > 0) imageInputCount++;
|
|
52
|
+
else textInputCount++;
|
|
53
|
+
return {
|
|
54
|
+
textInputCount,
|
|
55
|
+
imageInputCount
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
export { countEmbeddingInputModalities, requireTextOnlyEmbeddingInput, resolveEmbeddingInput };
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=embedding-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding-input.js","names":[],"sources":["../../../src/utilities/embedding-input.ts"],"sourcesContent":["import type { EmbeddingInputItem, ImagePart } from '../types'\n\n/**\n * One embedding input item resolved into its text and image constituents.\n * Produced by {@link resolveEmbeddingInput}; adapters map each entry onto\n * one provider-native input (one vector per entry).\n */\nexport interface ResolvedEmbeddingItem {\n /** Text contents of the item, in order (empty for image-only items) */\n texts: Array<string>\n /** Image parts of the item, in order (empty for text-only items) */\n images: Array<ImagePart>\n}\n\nfunction resolveItem(item: EmbeddingInputItem): ResolvedEmbeddingItem {\n if (typeof item === 'string') {\n return { texts: [item], images: [] }\n }\n // A nested array is a fused item: its parts embed together into one vector.\n if (Array.isArray(item)) {\n const resolved: ResolvedEmbeddingItem = { texts: [], images: [] }\n for (const part of item) {\n if (part.type === 'text') {\n resolved.texts.push(part.content)\n } else {\n resolved.images.push(part)\n }\n }\n return resolved\n }\n if (item.type === 'text') {\n return { texts: [item.content], images: [] }\n }\n return { texts: [], images: [item] }\n}\n\n/**\n * Resolve each embedding input item into its text and image constituents,\n * preserving input order (result[i] corresponds to input[i] and to the\n * vector at index i).\n */\nexport function resolveEmbeddingInput(\n input: Array<EmbeddingInputItem>,\n): Array<ResolvedEmbeddingItem> {\n return input.map(resolveItem)\n}\n\n/**\n * Extract plain text inputs for a text-only embedding model, throwing a\n * uniform error if any item carries an image. The per-model modality typing\n * rejects these at compile time; this guard covers untyped/dynamic callers.\n */\nexport function requireTextOnlyEmbeddingInput(\n input: Array<EmbeddingInputItem>,\n provider: string,\n model: string,\n): Array<string> {\n return resolveEmbeddingInput(input).map((item, index) => {\n if (item.images.length > 0) {\n throw new Error(\n `${provider} model \"${model}\" only supports text embedding inputs; ` +\n `input item at index ${index} contains an image part`,\n )\n }\n return item.texts.join('\\n')\n })\n}\n\n/**\n * Count text-only and image-carrying items for observability events. Never\n * exposes input content.\n */\nexport function countEmbeddingInputModalities(\n input: Array<EmbeddingInputItem>,\n): { textInputCount: number; imageInputCount: number } {\n let textInputCount = 0\n let imageInputCount = 0\n for (const item of resolveEmbeddingInput(input)) {\n if (item.images.length > 0) imageInputCount++\n else textInputCount++\n }\n return { textInputCount, imageInputCount }\n}\n"],"mappings":";AAcA,SAAS,YAAY,MAAiD;CACpE,IAAI,OAAO,SAAS,UAClB,OAAO;EAAE,OAAO,CAAC,IAAI;EAAG,QAAQ,CAAC;CAAE;CAGrC,IAAI,MAAM,QAAQ,IAAI,GAAG;EACvB,MAAM,WAAkC;GAAE,OAAO,CAAC;GAAG,QAAQ,CAAC;EAAE;EAChE,KAAK,MAAM,QAAQ,MACjB,IAAI,KAAK,SAAS,QAChB,SAAS,MAAM,KAAK,KAAK,OAAO;OAEhC,SAAS,OAAO,KAAK,IAAI;EAG7B,OAAO;CACT;CACA,IAAI,KAAK,SAAS,QAChB,OAAO;EAAE,OAAO,CAAC,KAAK,OAAO;EAAG,QAAQ,CAAC;CAAE;CAE7C,OAAO;EAAE,OAAO,CAAC;EAAG,QAAQ,CAAC,IAAI;CAAE;AACrC;;;;;;AAOA,SAAgB,sBACd,OAC8B;CAC9B,OAAO,MAAM,IAAI,WAAW;AAC9B;;;;;;AAOA,SAAgB,8BACd,OACA,UACA,OACe;CACf,OAAO,sBAAsB,KAAK,CAAC,CAAC,KAAK,MAAM,UAAU;EACvD,IAAI,KAAK,OAAO,SAAS,GACvB,MAAM,IAAI,MACR,GAAG,SAAS,UAAU,MAAM,6DACH,MAAM,wBACjC;EAEF,OAAO,KAAK,MAAM,KAAK,IAAI;CAC7B,CAAC;AACH;;;;;AAMA,SAAgB,8BACd,OACqD;CACrD,IAAI,iBAAiB;CACrB,IAAI,kBAAkB;CACtB,KAAK,MAAM,QAAQ,sBAAsB,KAAK,GAC5C,IAAI,KAAK,OAAO,SAAS,GAAG;MACvB;CAEP,OAAO;EAAE;EAAgB;CAAgB;AAC3C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/ai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.44.0",
|
|
4
4
|
"description": "Type-safe TypeScript AI SDK for streaming chat, tool calling, agents, structured outputs, and multimodal generation.",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -80,8 +80,8 @@
|
|
|
80
80
|
"@ag-ui/core": "0.1.1-canary.beta.0",
|
|
81
81
|
"@standard-schema/spec": "^1.1.0",
|
|
82
82
|
"partial-json": "^0.1.7",
|
|
83
|
-
"@tanstack/ai-event-client": "0.
|
|
84
|
-
"@tanstack/ai-utils": "0.4.0"
|
|
83
|
+
"@tanstack/ai-event-client": "^0.8.0",
|
|
84
|
+
"@tanstack/ai-utils": "^0.4.0"
|
|
85
85
|
},
|
|
86
86
|
"peerDependencies": {
|
|
87
87
|
"@opentelemetry/api": ">=1.9.0"
|
|
@@ -184,8 +184,12 @@ function buildUserOrToolMessage(uiMessage: UIMessage): ModelMessage {
|
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
return {
|
|
187
|
+
id: uiMessage.id,
|
|
187
188
|
role: uiMessage.role as 'user' | 'assistant' | 'tool',
|
|
188
189
|
content: collapseContentParts(contentParts),
|
|
190
|
+
...(uiMessage.createdAt !== undefined && {
|
|
191
|
+
createdAt: uiMessage.createdAt,
|
|
192
|
+
}),
|
|
189
193
|
}
|
|
190
194
|
}
|
|
191
195
|
|
|
@@ -228,6 +232,8 @@ function isToolCallIncluded(part: ToolCallPart): boolean {
|
|
|
228
232
|
* result is emitted as a tool message.
|
|
229
233
|
*/
|
|
230
234
|
function buildAssistantMessages(uiMessage: UIMessage): Array<ModelMessage> {
|
|
235
|
+
// A single UI message can fan out into several model messages. Keep the
|
|
236
|
+
// shared UI id on each one so persistence can retain the original identity.
|
|
231
237
|
const messageList: Array<ModelMessage> = []
|
|
232
238
|
let current = createSegment()
|
|
233
239
|
let pendingThinking: Array<{ content: string; signature?: string }> = []
|
|
@@ -244,10 +250,14 @@ function buildAssistantMessages(uiMessage: UIMessage): Array<ModelMessage> {
|
|
|
244
250
|
|
|
245
251
|
if (hasContent || hasToolCalls) {
|
|
246
252
|
messageList.push({
|
|
253
|
+
id: uiMessage.id,
|
|
247
254
|
role: 'assistant',
|
|
248
255
|
content,
|
|
249
256
|
...(hasToolCalls && { toolCalls: current.toolCalls }),
|
|
250
257
|
...(pendingThinking.length > 0 && { thinking: pendingThinking }),
|
|
258
|
+
...(uiMessage.createdAt !== undefined && {
|
|
259
|
+
createdAt: uiMessage.createdAt,
|
|
260
|
+
}),
|
|
251
261
|
})
|
|
252
262
|
pendingThinking = []
|
|
253
263
|
}
|
|
@@ -288,9 +298,13 @@ function buildAssistantMessages(uiMessage: UIMessage): Array<ModelMessage> {
|
|
|
288
298
|
!emittedToolResultIds.has(part.toolCallId)
|
|
289
299
|
) {
|
|
290
300
|
messageList.push({
|
|
301
|
+
id: uiMessage.id,
|
|
291
302
|
role: 'tool',
|
|
292
303
|
content: part.content,
|
|
293
304
|
toolCallId: part.toolCallId,
|
|
305
|
+
...(uiMessage.createdAt !== undefined && {
|
|
306
|
+
createdAt: uiMessage.createdAt,
|
|
307
|
+
}),
|
|
294
308
|
})
|
|
295
309
|
emittedToolResultIds.add(part.toolCallId)
|
|
296
310
|
}
|
|
@@ -347,9 +361,13 @@ function buildAssistantMessages(uiMessage: UIMessage): Array<ModelMessage> {
|
|
|
347
361
|
// emit the concrete output regardless of approval metadata.
|
|
348
362
|
if (part.output !== undefined && !emittedToolResultIds.has(part.id)) {
|
|
349
363
|
messageList.push({
|
|
364
|
+
id: uiMessage.id,
|
|
350
365
|
role: 'tool',
|
|
351
366
|
content: normalizeToolResult(part.output),
|
|
352
367
|
toolCallId: part.id,
|
|
368
|
+
...(uiMessage.createdAt !== undefined && {
|
|
369
|
+
createdAt: uiMessage.createdAt,
|
|
370
|
+
}),
|
|
353
371
|
})
|
|
354
372
|
emittedToolResultIds.add(part.id)
|
|
355
373
|
}
|
|
@@ -363,6 +381,7 @@ function buildAssistantMessages(uiMessage: UIMessage): Array<ModelMessage> {
|
|
|
363
381
|
) {
|
|
364
382
|
const approved = part.approval.approved
|
|
365
383
|
messageList.push({
|
|
384
|
+
id: uiMessage.id,
|
|
366
385
|
role: 'tool',
|
|
367
386
|
content: JSON.stringify({
|
|
368
387
|
approved,
|
|
@@ -372,6 +391,9 @@ function buildAssistantMessages(uiMessage: UIMessage): Array<ModelMessage> {
|
|
|
372
391
|
: 'User denied this action',
|
|
373
392
|
}),
|
|
374
393
|
toolCallId: part.id,
|
|
394
|
+
...(uiMessage.createdAt !== undefined && {
|
|
395
|
+
createdAt: uiMessage.createdAt,
|
|
396
|
+
}),
|
|
375
397
|
})
|
|
376
398
|
emittedToolResultIds.add(part.id)
|
|
377
399
|
}
|
|
@@ -380,8 +402,12 @@ function buildAssistantMessages(uiMessage: UIMessage): Array<ModelMessage> {
|
|
|
380
402
|
// If no messages were produced (e.g., empty parts), emit a minimal assistant message
|
|
381
403
|
if (messageList.length === 0) {
|
|
382
404
|
messageList.push({
|
|
405
|
+
id: uiMessage.id,
|
|
383
406
|
role: 'assistant',
|
|
384
407
|
content: null,
|
|
408
|
+
...(uiMessage.createdAt !== undefined && {
|
|
409
|
+
createdAt: uiMessage.createdAt,
|
|
410
|
+
}),
|
|
385
411
|
})
|
|
386
412
|
}
|
|
387
413
|
|
|
@@ -469,6 +495,9 @@ export function modelMessageToUIMessage(
|
|
|
469
495
|
id: id || generateMessageId(),
|
|
470
496
|
role: modelMessage.role === 'tool' ? 'assistant' : modelMessage.role,
|
|
471
497
|
parts,
|
|
498
|
+
...(modelMessage.createdAt !== undefined && {
|
|
499
|
+
createdAt: modelMessage.createdAt,
|
|
500
|
+
}),
|
|
472
501
|
}
|
|
473
502
|
}
|
|
474
503
|
|
|
@@ -659,7 +688,7 @@ export function normalizeToUIMessage(
|
|
|
659
688
|
// ModelMessage - convert to UIMessage
|
|
660
689
|
return {
|
|
661
690
|
...modelMessageToUIMessage(message, generateId()),
|
|
662
|
-
createdAt: new Date(),
|
|
691
|
+
createdAt: message.createdAt ?? new Date(),
|
|
663
692
|
}
|
|
664
693
|
}
|
|
665
694
|
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
EmbeddingModelInputModalitiesByName,
|
|
3
|
+
EmbeddingOptions,
|
|
4
|
+
EmbeddingResult,
|
|
5
|
+
} from '../../types'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Configuration for embedding adapter instances
|
|
9
|
+
*/
|
|
10
|
+
export interface EmbeddingAdapterConfig {
|
|
11
|
+
apiKey?: string
|
|
12
|
+
baseUrl?: string
|
|
13
|
+
timeout?: number
|
|
14
|
+
maxRetries?: number
|
|
15
|
+
headers?: Record<string, string>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Embedding adapter interface with pre-resolved generics.
|
|
20
|
+
*
|
|
21
|
+
* An adapter is created by a provider function: `provider('model')` → `adapter`
|
|
22
|
+
* All type resolution happens at the provider call site, not in this interface.
|
|
23
|
+
*
|
|
24
|
+
* Generic parameters:
|
|
25
|
+
* - TModel: The specific model name (e.g., 'text-embedding-3-small')
|
|
26
|
+
* - TProviderOptions: Base provider-specific options (already resolved)
|
|
27
|
+
* - TModelProviderOptionsByName: Map from model name to its specific provider options
|
|
28
|
+
* - TModelInputModalitiesByName: Map from model name to the input modalities it
|
|
29
|
+
* accepts (constrains the `input` item types at compile time)
|
|
30
|
+
*/
|
|
31
|
+
export interface EmbeddingAdapter<
|
|
32
|
+
TModel extends string = string,
|
|
33
|
+
TProviderOptions extends object = Record<string, unknown>,
|
|
34
|
+
TModelProviderOptionsByName extends Record<string, any> = Record<string, any>,
|
|
35
|
+
TModelInputModalitiesByName extends EmbeddingModelInputModalitiesByName =
|
|
36
|
+
EmbeddingModelInputModalitiesByName,
|
|
37
|
+
> {
|
|
38
|
+
/** Discriminator for adapter kind */
|
|
39
|
+
readonly kind: 'embedding'
|
|
40
|
+
/** Adapter name identifier */
|
|
41
|
+
readonly name: string
|
|
42
|
+
/** The model this adapter is configured for */
|
|
43
|
+
readonly model: TModel
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* @internal Type-only properties for inference. Not assigned at runtime.
|
|
47
|
+
*/
|
|
48
|
+
'~types': {
|
|
49
|
+
providerOptions: TProviderOptions
|
|
50
|
+
modelProviderOptionsByName: TModelProviderOptionsByName
|
|
51
|
+
modelInputModalitiesByName: TModelInputModalitiesByName
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Generate embeddings for the input items (one vector per item)
|
|
56
|
+
*/
|
|
57
|
+
createEmbeddings: (
|
|
58
|
+
options: EmbeddingOptions<TProviderOptions>,
|
|
59
|
+
) => Promise<EmbeddingResult>
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* An EmbeddingAdapter with any/unknown type parameters.
|
|
64
|
+
* Useful as a constraint in generic functions and interfaces.
|
|
65
|
+
*/
|
|
66
|
+
export type AnyEmbeddingAdapter = EmbeddingAdapter<any, any, any, any>
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Abstract base class for embedding adapters.
|
|
70
|
+
* Extend this class to implement an embedding adapter for a specific provider.
|
|
71
|
+
*
|
|
72
|
+
* Generic parameters match EmbeddingAdapter - all pre-resolved by the provider function.
|
|
73
|
+
*/
|
|
74
|
+
export abstract class BaseEmbeddingAdapter<
|
|
75
|
+
TModel extends string = string,
|
|
76
|
+
TProviderOptions extends object = Record<string, unknown>,
|
|
77
|
+
TModelProviderOptionsByName extends Record<string, any> = Record<string, any>,
|
|
78
|
+
TModelInputModalitiesByName extends EmbeddingModelInputModalitiesByName =
|
|
79
|
+
EmbeddingModelInputModalitiesByName,
|
|
80
|
+
> implements EmbeddingAdapter<
|
|
81
|
+
TModel,
|
|
82
|
+
TProviderOptions,
|
|
83
|
+
TModelProviderOptionsByName,
|
|
84
|
+
TModelInputModalitiesByName
|
|
85
|
+
> {
|
|
86
|
+
readonly kind = 'embedding' as const
|
|
87
|
+
abstract readonly name: string
|
|
88
|
+
readonly model: TModel
|
|
89
|
+
|
|
90
|
+
// Type-only property - never assigned at runtime
|
|
91
|
+
declare '~types': {
|
|
92
|
+
providerOptions: TProviderOptions
|
|
93
|
+
modelProviderOptionsByName: TModelProviderOptionsByName
|
|
94
|
+
modelInputModalitiesByName: TModelInputModalitiesByName
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
protected config: EmbeddingAdapterConfig
|
|
98
|
+
|
|
99
|
+
constructor(model: TModel, config: EmbeddingAdapterConfig = {}) {
|
|
100
|
+
this.config = config
|
|
101
|
+
this.model = model
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
abstract createEmbeddings(
|
|
105
|
+
options: EmbeddingOptions<TProviderOptions>,
|
|
106
|
+
): Promise<EmbeddingResult>
|
|
107
|
+
|
|
108
|
+
protected generateId(prefix?: string): string {
|
|
109
|
+
const p = prefix ?? this.name
|
|
110
|
+
return `${p}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
|
|
111
|
+
}
|
|
112
|
+
}
|