@cloudflare/tanstack-ai 0.0.0 → 0.1.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.
Files changed (127) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +282 -0
  3. package/dist/_tsup-dts-rollup.d.cts +820 -0
  4. package/dist/_tsup-dts-rollup.d.ts +820 -0
  5. package/dist/adapters/anthropic.cjs +13 -0
  6. package/dist/adapters/anthropic.cjs.map +1 -0
  7. package/dist/adapters/anthropic.d.cts +5 -0
  8. package/dist/adapters/anthropic.d.ts +5 -0
  9. package/dist/adapters/anthropic.js +13 -0
  10. package/dist/adapters/anthropic.js.map +1 -0
  11. package/dist/adapters/gemini.cjs +22 -0
  12. package/dist/adapters/gemini.cjs.map +1 -0
  13. package/dist/adapters/gemini.d.cts +14 -0
  14. package/dist/adapters/gemini.d.ts +14 -0
  15. package/dist/adapters/gemini.js +22 -0
  16. package/dist/adapters/gemini.js.map +1 -0
  17. package/dist/adapters/grok.cjs +17 -0
  18. package/dist/adapters/grok.cjs.map +1 -0
  19. package/dist/adapters/grok.d.cts +9 -0
  20. package/dist/adapters/grok.d.ts +9 -0
  21. package/dist/adapters/grok.js +17 -0
  22. package/dist/adapters/grok.js.map +1 -0
  23. package/dist/adapters/openai.cjs +29 -0
  24. package/dist/adapters/openai.cjs.map +1 -0
  25. package/dist/adapters/openai.d.cts +17 -0
  26. package/dist/adapters/openai.d.ts +17 -0
  27. package/dist/adapters/openai.js +29 -0
  28. package/dist/adapters/openai.js.map +1 -0
  29. package/dist/adapters/openrouter.cjs +13 -0
  30. package/dist/adapters/openrouter.cjs.map +1 -0
  31. package/dist/adapters/openrouter.d.cts +7 -0
  32. package/dist/adapters/openrouter.d.ts +7 -0
  33. package/dist/adapters/openrouter.js +13 -0
  34. package/dist/adapters/openrouter.js.map +1 -0
  35. package/dist/adapters/workers-ai-image.cjs +13 -0
  36. package/dist/adapters/workers-ai-image.cjs.map +1 -0
  37. package/dist/adapters/workers-ai-image.d.cts +3 -0
  38. package/dist/adapters/workers-ai-image.d.ts +3 -0
  39. package/dist/adapters/workers-ai-image.js +13 -0
  40. package/dist/adapters/workers-ai-image.js.map +1 -0
  41. package/dist/adapters/workers-ai-summarize.cjs +12 -0
  42. package/dist/adapters/workers-ai-summarize.cjs.map +1 -0
  43. package/dist/adapters/workers-ai-summarize.d.cts +3 -0
  44. package/dist/adapters/workers-ai-summarize.d.ts +3 -0
  45. package/dist/adapters/workers-ai-summarize.js +12 -0
  46. package/dist/adapters/workers-ai-summarize.js.map +1 -0
  47. package/dist/adapters/workers-ai-transcription.cjs +13 -0
  48. package/dist/adapters/workers-ai-transcription.cjs.map +1 -0
  49. package/dist/adapters/workers-ai-transcription.d.cts +3 -0
  50. package/dist/adapters/workers-ai-transcription.d.ts +3 -0
  51. package/dist/adapters/workers-ai-transcription.js +13 -0
  52. package/dist/adapters/workers-ai-transcription.js.map +1 -0
  53. package/dist/adapters/workers-ai-tts.cjs +13 -0
  54. package/dist/adapters/workers-ai-tts.cjs.map +1 -0
  55. package/dist/adapters/workers-ai-tts.d.cts +3 -0
  56. package/dist/adapters/workers-ai-tts.d.ts +3 -0
  57. package/dist/adapters/workers-ai-tts.js +13 -0
  58. package/dist/adapters/workers-ai-tts.js.map +1 -0
  59. package/dist/adapters/workers-ai.cjs +11 -0
  60. package/dist/adapters/workers-ai.cjs.map +1 -0
  61. package/dist/adapters/workers-ai.d.cts +3 -0
  62. package/dist/adapters/workers-ai.d.ts +3 -0
  63. package/dist/adapters/workers-ai.js +11 -0
  64. package/dist/adapters/workers-ai.js.map +1 -0
  65. package/dist/chunk-2AJ6LV2D.js +84 -0
  66. package/dist/chunk-2AJ6LV2D.js.map +1 -0
  67. package/dist/chunk-2VII5BK2.js +42 -0
  68. package/dist/chunk-2VII5BK2.js.map +1 -0
  69. package/dist/chunk-3VQDXJLW.cjs +46 -0
  70. package/dist/chunk-3VQDXJLW.cjs.map +1 -0
  71. package/dist/chunk-4DE2IREA.cjs +8 -0
  72. package/dist/chunk-4DE2IREA.cjs.map +1 -0
  73. package/dist/chunk-7AEFXYJG.js +65 -0
  74. package/dist/chunk-7AEFXYJG.js.map +1 -0
  75. package/dist/chunk-7HSUHP63.cjs +42 -0
  76. package/dist/chunk-7HSUHP63.cjs.map +1 -0
  77. package/dist/chunk-7T4CVHKD.cjs +84 -0
  78. package/dist/chunk-7T4CVHKD.cjs.map +1 -0
  79. package/dist/chunk-BD4CRW3Q.js +389 -0
  80. package/dist/chunk-BD4CRW3Q.js.map +1 -0
  81. package/dist/chunk-BPWGWJJV.cjs +389 -0
  82. package/dist/chunk-BPWGWJJV.cjs.map +1 -0
  83. package/dist/chunk-F5YJMXZR.js +315 -0
  84. package/dist/chunk-F5YJMXZR.js.map +1 -0
  85. package/dist/chunk-GOU66I5T.cjs +315 -0
  86. package/dist/chunk-GOU66I5T.cjs.map +1 -0
  87. package/dist/chunk-IWZJCLOE.cjs +31 -0
  88. package/dist/chunk-IWZJCLOE.cjs.map +1 -0
  89. package/dist/chunk-LBYDBPHY.cjs +109 -0
  90. package/dist/chunk-LBYDBPHY.cjs.map +1 -0
  91. package/dist/chunk-LIUHRGEK.cjs +96 -0
  92. package/dist/chunk-LIUHRGEK.cjs.map +1 -0
  93. package/dist/chunk-M6NETFDR.cjs +48 -0
  94. package/dist/chunk-M6NETFDR.cjs.map +1 -0
  95. package/dist/chunk-O2C4CR57.cjs +54 -0
  96. package/dist/chunk-O2C4CR57.cjs.map +1 -0
  97. package/dist/chunk-PLTFCUMO.js +216 -0
  98. package/dist/chunk-PLTFCUMO.js.map +1 -0
  99. package/dist/chunk-QRHKPL75.js +54 -0
  100. package/dist/chunk-QRHKPL75.js.map +1 -0
  101. package/dist/chunk-RGDUK5KX.cjs +65 -0
  102. package/dist/chunk-RGDUK5KX.cjs.map +1 -0
  103. package/dist/chunk-RQT7M6MU.js +96 -0
  104. package/dist/chunk-RQT7M6MU.js.map +1 -0
  105. package/dist/chunk-U5YJQYLZ.cjs +57 -0
  106. package/dist/chunk-U5YJQYLZ.cjs.map +1 -0
  107. package/dist/chunk-V6TY7KAL.js +8 -0
  108. package/dist/chunk-V6TY7KAL.js.map +1 -0
  109. package/dist/chunk-VTDJEUFS.js +57 -0
  110. package/dist/chunk-VTDJEUFS.js.map +1 -0
  111. package/dist/chunk-XCNU7EEC.js +48 -0
  112. package/dist/chunk-XCNU7EEC.js.map +1 -0
  113. package/dist/chunk-XI2BOYEI.js +109 -0
  114. package/dist/chunk-XI2BOYEI.js.map +1 -0
  115. package/dist/chunk-XKSFDPDY.cjs +216 -0
  116. package/dist/chunk-XKSFDPDY.cjs.map +1 -0
  117. package/dist/chunk-XU7YEPML.js +46 -0
  118. package/dist/chunk-XU7YEPML.js.map +1 -0
  119. package/dist/chunk-YIA5B3QT.js +31 -0
  120. package/dist/chunk-YIA5B3QT.js.map +1 -0
  121. package/dist/index.cjs +97 -0
  122. package/dist/index.cjs.map +1 -0
  123. package/dist/index.d.cts +64 -0
  124. package/dist/index.d.ts +64 -0
  125. package/dist/index.js +97 -0
  126. package/dist/index.js.map +1 -0
  127. package/package.json +119 -10
