@tanstack/ai 0.58.0 → 0.61.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/adapter.d.ts +9 -0
- package/dist/esm/activities/chat/adapter.js +1 -0
- package/dist/esm/activities/chat/adapter.js.map +1 -1
- package/dist/esm/activities/chat/agents/define-agent.d.ts +81 -0
- package/dist/esm/activities/chat/agents/define-agent.js +34 -0
- package/dist/esm/activities/chat/agents/define-agent.js.map +1 -0
- package/dist/esm/activities/chat/agents/route.d.ts +53 -0
- package/dist/esm/activities/chat/agents/route.js +59 -0
- package/dist/esm/activities/chat/agents/route.js.map +1 -0
- package/dist/esm/activities/chat/agents/spawn.d.ts +124 -0
- package/dist/esm/activities/chat/agents/spawn.js +490 -0
- package/dist/esm/activities/chat/agents/spawn.js.map +1 -0
- package/dist/esm/activities/chat/agents/turn.d.ts +36 -0
- package/dist/esm/activities/chat/agents/turn.js +78 -0
- package/dist/esm/activities/chat/agents/turn.js.map +1 -0
- package/dist/esm/activities/chat/index.d.ts +13 -3
- package/dist/esm/activities/chat/index.js +462 -26
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/messages.d.ts +7 -1
- package/dist/esm/activities/chat/messages.js +99 -19
- package/dist/esm/activities/chat/messages.js.map +1 -1
- package/dist/esm/activities/chat/middleware/run-store.d.ts +43 -7
- package/dist/esm/activities/chat/middleware/run-store.js +8 -1
- package/dist/esm/activities/chat/middleware/run-store.js.map +1 -1
- package/dist/esm/activities/chat/middleware/types.d.ts +47 -1
- package/dist/esm/activities/chat/middleware/types.js.map +1 -1
- package/dist/esm/activities/chat/stream/message-updaters.js +9 -2
- package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
- package/dist/esm/activities/chat/stream/processor.d.ts +46 -1
- package/dist/esm/activities/chat/stream/processor.js +294 -18
- package/dist/esm/activities/chat/stream/processor.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-calls.d.ts +17 -3
- package/dist/esm/activities/chat/tools/tool-calls.js +56 -5
- package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
- package/dist/esm/activities/embed/adapter.d.ts +7 -0
- package/dist/esm/activities/embed/adapter.js +1 -0
- package/dist/esm/activities/embed/adapter.js.map +1 -1
- package/dist/esm/activities/embed/index.js +2 -0
- package/dist/esm/activities/embed/index.js.map +1 -1
- package/dist/esm/activities/files/adapter.d.ts +97 -0
- package/dist/esm/activities/files/adapter.js +45 -0
- package/dist/esm/activities/files/adapter.js.map +1 -0
- package/dist/esm/activities/files/index.d.ts +66 -0
- package/dist/esm/activities/files/index.js +78 -0
- package/dist/esm/activities/files/index.js.map +1 -0
- package/dist/esm/activities/generateAudio/index.js +1 -1
- package/dist/esm/activities/generateImage/adapter.d.ts +8 -0
- package/dist/esm/activities/generateImage/adapter.js +1 -0
- package/dist/esm/activities/generateImage/adapter.js.map +1 -1
- package/dist/esm/activities/generateImage/index.js +3 -1
- package/dist/esm/activities/generateImage/index.js.map +1 -1
- package/dist/esm/activities/generateLiveVideo/index.js +1 -1
- package/dist/esm/activities/generateSpeech/index.js +1 -1
- package/dist/esm/activities/generateTranscription/index.js +1 -1
- package/dist/esm/activities/generateVideo/adapter.d.ts +8 -0
- package/dist/esm/activities/generateVideo/adapter.js +1 -0
- package/dist/esm/activities/generateVideo/adapter.js.map +1 -1
- package/dist/esm/activities/generateVideo/index.js +3 -0
- package/dist/esm/activities/generateVideo/index.js.map +1 -1
- package/dist/esm/activities/generateVoice/index.js +1 -1
- package/dist/esm/activities/generateWorld/adapter.d.ts +4 -2
- package/dist/esm/activities/generateWorld/adapter.js.map +1 -1
- package/dist/esm/activities/generateWorld/index.d.ts +4 -3
- package/dist/esm/activities/generateWorld/index.js +6 -5
- package/dist/esm/activities/generateWorld/index.js.map +1 -1
- package/dist/esm/activities/index.d.ts +9 -3
- package/dist/esm/activities/index.js +17 -13
- package/dist/esm/activities/summarize/chat-stream-summarize.d.ts +2 -0
- package/dist/esm/activities/summarize/chat-stream-summarize.js +8 -8
- package/dist/esm/activities/summarize/chat-stream-summarize.js.map +1 -1
- package/dist/esm/activities/summarize/index.js +1 -1
- package/dist/esm/client.d.ts +7 -36
- package/dist/esm/client.js +5 -37
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/index.d.ts +8 -2
- package/dist/esm/index.js +9 -4
- package/dist/esm/middlewares/content-guard.js.map +1 -1
- package/dist/esm/types.d.ts +179 -98
- package/dist/esm/utilities/adapter-yield-chunk.d.ts +5 -1
- package/dist/esm/utilities/ag-ui-usage.d.ts +9 -9
- package/dist/esm/utilities/ag-ui-usage.js +66 -3
- package/dist/esm/utilities/ag-ui-usage.js.map +1 -1
- package/dist/esm/utilities/ag-ui-wire.js +90 -13
- package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
- package/dist/esm/utilities/content-source.d.ts +60 -0
- package/dist/esm/utilities/content-source.js +85 -0
- package/dist/esm/utilities/content-source.js.map +1 -0
- package/dist/esm/utilities/normalize-stream-chunk.js +7 -2
- package/dist/esm/utilities/normalize-stream-chunk.js.map +1 -1
- package/dist/esm/utilities/provider-executed.d.ts +7 -0
- package/dist/esm/utilities/provider-executed.js +10 -1
- package/dist/esm/utilities/provider-executed.js.map +1 -1
- package/dist/esm/utilities/spec-event-keys.js +13 -8
- package/dist/esm/utilities/spec-event-keys.js.map +1 -1
- package/dist/esm/utilities/subagent-wire.d.ts +36 -0
- package/dist/esm/utilities/subagent-wire.js +131 -0
- package/dist/esm/utilities/subagent-wire.js.map +1 -0
- package/dist/esm/utilities/tool-result.d.ts +12 -2
- package/dist/esm/utilities/tool-result.js +23 -3
- package/dist/esm/utilities/tool-result.js.map +1 -1
- package/package.json +3 -3
- package/skills/ai-core/adapter-configuration/SKILL.md +62 -0
- package/skills/ai-core/adapter-configuration/references/grok-adapter.md +1 -1
- package/skills/ai-core/chat-experience/SKILL.md +14 -0
- package/skills/ai-core/media-generation/SKILL.md +10 -2
- package/skills/ai-core/middleware/SKILL.md +7 -4
- package/src/activities/chat/adapter.ts +10 -0
- package/src/activities/chat/agents/define-agent.ts +121 -0
- package/src/activities/chat/agents/route.ts +115 -0
- package/src/activities/chat/agents/spawn.ts +806 -0
- package/src/activities/chat/agents/turn.ts +151 -0
- package/src/activities/chat/index.ts +734 -30
- package/src/activities/chat/messages.ts +137 -16
- package/src/activities/chat/middleware/run-store.ts +56 -7
- package/src/activities/chat/middleware/types.ts +47 -0
- package/src/activities/chat/stream/message-updaters.ts +24 -2
- package/src/activities/chat/stream/processor.ts +452 -30
- package/src/activities/chat/tools/tool-calls.ts +83 -11
- package/src/activities/embed/adapter.ts +7 -0
- package/src/activities/embed/index.ts +5 -0
- package/src/activities/files/adapter.ts +120 -0
- package/src/activities/files/index.ts +113 -0
- package/src/activities/generateImage/adapter.ts +8 -0
- package/src/activities/generateImage/index.ts +4 -0
- package/src/activities/generateVideo/adapter.ts +8 -0
- package/src/activities/generateVideo/index.ts +7 -0
- package/src/activities/generateWorld/adapter.ts +4 -2
- package/src/activities/generateWorld/index.ts +7 -6
- package/src/activities/index.ts +40 -1
- package/src/activities/summarize/chat-stream-summarize.ts +22 -12
- package/src/client.ts +29 -35
- package/src/index.ts +39 -0
- package/src/middlewares/content-guard.ts +7 -5
- package/src/types.ts +226 -103
- package/src/utilities/adapter-yield-chunk.ts +10 -2
- package/src/utilities/ag-ui-usage.test.ts +38 -0
- package/src/utilities/ag-ui-usage.ts +98 -11
- package/src/utilities/ag-ui-wire.ts +134 -16
- package/src/utilities/content-source.ts +138 -0
- package/src/utilities/normalize-stream-chunk.ts +10 -2
- package/src/utilities/provider-executed.ts +13 -0
- package/src/utilities/spec-event-keys.ts +34 -7
- package/src/utilities/subagent-wire.ts +184 -0
- package/src/utilities/tool-result.ts +38 -2
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { base64ToArrayBuffer } from "@tanstack/ai-utils";
|
|
2
|
+
//#region src/activities/files/adapter.ts
|
|
3
|
+
/**
|
|
4
|
+
* Files Adapter
|
|
5
|
+
*
|
|
6
|
+
* Base class and interface for the `files` activity — a provider's native Files
|
|
7
|
+
* API (upload a media asset once, reference it later by the returned handle
|
|
8
|
+
* instead of re-sending base64 or a public URL each request).
|
|
9
|
+
*
|
|
10
|
+
* Providers with a native surface expose a factory (`openaiFiles()`,
|
|
11
|
+
* `anthropicFiles()`, `geminiFiles()`, `falFiles()`). `upload` is required;
|
|
12
|
+
* `get`/`delete` are optional because not every provider has a lifecycle API
|
|
13
|
+
* (fal's storage is upload-only).
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Normalize a {@link FileUploadInput} to a `Blob` (plus best-effort MIME /
|
|
17
|
+
* filename) so provider adapters can hand it straight to their SDK. A `Blob`
|
|
18
|
+
* input passes through; base64 `{ data }` is decoded to bytes. Shared so
|
|
19
|
+
* provider files adapters don't each re-implement the decode.
|
|
20
|
+
*/
|
|
21
|
+
function normalizeFileUploadInput(input) {
|
|
22
|
+
if (input instanceof Blob) return {
|
|
23
|
+
blob: input,
|
|
24
|
+
mimeType: input.type || void 0
|
|
25
|
+
};
|
|
26
|
+
const bytes = base64ToArrayBuffer(input.data);
|
|
27
|
+
return {
|
|
28
|
+
blob: new Blob([bytes], { type: input.mimeType }),
|
|
29
|
+
mimeType: input.mimeType,
|
|
30
|
+
filename: input.filename
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Abstract base for provider files adapters. Subclasses bind `TName` to their
|
|
35
|
+
* provider literal, set `name`, implement `upload`, and may add `get`/`delete`
|
|
36
|
+
* (declared on {@link FilesAdapter}, not here, since not every provider has a
|
|
37
|
+
* lifecycle API).
|
|
38
|
+
*/
|
|
39
|
+
var BaseFilesAdapter = class {
|
|
40
|
+
kind = "files";
|
|
41
|
+
};
|
|
42
|
+
//#endregion
|
|
43
|
+
export { BaseFilesAdapter, normalizeFileUploadInput };
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","names":[],"sources":["../../../../src/activities/files/adapter.ts"],"sourcesContent":["/**\n * Files Adapter\n *\n * Base class and interface for the `files` activity — a provider's native Files\n * API (upload a media asset once, reference it later by the returned handle\n * instead of re-sending base64 or a public URL each request).\n *\n * Providers with a native surface expose a factory (`openaiFiles()`,\n * `anthropicFiles()`, `geminiFiles()`, `falFiles()`). `upload` is required;\n * `get`/`delete` are optional because not every provider has a lifecycle API\n * (fal's storage is upload-only).\n */\n\nimport { base64ToArrayBuffer } from '@tanstack/ai-utils'\n\n/**\n * Input to {@link FilesAdapter.upload}. Either a `Blob` (memory-efficient,\n * preferred for large assets) or base64 `data` plus its `mimeType`.\n */\nexport type FileUploadInput =\n | Blob\n | {\n /** Base64-encoded file bytes. */\n data: string\n /** MIME type of the bytes (e.g. `'image/png'`, `'application/pdf'`). */\n mimeType: string\n /** Optional filename hint sent to providers that accept one. */\n filename?: string\n }\n\n/**\n * A provider-issued file handle returned by {@link FilesAdapter.upload} /\n * {@link FilesAdapter.get}. Reference it in a message via a `{ type: 'file' }`\n * content source — use `fileSourceFromHandle` to build one.\n *\n * `TProvider` carries the issuing provider's name as a literal (`'openai'`,\n * `'gemini'`, ...) when the handle came from a concrete files adapter, so\n * cross-provider lifecycle calls (`deleteFile` with a foreign handle) fail at\n * compile time. It defaults to `string` so wire-deserialized handles still fit.\n */\nexport interface FileHandle<TProvider extends string = string> {\n /**\n * Provider handle used for lifecycle operations (`get`/`delete`): the\n * OpenAI/Anthropic `file_id`, the Gemini file resource name (`files/...`), or\n * the fal storage URL (fal itself has no lifecycle API — the URL doubles as\n * the wire reference).\n */\n id: string\n /** The provider that issued the handle (`'openai'`, `'gemini'`, ...). */\n provider: TProvider\n /**\n * The handle's URL form when the provider exposes one (Gemini file URI, fal\n * storage URL). For providers whose handle is an opaque id (OpenAI,\n * Anthropic) this is `undefined`.\n */\n uri?: string\n /** MIME type reported by the provider (or echoed from the upload input). */\n mimeType?: string\n /** File size in bytes when the provider reports it. */\n sizeBytes?: number\n /** Expiry as epoch milliseconds when the handle is scheduled to expire. */\n expiresAt?: number\n /** Original filename when the provider reports it. */\n filename?: string\n}\n\n/**\n * The `files` adapter contract. `upload` is required; `get`/`delete` are\n * optional and present only when the provider has a lifecycle API.\n *\n * `TName` is the provider name literal (`'openai'`, `'gemini'`, ...); concrete\n * adapters bind it so the handles they issue carry their provenance in the\n * type system.\n */\nexport interface FilesAdapter<TName extends string = string> {\n readonly kind: 'files'\n readonly name: TName\n upload: (input: FileUploadInput) => Promise<FileHandle<TName>>\n get?: (id: string) => Promise<FileHandle<TName>>\n delete?: (id: string) => Promise<void>\n}\n\nexport type AnyFilesAdapter = FilesAdapter<string>\n\n/**\n * Normalize a {@link FileUploadInput} to a `Blob` (plus best-effort MIME /\n * filename) so provider adapters can hand it straight to their SDK. A `Blob`\n * input passes through; base64 `{ data }` is decoded to bytes. Shared so\n * provider files adapters don't each re-implement the decode.\n */\nexport function normalizeFileUploadInput(input: FileUploadInput): {\n blob: Blob\n mimeType?: string\n filename?: string\n} {\n if (input instanceof Blob) {\n return { blob: input, mimeType: input.type || undefined }\n }\n const bytes = base64ToArrayBuffer(input.data)\n return {\n blob: new Blob([bytes], { type: input.mimeType }),\n mimeType: input.mimeType,\n filename: input.filename,\n }\n}\n\n/**\n * Abstract base for provider files adapters. Subclasses bind `TName` to their\n * provider literal, set `name`, implement `upload`, and may add `get`/`delete`\n * (declared on {@link FilesAdapter}, not here, since not every provider has a\n * lifecycle API).\n */\nexport abstract class BaseFilesAdapter<\n TName extends string = string,\n> implements FilesAdapter<TName> {\n readonly kind = 'files' as const\n abstract readonly name: TName\n\n abstract upload(input: FileUploadInput): Promise<FileHandle<TName>>\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA0FA,SAAgB,yBAAyB,OAIvC;CACA,IAAI,iBAAiB,MACnB,OAAO;EAAE,MAAM;EAAO,UAAU,MAAM,QAAQ,KAAA;CAAU;CAE1D,MAAM,QAAQ,oBAAoB,MAAM,IAAI;CAC5C,OAAO;EACL,MAAM,IAAI,KAAK,CAAC,KAAK,GAAG,EAAE,MAAM,MAAM,SAAS,CAAC;EAChD,UAAU,MAAM;EAChB,UAAU,MAAM;CAClB;AACF;;;;;;;AAQA,IAAsB,mBAAtB,MAEiC;CAC/B,OAAgB;AAIlB"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { ContentPartFileSource } from '../../types.js';
|
|
2
|
+
import { FileHandle, FileUploadInput, FilesAdapter } from './adapter.js';
|
|
3
|
+
/** The adapter kind this activity handles */
|
|
4
|
+
export declare const kind: "files";
|
|
5
|
+
/**
|
|
6
|
+
* Upload a file to a provider's Files API and return its handle. The handle
|
|
7
|
+
* carries the provider name as a literal type, so passing it to another
|
|
8
|
+
* provider's lifecycle call is a compile error.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const files = openaiFiles()
|
|
13
|
+
* const handle = await uploadFile({ adapter: files, input: { data, mimeType: 'image/png' } })
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function uploadFile<TName extends string>(options: {
|
|
17
|
+
adapter: FilesAdapter<TName> & {
|
|
18
|
+
kind: typeof kind;
|
|
19
|
+
};
|
|
20
|
+
input: FileUploadInput;
|
|
21
|
+
}): Promise<FileHandle<TName>>;
|
|
22
|
+
/**
|
|
23
|
+
* Fetch metadata for a previously uploaded file. Accepts the handle itself
|
|
24
|
+
* (preferred — the provider-literal type rejects a foreign provider's handle
|
|
25
|
+
* at compile time) or its raw lifecycle id.
|
|
26
|
+
*
|
|
27
|
+
* @throws if the provider's files adapter has no `get` (e.g. fal storage).
|
|
28
|
+
*/
|
|
29
|
+
export declare function getFile<TName extends string>(options: {
|
|
30
|
+
adapter: FilesAdapter<TName> & {
|
|
31
|
+
kind: typeof kind;
|
|
32
|
+
};
|
|
33
|
+
id: string | FileHandle<NoInfer<TName>>;
|
|
34
|
+
}): Promise<FileHandle<TName>>;
|
|
35
|
+
/**
|
|
36
|
+
* Delete a previously uploaded file. Accepts the handle itself (preferred —
|
|
37
|
+
* the provider-literal type rejects a foreign provider's handle at compile
|
|
38
|
+
* time) or its raw lifecycle id.
|
|
39
|
+
*
|
|
40
|
+
* @throws if the provider's files adapter has no `delete` (e.g. fal storage).
|
|
41
|
+
*/
|
|
42
|
+
export declare function deleteFile<TName extends string>(options: {
|
|
43
|
+
adapter: FilesAdapter<TName> & {
|
|
44
|
+
kind: typeof kind;
|
|
45
|
+
};
|
|
46
|
+
id: string | FileHandle<NoInfer<TName>>;
|
|
47
|
+
}): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Build a `{ type: 'file' }` content source from an uploaded
|
|
50
|
+
* {@link FileHandle}, for use in a chat message (image/audio/document part
|
|
51
|
+
* `source`).
|
|
52
|
+
*
|
|
53
|
+
* The source's `value` is the handle's wire form: the handle URL when the
|
|
54
|
+
* provider exposes one (Gemini, fal, Grok), otherwise the opaque id (OpenAI,
|
|
55
|
+
* Anthropic). `provider` records the issuer, so an adapter for a different
|
|
56
|
+
* provider rejects the source rather than sending a handle it cannot resolve.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```ts
|
|
60
|
+
* const handle = await uploadFile({ adapter: openaiFiles(), input })
|
|
61
|
+
* messages.push({ role: 'user', content: [
|
|
62
|
+
* { type: 'image', source: fileSourceFromHandle(handle) },
|
|
63
|
+
* ] })
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function fileSourceFromHandle<TProvider extends string>(handle: FileHandle<TProvider>): ContentPartFileSource<TProvider>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
//#region src/activities/files/index.ts
|
|
2
|
+
/** The adapter kind this activity handles */
|
|
3
|
+
var kind = "files";
|
|
4
|
+
/**
|
|
5
|
+
* Upload a file to a provider's Files API and return its handle. The handle
|
|
6
|
+
* carries the provider name as a literal type, so passing it to another
|
|
7
|
+
* provider's lifecycle call is a compile error.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* const files = openaiFiles()
|
|
12
|
+
* const handle = await uploadFile({ adapter: files, input: { data, mimeType: 'image/png' } })
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
async function uploadFile(options) {
|
|
16
|
+
return options.adapter.upload(options.input);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolve a lifecycle id from either a raw id string or a {@link FileHandle}
|
|
20
|
+
* (whose `id` — not its `uri`/wire value — is the lifecycle currency).
|
|
21
|
+
*/
|
|
22
|
+
function toLifecycleId(id) {
|
|
23
|
+
return typeof id === "string" ? id : id.id;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Fetch metadata for a previously uploaded file. Accepts the handle itself
|
|
27
|
+
* (preferred — the provider-literal type rejects a foreign provider's handle
|
|
28
|
+
* at compile time) or its raw lifecycle id.
|
|
29
|
+
*
|
|
30
|
+
* @throws if the provider's files adapter has no `get` (e.g. fal storage).
|
|
31
|
+
*/
|
|
32
|
+
async function getFile(options) {
|
|
33
|
+
const { adapter } = options;
|
|
34
|
+
if (!adapter.get) throw new Error(`${adapter.name}: files adapter does not support get() — this provider has no file-retrieval API.`);
|
|
35
|
+
return adapter.get(toLifecycleId(options.id));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Delete a previously uploaded file. Accepts the handle itself (preferred —
|
|
39
|
+
* the provider-literal type rejects a foreign provider's handle at compile
|
|
40
|
+
* time) or its raw lifecycle id.
|
|
41
|
+
*
|
|
42
|
+
* @throws if the provider's files adapter has no `delete` (e.g. fal storage).
|
|
43
|
+
*/
|
|
44
|
+
async function deleteFile(options) {
|
|
45
|
+
const { adapter } = options;
|
|
46
|
+
if (!adapter.delete) throw new Error(`${adapter.name}: files adapter does not support delete() — this provider has no file-deletion API.`);
|
|
47
|
+
return adapter.delete(toLifecycleId(options.id));
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Build a `{ type: 'file' }` content source from an uploaded
|
|
51
|
+
* {@link FileHandle}, for use in a chat message (image/audio/document part
|
|
52
|
+
* `source`).
|
|
53
|
+
*
|
|
54
|
+
* The source's `value` is the handle's wire form: the handle URL when the
|
|
55
|
+
* provider exposes one (Gemini, fal, Grok), otherwise the opaque id (OpenAI,
|
|
56
|
+
* Anthropic). `provider` records the issuer, so an adapter for a different
|
|
57
|
+
* provider rejects the source rather than sending a handle it cannot resolve.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* const handle = await uploadFile({ adapter: openaiFiles(), input })
|
|
62
|
+
* messages.push({ role: 'user', content: [
|
|
63
|
+
* { type: 'image', source: fileSourceFromHandle(handle) },
|
|
64
|
+
* ] })
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
function fileSourceFromHandle(handle) {
|
|
68
|
+
return {
|
|
69
|
+
type: "file",
|
|
70
|
+
value: handle.uri ?? handle.id,
|
|
71
|
+
provider: handle.provider,
|
|
72
|
+
...handle.mimeType ? { mimeType: handle.mimeType } : {}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { deleteFile, fileSourceFromHandle, getFile, kind, uploadFile };
|
|
77
|
+
|
|
78
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/activities/files/index.ts"],"sourcesContent":["/**\n * Files Activity\n *\n * Dispatch functions for provider Files APIs. Each takes `{ adapter, ... }` and\n * calls the adapter method directly (mirrors the other activity dispatchers).\n * `get`/`delete` are optional on the adapter; the dispatchers throw a clear\n * error when the selected provider has no lifecycle API.\n */\n\nimport type { ContentPartFileSource } from '../../types'\nimport type { FileHandle, FileUploadInput, FilesAdapter } from './adapter'\n\n/** The adapter kind this activity handles */\nexport const kind = 'files' as const\n\n/**\n * Upload a file to a provider's Files API and return its handle. The handle\n * carries the provider name as a literal type, so passing it to another\n * provider's lifecycle call is a compile error.\n *\n * @example\n * ```ts\n * const files = openaiFiles()\n * const handle = await uploadFile({ adapter: files, input: { data, mimeType: 'image/png' } })\n * ```\n */\nexport async function uploadFile<TName extends string>(options: {\n adapter: FilesAdapter<TName> & { kind: typeof kind }\n input: FileUploadInput\n}): Promise<FileHandle<TName>> {\n return options.adapter.upload(options.input)\n}\n\n/**\n * Resolve a lifecycle id from either a raw id string or a {@link FileHandle}\n * (whose `id` — not its `uri`/wire value — is the lifecycle currency).\n */\nfunction toLifecycleId(id: string | FileHandle): string {\n return typeof id === 'string' ? id : id.id\n}\n\n/**\n * Fetch metadata for a previously uploaded file. Accepts the handle itself\n * (preferred — the provider-literal type rejects a foreign provider's handle\n * at compile time) or its raw lifecycle id.\n *\n * @throws if the provider's files adapter has no `get` (e.g. fal storage).\n */\nexport async function getFile<TName extends string>(options: {\n adapter: FilesAdapter<TName> & { kind: typeof kind }\n // `NoInfer` so `TName` comes from the adapter only. Otherwise a foreign\n // handle widens it to a union and the call compiles.\n id: string | FileHandle<NoInfer<TName>>\n}): Promise<FileHandle<TName>> {\n const { adapter } = options\n if (!adapter.get) {\n throw new Error(\n `${adapter.name}: files adapter does not support get() — this provider ` +\n `has no file-retrieval API.`,\n )\n }\n return adapter.get(toLifecycleId(options.id))\n}\n\n/**\n * Delete a previously uploaded file. Accepts the handle itself (preferred —\n * the provider-literal type rejects a foreign provider's handle at compile\n * time) or its raw lifecycle id.\n *\n * @throws if the provider's files adapter has no `delete` (e.g. fal storage).\n */\nexport async function deleteFile<TName extends string>(options: {\n adapter: FilesAdapter<TName> & { kind: typeof kind }\n id: string | FileHandle<NoInfer<TName>>\n}): Promise<void> {\n const { adapter } = options\n if (!adapter.delete) {\n throw new Error(\n `${adapter.name}: files adapter does not support delete() — this ` +\n `provider has no file-deletion API.`,\n )\n }\n return adapter.delete(toLifecycleId(options.id))\n}\n\n/**\n * Build a `{ type: 'file' }` content source from an uploaded\n * {@link FileHandle}, for use in a chat message (image/audio/document part\n * `source`).\n *\n * The source's `value` is the handle's wire form: the handle URL when the\n * provider exposes one (Gemini, fal, Grok), otherwise the opaque id (OpenAI,\n * Anthropic). `provider` records the issuer, so an adapter for a different\n * provider rejects the source rather than sending a handle it cannot resolve.\n *\n * @example\n * ```ts\n * const handle = await uploadFile({ adapter: openaiFiles(), input })\n * messages.push({ role: 'user', content: [\n * { type: 'image', source: fileSourceFromHandle(handle) },\n * ] })\n * ```\n */\nexport function fileSourceFromHandle<TProvider extends string>(\n handle: FileHandle<TProvider>,\n): ContentPartFileSource<TProvider> {\n return {\n type: 'file',\n value: handle.uri ?? handle.id,\n provider: handle.provider,\n ...(handle.mimeType ? { mimeType: handle.mimeType } : {}),\n }\n}\n"],"mappings":";;AAaA,IAAa,OAAO;;;;;;;;;;;;AAapB,eAAsB,WAAiC,SAGxB;CAC7B,OAAO,QAAQ,QAAQ,OAAO,QAAQ,KAAK;AAC7C;;;;;AAMA,SAAS,cAAc,IAAiC;CACtD,OAAO,OAAO,OAAO,WAAW,KAAK,GAAG;AAC1C;;;;;;;;AASA,eAAsB,QAA8B,SAKrB;CAC7B,MAAM,EAAE,YAAY;CACpB,IAAI,CAAC,QAAQ,KACX,MAAM,IAAI,MACR,GAAG,QAAQ,KAAK,kFAElB;CAEF,OAAO,QAAQ,IAAI,cAAc,QAAQ,EAAE,CAAC;AAC9C;;;;;;;;AASA,eAAsB,WAAiC,SAGrC;CAChB,MAAM,EAAE,YAAY;CACpB,IAAI,CAAC,QAAQ,QACX,MAAM,IAAI,MACR,GAAG,QAAQ,KAAK,oFAElB;CAEF,OAAO,QAAQ,OAAO,cAAc,QAAQ,EAAE,CAAC;AACjD;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,qBACd,QACkC;CAClC,OAAO;EACL,MAAM;EACN,OAAO,OAAO,OAAO,OAAO;EAC5B,UAAU,OAAO;EACjB,GAAI,OAAO,WAAW,EAAE,UAAU,OAAO,SAAS,IAAI,CAAC;CACzD;AACF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolveDebugOption } from "../../logger/resolve.js";
|
|
2
|
-
import { streamGenerationResult } from "../stream-generation-result.js";
|
|
3
2
|
import { applyGenerationResultTransforms, createGenerationContext, runGenerationAbort, runGenerationError, runGenerationFinish, runGenerationStart, runGenerationUsage } from "../middleware/run.js";
|
|
3
|
+
import { streamGenerationResult } from "../stream-generation-result.js";
|
|
4
4
|
import { abortReasonMessage, createActivityAbortControls, isActivityAbortError, raceWithAbort } from "../../utilities/activity-abort.js";
|
|
5
5
|
import "./adapter.js";
|
|
6
6
|
import { aiEventClient } from "@tanstack/ai-event-client";
|
|
@@ -34,6 +34,13 @@ export interface ImageAdapter<TModel extends string = string, TProviderOptions e
|
|
|
34
34
|
readonly kind: 'image';
|
|
35
35
|
/** Adapter name identifier */
|
|
36
36
|
readonly name: string;
|
|
37
|
+
/**
|
|
38
|
+
* Declares that this adapter can consume `{ type: 'file' }` content
|
|
39
|
+
* sources (provider Files API references). The activity dispatcher rejects
|
|
40
|
+
* file sources in preflight for adapters that don't declare this, so
|
|
41
|
+
* adapters written before the file arm existed fail closed.
|
|
42
|
+
*/
|
|
43
|
+
readonly supportsFileSources?: boolean;
|
|
37
44
|
/** The model this adapter is configured for */
|
|
38
45
|
readonly model: TModel;
|
|
39
46
|
/**
|
|
@@ -64,6 +71,7 @@ export type AnyImageAdapter = ImageAdapter<any, any, any, any, any>;
|
|
|
64
71
|
export declare abstract class BaseImageAdapter<TModel extends string = string, TProviderOptions extends object = Record<string, unknown>, TModelProviderOptionsByName extends Record<string, any> = Record<string, any>, TModelSizeByName extends Record<string, string | undefined> = Record<string, string>, TModelInputModalitiesByName extends ModelInputModalitiesByName = ModelInputModalitiesByName> implements ImageAdapter<TModel, TProviderOptions, TModelProviderOptionsByName, TModelSizeByName, TModelInputModalitiesByName> {
|
|
65
72
|
readonly kind: "image";
|
|
66
73
|
abstract readonly name: string;
|
|
74
|
+
readonly supportsFileSources: boolean;
|
|
67
75
|
readonly model: TModel;
|
|
68
76
|
'~types': {
|
|
69
77
|
providerOptions: TProviderOptions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","names":[],"sources":["../../../../src/activities/generateImage/adapter.ts"],"sourcesContent":["import type {\n ImageGenerationOptions,\n ImageGenerationResult,\n ModelInputModalitiesByName,\n} from '../../types'\n\n/**\n * Resolve the size type for a model from the model-size map.\n * If the map has an index signature (i.e. no explicit keys), falls back to string.\n * If the model is an explicit key, uses its mapped size type.\n * Otherwise falls back to string.\n */\n\n/**\n * Configuration for image adapter instances\n */\nexport interface ImageAdapterConfig {\n apiKey?: string\n baseUrl?: string\n timeout?: number\n maxRetries?: number\n headers?: Record<string, string>\n}\n\n/**\n * Image adapter interface with pre-resolved generics.\n *\n * An adapter is created by a provider function: `provider('model')` → `adapter`\n * All type resolution happens at the provider call site, not in this interface.\n *\n * Generic parameters:\n * - TModel: The specific model name (e.g., 'dall-e-3')\n * - TProviderOptions: Base provider-specific options (already resolved)\n * - TModelProviderOptionsByName: Map from model name to its specific provider options\n * - TModelSizeByName: Map from model name to its supported sizes\n * - TModelInputModalitiesByName: Map from model name to the non-text prompt\n * modalities it accepts (constrains the `prompt` part types at compile time)\n */\nexport interface ImageAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n TModelProviderOptionsByName extends Record<string, any> = Record<string, any>,\n TModelSizeByName extends Record<string, string | undefined> = Record<\n string,\n string\n >,\n TModelInputModalitiesByName extends ModelInputModalitiesByName =\n ModelInputModalitiesByName,\n> {\n /** Discriminator for adapter kind - used by generate() to determine API shape */\n readonly kind: 'image'\n /** Adapter name identifier */\n readonly name: string\n /** The model this adapter is configured for */\n readonly model: TModel\n\n /**\n * @internal Type-only properties for inference. Not assigned at runtime.\n */\n '~types': {\n providerOptions: TProviderOptions\n modelProviderOptionsByName: TModelProviderOptionsByName\n modelSizeByName: TModelSizeByName\n modelInputModalitiesByName: TModelInputModalitiesByName\n }\n\n /**\n * Generate images from a prompt\n */\n generateImages: (\n options: ImageGenerationOptions<TProviderOptions, TModelSizeByName[TModel]>,\n ) => Promise<ImageGenerationResult>\n}\n\n/**\n * An ImageAdapter with any/unknown type parameters.\n * Useful as a constraint in generic functions and interfaces.\n */\nexport type AnyImageAdapter = ImageAdapter<any, any, any, any, any>\n\n/**\n * Abstract base class for image generation adapters.\n * Extend this class to implement an image adapter for a specific provider.\n *\n * Generic parameters match ImageAdapter - all pre-resolved by the provider function.\n */\nexport abstract class BaseImageAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n TModelProviderOptionsByName extends Record<string, any> = Record<string, any>,\n TModelSizeByName extends Record<string, string | undefined> = Record<\n string,\n string\n >,\n TModelInputModalitiesByName extends ModelInputModalitiesByName =\n ModelInputModalitiesByName,\n> implements ImageAdapter<\n TModel,\n TProviderOptions,\n TModelProviderOptionsByName,\n TModelSizeByName,\n TModelInputModalitiesByName\n> {\n readonly kind = 'image' as const\n abstract readonly name: string\n readonly model: TModel\n\n // Type-only property - never assigned at runtime\n declare '~types': {\n providerOptions: TProviderOptions\n modelProviderOptionsByName: TModelProviderOptionsByName\n modelSizeByName: TModelSizeByName\n modelInputModalitiesByName: TModelInputModalitiesByName\n }\n\n protected config: ImageAdapterConfig\n\n constructor(model: TModel, config: ImageAdapterConfig = {}) {\n this.config = config\n this.model = model\n }\n\n abstract generateImages(\n options: ImageGenerationOptions<TProviderOptions, TModelSizeByName[TModel]>,\n ): Promise<ImageGenerationResult>\n\n protected generateId(): string {\n return `${this.name}-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n}\n"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"adapter.js","names":[],"sources":["../../../../src/activities/generateImage/adapter.ts"],"sourcesContent":["import type {\n ImageGenerationOptions,\n ImageGenerationResult,\n ModelInputModalitiesByName,\n} from '../../types'\n\n/**\n * Resolve the size type for a model from the model-size map.\n * If the map has an index signature (i.e. no explicit keys), falls back to string.\n * If the model is an explicit key, uses its mapped size type.\n * Otherwise falls back to string.\n */\n\n/**\n * Configuration for image adapter instances\n */\nexport interface ImageAdapterConfig {\n apiKey?: string\n baseUrl?: string\n timeout?: number\n maxRetries?: number\n headers?: Record<string, string>\n}\n\n/**\n * Image adapter interface with pre-resolved generics.\n *\n * An adapter is created by a provider function: `provider('model')` → `adapter`\n * All type resolution happens at the provider call site, not in this interface.\n *\n * Generic parameters:\n * - TModel: The specific model name (e.g., 'dall-e-3')\n * - TProviderOptions: Base provider-specific options (already resolved)\n * - TModelProviderOptionsByName: Map from model name to its specific provider options\n * - TModelSizeByName: Map from model name to its supported sizes\n * - TModelInputModalitiesByName: Map from model name to the non-text prompt\n * modalities it accepts (constrains the `prompt` part types at compile time)\n */\nexport interface ImageAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n TModelProviderOptionsByName extends Record<string, any> = Record<string, any>,\n TModelSizeByName extends Record<string, string | undefined> = Record<\n string,\n string\n >,\n TModelInputModalitiesByName extends ModelInputModalitiesByName =\n ModelInputModalitiesByName,\n> {\n /** Discriminator for adapter kind - used by generate() to determine API shape */\n readonly kind: 'image'\n /** Adapter name identifier */\n readonly name: string\n /**\n * Declares that this adapter can consume `{ type: 'file' }` content\n * sources (provider Files API references). The activity dispatcher rejects\n * file sources in preflight for adapters that don't declare this, so\n * adapters written before the file arm existed fail closed.\n */\n readonly supportsFileSources?: boolean\n /** The model this adapter is configured for */\n readonly model: TModel\n\n /**\n * @internal Type-only properties for inference. Not assigned at runtime.\n */\n '~types': {\n providerOptions: TProviderOptions\n modelProviderOptionsByName: TModelProviderOptionsByName\n modelSizeByName: TModelSizeByName\n modelInputModalitiesByName: TModelInputModalitiesByName\n }\n\n /**\n * Generate images from a prompt\n */\n generateImages: (\n options: ImageGenerationOptions<TProviderOptions, TModelSizeByName[TModel]>,\n ) => Promise<ImageGenerationResult>\n}\n\n/**\n * An ImageAdapter with any/unknown type parameters.\n * Useful as a constraint in generic functions and interfaces.\n */\nexport type AnyImageAdapter = ImageAdapter<any, any, any, any, any>\n\n/**\n * Abstract base class for image generation adapters.\n * Extend this class to implement an image adapter for a specific provider.\n *\n * Generic parameters match ImageAdapter - all pre-resolved by the provider function.\n */\nexport abstract class BaseImageAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n TModelProviderOptionsByName extends Record<string, any> = Record<string, any>,\n TModelSizeByName extends Record<string, string | undefined> = Record<\n string,\n string\n >,\n TModelInputModalitiesByName extends ModelInputModalitiesByName =\n ModelInputModalitiesByName,\n> implements ImageAdapter<\n TModel,\n TProviderOptions,\n TModelProviderOptionsByName,\n TModelSizeByName,\n TModelInputModalitiesByName\n> {\n readonly kind = 'image' as const\n abstract readonly name: string\n readonly supportsFileSources: boolean = false\n readonly model: TModel\n\n // Type-only property - never assigned at runtime\n declare '~types': {\n providerOptions: TProviderOptions\n modelProviderOptionsByName: TModelProviderOptionsByName\n modelSizeByName: TModelSizeByName\n modelInputModalitiesByName: TModelInputModalitiesByName\n }\n\n protected config: ImageAdapterConfig\n\n constructor(model: TModel, config: ImageAdapterConfig = {}) {\n this.config = config\n this.model = model\n }\n\n abstract generateImages(\n options: ImageGenerationOptions<TProviderOptions, TModelSizeByName[TModel]>,\n ): Promise<ImageGenerationResult>\n\n protected generateId(): string {\n return `${this.name}-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n}\n"],"mappings":";;;;;;;AA6FA,IAAsB,mBAAtB,MAgBE;CACA,OAAgB;CAEhB,sBAAwC;CACxC;CAUA;CAEA,YAAY,OAAe,SAA6B,CAAC,GAAG;EAC1D,KAAK,SAAS;EACd,KAAK,QAAQ;CACf;CAMA,aAA+B;EAC7B,OAAO,GAAG,KAAK,KAAK,GAAG,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,UAAU,CAAC;CAC7E;AACF"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { resolveDebugOption } from "../../logger/resolve.js";
|
|
2
|
-
import {
|
|
2
|
+
import { assertPromptFileSourceSupport } from "../../utilities/content-source.js";
|
|
3
3
|
import { applyGenerationResultTransforms, createGenerationContext, runGenerationAbort, runGenerationError, runGenerationFinish, runGenerationStart, runGenerationUsage } from "../middleware/run.js";
|
|
4
|
+
import { streamGenerationResult } from "../stream-generation-result.js";
|
|
4
5
|
import { abortReasonMessage, createActivityAbortControls, isActivityAbortError, raceWithAbort } from "../../utilities/activity-abort.js";
|
|
5
6
|
import { resolveMediaPrompt } from "../../utilities/media-prompt.js";
|
|
6
7
|
import "./adapter.js";
|
|
@@ -63,6 +64,7 @@ function createId(prefix) {
|
|
|
63
64
|
* ```
|
|
64
65
|
*/
|
|
65
66
|
function generateImage(options) {
|
|
67
|
+
assertPromptFileSourceSupport(options.adapter, options.prompt);
|
|
66
68
|
if (options.stream) return streamGenerationResult((resolved) => runGenerateImage({
|
|
67
69
|
...options,
|
|
68
70
|
runId: resolved.runId
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/activities/generateImage/index.ts"],"sourcesContent":["/**\n * Image Activity\n *\n * Generates images from text prompts.\n * This is a self-contained module with implementation, types, and JSDoc.\n */\n\nimport { aiEventClient } from '@tanstack/ai-event-client'\nimport { streamGenerationResult } from '../stream-generation-result.js'\nimport { resolveDebugOption } from '../../logger/resolve'\nimport {\n applyGenerationResultTransforms,\n createGenerationContext,\n runGenerationAbort,\n runGenerationError,\n runGenerationFinish,\n runGenerationStart,\n runGenerationUsage,\n} from '../middleware/run'\nimport {\n abortReasonMessage,\n createActivityAbortControls,\n isActivityAbortError,\n raceWithAbort,\n} from '../../utilities/activity-abort'\nimport { resolveMediaPrompt } from '../../utilities/media-prompt'\nimport type { InternalLogger } from '../../logger/internal-logger'\nimport type { DebugOption } from '../../logger/types'\nimport type { GenerationMiddleware } from '../middleware/types'\nimport type { ImageAdapter } from './adapter'\nimport type {\n ImageGenerationResult,\n MediaPrompt,\n MediaPromptFor,\n StreamChunk,\n} from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'image' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract model-specific provider options from an ImageAdapter via ~types.\n * If the model has specific options defined in ModelProviderOptions (and not just via index signature),\n * use those; otherwise fall back to base provider options.\n */\nexport type ImageProviderOptionsForModel<TAdapter, TModel extends string> =\n TAdapter extends ImageAdapter<any, infer BaseOptions, infer ModelOptions, any>\n ? string extends keyof ModelOptions\n ? // ModelOptions is Record<string, unknown> or has index signature - use BaseOptions\n BaseOptions\n : // ModelOptions has explicit keys - check if TModel is one of them\n TModel extends keyof ModelOptions\n ? ModelOptions[TModel]\n : BaseOptions\n : object\n\n/**\n * Extract model-specific size options from an ImageAdapter via ~types.\n * If the model has specific sizes defined, use those; otherwise fall back to string.\n */\nexport type ImageSizeForModel<TAdapter, TModel extends string> =\n TAdapter extends ImageAdapter<any, any, any, infer SizeByName>\n ? string extends keyof SizeByName\n ? // SizeByName has index signature - fall back to string\n string\n : // SizeByName has explicit keys - check if TModel is one of them\n TModel extends keyof SizeByName\n ? SizeByName[TModel]\n : string\n : string\n\n/**\n * Extract the prompt type a model accepts from an ImageAdapter via ~types.\n * Adapters declare a per-model input-modality map; models in the map get a\n * `prompt` narrowed to text + their supported part types (text-only models\n * accept `string | Array<TextPart>`), so unsupported media parts fail at\n * compile time. Adapters without a map fall back to the full MediaPrompt.\n */\nexport type ImagePromptForModel<TAdapter, TModel extends string> =\n TAdapter extends ImageAdapter<any, any, any, any, infer ModsByName>\n ? string extends keyof ModsByName\n ? // No explicit map - accept the full union\n MediaPrompt\n : TModel extends keyof ModsByName\n ? MediaPromptFor<ModsByName[TModel][number]>\n : MediaPrompt\n : MediaPrompt\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the image activity.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The image adapter type\n * @template TStream - Whether to stream the output\n */\nexport type ImageActivityOptions<\n TAdapter extends ImageAdapter<string, any, any, any>,\n TStream extends boolean = false,\n> = {\n /** The image adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /**\n * Description of the desired image(s). Either a plain string, or — for\n * models that support image-conditioned generation — an ordered array of\n * content parts interleaving text with image inputs (image-to-image,\n * reference-guided, edit, multi-reference). Media parts may carry\n * `metadata.role` (`'reference' | 'mask' | 'control' | 'character'`) to\n * disambiguate intent. The accepted part types are narrowed per model via\n * the adapter's input-modality map.\n */\n prompt: ImagePromptForModel<TAdapter, TAdapter['model']>\n /** Number of images to generate (default: 1) */\n numberOfImages?: number\n /** Image size in WIDTHxHEIGHT format (e.g., \"1024x1024\") */\n size?: ImageSizeForModel<TAdapter, TAdapter['model']>\n /**\n * Whether to stream the image generation result.\n * When true, returns an AsyncIterable<StreamChunk> for streaming transport.\n * When false or not provided, returns a Promise<ImageGenerationResult>.\n *\n * @default false\n */\n stream?: TStream\n /**\n * Enable debug logging. Pass `true` to enable all categories, `false` to\n * silence everything including errors, or a `DebugConfig` object for granular\n * control and/or a custom `Logger`.\n */\n debug?: DebugOption\n /**\n * Observe-only middleware notified on start, usage, success, and error. Pass\n * `otelMiddleware()` to emit OpenTelemetry spans, or implement the\n * `GenerationMiddleware` contract for a custom backend.\n */\n middleware?: Array<GenerationMiddleware>\n /** Stable conversation/thread id for correlating this run when persisted. */\n threadId?: string\n /** Stable run id for correlating this run when persisted. */\n runId?: string\n /**\n * Maximum duration of this activity invocation in milliseconds.\n * No SDK-wide default — choose a value suitable for the provider and job.\n * Composed with {@link abortSignal}; the first abort wins.\n */\n timeout?: number\n /**\n * Caller cancellation signal (request disconnects, job/runtime cancellation).\n * Composed with {@link timeout} into an effective signal forwarded to the\n * adapter. Request-specific — not stored on global provider client config.\n */\n abortSignal?: AbortSignal\n} & ({} extends ImageProviderOptionsForModel<TAdapter, TAdapter['model']>\n ? {\n /** Provider-specific options for image generation */ modelOptions?: ImageProviderOptionsForModel<\n TAdapter,\n TAdapter['model']\n >\n }\n : {\n /** Provider-specific options for image generation */ modelOptions: ImageProviderOptionsForModel<\n TAdapter,\n TAdapter['model']\n >\n })\n\n// ===========================\n// Activity Result Type\n// ===========================\n\n/**\n * Result type for the image activity.\n * - If stream is true: AsyncIterable<StreamChunk>\n * - Otherwise: Promise<ImageGenerationResult>\n */\nexport type ImageActivityResult<TStream extends boolean = false> =\n TStream extends true\n ? AsyncIterable<StreamChunk>\n : Promise<ImageGenerationResult>\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * Image activity - generates images from text prompts.\n *\n * Uses AI image generation models to create images based on natural language descriptions.\n *\n * @example Generate a single image\n * ```ts\n * import { generateImage } from '@tanstack/ai'\n * import { openaiImage } from '@tanstack/ai-openai'\n *\n * const result = await generateImage({\n * adapter: openaiImage('dall-e-3'),\n * prompt: 'A serene mountain landscape at sunset'\n * })\n *\n * console.log(result.images[0].url)\n * ```\n *\n * @example Generate multiple images\n * ```ts\n * const result = await generateImage({\n * adapter: openaiImage('dall-e-2'),\n * prompt: 'A cute robot mascot',\n * numberOfImages: 4,\n * size: '512x512'\n * })\n *\n * result.images.forEach((image, i) => {\n * console.log(`Image ${i + 1}: ${image.url}`)\n * })\n * ```\n *\n * @example With provider-specific options\n * ```ts\n * const result = await generateImage({\n * adapter: openaiImage('dall-e-3'),\n * prompt: 'A professional headshot photo',\n * size: '1024x1024',\n * modelOptions: {\n * quality: 'hd',\n * style: 'natural'\n * }\n * })\n * ```\n */\nexport function generateImage<\n TAdapter extends ImageAdapter<string, any, any, any>,\n TStream extends boolean = false,\n>(\n options: ImageActivityOptions<TAdapter, TStream>,\n): ImageActivityResult<TStream> {\n if (options.stream) {\n return streamGenerationResult(\n // Only `runId` is taken from the resolved wire identity. `threadId` stays\n // the CALLER's: `streamGenerationResult` mints one for the RUN_* chunks\n // when none was passed, and spreading that over the options would hand\n // middleware a thread id known to nobody, which persistence would then\n // file the run under. Matches `generateVideo`.\n (resolved) => runGenerateImage({ ...options, runId: resolved.runId }),\n options,\n ) as ImageActivityResult<TStream>\n }\n\n return runGenerateImage(options) as ImageActivityResult<TStream>\n}\n\n/**\n * Internal implementation of image generation (always non-streaming).\n * Contains all devtools event emission logic.\n */\nasync function runGenerateImage<\n TAdapter extends ImageAdapter<string, any, any, any>,\n>(\n options: ImageActivityOptions<TAdapter, boolean>,\n): Promise<ImageGenerationResult> {\n const {\n adapter,\n stream: _stream,\n debug: _debug,\n middleware,\n threadId,\n runId,\n timeout,\n abortSignal: callerAbortSignal,\n ...rest\n } = options\n const model = adapter.model\n const requestId = createId('image')\n const startTime = Date.now()\n const logger: InternalLogger = resolveDebugOption(options.debug)\n const abortControls = createActivityAbortControls({\n timeout,\n abortSignal: callerAbortSignal,\n })\n\n const mwCtx = createGenerationContext({\n requestId,\n activity: 'image',\n provider: adapter.name,\n model,\n modelOptions: rest.modelOptions,\n threadId,\n runId,\n artifactInputs: { prompt: rest.prompt },\n createId,\n })\n\n await runGenerationStart(middleware, mwCtx)\n\n // Devtools events carry the flattened prompt text plus media-part counts —\n // the wire payload stays `prompt: string` regardless of the prompt shape.\n const resolved = resolveMediaPrompt(rest.prompt)\n\n aiEventClient.emit('image:request:started', {\n requestId,\n provider: adapter.name,\n model,\n prompt: resolved.text,\n numberOfImages: rest.numberOfImages,\n size: rest.size,\n ...(resolved.images.length > 0 && {\n imageInputCount: resolved.images.length,\n }),\n ...(resolved.videos.length > 0 && {\n videoInputCount: resolved.videos.length,\n }),\n ...(resolved.audios.length > 0 && {\n audioInputCount: resolved.audios.length,\n }),\n modelOptions: rest.modelOptions,\n timestamp: startTime,\n })\n\n logger.request(`activity=generateImage provider=${adapter.name}`, {\n provider: adapter.name,\n model,\n })\n\n try {\n const rawResult = await raceWithAbort(\n adapter.generateImages({\n ...rest,\n model,\n logger,\n ...(abortControls.signal ? { abortSignal: abortControls.signal } : {}),\n }),\n abortControls.signal,\n )\n abortControls.clear()\n const result = await applyGenerationResultTransforms(mwCtx, rawResult)\n const duration = Date.now() - startTime\n\n aiEventClient.emit('image:request:completed', {\n requestId,\n provider: adapter.name,\n model,\n // GeneratedImage is a discriminated `{ url } | { b64Json }` union, but the\n // wire shape on the devtools event is a plain optional pair. Use\n // conditional spreads so the emitted record only sets the field actually\n // present — `exactOptionalPropertyTypes` rejects `field: undefined`\n // against `field?: string` targets.\n images: result.images.map((image) => ({\n url: image.url,\n b64Json: image.b64Json,\n })),\n duration,\n modelOptions: rest.modelOptions,\n timestamp: Date.now(),\n })\n\n if (result.usage) {\n aiEventClient.emit('image:usage', {\n requestId,\n model,\n usage: result.usage,\n modelOptions: rest.modelOptions,\n timestamp: Date.now(),\n })\n }\n\n logger.output(`activity=generateImage count=${result.images.length}`, {\n count: result.images.length,\n })\n\n if (result.usage) await runGenerationUsage(middleware, mwCtx, result.usage)\n await runGenerationFinish(middleware, mwCtx, {\n duration,\n usage: result.usage,\n })\n\n return result\n } catch (error) {\n abortControls.clear()\n const duration = Date.now() - startTime\n if (isActivityAbortError(error, abortControls.signal)) {\n await runGenerationAbort(middleware, mwCtx, {\n reason: abortReasonMessage(error, abortControls.signal),\n duration,\n })\n } else {\n await runGenerationError(middleware, mwCtx, {\n error,\n duration,\n })\n }\n logger.errors('generateImage activity failed', {\n error,\n source: 'generateImage',\n })\n throw error\n }\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateImage() function without executing.\n */\nexport function createImageOptions<\n TAdapter extends ImageAdapter<string, any, any, any>,\n TStream extends boolean = false,\n>(\n options: ImageActivityOptions<TAdapter, TStream>,\n): ImageActivityOptions<TAdapter, TStream> {\n return options\n}\n\n// Re-export adapter types\nexport type {\n ImageAdapter,\n ImageAdapterConfig,\n AnyImageAdapter,\n} from './adapter'\nexport { BaseImageAdapter } from './adapter'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/activities/generateImage/index.ts"],"sourcesContent":["/**\n * Image Activity\n *\n * Generates images from text prompts.\n * This is a self-contained module with implementation, types, and JSDoc.\n */\n\nimport { aiEventClient } from '@tanstack/ai-event-client'\nimport { streamGenerationResult } from '../stream-generation-result.js'\nimport { resolveDebugOption } from '../../logger/resolve'\nimport {\n applyGenerationResultTransforms,\n createGenerationContext,\n runGenerationAbort,\n runGenerationError,\n runGenerationFinish,\n runGenerationStart,\n runGenerationUsage,\n} from '../middleware/run'\nimport {\n abortReasonMessage,\n createActivityAbortControls,\n isActivityAbortError,\n raceWithAbort,\n} from '../../utilities/activity-abort'\nimport { resolveMediaPrompt } from '../../utilities/media-prompt'\nimport { assertPromptFileSourceSupport } from '../../utilities/content-source'\nimport type { InternalLogger } from '../../logger/internal-logger'\nimport type { DebugOption } from '../../logger/types'\nimport type { GenerationMiddleware } from '../middleware/types'\nimport type { ImageAdapter } from './adapter'\nimport type {\n ImageGenerationResult,\n MediaPrompt,\n MediaPromptFor,\n StreamChunk,\n} from '../../types'\n\n// ===========================\n// Activity Kind\n// ===========================\n\n/** The adapter kind this activity handles */\nexport const kind = 'image' as const\n\n// ===========================\n// Type Extraction Helpers\n// ===========================\n\n/**\n * Extract model-specific provider options from an ImageAdapter via ~types.\n * If the model has specific options defined in ModelProviderOptions (and not just via index signature),\n * use those; otherwise fall back to base provider options.\n */\nexport type ImageProviderOptionsForModel<TAdapter, TModel extends string> =\n TAdapter extends ImageAdapter<any, infer BaseOptions, infer ModelOptions, any>\n ? string extends keyof ModelOptions\n ? // ModelOptions is Record<string, unknown> or has index signature - use BaseOptions\n BaseOptions\n : // ModelOptions has explicit keys - check if TModel is one of them\n TModel extends keyof ModelOptions\n ? ModelOptions[TModel]\n : BaseOptions\n : object\n\n/**\n * Extract model-specific size options from an ImageAdapter via ~types.\n * If the model has specific sizes defined, use those; otherwise fall back to string.\n */\nexport type ImageSizeForModel<TAdapter, TModel extends string> =\n TAdapter extends ImageAdapter<any, any, any, infer SizeByName>\n ? string extends keyof SizeByName\n ? // SizeByName has index signature - fall back to string\n string\n : // SizeByName has explicit keys - check if TModel is one of them\n TModel extends keyof SizeByName\n ? SizeByName[TModel]\n : string\n : string\n\n/**\n * Extract the prompt type a model accepts from an ImageAdapter via ~types.\n * Adapters declare a per-model input-modality map; models in the map get a\n * `prompt` narrowed to text + their supported part types (text-only models\n * accept `string | Array<TextPart>`), so unsupported media parts fail at\n * compile time. Adapters without a map fall back to the full MediaPrompt.\n */\nexport type ImagePromptForModel<TAdapter, TModel extends string> =\n TAdapter extends ImageAdapter<any, any, any, any, infer ModsByName>\n ? string extends keyof ModsByName\n ? // No explicit map - accept the full union\n MediaPrompt\n : TModel extends keyof ModsByName\n ? MediaPromptFor<ModsByName[TModel][number]>\n : MediaPrompt\n : MediaPrompt\n\n// ===========================\n// Activity Options Type\n// ===========================\n\n/**\n * Options for the image activity.\n * The model is extracted from the adapter's model property.\n *\n * @template TAdapter - The image adapter type\n * @template TStream - Whether to stream the output\n */\nexport type ImageActivityOptions<\n TAdapter extends ImageAdapter<string, any, any, any>,\n TStream extends boolean = false,\n> = {\n /** The image adapter to use (must be created with a model) */\n adapter: TAdapter & { kind: typeof kind }\n /**\n * Description of the desired image(s). Either a plain string, or — for\n * models that support image-conditioned generation — an ordered array of\n * content parts interleaving text with image inputs (image-to-image,\n * reference-guided, edit, multi-reference). Media parts may carry\n * `metadata.role` (`'reference' | 'mask' | 'control' | 'character'`) to\n * disambiguate intent. The accepted part types are narrowed per model via\n * the adapter's input-modality map.\n */\n prompt: ImagePromptForModel<TAdapter, TAdapter['model']>\n /** Number of images to generate (default: 1) */\n numberOfImages?: number\n /** Image size in WIDTHxHEIGHT format (e.g., \"1024x1024\") */\n size?: ImageSizeForModel<TAdapter, TAdapter['model']>\n /**\n * Whether to stream the image generation result.\n * When true, returns an AsyncIterable<StreamChunk> for streaming transport.\n * When false or not provided, returns a Promise<ImageGenerationResult>.\n *\n * @default false\n */\n stream?: TStream\n /**\n * Enable debug logging. Pass `true` to enable all categories, `false` to\n * silence everything including errors, or a `DebugConfig` object for granular\n * control and/or a custom `Logger`.\n */\n debug?: DebugOption\n /**\n * Observe-only middleware notified on start, usage, success, and error. Pass\n * `otelMiddleware()` to emit OpenTelemetry spans, or implement the\n * `GenerationMiddleware` contract for a custom backend.\n */\n middleware?: Array<GenerationMiddleware>\n /** Stable conversation/thread id for correlating this run when persisted. */\n threadId?: string\n /** Stable run id for correlating this run when persisted. */\n runId?: string\n /**\n * Maximum duration of this activity invocation in milliseconds.\n * No SDK-wide default — choose a value suitable for the provider and job.\n * Composed with {@link abortSignal}; the first abort wins.\n */\n timeout?: number\n /**\n * Caller cancellation signal (request disconnects, job/runtime cancellation).\n * Composed with {@link timeout} into an effective signal forwarded to the\n * adapter. Request-specific — not stored on global provider client config.\n */\n abortSignal?: AbortSignal\n} & ({} extends ImageProviderOptionsForModel<TAdapter, TAdapter['model']>\n ? {\n /** Provider-specific options for image generation */ modelOptions?: ImageProviderOptionsForModel<\n TAdapter,\n TAdapter['model']\n >\n }\n : {\n /** Provider-specific options for image generation */ modelOptions: ImageProviderOptionsForModel<\n TAdapter,\n TAdapter['model']\n >\n })\n\n// ===========================\n// Activity Result Type\n// ===========================\n\n/**\n * Result type for the image activity.\n * - If stream is true: AsyncIterable<StreamChunk>\n * - Otherwise: Promise<ImageGenerationResult>\n */\nexport type ImageActivityResult<TStream extends boolean = false> =\n TStream extends true\n ? AsyncIterable<StreamChunk>\n : Promise<ImageGenerationResult>\n\nfunction createId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`\n}\n\n// ===========================\n// Activity Implementation\n// ===========================\n\n/**\n * Image activity - generates images from text prompts.\n *\n * Uses AI image generation models to create images based on natural language descriptions.\n *\n * @example Generate a single image\n * ```ts\n * import { generateImage } from '@tanstack/ai'\n * import { openaiImage } from '@tanstack/ai-openai'\n *\n * const result = await generateImage({\n * adapter: openaiImage('dall-e-3'),\n * prompt: 'A serene mountain landscape at sunset'\n * })\n *\n * console.log(result.images[0].url)\n * ```\n *\n * @example Generate multiple images\n * ```ts\n * const result = await generateImage({\n * adapter: openaiImage('dall-e-2'),\n * prompt: 'A cute robot mascot',\n * numberOfImages: 4,\n * size: '512x512'\n * })\n *\n * result.images.forEach((image, i) => {\n * console.log(`Image ${i + 1}: ${image.url}`)\n * })\n * ```\n *\n * @example With provider-specific options\n * ```ts\n * const result = await generateImage({\n * adapter: openaiImage('dall-e-3'),\n * prompt: 'A professional headshot photo',\n * size: '1024x1024',\n * modelOptions: {\n * quality: 'hd',\n * style: 'natural'\n * }\n * })\n * ```\n */\nexport function generateImage<\n TAdapter extends ImageAdapter<string, any, any, any>,\n TStream extends boolean = false,\n>(\n options: ImageActivityOptions<TAdapter, TStream>,\n): ImageActivityResult<TStream> {\n // Fail closed before middleware start and before `stream: true` emits\n // RUN_STARTED, so an unsupported file source never opens a run.\n assertPromptFileSourceSupport(options.adapter, options.prompt)\n if (options.stream) {\n return streamGenerationResult(\n // Only `runId` is taken from the resolved wire identity. `threadId` stays\n // the CALLER's: `streamGenerationResult` mints one for the RUN_* chunks\n // when none was passed, and spreading that over the options would hand\n // middleware a thread id known to nobody, which persistence would then\n // file the run under. Matches `generateVideo`.\n (resolved) => runGenerateImage({ ...options, runId: resolved.runId }),\n options,\n ) as ImageActivityResult<TStream>\n }\n\n return runGenerateImage(options) as ImageActivityResult<TStream>\n}\n\n/**\n * Internal implementation of image generation (always non-streaming).\n * Contains all devtools event emission logic.\n */\nasync function runGenerateImage<\n TAdapter extends ImageAdapter<string, any, any, any>,\n>(\n options: ImageActivityOptions<TAdapter, boolean>,\n): Promise<ImageGenerationResult> {\n const {\n adapter,\n stream: _stream,\n debug: _debug,\n middleware,\n threadId,\n runId,\n timeout,\n abortSignal: callerAbortSignal,\n ...rest\n } = options\n const model = adapter.model\n const requestId = createId('image')\n const startTime = Date.now()\n const logger: InternalLogger = resolveDebugOption(options.debug)\n const abortControls = createActivityAbortControls({\n timeout,\n abortSignal: callerAbortSignal,\n })\n\n const mwCtx = createGenerationContext({\n requestId,\n activity: 'image',\n provider: adapter.name,\n model,\n modelOptions: rest.modelOptions,\n threadId,\n runId,\n artifactInputs: { prompt: rest.prompt },\n createId,\n })\n\n await runGenerationStart(middleware, mwCtx)\n\n // Devtools events carry the flattened prompt text plus media-part counts —\n // the wire payload stays `prompt: string` regardless of the prompt shape.\n const resolved = resolveMediaPrompt(rest.prompt)\n\n aiEventClient.emit('image:request:started', {\n requestId,\n provider: adapter.name,\n model,\n prompt: resolved.text,\n numberOfImages: rest.numberOfImages,\n size: rest.size,\n ...(resolved.images.length > 0 && {\n imageInputCount: resolved.images.length,\n }),\n ...(resolved.videos.length > 0 && {\n videoInputCount: resolved.videos.length,\n }),\n ...(resolved.audios.length > 0 && {\n audioInputCount: resolved.audios.length,\n }),\n modelOptions: rest.modelOptions,\n timestamp: startTime,\n })\n\n logger.request(`activity=generateImage provider=${adapter.name}`, {\n provider: adapter.name,\n model,\n })\n\n try {\n const rawResult = await raceWithAbort(\n adapter.generateImages({\n ...rest,\n model,\n logger,\n ...(abortControls.signal ? { abortSignal: abortControls.signal } : {}),\n }),\n abortControls.signal,\n )\n abortControls.clear()\n const result = await applyGenerationResultTransforms(mwCtx, rawResult)\n const duration = Date.now() - startTime\n\n aiEventClient.emit('image:request:completed', {\n requestId,\n provider: adapter.name,\n model,\n // GeneratedImage is a discriminated `{ url } | { b64Json }` union, but the\n // wire shape on the devtools event is a plain optional pair. Use\n // conditional spreads so the emitted record only sets the field actually\n // present — `exactOptionalPropertyTypes` rejects `field: undefined`\n // against `field?: string` targets.\n images: result.images.map((image) => ({\n url: image.url,\n b64Json: image.b64Json,\n })),\n duration,\n modelOptions: rest.modelOptions,\n timestamp: Date.now(),\n })\n\n if (result.usage) {\n aiEventClient.emit('image:usage', {\n requestId,\n model,\n usage: result.usage,\n modelOptions: rest.modelOptions,\n timestamp: Date.now(),\n })\n }\n\n logger.output(`activity=generateImage count=${result.images.length}`, {\n count: result.images.length,\n })\n\n if (result.usage) await runGenerationUsage(middleware, mwCtx, result.usage)\n await runGenerationFinish(middleware, mwCtx, {\n duration,\n usage: result.usage,\n })\n\n return result\n } catch (error) {\n abortControls.clear()\n const duration = Date.now() - startTime\n if (isActivityAbortError(error, abortControls.signal)) {\n await runGenerationAbort(middleware, mwCtx, {\n reason: abortReasonMessage(error, abortControls.signal),\n duration,\n })\n } else {\n await runGenerationError(middleware, mwCtx, {\n error,\n duration,\n })\n }\n logger.errors('generateImage activity failed', {\n error,\n source: 'generateImage',\n })\n throw error\n }\n}\n\n// ===========================\n// Options Factory\n// ===========================\n\n/**\n * Create typed options for the generateImage() function without executing.\n */\nexport function createImageOptions<\n TAdapter extends ImageAdapter<string, any, any, any>,\n TStream extends boolean = false,\n>(\n options: ImageActivityOptions<TAdapter, TStream>,\n): ImageActivityOptions<TAdapter, TStream> {\n return options\n}\n\n// Re-export adapter types\nexport type {\n ImageAdapter,\n ImageAdapterConfig,\n AnyImageAdapter,\n} from './adapter'\nexport { BaseImageAdapter } from './adapter'\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolveDebugOption } from "../../logger/resolve.js";
|
|
2
|
-
import { streamGenerationResult } from "../stream-generation-result.js";
|
|
3
2
|
import { applyGenerationResultTransforms, createGenerationContext, runGenerationAbort, runGenerationError, runGenerationFinish, runGenerationStart, runGenerationUsage } from "../middleware/run.js";
|
|
3
|
+
import { streamGenerationResult } from "../stream-generation-result.js";
|
|
4
4
|
import { abortReasonMessage, createActivityAbortControls, isActivityAbortError, raceWithAbort } from "../../utilities/activity-abort.js";
|
|
5
5
|
import "./adapter.js";
|
|
6
6
|
import { aiEventClient } from "@tanstack/ai-event-client";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolveDebugOption } from "../../logger/resolve.js";
|
|
2
|
-
import { streamGenerationResult } from "../stream-generation-result.js";
|
|
3
2
|
import { applyGenerationResultTransforms, createGenerationContext, runGenerationAbort, runGenerationError, runGenerationFinish, runGenerationStart, runGenerationUsage } from "../middleware/run.js";
|
|
3
|
+
import { streamGenerationResult } from "../stream-generation-result.js";
|
|
4
4
|
import { abortReasonMessage, createActivityAbortControls, isActivityAbortError, raceWithAbort } from "../../utilities/activity-abort.js";
|
|
5
5
|
import "./adapter.js";
|
|
6
6
|
import { aiEventClient } from "@tanstack/ai-event-client";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolveDebugOption } from "../../logger/resolve.js";
|
|
2
|
-
import { streamGenerationResult } from "../stream-generation-result.js";
|
|
3
2
|
import { applyGenerationResultTransforms, createGenerationContext, runGenerationAbort, runGenerationError, runGenerationFinish, runGenerationStart, runGenerationUsage } from "../middleware/run.js";
|
|
3
|
+
import { streamGenerationResult } from "../stream-generation-result.js";
|
|
4
4
|
import { abortReasonMessage, createActivityAbortControls, isActivityAbortError, raceWithAbort } from "../../utilities/activity-abort.js";
|
|
5
5
|
import "./adapter.js";
|
|
6
6
|
import { aiEventClient } from "@tanstack/ai-event-client";
|
|
@@ -64,6 +64,13 @@ export interface VideoAdapter<TModel extends string = string, TProviderOptions e
|
|
|
64
64
|
readonly kind: 'video';
|
|
65
65
|
/** Adapter name identifier */
|
|
66
66
|
readonly name: string;
|
|
67
|
+
/**
|
|
68
|
+
* Declares that this adapter can consume `{ type: 'file' }` content
|
|
69
|
+
* sources (provider Files API references). The activity dispatcher rejects
|
|
70
|
+
* file sources in preflight for adapters that don't declare this, so
|
|
71
|
+
* adapters written before the file arm existed fail closed.
|
|
72
|
+
*/
|
|
73
|
+
readonly supportsFileSources?: boolean;
|
|
67
74
|
/** The model this adapter is configured for */
|
|
68
75
|
readonly model: TModel;
|
|
69
76
|
/**
|
|
@@ -118,6 +125,7 @@ export type AnyVideoAdapter = VideoAdapter<any, any, any, any, any, any>;
|
|
|
118
125
|
export declare abstract class BaseVideoAdapter<TModel extends string = string, TProviderOptions extends object = Record<string, unknown>, TModelProviderOptionsByName extends Record<string, any> = Record<string, any>, TModelSizeByName extends Record<string, string | undefined> = Record<string, string>, TModelInputModalitiesByName extends ModelInputModalitiesByName = ModelInputModalitiesByName, TModelDurationByName extends Record<string, string | number | undefined> = Record<string, number>> implements VideoAdapter<TModel, TProviderOptions, TModelProviderOptionsByName, TModelSizeByName, TModelInputModalitiesByName, TModelDurationByName> {
|
|
119
126
|
readonly kind: "video";
|
|
120
127
|
abstract readonly name: string;
|
|
128
|
+
readonly supportsFileSources: boolean;
|
|
121
129
|
readonly model: TModel;
|
|
122
130
|
'~types': {
|
|
123
131
|
providerOptions: TProviderOptions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","names":[],"sources":["../../../../src/activities/generateVideo/adapter.ts"],"sourcesContent":["import type {\n ModelInputModalitiesByName,\n VideoGenerationOptions,\n VideoJobResult,\n VideoStatusResult,\n VideoUrlResult,\n} from '../../types'\n\n/**\n * Structured description of the durations a video model accepts.\n *\n * Tagged union so the same shape can express discrete enums (OpenAI Sora,\n * Veo), continuous ranges, mixed shapes, and models with no duration field.\n * Consumed by `VideoAdapter.availableDurations()`.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type DurationOptions<T extends string | number | undefined> =\n | { kind: 'discrete'; values: ReadonlyArray<NonNullable<T>> }\n | { kind: 'range'; min: number; max: number; step?: number; unit: 'seconds' }\n | {\n kind: 'mixed'\n values: ReadonlyArray<NonNullable<T>>\n range?: { min: number; max: number; step?: number }\n }\n | { kind: 'none' }\n\n/**\n * Configuration for video adapter instances\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport interface VideoAdapterConfig {\n apiKey?: string\n baseUrl?: string\n timeout?: number\n maxRetries?: number\n headers?: Record<string, string>\n}\n\n/**\n * Video adapter interface with pre-resolved generics.\n *\n * An adapter is created by a provider function: `provider('model')` → `adapter`\n * All type resolution happens at the provider call site, not in this interface.\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * Generic parameters:\n * - TModel: The specific model name (e.g., 'sora-2')\n * - TProviderOptions: Provider-specific options (already resolved)\n * - TModelProviderOptionsByName: Map from model name to its specific provider options\n * - TModelSizeByName: Map from model name to its supported sizes\n * - TModelInputModalitiesByName: Map from model name to the non-text prompt\n * modalities it accepts (constrains the `prompt` part types at compile time)\n * - TModelDurationByName: Map from model name to its supported duration\n * union. Defaults to `Record<string, number>` so adapters that haven't\n * declared a map keep today's `duration?: number` typing.\n */\nexport interface VideoAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n TModelProviderOptionsByName extends Record<string, any> = Record<string, any>,\n TModelSizeByName extends Record<string, string | undefined> = Record<\n string,\n string\n >,\n TModelInputModalitiesByName extends ModelInputModalitiesByName =\n ModelInputModalitiesByName,\n TModelDurationByName extends Record<string, string | number | undefined> =\n Record<string, number>,\n> {\n /** Discriminator for adapter kind - used to determine API shape */\n readonly kind: 'video'\n /** Adapter name identifier */\n readonly name: string\n /** The model this adapter is configured for */\n readonly model: TModel\n\n /**\n * @internal Type-only properties for inference. Not assigned at runtime.\n */\n '~types': {\n providerOptions: TProviderOptions\n modelProviderOptionsByName: TModelProviderOptionsByName\n modelSizeByName: TModelSizeByName\n modelInputModalitiesByName: TModelInputModalitiesByName\n modelDurationByName: TModelDurationByName\n }\n\n /**\n * Create a new video generation job.\n * Returns a job ID that can be used to poll for status and retrieve the video.\n */\n createVideoJob: (\n options: VideoGenerationOptions<\n TProviderOptions,\n TModelSizeByName[TModel],\n TModelDurationByName[TModel]\n >,\n ) => Promise<VideoJobResult>\n\n /**\n * Get the current status of a video generation job.\n */\n getVideoStatus: (jobId: string) => Promise<VideoStatusResult>\n\n /**\n * Get the URL to download/view the generated video.\n * Should only be called after status is 'completed'.\n */\n getVideoUrl: (jobId: string) => Promise<VideoUrlResult>\n\n /**\n * Describe the durations this adapter's model accepts. Returns a tagged\n * union so consumers can render UI / coerce input without provider-specific\n * knowledge.\n */\n availableDurations: () => DurationOptions<TModelDurationByName[TModel]>\n\n /**\n * Coerce a raw seconds value to the closest valid duration for this model.\n * Returns `undefined` for models with no duration field.\n */\n snapDuration: (seconds: number) => TModelDurationByName[TModel] | undefined\n}\n\n/**\n * A VideoAdapter with any/unknown type parameters.\n * Useful as a constraint in generic functions and interfaces.\n */\nexport type AnyVideoAdapter = VideoAdapter<any, any, any, any, any, any>\n\n/**\n * Abstract base class for video generation adapters.\n * Extend this class to implement a video adapter for a specific provider.\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * Generic parameters match VideoAdapter - all pre-resolved by the provider function.\n */\nexport abstract class BaseVideoAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n TModelProviderOptionsByName extends Record<string, any> = Record<string, any>,\n TModelSizeByName extends Record<string, string | undefined> = Record<\n string,\n string\n >,\n TModelInputModalitiesByName extends ModelInputModalitiesByName =\n ModelInputModalitiesByName,\n TModelDurationByName extends Record<string, string | number | undefined> =\n Record<string, number>,\n> implements VideoAdapter<\n TModel,\n TProviderOptions,\n TModelProviderOptionsByName,\n TModelSizeByName,\n TModelInputModalitiesByName,\n TModelDurationByName\n> {\n readonly kind = 'video' as const\n abstract readonly name: string\n readonly model: TModel\n\n // Type-only property - never assigned at runtime\n declare '~types': {\n providerOptions: TProviderOptions\n modelProviderOptionsByName: TModelProviderOptionsByName\n modelSizeByName: TModelSizeByName\n modelInputModalitiesByName: TModelInputModalitiesByName\n modelDurationByName: TModelDurationByName\n }\n\n protected config: VideoAdapterConfig\n\n constructor(config: VideoAdapterConfig = {}, model: TModel) {\n this.config = config\n this.model = model\n }\n\n abstract createVideoJob(\n options: VideoGenerationOptions<\n TProviderOptions,\n TModelSizeByName[TModel],\n TModelDurationByName[TModel]\n >,\n ): Promise<VideoJobResult>\n\n abstract getVideoStatus(jobId: string): Promise<VideoStatusResult>\n\n abstract getVideoUrl(jobId: string): Promise<VideoUrlResult>\n\n /**\n * Default implementation returns `{ kind: 'none' }`. Adapters that have\n * declared their per-model duration map should override this.\n */\n availableDurations(): DurationOptions<TModelDurationByName[TModel]> {\n return { kind: 'none' }\n }\n\n /**\n * Default implementation returns `undefined`. Adapters that have declared\n * their per-model duration map should override.\n */\n snapDuration(_seconds: number): TModelDurationByName[TModel] | undefined {\n return undefined\n }\n\n protected generateId(): string {\n return `${this.name}-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n}\n"],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"adapter.js","names":[],"sources":["../../../../src/activities/generateVideo/adapter.ts"],"sourcesContent":["import type {\n ModelInputModalitiesByName,\n VideoGenerationOptions,\n VideoJobResult,\n VideoStatusResult,\n VideoUrlResult,\n} from '../../types'\n\n/**\n * Structured description of the durations a video model accepts.\n *\n * Tagged union so the same shape can express discrete enums (OpenAI Sora,\n * Veo), continuous ranges, mixed shapes, and models with no duration field.\n * Consumed by `VideoAdapter.availableDurations()`.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport type DurationOptions<T extends string | number | undefined> =\n | { kind: 'discrete'; values: ReadonlyArray<NonNullable<T>> }\n | { kind: 'range'; min: number; max: number; step?: number; unit: 'seconds' }\n | {\n kind: 'mixed'\n values: ReadonlyArray<NonNullable<T>>\n range?: { min: number; max: number; step?: number }\n }\n | { kind: 'none' }\n\n/**\n * Configuration for video adapter instances\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport interface VideoAdapterConfig {\n apiKey?: string\n baseUrl?: string\n timeout?: number\n maxRetries?: number\n headers?: Record<string, string>\n}\n\n/**\n * Video adapter interface with pre-resolved generics.\n *\n * An adapter is created by a provider function: `provider('model')` → `adapter`\n * All type resolution happens at the provider call site, not in this interface.\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * Generic parameters:\n * - TModel: The specific model name (e.g., 'sora-2')\n * - TProviderOptions: Provider-specific options (already resolved)\n * - TModelProviderOptionsByName: Map from model name to its specific provider options\n * - TModelSizeByName: Map from model name to its supported sizes\n * - TModelInputModalitiesByName: Map from model name to the non-text prompt\n * modalities it accepts (constrains the `prompt` part types at compile time)\n * - TModelDurationByName: Map from model name to its supported duration\n * union. Defaults to `Record<string, number>` so adapters that haven't\n * declared a map keep today's `duration?: number` typing.\n */\nexport interface VideoAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n TModelProviderOptionsByName extends Record<string, any> = Record<string, any>,\n TModelSizeByName extends Record<string, string | undefined> = Record<\n string,\n string\n >,\n TModelInputModalitiesByName extends ModelInputModalitiesByName =\n ModelInputModalitiesByName,\n TModelDurationByName extends Record<string, string | number | undefined> =\n Record<string, number>,\n> {\n /** Discriminator for adapter kind - used to determine API shape */\n readonly kind: 'video'\n /** Adapter name identifier */\n readonly name: string\n /**\n * Declares that this adapter can consume `{ type: 'file' }` content\n * sources (provider Files API references). The activity dispatcher rejects\n * file sources in preflight for adapters that don't declare this, so\n * adapters written before the file arm existed fail closed.\n */\n readonly supportsFileSources?: boolean\n /** The model this adapter is configured for */\n readonly model: TModel\n\n /**\n * @internal Type-only properties for inference. Not assigned at runtime.\n */\n '~types': {\n providerOptions: TProviderOptions\n modelProviderOptionsByName: TModelProviderOptionsByName\n modelSizeByName: TModelSizeByName\n modelInputModalitiesByName: TModelInputModalitiesByName\n modelDurationByName: TModelDurationByName\n }\n\n /**\n * Create a new video generation job.\n * Returns a job ID that can be used to poll for status and retrieve the video.\n */\n createVideoJob: (\n options: VideoGenerationOptions<\n TProviderOptions,\n TModelSizeByName[TModel],\n TModelDurationByName[TModel]\n >,\n ) => Promise<VideoJobResult>\n\n /**\n * Get the current status of a video generation job.\n */\n getVideoStatus: (jobId: string) => Promise<VideoStatusResult>\n\n /**\n * Get the URL to download/view the generated video.\n * Should only be called after status is 'completed'.\n */\n getVideoUrl: (jobId: string) => Promise<VideoUrlResult>\n\n /**\n * Describe the durations this adapter's model accepts. Returns a tagged\n * union so consumers can render UI / coerce input without provider-specific\n * knowledge.\n */\n availableDurations: () => DurationOptions<TModelDurationByName[TModel]>\n\n /**\n * Coerce a raw seconds value to the closest valid duration for this model.\n * Returns `undefined` for models with no duration field.\n */\n snapDuration: (seconds: number) => TModelDurationByName[TModel] | undefined\n}\n\n/**\n * A VideoAdapter with any/unknown type parameters.\n * Useful as a constraint in generic functions and interfaces.\n */\nexport type AnyVideoAdapter = VideoAdapter<any, any, any, any, any, any>\n\n/**\n * Abstract base class for video generation adapters.\n * Extend this class to implement a video adapter for a specific provider.\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * Generic parameters match VideoAdapter - all pre-resolved by the provider function.\n */\nexport abstract class BaseVideoAdapter<\n TModel extends string = string,\n TProviderOptions extends object = Record<string, unknown>,\n TModelProviderOptionsByName extends Record<string, any> = Record<string, any>,\n TModelSizeByName extends Record<string, string | undefined> = Record<\n string,\n string\n >,\n TModelInputModalitiesByName extends ModelInputModalitiesByName =\n ModelInputModalitiesByName,\n TModelDurationByName extends Record<string, string | number | undefined> =\n Record<string, number>,\n> implements VideoAdapter<\n TModel,\n TProviderOptions,\n TModelProviderOptionsByName,\n TModelSizeByName,\n TModelInputModalitiesByName,\n TModelDurationByName\n> {\n readonly kind = 'video' as const\n abstract readonly name: string\n readonly supportsFileSources: boolean = false\n readonly model: TModel\n\n // Type-only property - never assigned at runtime\n declare '~types': {\n providerOptions: TProviderOptions\n modelProviderOptionsByName: TModelProviderOptionsByName\n modelSizeByName: TModelSizeByName\n modelInputModalitiesByName: TModelInputModalitiesByName\n modelDurationByName: TModelDurationByName\n }\n\n protected config: VideoAdapterConfig\n\n constructor(config: VideoAdapterConfig = {}, model: TModel) {\n this.config = config\n this.model = model\n }\n\n abstract createVideoJob(\n options: VideoGenerationOptions<\n TProviderOptions,\n TModelSizeByName[TModel],\n TModelDurationByName[TModel]\n >,\n ): Promise<VideoJobResult>\n\n abstract getVideoStatus(jobId: string): Promise<VideoStatusResult>\n\n abstract getVideoUrl(jobId: string): Promise<VideoUrlResult>\n\n /**\n * Default implementation returns `{ kind: 'none' }`. Adapters that have\n * declared their per-model duration map should override this.\n */\n availableDurations(): DurationOptions<TModelDurationByName[TModel]> {\n return { kind: 'none' }\n }\n\n /**\n * Default implementation returns `undefined`. Adapters that have declared\n * their per-model duration map should override.\n */\n snapDuration(_seconds: number): TModelDurationByName[TModel] | undefined {\n return undefined\n }\n\n protected generateId(): string {\n return `${this.name}-${Date.now()}-${Math.random().toString(36).substring(7)}`\n }\n}\n"],"mappings":";;;;;;;;;AAoJA,IAAsB,mBAAtB,MAmBE;CACA,OAAgB;CAEhB,sBAAwC;CACxC;CAWA;CAEA,YAAY,SAA6B,CAAC,GAAG,OAAe;EAC1D,KAAK,SAAS;EACd,KAAK,QAAQ;CACf;;;;;CAkBA,qBAAoE;EAClE,OAAO,EAAE,MAAM,OAAO;CACxB;;;;;CAMA,aAAa,UAA4D,CAEzE;CAEA,aAA+B;EAC7B,OAAO,GAAG,KAAK,KAAK,GAAG,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,UAAU,CAAC;CAC7E;AACF"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { toRunErrorPayload } from "../error-payload.js";
|
|
2
2
|
import { normalizeStreamChunk } from "../../utilities/normalize-stream-chunk.js";
|
|
3
3
|
import { resolveDebugOption } from "../../logger/resolve.js";
|
|
4
|
+
import { assertPromptFileSourceSupport } from "../../utilities/content-source.js";
|
|
4
5
|
import { applyGenerationResultTransforms, createGenerationContext, runGenerationAbort, runGenerationError, runGenerationFinish, runGenerationStart, runGenerationUsage } from "../middleware/run.js";
|
|
5
6
|
import { abortReasonMessage, createActivityAbortControls, isActivityAbortError, raceWithAbort, toAbortError } from "../../utilities/activity-abort.js";
|
|
6
7
|
import "./adapter.js";
|
|
@@ -108,6 +109,7 @@ function videoRunIdForJob(provider, jobId) {
|
|
|
108
109
|
*/
|
|
109
110
|
async function runCreateVideoJob(options) {
|
|
110
111
|
const { adapter, prompt, size, duration, modelOptions, middleware, timeout, abortSignal: callerAbortSignal } = options;
|
|
112
|
+
assertPromptFileSourceSupport(adapter, prompt);
|
|
111
113
|
const model = adapter.model;
|
|
112
114
|
const requestId = createId("video");
|
|
113
115
|
const startTime = Date.now();
|
|
@@ -193,6 +195,7 @@ function sleep(ms, signal) {
|
|
|
193
195
|
*/
|
|
194
196
|
async function* runStreamingVideoGeneration(options) {
|
|
195
197
|
const { adapter, prompt, size, duration, modelOptions, middleware, timeout, abortSignal: callerAbortSignal } = options;
|
|
198
|
+
assertPromptFileSourceSupport(adapter, prompt);
|
|
196
199
|
const model = adapter.model;
|
|
197
200
|
const runId = options.runId ?? createId("run");
|
|
198
201
|
const requestId = createId("video");
|