@@ -0,0 +1,84 @@
1
+ import {
2
+ workersAiRestFetch
3
+ } from "./chunk-2VII5BK2.js";
4
+ import {
5
+ createGatewayFetch,
6
+ isDirectBindingConfig,
7
+ isDirectCredentialsConfig
8
+ } from "./chunk-F5YJMXZR.js";
9
+ import {
10
+ __publicField
11
+ } from "./chunk-V6TY7KAL.js";
12
+
13
+ // src/adapters/workers-ai-summarize.ts
14
+ import { BaseSummarizeAdapter } from "@tanstack/ai/adapters";
15
+ var WorkersAiSummarizeAdapter = class extends BaseSummarizeAdapter {
16
+ constructor(config, model) {
17
+ super({}, model);
18
+ __publicField(this, "name", "workers-ai-summarize");
19
+ __publicField(this, "adapterConfig");
20
+ this.adapterConfig = config;
21
+ }
22
+ async summarize(options) {
23
+ const { text, maxLength } = options;
24
+ const payload = { input_text: text };
25
+ if (maxLength != null) payload.max_length = maxLength;
26
+ if (isDirectBindingConfig(this.adapterConfig)) {
27
+ return this.summarizeViaBinding(payload);
28
+ }
29
+ if (isDirectCredentialsConfig(this.adapterConfig)) {
30
+ return this.summarizeViaRest(payload);
31
+ }
32
+ return this.summarizeViaGateway(payload);
33
+ }
34
+ async summarizeViaBinding(payload) {
35
+ const ai = this.adapterConfig.binding;
36
+ const result = await ai.run(this.model, payload);
37
+ return this.wrapResult(result.summary ?? "");
38
+ }
39
+ async summarizeViaRest(payload) {
40
+ const config = this.adapterConfig;
41
+ const response = await workersAiRestFetch(config, this.model, payload, {
42
+ label: "Workers AI summarize"
43
+ });
44
+ const data = await response.json();
45
+ return this.wrapResult(data.result?.summary ?? "");
46
+ }
47
+ async summarizeViaGateway(payload) {
48
+ const gatewayConfig = this.adapterConfig;
49
+ const gatewayFetch = createGatewayFetch("workers-ai", gatewayConfig);
50
+ const response = await gatewayFetch("https://api.cloudflare.com/v1/ai/summarization", {
51
+ method: "POST",
52
+ body: JSON.stringify({
53
+ model: this.model,
54
+ ...payload
55
+ })
56
+ });
57
+ if (!response.ok) {
58
+ const errorText = await response.text();
59
+ throw new Error(
60
+ `Workers AI summarize gateway request failed (${response.status}): ${errorText}`
61
+ );
62
+ }
63
+ const data = await response.json();
64
+ return this.wrapResult(data.result?.summary ?? data.summary ?? "");
65
+ }
66
+ wrapResult(summary) {
67
+ return {
68
+ id: this.generateId(),
69
+ model: this.model,
70
+ summary,
71
+ // BART-large-CNN doesn't return token usage
72
+ usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 }
73
+ };
74
+ }
75
+ };
76
+ function createWorkersAiSummarize(model, config) {
77
+ return new WorkersAiSummarizeAdapter(config, model);
78
+ }
79
+
80
+ export {
81
+ WorkersAiSummarizeAdapter,
82
+ createWorkersAiSummarize
83
+ };
84
+ //# sourceMappingURL=chunk-2AJ6LV2D.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/workers-ai-summarize.ts"],"sourcesContent":["import { BaseSummarizeAdapter } from \"@tanstack/ai/adapters\";\nimport type { SummarizationOptions, SummarizationResult } from \"@tanstack/ai\";\nimport {\n\ttype WorkersAiAdapterConfig,\n\ttype WorkersAiDirectBindingConfig,\n\ttype WorkersAiDirectCredentialsConfig,\n\ttype AiGatewayAdapterConfig,\n\tcreateGatewayFetch,\n\tisDirectBindingConfig,\n\tisDirectCredentialsConfig,\n} from \"../utils/create-fetcher\";\nimport { workersAiRestFetch } from \"../utils/workers-ai-rest\";\n\n// ---------------------------------------------------------------------------\n// Model types\n// ---------------------------------------------------------------------------\n\n/**\n * Workers AI models that support summarization.\n */\nexport type WorkersAiSummarizeModel = \"@cf/facebook/bart-large-cnn\";\n\n// ---------------------------------------------------------------------------\n// WorkersAiSummarizeAdapter\n// ---------------------------------------------------------------------------\n\nexport class WorkersAiSummarizeAdapter extends BaseSummarizeAdapter<WorkersAiSummarizeModel> {\n\treadonly name = \"workers-ai-summarize\" as const;\n\tprivate adapterConfig: WorkersAiAdapterConfig;\n\n\tconstructor(config: WorkersAiAdapterConfig, model: WorkersAiSummarizeModel) {\n\t\tsuper({}, model);\n\t\tthis.adapterConfig = config;\n\t}\n\n\tasync summarize(options: SummarizationOptions): Promise<SummarizationResult> {\n\t\tconst { text, maxLength } = options;\n\n\t\tconst payload: Record<string, unknown> = { input_text: text };\n\t\tif (maxLength != null) payload.max_length = maxLength;\n\n\t\tif (isDirectBindingConfig(this.adapterConfig)) {\n\t\t\treturn this.summarizeViaBinding(payload);\n\t\t}\n\n\t\tif (isDirectCredentialsConfig(this.adapterConfig)) {\n\t\t\treturn this.summarizeViaRest(payload);\n\t\t}\n\n\t\treturn this.summarizeViaGateway(payload);\n\t}\n\n\tprivate async summarizeViaBinding(\n\t\tpayload: Record<string, unknown>,\n\t): Promise<SummarizationResult> {\n\t\tconst ai = (this.adapterConfig as WorkersAiDirectBindingConfig).binding;\n\t\tconst result = (await ai.run(this.model, payload)) as Record<string, unknown>;\n\t\treturn this.wrapResult((result.summary as string) ?? \"\");\n\t}\n\n\tprivate async summarizeViaRest(payload: Record<string, unknown>): Promise<SummarizationResult> {\n\t\tconst config = this.adapterConfig as WorkersAiDirectCredentialsConfig;\n\t\tconst response = await workersAiRestFetch(config, this.model, payload, {\n\t\t\tlabel: \"Workers AI summarize\",\n\t\t});\n\n\t\tconst data = (await response.json()) as { result?: { summary?: string } };\n\t\treturn this.wrapResult(data.result?.summary ?? \"\");\n\t}\n\n\tprivate async summarizeViaGateway(\n\t\tpayload: Record<string, unknown>,\n\t): Promise<SummarizationResult> {\n\t\tconst gatewayConfig = this.adapterConfig as AiGatewayAdapterConfig;\n\t\tconst gatewayFetch = createGatewayFetch(\"workers-ai\", gatewayConfig);\n\n\t\t// The URL here is a placeholder — createGatewayFetch for \"workers-ai\" extracts\n\t\t// the model from the body, sets it as the endpoint, and routes through the gateway.\n\t\t// The actual URL path is not used.\n\t\tconst response = await gatewayFetch(\"https://api.cloudflare.com/v1/ai/summarization\", {\n\t\t\tmethod: \"POST\",\n\t\t\tbody: JSON.stringify({\n\t\t\t\tmodel: this.model,\n\t\t\t\t...payload,\n\t\t\t}),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst errorText = await response.text();\n\t\t\tthrow new Error(\n\t\t\t\t`Workers AI summarize gateway request failed (${response.status}): ${errorText}`,\n\t\t\t);\n\t\t}\n\n\t\tconst data = (await response.json()) as { result?: { summary?: string }; summary?: string };\n\t\treturn this.wrapResult(data.result?.summary ?? data.summary ?? \"\");\n\t}\n\n\tprivate wrapResult(summary: string): SummarizationResult {\n\t\treturn {\n\t\t\tid: this.generateId(),\n\t\t\tmodel: this.model,\n\t\t\tsummary,\n\t\t\t// BART-large-CNN doesn't return token usage\n\t\t\tusage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n\t\t};\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Factory function\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a Workers AI summarization adapter.\n *\n * Works with TanStack AI's `summarize()` activity function:\n * ```ts\n * import { summarize } from \"@tanstack/ai\";\n * import { createWorkersAiSummarize } from \"@cloudflare/tanstack-ai\";\n *\n * const adapter = createWorkersAiSummarize(\"@cf/facebook/bart-large-cnn\", {\n * binding: env.AI,\n * });\n *\n * const result = await summarize({ adapter, text: \"Long article here...\" });\n * // result.summary\n * ```\n *\n * Note: Factory takes `(model, config)` for ergonomics — the class constructor\n * uses `(config, model)` to match TanStack AI's upstream convention.\n */\nexport function createWorkersAiSummarize(\n\tmodel: WorkersAiSummarizeModel,\n\tconfig: WorkersAiAdapterConfig,\n) {\n\treturn new WorkersAiSummarizeAdapter(config, model);\n}\n"],"mappings":";;;;;;;;;;;;;AAAA,SAAS,4BAA4B;AA0B9B,IAAM,4BAAN,cAAwC,qBAA8C;AAAA,EAI5F,YAAY,QAAgC,OAAgC;AAC3E,UAAM,CAAC,GAAG,KAAK;AAJhB,wBAAS,QAAO;AAChB,wBAAQ;AAIP,SAAK,gBAAgB;AAAA,EACtB;AAAA,EAEA,MAAM,UAAU,SAA6D;AAC5E,UAAM,EAAE,MAAM,UAAU,IAAI;AAE5B,UAAM,UAAmC,EAAE,YAAY,KAAK;AAC5D,QAAI,aAAa,KAAM,SAAQ,aAAa;AAE5C,QAAI,sBAAsB,KAAK,aAAa,GAAG;AAC9C,aAAO,KAAK,oBAAoB,OAAO;AAAA,IACxC;AAEA,QAAI,0BAA0B,KAAK,aAAa,GAAG;AAClD,aAAO,KAAK,iBAAiB,OAAO;AAAA,IACrC;AAEA,WAAO,KAAK,oBAAoB,OAAO;AAAA,EACxC;AAAA,EAEA,MAAc,oBACb,SAC+B;AAC/B,UAAM,KAAM,KAAK,cAA+C;AAChE,UAAM,SAAU,MAAM,GAAG,IAAI,KAAK,OAAO,OAAO;AAChD,WAAO,KAAK,WAAY,OAAO,WAAsB,EAAE;AAAA,EACxD;AAAA,EAEA,MAAc,iBAAiB,SAAgE;AAC9F,UAAM,SAAS,KAAK;AACpB,UAAM,WAAW,MAAM,mBAAmB,QAAQ,KAAK,OAAO,SAAS;AAAA,MACtE,OAAO;AAAA,IACR,CAAC;AAED,UAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,WAAO,KAAK,WAAW,KAAK,QAAQ,WAAW,EAAE;AAAA,EAClD;AAAA,EAEA,MAAc,oBACb,SAC+B;AAC/B,UAAM,gBAAgB,KAAK;AAC3B,UAAM,eAAe,mBAAmB,cAAc,aAAa;AAKnE,UAAM,WAAW,MAAM,aAAa,kDAAkD;AAAA,MACrF,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU;AAAA,QACpB,OAAO,KAAK;AAAA,QACZ,GAAG;AAAA,MACJ,CAAC;AAAA,IACF,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AACjB,YAAM,YAAY,MAAM,SAAS,KAAK;AACtC,YAAM,IAAI;AAAA,QACT,gDAAgD,SAAS,MAAM,MAAM,SAAS;AAAA,MAC/E;AAAA,IACD;AAEA,UAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,WAAO,KAAK,WAAW,KAAK,QAAQ,WAAW,KAAK,WAAW,EAAE;AAAA,EAClE;AAAA,EAEQ,WAAW,SAAsC;AACxD,WAAO;AAAA,MACN,IAAI,KAAK,WAAW;AAAA,MACpB,OAAO,KAAK;AAAA,MACZ;AAAA;AAAA,MAEA,OAAO,EAAE,cAAc,GAAG,kBAAkB,GAAG,aAAa,EAAE;AAAA,IAC/D;AAAA,EACD;AACD;AAyBO,SAAS,yBACf,OACA,QACC;AACD,SAAO,IAAI,0BAA0B,QAAQ,KAAK;AACnD;","names":[]}
@@ -0,0 +1,42 @@
1
+ // src/utils/workers-ai-rest.ts
2
+ var WORKERS_AI_REST_BASE = "https://api.cloudflare.com/client/v4/accounts";
3
+ async function workersAiRestFetch(config, model, body, options) {
4
+ const response = await fetch(`${WORKERS_AI_REST_BASE}/${config.accountId}/ai/run/${model}`, {
5
+ method: "POST",
6
+ headers: {
7
+ Authorization: `Bearer ${config.apiKey}`,
8
+ "Content-Type": "application/json"
9
+ },
10
+ body: JSON.stringify(body),
11
+ signal: options?.signal
12
+ });
13
+ if (!response.ok) {
14
+ const errorText = await response.text();
15
+ const label = options?.label ?? "Workers AI";
16
+ throw new Error(`${label} request failed (${response.status}): ${errorText}`);
17
+ }
18
+ return response;
19
+ }
20
+ async function workersAiRestFetchBinary(config, model, audioBytes, contentType, options) {
21
+ const response = await fetch(`${WORKERS_AI_REST_BASE}/${config.accountId}/ai/run/${model}`, {
22
+ method: "POST",
23
+ headers: {
24
+ Authorization: `Bearer ${config.apiKey}`,
25
+ "Content-Type": contentType
26
+ },
27
+ body: audioBytes,
28
+ signal: options?.signal
29
+ });
30
+ if (!response.ok) {
31
+ const errorText = await response.text();
32
+ const label = options?.label ?? "Workers AI";
33
+ throw new Error(`${label} request failed (${response.status}): ${errorText}`);
34
+ }
35
+ return response;
36
+ }
37
+
38
+ export {
39
+ workersAiRestFetch,
40
+ workersAiRestFetchBinary
41
+ };
42
+ //# sourceMappingURL=chunk-2VII5BK2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/workers-ai-rest.ts"],"sourcesContent":["import type { WorkersAiDirectCredentialsConfig } from \"./create-fetcher\";\n\n/**\n * Workers AI REST API base URL.\n * All model endpoints follow the pattern: `${BASE_URL}/${accountId}/ai/run/${model}`\n */\nconst WORKERS_AI_REST_BASE = \"https://api.cloudflare.com/client/v4/accounts\";\n\n/**\n * Make a REST API call to Workers AI.\n *\n * Handles the common pattern shared by all Workers AI adapters:\n * - Build the URL from account ID and model name\n * - Set Authorization and Content-Type headers\n * - Check response.ok and throw a descriptive error on failure\n *\n * @param config Credentials config with accountId and apiKey\n * @param model Workers AI model name (e.g. \"@cf/stabilityai/stable-diffusion-xl-base-1.0\")\n * @param body JSON request body\n * @param options Optional settings:\n * - `label` — human-readable label for error messages (default: \"Workers AI\")\n * - `signal` — AbortSignal for request cancellation / timeout\n * @returns The raw Response object — caller is responsible for parsing\n */\nexport async function workersAiRestFetch(\n\tconfig: WorkersAiDirectCredentialsConfig,\n\tmodel: string,\n\tbody: Record<string, unknown>,\n\toptions?: { label?: string; signal?: AbortSignal },\n): Promise<Response> {\n\tconst response = await fetch(`${WORKERS_AI_REST_BASE}/${config.accountId}/ai/run/${model}`, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${config.apiKey}`,\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tbody: JSON.stringify(body),\n\t\tsignal: options?.signal,\n\t});\n\n\tif (!response.ok) {\n\t\tconst errorText = await response.text();\n\t\tconst label = options?.label ?? \"Workers AI\";\n\t\tthrow new Error(`${label} request failed (${response.status}): ${errorText}`);\n\t}\n\n\treturn response;\n}\n\n/**\n * Make a binary REST API call to Workers AI.\n *\n * Some models (e.g. `@cf/deepgram/nova-3`) require raw binary audio with an\n * appropriate `Content-Type` header instead of JSON. This function sends the\n * audio bytes directly as the request body.\n *\n * @param config Credentials config with accountId and apiKey\n * @param model Workers AI model name\n * @param audioBytes Raw audio bytes\n * @param contentType MIME type of the audio (e.g. \"audio/wav\")\n * @param options Optional settings\n * @returns The raw Response object\n */\nexport async function workersAiRestFetchBinary(\n\tconfig: WorkersAiDirectCredentialsConfig,\n\tmodel: string,\n\taudioBytes: Uint8Array,\n\tcontentType: string,\n\toptions?: { label?: string; signal?: AbortSignal },\n): Promise<Response> {\n\tconst response = await fetch(`${WORKERS_AI_REST_BASE}/${config.accountId}/ai/run/${model}`, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${config.apiKey}`,\n\t\t\t\"Content-Type\": contentType,\n\t\t},\n\t\tbody: audioBytes,\n\t\tsignal: options?.signal,\n\t});\n\n\tif (!response.ok) {\n\t\tconst errorText = await response.text();\n\t\tconst label = options?.label ?? \"Workers AI\";\n\t\tthrow new Error(`${label} request failed (${response.status}): ${errorText}`);\n\t}\n\n\treturn response;\n}\n"],"mappings":";AAMA,IAAM,uBAAuB;AAkB7B,eAAsB,mBACrB,QACA,OACA,MACA,SACoB;AACpB,QAAM,WAAW,MAAM,MAAM,GAAG,oBAAoB,IAAI,OAAO,SAAS,WAAW,KAAK,IAAI;AAAA,IAC3F,QAAQ;AAAA,IACR,SAAS;AAAA,MACR,eAAe,UAAU,OAAO,MAAM;AAAA,MACtC,gBAAgB;AAAA,IACjB;AAAA,IACA,MAAM,KAAK,UAAU,IAAI;AAAA,IACzB,QAAQ,SAAS;AAAA,EAClB,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AACjB,UAAM,YAAY,MAAM,SAAS,KAAK;AACtC,UAAM,QAAQ,SAAS,SAAS;AAChC,UAAM,IAAI,MAAM,GAAG,KAAK,oBAAoB,SAAS,MAAM,MAAM,SAAS,EAAE;AAAA,EAC7E;AAEA,SAAO;AACR;AAgBA,eAAsB,yBACrB,QACA,OACA,YACA,aACA,SACoB;AACpB,QAAM,WAAW,MAAM,MAAM,GAAG,oBAAoB,IAAI,OAAO,SAAS,WAAW,KAAK,IAAI;AAAA,IAC3F,QAAQ;AAAA,IACR,SAAS;AAAA,MACR,eAAe,UAAU,OAAO,MAAM;AAAA,MACtC,gBAAgB;AAAA,IACjB;AAAA,IACA,MAAM;AAAA,IACN,QAAQ,SAAS;AAAA,EAClB,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AACjB,UAAM,YAAY,MAAM,SAAS,KAAK;AACtC,UAAM,QAAQ,SAAS,SAAS;AAChC,UAAM,IAAI,MAAM,GAAG,KAAK,oBAAoB,SAAS,MAAM,MAAM,SAAS,EAAE;AAAA,EAC7E;AAEA,SAAO;AACR;","names":[]}
@@ -0,0 +1,46 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/utils/binary.ts
2
+ function uint8ArrayToBase64(bytes) {
3
+ let binary = "";
4
+ for (let i = 0; i < bytes.length; i++) {
5
+ binary += String.fromCharCode(bytes[i]);
6
+ }
7
+ return btoa(binary);
8
+ }
9
+ async function collectStream(stream) {
10
+ const reader = stream.getReader();
11
+ const chunks = [];
12
+ while (true) {
13
+ const { done, value } = await reader.read();
14
+ if (done) break;
15
+ chunks.push(value);
16
+ }
17
+ const totalLength = chunks.reduce((acc, c) => acc + c.length, 0);
18
+ const combined = new Uint8Array(totalLength);
19
+ let offset = 0;
20
+ for (const chunk of chunks) {
21
+ combined.set(chunk, offset);
22
+ offset += chunk.length;
23
+ }
24
+ return combined;
25
+ }
26
+ async function binaryToBase64(result, binaryKey = "image") {
27
+ if (result instanceof ReadableStream) {
28
+ return uint8ArrayToBase64(await collectStream(result));
29
+ }
30
+ if (result instanceof Uint8Array || result instanceof ArrayBuffer) {
31
+ const bytes = result instanceof ArrayBuffer ? new Uint8Array(result) : result;
32
+ return uint8ArrayToBase64(bytes);
33
+ }
34
+ if (typeof result === "object" && result !== null && binaryKey in result) {
35
+ return result[binaryKey];
36
+ }
37
+ throw new Error(
38
+ `Unexpected binary response format from Workers AI (expected Uint8Array, ArrayBuffer, ReadableStream, or { ${binaryKey}: string })`
39
+ );
40
+ }
41
+
42
+
43
+
44
+
45
+ exports.uint8ArrayToBase64 = uint8ArrayToBase64; exports.binaryToBase64 = binaryToBase64;
46
+ //# sourceMappingURL=chunk-3VQDXJLW.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/ai/ai/packages/tanstack-ai/dist/chunk-3VQDXJLW.cjs","../src/utils/binary.ts"],"names":[],"mappings":"AAAA;ACYO,SAAS,kBAAA,CAAmB,KAAA,EAA2B;AAC7D,EAAA,IAAI,OAAA,EAAS,EAAA;AACb,EAAA,IAAA,CAAA,IAAS,EAAA,EAAI,CAAA,EAAG,EAAA,EAAI,KAAA,CAAM,MAAA,EAAQ,CAAA,EAAA,EAAK;AACtC,IAAA,OAAA,GAAU,MAAA,CAAO,YAAA,CAAa,KAAA,CAAM,CAAC,CAAE,CAAA;AAAA,EACxC;AACA,EAAA,OAAO,IAAA,CAAK,MAAM,CAAA;AACnB;AAKA,MAAA,SAAsB,aAAA,CAAc,MAAA,EAAyD;AAC5F,EAAA,MAAM,OAAA,EAAS,MAAA,CAAO,SAAA,CAAU,CAAA;AAChC,EAAA,MAAM,OAAA,EAAuB,CAAC,CAAA;AAC9B,EAAA,MAAA,CAAO,IAAA,EAAM;AACZ,IAAA,MAAM,EAAE,IAAA,EAAM,MAAM,EAAA,EAAI,MAAM,MAAA,CAAO,IAAA,CAAK,CAAA;AAC1C,IAAA,GAAA,CAAI,IAAA,EAAM,KAAA;AACV,IAAA,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA;AAAA,EAClB;AACA,EAAA,MAAM,YAAA,EAAc,MAAA,CAAO,MAAA,CAAO,CAAC,GAAA,EAAK,CAAA,EAAA,GAAM,IAAA,EAAM,CAAA,CAAE,MAAA,EAAQ,CAAC,CAAA;AAC/D,EAAA,MAAM,SAAA,EAAW,IAAI,UAAA,CAAW,WAAW,CAAA;AAC3C,EAAA,IAAI,OAAA,EAAS,CAAA;AACb,EAAA,IAAA,CAAA,MAAW,MAAA,GAAS,MAAA,EAAQ;AAC3B,IAAA,QAAA,CAAS,GAAA,CAAI,KAAA,EAAO,MAAM,CAAA;AAC1B,IAAA,OAAA,GAAU,KAAA,CAAM,MAAA;AAAA,EACjB;AACA,EAAA,OAAO,QAAA;AACR;AAcA,MAAA,SAAsB,cAAA,CACrB,MAAA,EACA,UAAA,EAAoB,OAAA,EACF;AAClB,EAAA,GAAA,CAAI,OAAA,WAAkB,cAAA,EAAgB;AACrC,IAAA,OAAO,kBAAA,CAAmB,MAAM,aAAA,CAAc,MAAM,CAAC,CAAA;AAAA,EACtD;AAEA,EAAA,GAAA,CAAI,OAAA,WAAkB,WAAA,GAAc,OAAA,WAAkB,WAAA,EAAa;AAClE,IAAA,MAAM,MAAA,EAAQ,OAAA,WAAkB,YAAA,EAAc,IAAI,UAAA,CAAW,MAAM,EAAA,EAAI,MAAA;AACvE,IAAA,OAAO,kBAAA,CAAmB,KAAK,CAAA;AAAA,EAChC;AAGA,EAAA,GAAA,CAAI,OAAO,OAAA,IAAW,SAAA,GAAY,OAAA,IAAW,KAAA,GAAQ,UAAA,GAAa,MAAA,EAAQ;AACzE,IAAA,OAAQ,MAAA,CAAkC,SAAS,CAAA;AAAA,EACpD;AAEA,EAAA,MAAM,IAAI,KAAA;AAAA,IACT,CAAA,0GAAA,EAA6G,SAAS,CAAA,WAAA;AAAA,EACvH,CAAA;AACD;ADlCA;AACA;AACE;AACA;AACF,yFAAC","file":"/home/runner/work/ai/ai/packages/tanstack-ai/dist/chunk-3VQDXJLW.cjs","sourcesContent":[null,"/**\n * Shared binary-data utilities for Workers AI adapters.\n *\n * Workers AI returns binary data (images, audio) in various formats —\n * Uint8Array, ArrayBuffer, ReadableStream, or JSON objects with a base64 field.\n * These helpers normalise everything into base64 strings for the TanStack AI\n * result types.\n */\n\n/**\n * Convert a Uint8Array to a base64 string.\n */\nexport function uint8ArrayToBase64(bytes: Uint8Array): string {\n\tlet binary = \"\";\n\tfor (let i = 0; i < bytes.length; i++) {\n\t\tbinary += String.fromCharCode(bytes[i]!);\n\t}\n\treturn btoa(binary);\n}\n\n/**\n * Collect all chunks from a ReadableStream<Uint8Array> into a single Uint8Array.\n */\nexport async function collectStream(stream: ReadableStream<Uint8Array>): Promise<Uint8Array> {\n\tconst reader = stream.getReader();\n\tconst chunks: Uint8Array[] = [];\n\twhile (true) {\n\t\tconst { done, value } = await reader.read();\n\t\tif (done) break;\n\t\tchunks.push(value);\n\t}\n\tconst totalLength = chunks.reduce((acc, c) => acc + c.length, 0);\n\tconst combined = new Uint8Array(totalLength);\n\tlet offset = 0;\n\tfor (const chunk of chunks) {\n\t\tcombined.set(chunk, offset);\n\t\toffset += chunk.length;\n\t}\n\treturn combined;\n}\n\n/**\n * Normalise a Workers AI binary response to a base64 string.\n *\n * Handles:\n * - `Uint8Array` / `ArrayBuffer` — raw bytes\n * - `ReadableStream<Uint8Array>` — streamed bytes\n * - `{ [binaryKey]: \"base64...\" }` — JSON wrapper (e.g. `{ image: \"...\" }`)\n *\n * @param result The raw value returned from Workers AI\n * @param binaryKey The JSON field to look for when the result is an object\n * (defaults to `\"image\"`; pass `\"audio\"` for TTS responses)\n */\nexport async function binaryToBase64(\n\tresult: unknown,\n\tbinaryKey: string = \"image\",\n): Promise<string> {\n\tif (result instanceof ReadableStream) {\n\t\treturn uint8ArrayToBase64(await collectStream(result));\n\t}\n\n\tif (result instanceof Uint8Array || result instanceof ArrayBuffer) {\n\t\tconst bytes = result instanceof ArrayBuffer ? new Uint8Array(result) : result;\n\t\treturn uint8ArrayToBase64(bytes);\n\t}\n\n\t// Some models return { image: \"base64...\" } or { audio: \"base64...\" }\n\tif (typeof result === \"object\" && result !== null && binaryKey in result) {\n\t\treturn (result as Record<string, string>)[binaryKey]!;\n\t}\n\n\tthrow new Error(\n\t\t`Unexpected binary response format from Workers AI (expected Uint8Array, ArrayBuffer, ReadableStream, or { ${binaryKey}: string })`,\n\t);\n}\n"]}
@@ -0,0 +1,8 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+
5
+
6
+
7
+ exports.__publicField = __publicField;
8
+ //# sourceMappingURL=chunk-4DE2IREA.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/ai/ai/packages/tanstack-ai/dist/chunk-4DE2IREA.cjs"],"names":[],"mappings":"AAAA,6EAAI,UAAU,EAAE,MAAM,CAAC,cAAc;AACrC,IAAI,gBAAgB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK;AAC/J,IAAI,cAAc,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC,GAAG,EAAE,OAAO,IAAI,IAAI,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC;AAC9G;AACA;AACE;AACF,sCAAC","file":"/home/runner/work/ai/ai/packages/tanstack-ai/dist/chunk-4DE2IREA.cjs"}
@@ -0,0 +1,65 @@
1
+ // src/adapters/gemini.ts
2
+ import {
3
+ GeminiTextAdapter,
4
+ GeminiImageAdapter,
5
+ GeminiSummarizeAdapter,
6
+ GeminiTTSAdapter,
7
+ GeminiTextModels,
8
+ GeminiImageModels,
9
+ GeminiSummarizeModels,
10
+ GeminiTTSModels
11
+ } from "@tanstack/ai-gemini";
12
+ function buildGeminiGatewayConfig(config) {
13
+ if ("binding" in config) {
14
+ throw new Error(
15
+ "Gemini adapters do not support binding config. The Google GenAI SDK does not support a custom fetch function \u2014 only credential-based config ({ accountId, gatewayId }) is supported. See https://github.com/googleapis/js-genai/issues/999"
16
+ );
17
+ }
18
+ const headers = {};
19
+ if (config.cfApiKey) {
20
+ headers["cf-aig-authorization"] = `Bearer ${config.cfApiKey}`;
21
+ }
22
+ if (config.skipCache) {
23
+ headers["cf-aig-skip-cache"] = "true";
24
+ }
25
+ if (typeof config.cacheTtl === "number") {
26
+ headers["cf-aig-cache-ttl"] = String(config.cacheTtl);
27
+ }
28
+ if (typeof config.customCacheKey === "string") {
29
+ headers["cf-aig-cache-key"] = config.customCacheKey;
30
+ }
31
+ if (typeof config.metadata === "object") {
32
+ headers["cf-aig-metadata"] = JSON.stringify(config.metadata);
33
+ }
34
+ return {
35
+ apiKey: config.apiKey ?? "unused",
36
+ httpOptions: {
37
+ baseUrl: `https://gateway.ai.cloudflare.com/v1/${config.accountId}/${config.gatewayId}/google-ai-studio`,
38
+ headers: Object.keys(headers).length > 0 ? headers : void 0
39
+ }
40
+ };
41
+ }
42
+ function createGeminiChat(model, config) {
43
+ return new GeminiTextAdapter(buildGeminiGatewayConfig(config), model);
44
+ }
45
+ function createGeminiImage(model, config) {
46
+ return new GeminiImageAdapter(buildGeminiGatewayConfig(config), model);
47
+ }
48
+ function createGeminiSummarize(model, config) {
49
+ return new GeminiSummarizeAdapter(buildGeminiGatewayConfig(config), model);
50
+ }
51
+ function createGeminiTts(model, config) {
52
+ return new GeminiTTSAdapter(buildGeminiGatewayConfig(config), model);
53
+ }
54
+
55
+ export {
56
+ GeminiTextModels,
57
+ GeminiImageModels,
58
+ GeminiSummarizeModels,
59
+ GeminiTTSModels,
60
+ createGeminiChat,
61
+ createGeminiImage,
62
+ createGeminiSummarize,
63
+ createGeminiTts
64
+ };
65
+ //# sourceMappingURL=chunk-7AEFXYJG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapters/gemini.ts"],"sourcesContent":["import {\n\tGeminiTextAdapter,\n\tGeminiImageAdapter,\n\tGeminiSummarizeAdapter,\n\tGeminiTTSAdapter,\n\tGeminiTextModels,\n\tGeminiImageModels,\n\tGeminiSummarizeModels,\n\tGeminiTTSModels,\n\ttype GeminiTextModel,\n\ttype GeminiImageModel,\n\ttype GeminiSummarizeModel,\n} from \"@tanstack/ai-gemini\";\n\n/** Derived from GeminiTTSModels since @tanstack/ai-gemini doesn't export a GeminiTTSModel type. */\nexport type GeminiTTSModel = (typeof GeminiTTSModels)[number];\nimport type { AnyTextAdapter } from \"@tanstack/ai\";\nimport type { AiGatewayCredentialsConfig, AiGatewayConfig } from \"../utils/create-fetcher\";\n\n/**\n * Gemini-specific gateway config (credentials only, no binding support).\n * Includes cache control options from AiGatewayConfig.\n * See {@link https://github.com/googleapis/js-genai/issues/999 | googleapis/js-genai#999}.\n */\nexport type GeminiGatewayConfig = AiGatewayCredentialsConfig & AiGatewayConfig;\n\n/**\n * Build Gemini client config that routes through AI Gateway.\n * Since GeminiClientConfig extends GoogleGenAIOptions, we can inject\n * httpOptions.baseUrl directly — no subclassing needed.\n *\n * The Google GenAI SDK doesn't support a custom `fetch` override,\n * so we set the baseUrl to the AI Gateway endpoint for Google AI Studio.\n *\n * Tracking issue: https://github.com/googleapis/js-genai/issues/999\n */\nfunction buildGeminiGatewayConfig(config: GeminiGatewayConfig) {\n\t// Runtime guard: catch binding configs that bypass TypeScript (JS callers, `as any`, etc.)\n\t// We integrate with the Gemini SDK via `httpOptions` (baseUrl + headers), which allows\n\t// gateway routing and cache control but not request interception. A binding config\n\t// requires a custom `fetch` to route through the AI Gateway binding, and the Google\n\t// GenAI SDK doesn't support that yet.\n\tif (\"binding\" in config) {\n\t\tthrow new Error(\n\t\t\t\"Gemini adapters do not support binding config. \" +\n\t\t\t\t\"The Google GenAI SDK does not support a custom fetch function — \" +\n\t\t\t\t\"only credential-based config ({ accountId, gatewayId }) is supported. \" +\n\t\t\t\t\"See https://github.com/googleapis/js-genai/issues/999\",\n\t\t);\n\t}\n\n\tconst headers: Record<string, string> = {};\n\tif (config.cfApiKey) {\n\t\theaders[\"cf-aig-authorization\"] = `Bearer ${config.cfApiKey}`;\n\t}\n\tif (config.skipCache) {\n\t\theaders[\"cf-aig-skip-cache\"] = \"true\";\n\t}\n\tif (typeof config.cacheTtl === \"number\") {\n\t\theaders[\"cf-aig-cache-ttl\"] = String(config.cacheTtl);\n\t}\n\tif (typeof config.customCacheKey === \"string\") {\n\t\theaders[\"cf-aig-cache-key\"] = config.customCacheKey;\n\t}\n\tif (typeof config.metadata === \"object\") {\n\t\theaders[\"cf-aig-metadata\"] = JSON.stringify(config.metadata);\n\t}\n\n\treturn {\n\t\tapiKey: config.apiKey ?? \"unused\",\n\t\thttpOptions: {\n\t\t\tbaseUrl: `https://gateway.ai.cloudflare.com/v1/${config.accountId}/${config.gatewayId}/google-ai-studio`,\n\t\t\theaders: Object.keys(headers).length > 0 ? headers : undefined,\n\t\t},\n\t};\n}\n\n/** Alias for consistency with other providers (AnthropicChatModel, GrokChatModel, etc.) */\nexport type GeminiChatModel = GeminiTextModel;\n\n/**\n * Creates a Gemini adapter which uses Cloudflare AI Gateway.\n * Does not support the AI binding (Google GenAI SDK lacks custom fetch support).\n * See {@link https://github.com/googleapis/js-genai/issues/999 | googleapis/js-genai#999}.\n * @param model The Gemini model to use\n * @param config Configuration options (credentials only)\n */\nexport function createGeminiChat(\n\tmodel: GeminiChatModel,\n\tconfig: GeminiGatewayConfig,\n): AnyTextAdapter {\n\treturn new GeminiTextAdapter(buildGeminiGatewayConfig(config), model);\n}\n\n/**\n * Creates a Gemini Image adapter which uses Cloudflare AI Gateway.\n * Does not support the AI binding (Google GenAI SDK lacks custom fetch support).\n * See {@link https://github.com/googleapis/js-genai/issues/999 | googleapis/js-genai#999}.\n * @param model The Gemini model to use\n * @param config Configuration options (credentials only)\n */\nexport function createGeminiImage(model: GeminiImageModel, config: GeminiGatewayConfig) {\n\treturn new GeminiImageAdapter(buildGeminiGatewayConfig(config), model);\n}\n\n/**\n * Creates a Gemini Summarize adapter which uses Cloudflare AI Gateway.\n * Does not support the AI binding (Google GenAI SDK lacks custom fetch support).\n * See {@link https://github.com/googleapis/js-genai/issues/999 | googleapis/js-genai#999}.\n * @param model The Gemini model to use\n * @param config Configuration options (credentials only)\n */\nexport function createGeminiSummarize(model: GeminiSummarizeModel, config: GeminiGatewayConfig) {\n\treturn new GeminiSummarizeAdapter(buildGeminiGatewayConfig(config), model);\n}\n\n/**\n * Creates a Gemini TTS adapter which uses Cloudflare AI Gateway.\n * Does not support the AI binding (Google GenAI SDK lacks custom fetch support).\n * See {@link https://github.com/googleapis/js-genai/issues/999 | googleapis/js-genai#999}.\n *\n * @experimental Gemini TTS is an experimental feature and may change.\n * @param model The Gemini TTS model to use\n * @param config Configuration options (credentials only)\n */\nexport function createGeminiTts(model: GeminiTTSModel, config: GeminiGatewayConfig) {\n\treturn new GeminiTTSAdapter(buildGeminiGatewayConfig(config), model);\n}\n\nexport {\n\tGeminiTextModels,\n\tGeminiImageModels,\n\tGeminiSummarizeModels,\n\tGeminiTTSModels,\n\ttype GeminiTextModel,\n\ttype GeminiImageModel,\n\ttype GeminiSummarizeModel,\n};\n"],"mappings":";AAAA;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIM;AAwBP,SAAS,yBAAyB,QAA6B;AAM9D,MAAI,aAAa,QAAQ;AACxB,UAAM,IAAI;AAAA,MACT;AAAA,IAID;AAAA,EACD;AAEA,QAAM,UAAkC,CAAC;AACzC,MAAI,OAAO,UAAU;AACpB,YAAQ,sBAAsB,IAAI,UAAU,OAAO,QAAQ;AAAA,EAC5D;AACA,MAAI,OAAO,WAAW;AACrB,YAAQ,mBAAmB,IAAI;AAAA,EAChC;AACA,MAAI,OAAO,OAAO,aAAa,UAAU;AACxC,YAAQ,kBAAkB,IAAI,OAAO,OAAO,QAAQ;AAAA,EACrD;AACA,MAAI,OAAO,OAAO,mBAAmB,UAAU;AAC9C,YAAQ,kBAAkB,IAAI,OAAO;AAAA,EACtC;AACA,MAAI,OAAO,OAAO,aAAa,UAAU;AACxC,YAAQ,iBAAiB,IAAI,KAAK,UAAU,OAAO,QAAQ;AAAA,EAC5D;AAEA,SAAO;AAAA,IACN,QAAQ,OAAO,UAAU;AAAA,IACzB,aAAa;AAAA,MACZ,SAAS,wCAAwC,OAAO,SAAS,IAAI,OAAO,SAAS;AAAA,MACrF,SAAS,OAAO,KAAK,OAAO,EAAE,SAAS,IAAI,UAAU;AAAA,IACtD;AAAA,EACD;AACD;AAYO,SAAS,iBACf,OACA,QACiB;AACjB,SAAO,IAAI,kBAAkB,yBAAyB,MAAM,GAAG,KAAK;AACrE;AASO,SAAS,kBAAkB,OAAyB,QAA6B;AACvF,SAAO,IAAI,mBAAmB,yBAAyB,MAAM,GAAG,KAAK;AACtE;AASO,SAAS,sBAAsB,OAA6B,QAA6B;AAC/F,SAAO,IAAI,uBAAuB,yBAAyB,MAAM,GAAG,KAAK;AAC1E;AAWO,SAAS,gBAAgB,OAAuB,QAA6B;AACnF,SAAO,IAAI,iBAAiB,yBAAyB,MAAM,GAAG,KAAK;AACpE;","names":[]}
@@ -0,0 +1,42 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/utils/workers-ai-rest.ts
2
+ var WORKERS_AI_REST_BASE = "https://api.cloudflare.com/client/v4/accounts";
3
+ async function workersAiRestFetch(config, model, body, options) {
4
+ const response = await fetch(`${WORKERS_AI_REST_BASE}/${config.accountId}/ai/run/${model}`, {
5
+ method: "POST",
6
+ headers: {
7
+ Authorization: `Bearer ${config.apiKey}`,
8
+ "Content-Type": "application/json"
9
+ },
10
+ body: JSON.stringify(body),
11
+ signal: _optionalChain([options, 'optionalAccess', _ => _.signal])
12
+ });
13
+ if (!response.ok) {
14
+ const errorText = await response.text();
15
+ const label = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _2 => _2.label]), () => ( "Workers AI"));
16
+ throw new Error(`${label} request failed (${response.status}): ${errorText}`);
17
+ }
18
+ return response;
19
+ }
20
+ async function workersAiRestFetchBinary(config, model, audioBytes, contentType, options) {
21
+ const response = await fetch(`${WORKERS_AI_REST_BASE}/${config.accountId}/ai/run/${model}`, {
22
+ method: "POST",
23
+ headers: {
24
+ Authorization: `Bearer ${config.apiKey}`,
25
+ "Content-Type": contentType
26
+ },
27
+ body: audioBytes,
28
+ signal: _optionalChain([options, 'optionalAccess', _3 => _3.signal])
29
+ });
30
+ if (!response.ok) {
31
+ const errorText = await response.text();
32
+ const label = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _4 => _4.label]), () => ( "Workers AI"));
33
+ throw new Error(`${label} request failed (${response.status}): ${errorText}`);
34
+ }
35
+ return response;
36
+ }
37
+
38
+
39
+
40
+
41
+ exports.workersAiRestFetch = workersAiRestFetch; exports.workersAiRestFetchBinary = workersAiRestFetchBinary;
42
+ //# sourceMappingURL=chunk-7HSUHP63.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/ai/ai/packages/tanstack-ai/dist/chunk-7HSUHP63.cjs","../src/utils/workers-ai-rest.ts"],"names":[],"mappings":"AAAA;ACMA,IAAM,qBAAA,EAAuB,+CAAA;AAkB7B,MAAA,SAAsB,kBAAA,CACrB,MAAA,EACA,KAAA,EACA,IAAA,EACA,OAAA,EACoB;AACpB,EAAA,MAAM,SAAA,EAAW,MAAM,KAAA,CAAM,CAAA,EAAA;AACpB,IAAA;AACC,IAAA;AACiB,MAAA;AACT,MAAA;AACjB,IAAA;AACyB,IAAA;AACR,IAAA;AACjB,EAAA;AAEiB,EAAA;AACO,IAAA;AACD,IAAA;AACC,IAAA;AACzB,EAAA;AAEO,EAAA;AACR;AAgBsB;AAOQ,EAAA;AACpB,IAAA;AACC,IAAA;AACiB,MAAA;AACT,MAAA;AACjB,IAAA;AACM,IAAA;AACW,IAAA;AACjB,EAAA;AAEiB,EAAA;AACO,IAAA;AACD,IAAA;AACC,IAAA;AACzB,EAAA;AAEO,EAAA;AACR;ADnDgC;AACA;AACA;AACA;AACA","file":"/home/runner/work/ai/ai/packages/tanstack-ai/dist/chunk-7HSUHP63.cjs","sourcesContent":[null,"import type { WorkersAiDirectCredentialsConfig } from \"./create-fetcher\";\n\n/**\n * Workers AI REST API base URL.\n * All model endpoints follow the pattern: `${BASE_URL}/${accountId}/ai/run/${model}`\n */\nconst WORKERS_AI_REST_BASE = \"https://api.cloudflare.com/client/v4/accounts\";\n\n/**\n * Make a REST API call to Workers AI.\n *\n * Handles the common pattern shared by all Workers AI adapters:\n * - Build the URL from account ID and model name\n * - Set Authorization and Content-Type headers\n * - Check response.ok and throw a descriptive error on failure\n *\n * @param config Credentials config with accountId and apiKey\n * @param model Workers AI model name (e.g. \"@cf/stabilityai/stable-diffusion-xl-base-1.0\")\n * @param body JSON request body\n * @param options Optional settings:\n * - `label` — human-readable label for error messages (default: \"Workers AI\")\n * - `signal` — AbortSignal for request cancellation / timeout\n * @returns The raw Response object — caller is responsible for parsing\n */\nexport async function workersAiRestFetch(\n\tconfig: WorkersAiDirectCredentialsConfig,\n\tmodel: string,\n\tbody: Record<string, unknown>,\n\toptions?: { label?: string; signal?: AbortSignal },\n): Promise<Response> {\n\tconst response = await fetch(`${WORKERS_AI_REST_BASE}/${config.accountId}/ai/run/${model}`, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${config.apiKey}`,\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t},\n\t\tbody: JSON.stringify(body),\n\t\tsignal: options?.signal,\n\t});\n\n\tif (!response.ok) {\n\t\tconst errorText = await response.text();\n\t\tconst label = options?.label ?? \"Workers AI\";\n\t\tthrow new Error(`${label} request failed (${response.status}): ${errorText}`);\n\t}\n\n\treturn response;\n}\n\n/**\n * Make a binary REST API call to Workers AI.\n *\n * Some models (e.g. `@cf/deepgram/nova-3`) require raw binary audio with an\n * appropriate `Content-Type` header instead of JSON. This function sends the\n * audio bytes directly as the request body.\n *\n * @param config Credentials config with accountId and apiKey\n * @param model Workers AI model name\n * @param audioBytes Raw audio bytes\n * @param contentType MIME type of the audio (e.g. \"audio/wav\")\n * @param options Optional settings\n * @returns The raw Response object\n */\nexport async function workersAiRestFetchBinary(\n\tconfig: WorkersAiDirectCredentialsConfig,\n\tmodel: string,\n\taudioBytes: Uint8Array,\n\tcontentType: string,\n\toptions?: { label?: string; signal?: AbortSignal },\n): Promise<Response> {\n\tconst response = await fetch(`${WORKERS_AI_REST_BASE}/${config.accountId}/ai/run/${model}`, {\n\t\tmethod: \"POST\",\n\t\theaders: {\n\t\t\tAuthorization: `Bearer ${config.apiKey}`,\n\t\t\t\"Content-Type\": contentType,\n\t\t},\n\t\tbody: audioBytes,\n\t\tsignal: options?.signal,\n\t});\n\n\tif (!response.ok) {\n\t\tconst errorText = await response.text();\n\t\tconst label = options?.label ?? \"Workers AI\";\n\t\tthrow new Error(`${label} request failed (${response.status}): ${errorText}`);\n\t}\n\n\treturn response;\n}\n"]}
@@ -0,0 +1,84 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+ var _chunk7HSUHP63cjs = require('./chunk-7HSUHP63.cjs');
4
+
5
+
6
+
7
+
8
+ var _chunkGOU66I5Tcjs = require('./chunk-GOU66I5T.cjs');
9
+
10
+
11
+ var _chunk4DE2IREAcjs = require('./chunk-4DE2IREA.cjs');
12
+
13
+ // src/adapters/workers-ai-summarize.ts
14
+ var _adapters = require('@tanstack/ai/adapters');
15
+ var WorkersAiSummarizeAdapter = class extends _adapters.BaseSummarizeAdapter {
16
+ constructor(config, model) {
17
+ super({}, model);
18
+ _chunk4DE2IREAcjs.__publicField.call(void 0, this, "name", "workers-ai-summarize");
19
+ _chunk4DE2IREAcjs.__publicField.call(void 0, this, "adapterConfig");
20
+ this.adapterConfig = config;
21
+ }
22
+ async summarize(options) {
23
+ const { text, maxLength } = options;
24
+ const payload = { input_text: text };
25
+ if (maxLength != null) payload.max_length = maxLength;
26
+ if (_chunkGOU66I5Tcjs.isDirectBindingConfig.call(void 0, this.adapterConfig)) {
27
+ return this.summarizeViaBinding(payload);
28
+ }
29
+ if (_chunkGOU66I5Tcjs.isDirectCredentialsConfig.call(void 0, this.adapterConfig)) {
30
+ return this.summarizeViaRest(payload);
31
+ }
32
+ return this.summarizeViaGateway(payload);
33
+ }
34
+ async summarizeViaBinding(payload) {
35
+ const ai = this.adapterConfig.binding;
36
+ const result = await ai.run(this.model, payload);
37
+ return this.wrapResult(_nullishCoalesce(result.summary, () => ( "")));
38
+ }
39
+ async summarizeViaRest(payload) {
40
+ const config = this.adapterConfig;
41
+ const response = await _chunk7HSUHP63cjs.workersAiRestFetch.call(void 0, config, this.model, payload, {
42
+ label: "Workers AI summarize"
43
+ });
44
+ const data = await response.json();
45
+ return this.wrapResult(_nullishCoalesce(_optionalChain([data, 'access', _ => _.result, 'optionalAccess', _2 => _2.summary]), () => ( "")));
46
+ }
47
+ async summarizeViaGateway(payload) {
48
+ const gatewayConfig = this.adapterConfig;
49
+ const gatewayFetch = _chunkGOU66I5Tcjs.createGatewayFetch.call(void 0, "workers-ai", gatewayConfig);
50
+ const response = await gatewayFetch("https://api.cloudflare.com/v1/ai/summarization", {
51
+ method: "POST",
52
+ body: JSON.stringify({
53
+ model: this.model,
54
+ ...payload
55
+ })
56
+ });
57
+ if (!response.ok) {
58
+ const errorText = await response.text();
59
+ throw new Error(
60
+ `Workers AI summarize gateway request failed (${response.status}): ${errorText}`
61
+ );
62
+ }
63
+ const data = await response.json();
64
+ return this.wrapResult(_nullishCoalesce(_nullishCoalesce(_optionalChain([data, 'access', _3 => _3.result, 'optionalAccess', _4 => _4.summary]), () => ( data.summary)), () => ( "")));
65
+ }
66
+ wrapResult(summary) {
67
+ return {
68
+ id: this.generateId(),
69
+ model: this.model,
70
+ summary,
71
+ // BART-large-CNN doesn't return token usage
72
+ usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 }
73
+ };
74
+ }
75
+ };
76
+ function createWorkersAiSummarize(model, config) {
77
+ return new WorkersAiSummarizeAdapter(config, model);
78
+ }
79
+
80
+
81
+
82
+
83
+ exports.WorkersAiSummarizeAdapter = WorkersAiSummarizeAdapter; exports.createWorkersAiSummarize = createWorkersAiSummarize;
84
+ //# sourceMappingURL=chunk-7T4CVHKD.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/ai/ai/packages/tanstack-ai/dist/chunk-7T4CVHKD.cjs","../src/adapters/workers-ai-summarize.ts"],"names":[],"mappings":"AAAA;AACE;AACF,wDAA6B;AAC7B;AACE;AACA;AACA;AACF,wDAA6B;AAC7B;AACE;AACF,wDAA6B;AAC7B;AACA;ACZA,iDAAqC;AA0B9B,IAAM,0BAAA,EAAN,MAAA,QAAwC,+BAA8C;AAAA,EAI5F,WAAA,CAAY,MAAA,EAAgC,KAAA,EAAgC;AAC3E,IAAA,KAAA,CAAM,CAAC,CAAA,EAAG,KAAK,CAAA;AAJhB,IAAA,6CAAA,IAAA,EAAS,MAAA,EAAO,sBAAA,CAAA;AAChB,IAAA,6CAAA,IAAA,EAAQ,eAAA,CAAA;AAIP,IAAA,IAAA,CAAK,cAAA,EAAgB,MAAA;AAAA,EACtB;AAAA,EAEA,MAAM,SAAA,CAAU,OAAA,EAA6D;AAC5E,IAAA,MAAM,EAAE,IAAA,EAAM,UAAU,EAAA,EAAI,OAAA;AAE5B,IAAA,MAAM,QAAA,EAAmC,EAAE,UAAA,EAAY,KAAK,CAAA;AAC5D,IAAA,GAAA,CAAI,UAAA,GAAa,IAAA,EAAM,OAAA,CAAQ,WAAA,EAAa,SAAA;AAE5C,IAAA,GAAA,CAAI,qDAAA,IAAsB,CAAK,aAAa,CAAA,EAAG;AAC9C,MAAA,OAAO,IAAA,CAAK,mBAAA,CAAoB,OAAO,CAAA;AAAA,IACxC;AAEA,IAAA,GAAA,CAAI,yDAAA,IAA0B,CAAK,aAAa,CAAA,EAAG;AAClD,MAAA,OAAO,IAAA,CAAK,gBAAA,CAAiB,OAAO,CAAA;AAAA,IACrC;AAEA,IAAA,OAAO,IAAA,CAAK,mBAAA,CAAoB,OAAO,CAAA;AAAA,EACxC;AAAA,EAEA,MAAc,mBAAA,CACb,OAAA,EAC+B;AAC/B,IAAA,MAAM,GAAA,EAAM,IAAA,CAAK,aAAA,CAA+C,OAAA;AAChE,IAAA,MAAM,OAAA,EAAU,MAAM,EAAA,CAAG,GAAA,CAAI,IAAA,CAAK,KAAA,EAAO,OAAO,CAAA;AAChD,IAAA,OAAO,IAAA,CAAK,UAAA,kBAAY,MAAA,CAAO,OAAA,UAAsB,IAAE,CAAA;AAAA,EACxD;AAAA,EAEA,MAAc,gBAAA,CAAiB,OAAA,EAAgE;AAC9F,IAAA,MAAM,OAAA,EAAS,IAAA,CAAK,aAAA;AACpB,IAAA,MAAM,SAAA,EAAW,MAAM,kDAAA,MAAmB,EAAQ,IAAA,CAAK,KAAA,EAAO,OAAA,EAAS;AAAA,MACtE,KAAA,EAAO;AAAA,IACR,CAAC,CAAA;AAED,IAAA,MAAM,KAAA,EAAQ,MAAM,QAAA,CAAS,IAAA,CAAK,CAAA;AAClC,IAAA,OAAO,IAAA,CAAK,UAAA,kCAAW,IAAA,mBAAK,MAAA,6BAAQ,SAAA,UAAW,IAAE,CAAA;AAAA,EAClD;AAAA,EAEA,MAAc,mBAAA,CACb,OAAA,EAC+B;AAC/B,IAAA,MAAM,cAAA,EAAgB,IAAA,CAAK,aAAA;AAC3B,IAAA,MAAM,aAAA,EAAe,kDAAA,YAAmB,EAAc,aAAa,CAAA;AAKnE,IAAA,MAAM,SAAA,EAAW,MAAM,YAAA,CAAa,gDAAA,EAAkD;AAAA,MACrF,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU;AAAA,QACpB,KAAA,EAAO,IAAA,CAAK,KAAA;AAAA,QACZ,GAAG;AAAA,MACJ,CAAC;AAAA,IACF,CAAC,CAAA;AAED,IAAA,GAAA,CAAI,CAAC,QAAA,CAAS,EAAA,EAAI;AACjB,MAAA,MAAM,UAAA,EAAY,MAAM,QAAA,CAAS,IAAA,CAAK,CAAA;AACtC,MAAA,MAAM,IAAI,KAAA;AAAA,QACT,CAAA,6CAAA,EAAgD,QAAA,CAAS,MAAM,CAAA,GAAA,EAAM,SAAS,CAAA;AAAA,MAAA;AAC/E,IAAA;AAGD,IAAA;AACA,IAAA;AAAiE,EAAA;AAClE,EAAA;AAGC,IAAA;AAAO,MAAA;AACc,MAAA;AACR,MAAA;AACZ;AAAA,MAAA;AAE8D,IAAA;AAC/D,EAAA;AAEF;AAyBO;AAIN,EAAA;AACD;AD3DA;AACA;AACA;AACA;AACA","file":"/home/runner/work/ai/ai/packages/tanstack-ai/dist/chunk-7T4CVHKD.cjs","sourcesContent":[null,"import { BaseSummarizeAdapter } from \"@tanstack/ai/adapters\";\nimport type { SummarizationOptions, SummarizationResult } from \"@tanstack/ai\";\nimport {\n\ttype WorkersAiAdapterConfig,\n\ttype WorkersAiDirectBindingConfig,\n\ttype WorkersAiDirectCredentialsConfig,\n\ttype AiGatewayAdapterConfig,\n\tcreateGatewayFetch,\n\tisDirectBindingConfig,\n\tisDirectCredentialsConfig,\n} from \"../utils/create-fetcher\";\nimport { workersAiRestFetch } from \"../utils/workers-ai-rest\";\n\n// ---------------------------------------------------------------------------\n// Model types\n// ---------------------------------------------------------------------------\n\n/**\n * Workers AI models that support summarization.\n */\nexport type WorkersAiSummarizeModel = \"@cf/facebook/bart-large-cnn\";\n\n// ---------------------------------------------------------------------------\n// WorkersAiSummarizeAdapter\n// ---------------------------------------------------------------------------\n\nexport class WorkersAiSummarizeAdapter extends BaseSummarizeAdapter<WorkersAiSummarizeModel> {\n\treadonly name = \"workers-ai-summarize\" as const;\n\tprivate adapterConfig: WorkersAiAdapterConfig;\n\n\tconstructor(config: WorkersAiAdapterConfig, model: WorkersAiSummarizeModel) {\n\t\tsuper({}, model);\n\t\tthis.adapterConfig = config;\n\t}\n\n\tasync summarize(options: SummarizationOptions): Promise<SummarizationResult> {\n\t\tconst { text, maxLength } = options;\n\n\t\tconst payload: Record<string, unknown> = { input_text: text };\n\t\tif (maxLength != null) payload.max_length = maxLength;\n\n\t\tif (isDirectBindingConfig(this.adapterConfig)) {\n\t\t\treturn this.summarizeViaBinding(payload);\n\t\t}\n\n\t\tif (isDirectCredentialsConfig(this.adapterConfig)) {\n\t\t\treturn this.summarizeViaRest(payload);\n\t\t}\n\n\t\treturn this.summarizeViaGateway(payload);\n\t}\n\n\tprivate async summarizeViaBinding(\n\t\tpayload: Record<string, unknown>,\n\t): Promise<SummarizationResult> {\n\t\tconst ai = (this.adapterConfig as WorkersAiDirectBindingConfig).binding;\n\t\tconst result = (await ai.run(this.model, payload)) as Record<string, unknown>;\n\t\treturn this.wrapResult((result.summary as string) ?? \"\");\n\t}\n\n\tprivate async summarizeViaRest(payload: Record<string, unknown>): Promise<SummarizationResult> {\n\t\tconst config = this.adapterConfig as WorkersAiDirectCredentialsConfig;\n\t\tconst response = await workersAiRestFetch(config, this.model, payload, {\n\t\t\tlabel: \"Workers AI summarize\",\n\t\t});\n\n\t\tconst data = (await response.json()) as { result?: { summary?: string } };\n\t\treturn this.wrapResult(data.result?.summary ?? \"\");\n\t}\n\n\tprivate async summarizeViaGateway(\n\t\tpayload: Record<string, unknown>,\n\t): Promise<SummarizationResult> {\n\t\tconst gatewayConfig = this.adapterConfig as AiGatewayAdapterConfig;\n\t\tconst gatewayFetch = createGatewayFetch(\"workers-ai\", gatewayConfig);\n\n\t\t// The URL here is a placeholder — createGatewayFetch for \"workers-ai\" extracts\n\t\t// the model from the body, sets it as the endpoint, and routes through the gateway.\n\t\t// The actual URL path is not used.\n\t\tconst response = await gatewayFetch(\"https://api.cloudflare.com/v1/ai/summarization\", {\n\t\t\tmethod: \"POST\",\n\t\t\tbody: JSON.stringify({\n\t\t\t\tmodel: this.model,\n\t\t\t\t...payload,\n\t\t\t}),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tconst errorText = await response.text();\n\t\t\tthrow new Error(\n\t\t\t\t`Workers AI summarize gateway request failed (${response.status}): ${errorText}`,\n\t\t\t);\n\t\t}\n\n\t\tconst data = (await response.json()) as { result?: { summary?: string }; summary?: string };\n\t\treturn this.wrapResult(data.result?.summary ?? data.summary ?? \"\");\n\t}\n\n\tprivate wrapResult(summary: string): SummarizationResult {\n\t\treturn {\n\t\t\tid: this.generateId(),\n\t\t\tmodel: this.model,\n\t\t\tsummary,\n\t\t\t// BART-large-CNN doesn't return token usage\n\t\t\tusage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },\n\t\t};\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Factory function\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a Workers AI summarization adapter.\n *\n * Works with TanStack AI's `summarize()` activity function:\n * ```ts\n * import { summarize } from \"@tanstack/ai\";\n * import { createWorkersAiSummarize } from \"@cloudflare/tanstack-ai\";\n *\n * const adapter = createWorkersAiSummarize(\"@cf/facebook/bart-large-cnn\", {\n * binding: env.AI,\n * });\n *\n * const result = await summarize({ adapter, text: \"Long article here...\" });\n * // result.summary\n * ```\n *\n * Note: Factory takes `(model, config)` for ergonomics — the class constructor\n * uses `(config, model)` to match TanStack AI's upstream convention.\n */\nexport function createWorkersAiSummarize(\n\tmodel: WorkersAiSummarizeModel,\n\tconfig: WorkersAiAdapterConfig,\n) {\n\treturn new WorkersAiSummarizeAdapter(config, model);\n}\n"]}