@happyvertical/ai 0.102.0 → 0.102.2

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 (115) hide show
  1. package/AGENT.md +1 -1
  2. package/README.md +123 -2
  3. package/dist/chunks/{anthropic-6ZDF32jo.js → anthropic-CxOrttgj.js} +3 -4
  4. package/dist/chunks/{anthropic-6ZDF32jo.js.map → anthropic-CxOrttgj.js.map} +1 -1
  5. package/dist/chunks/{bedrock-BQi3Z9jR.js → bedrock-B0cNEXFa.js} +3 -4
  6. package/dist/chunks/{bedrock-BQi3Z9jR.js.map → bedrock-B0cNEXFa.js.map} +1 -1
  7. package/dist/chunks/{bifrost-DsI2I4ka.js → bifrost-CyO3-hBv.js} +4 -4
  8. package/dist/chunks/{bifrost-DsI2I4ka.js.map → bifrost-CyO3-hBv.js.map} +1 -1
  9. package/dist/chunks/{byteplus-modelark-Dq8AgCQD.js → byteplus-modelark-DZ0YL2vl.js} +3 -4
  10. package/dist/chunks/{byteplus-modelark-Dq8AgCQD.js.map → byteplus-modelark-DZ0YL2vl.js.map} +1 -1
  11. package/dist/chunks/{claude-cli-DIFxvG3c.js → claude-cli-CtBp-Uk-.js} +3 -4
  12. package/dist/chunks/{claude-cli-DIFxvG3c.js.map → claude-cli-CtBp-Uk-.js.map} +1 -1
  13. package/dist/chunks/{continuation-D0NisZA1.js → continuation-7o7400bp.js} +3 -3
  14. package/dist/chunks/continuation-7o7400bp.js.map +1 -0
  15. package/dist/chunks/{gateway-audio-models-Dn7Wrc6P.js → gateway-audio-models-BSZGgjd8.js} +2 -2
  16. package/dist/chunks/{gateway-audio-models-Dn7Wrc6P.js.map → gateway-audio-models-BSZGgjd8.js.map} +1 -1
  17. package/dist/chunks/{gemini-BLFwWN90.js → gemini-DUk4ssth.js} +3 -4
  18. package/dist/chunks/{gemini-BLFwWN90.js.map → gemini-DUk4ssth.js.map} +1 -1
  19. package/dist/chunks/{huggingface-BuRwlABZ.js → huggingface-C41BZOoI.js} +3 -4
  20. package/dist/chunks/{huggingface-BuRwlABZ.js.map → huggingface-C41BZOoI.js.map} +1 -1
  21. package/dist/chunks/{litellm-CpfCT6jN.js → litellm-BLR5cs8B.js} +4 -4
  22. package/dist/chunks/{litellm-CpfCT6jN.js.map → litellm-BLR5cs8B.js.map} +1 -1
  23. package/dist/chunks/{ollama-CnrskTUg.js → ollama--y88p8Bz.js} +4 -5
  24. package/dist/chunks/{ollama-CnrskTUg.js.map → ollama--y88p8Bz.js.map} +1 -1
  25. package/dist/chunks/{openai-compat-video-CJIDdkUO.js → openai-compat-video-erarPEz-.js} +3 -4
  26. package/dist/chunks/{openai-compat-video-CJIDdkUO.js.map → openai-compat-video-erarPEz-.js.map} +1 -1
  27. package/dist/chunks/{qwen-tts-PzEkWcEb.js → qwen-tts-C9w7teY6.js} +2 -2
  28. package/dist/chunks/{qwen-tts-PzEkWcEb.js.map → qwen-tts-C9w7teY6.js.map} +1 -1
  29. package/dist/chunks/{rate-limit-BzWfHA0e.js → rate-limit-Bln_w0rH.js} +3 -280
  30. package/dist/chunks/rate-limit-Bln_w0rH.js.map +1 -0
  31. package/dist/chunks/rolldown-runtime-D7D4PA-g.js +13 -0
  32. package/dist/chunks/{seevio-D2y5Io7C.js → seevio-CosohVa0.js} +3 -4
  33. package/dist/chunks/{seevio-D2y5Io7C.js.map → seevio-CosohVa0.js.map} +1 -1
  34. package/dist/chunks/{src-CLT6r1W0.js → src-DDEz_uOe.js} +25 -30
  35. package/dist/chunks/{src-CLT6r1W0.js.map → src-DDEz_uOe.js.map} +1 -1
  36. package/dist/chunks/{typesafe-CVUqQ8N1.js → typesafe-BNM-QAJ2.js} +3 -4
  37. package/dist/chunks/{typesafe-CVUqQ8N1.js.map → typesafe-BNM-QAJ2.js.map} +1 -1
  38. package/dist/chunks/usage-BaQKo8bc.js +484 -0
  39. package/dist/chunks/usage-BaQKo8bc.js.map +1 -0
  40. package/dist/chunks/webllm-CWgY5nnP.js +584 -0
  41. package/dist/chunks/webllm-CWgY5nnP.js.map +1 -0
  42. package/dist/index.d.ts +6 -6
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +3 -4
  45. package/dist/local.d.ts +33 -0
  46. package/dist/local.d.ts.map +1 -0
  47. package/dist/local.js +3 -0
  48. package/dist/node/factory.d.ts +6 -2
  49. package/dist/node/factory.d.ts.map +1 -1
  50. package/dist/node.d.ts +2 -2
  51. package/dist/node.d.ts.map +1 -1
  52. package/dist/node.js +4 -5
  53. package/dist/node.js.map +1 -1
  54. package/dist/shared/client.d.ts +3 -3
  55. package/dist/shared/client.d.ts.map +1 -1
  56. package/dist/shared/continuation.d.ts +2 -2
  57. package/dist/shared/continuation.d.ts.map +1 -1
  58. package/dist/shared/factory.d.ts +6 -2
  59. package/dist/shared/factory.d.ts.map +1 -1
  60. package/dist/shared/message.d.ts +1 -1
  61. package/dist/shared/message.d.ts.map +1 -1
  62. package/dist/shared/providers/anthropic.d.ts +8 -1
  63. package/dist/shared/providers/anthropic.d.ts.map +1 -1
  64. package/dist/shared/providers/bedrock.d.ts +4 -1
  65. package/dist/shared/providers/bedrock.d.ts.map +1 -1
  66. package/dist/shared/providers/bifrost.d.ts +3 -3
  67. package/dist/shared/providers/bifrost.d.ts.map +1 -1
  68. package/dist/shared/providers/byteplus-modelark.d.ts +24 -1
  69. package/dist/shared/providers/byteplus-modelark.d.ts.map +1 -1
  70. package/dist/shared/providers/claude-cli.d.ts +14 -1
  71. package/dist/shared/providers/claude-cli.d.ts.map +1 -1
  72. package/dist/shared/providers/gateway-admin.d.ts +1 -1
  73. package/dist/shared/providers/gateway-admin.d.ts.map +1 -1
  74. package/dist/shared/providers/gemini.d.ts +4 -1
  75. package/dist/shared/providers/gemini.d.ts.map +1 -1
  76. package/dist/shared/providers/huggingface.d.ts +4 -1
  77. package/dist/shared/providers/huggingface.d.ts.map +1 -1
  78. package/dist/shared/providers/litellm.d.ts +3 -3
  79. package/dist/shared/providers/litellm.d.ts.map +1 -1
  80. package/dist/shared/providers/ollama.d.ts +8 -1
  81. package/dist/shared/providers/ollama.d.ts.map +1 -1
  82. package/dist/shared/providers/openai-compat-video.d.ts +23 -1
  83. package/dist/shared/providers/openai-compat-video.d.ts.map +1 -1
  84. package/dist/shared/providers/openai.d.ts +9 -1
  85. package/dist/shared/providers/openai.d.ts.map +1 -1
  86. package/dist/shared/providers/qwen-tts.d.ts +12 -1
  87. package/dist/shared/providers/qwen-tts.d.ts.map +1 -1
  88. package/dist/shared/providers/seevio.d.ts +10 -1
  89. package/dist/shared/providers/seevio.d.ts.map +1 -1
  90. package/dist/shared/providers/typesafe.d.ts +7 -1
  91. package/dist/shared/providers/typesafe.d.ts.map +1 -1
  92. package/dist/shared/providers/usage.d.ts +7 -1
  93. package/dist/shared/providers/usage.d.ts.map +1 -1
  94. package/dist/shared/providers/webllm-shim.d.ts +9 -0
  95. package/dist/shared/providers/webllm-shim.d.ts.map +1 -0
  96. package/dist/shared/providers/webllm.d.ts +115 -0
  97. package/dist/shared/providers/webllm.d.ts.map +1 -0
  98. package/dist/shared/rate-limit.d.ts +3 -2
  99. package/dist/shared/rate-limit.d.ts.map +1 -1
  100. package/dist/shared/safety.d.ts +1 -1
  101. package/dist/shared/safety.d.ts.map +1 -1
  102. package/dist/shared/thread.d.ts +3 -3
  103. package/dist/shared/thread.d.ts.map +1 -1
  104. package/dist/shared/tool-messages.d.ts +11 -1
  105. package/dist/shared/tool-messages.d.ts.map +1 -1
  106. package/dist/shared/types.d.ts +73 -2
  107. package/dist/shared/types.d.ts.map +1 -1
  108. package/metadata.json +1 -0
  109. package/package.json +15 -2
  110. package/dist/chunks/continuation-D0NisZA1.js.map +0 -1
  111. package/dist/chunks/rate-limit-BzWfHA0e.js.map +0 -1
  112. package/dist/chunks/types-DB5W6_F-.js +0 -153
  113. package/dist/chunks/types-DB5W6_F-.js.map +0 -1
  114. package/dist/chunks/usage-C1Y1Nlg4.js +0 -35
  115. package/dist/chunks/usage-C1Y1Nlg4.js.map +0 -1
@@ -1,281 +1,4 @@
1
- import { c as RateLimitError, o as DEFAULT_RATE_LIMIT_MAX_RETRY_DELAY_MS, t as AIError, u as isRateLimitRetryableSoon } from "./types-DB5W6_F-.js";
2
- //#region src/shared/safety.ts
3
- var DEFAULT_AI_TIMEOUT_MS = 12e4;
4
- var DEFAULT_AI_MAX_RETRIES = 0;
5
- var DEFAULT_AI_GENERATION_LIMITS = Object.freeze({
6
- maxOutputTokens: 131072,
7
- defaultOutputTokens: 4096,
8
- maxReasoningTokens: 1024,
9
- maxImagesPerRequest: 1,
10
- onExceeded: "error"
11
- });
12
- function positiveInteger(value, fallback, field) {
13
- if (value === void 0) return fallback;
14
- if (!Number.isFinite(value) || value <= 0) throw new AIError(`${field} must be a positive finite number`, "AI_LIMIT_INVALID");
15
- return Math.trunc(value);
16
- }
17
- function normalizeBaseAIOptions(options) {
18
- const configuredLimits = options.generationLimits || {};
19
- const generationLimits = {
20
- maxOutputTokens: positiveInteger(configuredLimits.maxOutputTokens, DEFAULT_AI_GENERATION_LIMITS.maxOutputTokens, "generationLimits.maxOutputTokens"),
21
- defaultOutputTokens: Math.min(positiveInteger(configuredLimits.defaultOutputTokens, DEFAULT_AI_GENERATION_LIMITS.defaultOutputTokens, "generationLimits.defaultOutputTokens"), positiveInteger(configuredLimits.maxOutputTokens, DEFAULT_AI_GENERATION_LIMITS.maxOutputTokens, "generationLimits.maxOutputTokens")),
22
- maxReasoningTokens: positiveInteger(configuredLimits.maxReasoningTokens, DEFAULT_AI_GENERATION_LIMITS.maxReasoningTokens, "generationLimits.maxReasoningTokens"),
23
- maxImagesPerRequest: positiveInteger(configuredLimits.maxImagesPerRequest, DEFAULT_AI_GENERATION_LIMITS.maxImagesPerRequest, "generationLimits.maxImagesPerRequest"),
24
- onExceeded: configuredLimits.onExceeded || DEFAULT_AI_GENERATION_LIMITS.onExceeded
25
- };
26
- if (!["error", "clamp"].includes(generationLimits.onExceeded)) throw new AIError("generationLimits.onExceeded must be \"error\" or \"clamp\"", "AI_LIMIT_INVALID");
27
- return {
28
- ...options,
29
- timeout: positiveInteger(options.timeout, DEFAULT_AI_TIMEOUT_MS, "timeout"),
30
- maxRetries: (() => {
31
- if (options.maxRetries === void 0) return 0;
32
- if (!Number.isFinite(options.maxRetries) || options.maxRetries < 0) throw new AIError("maxRetries must be a non-negative finite number", "AI_LIMIT_INVALID");
33
- return Math.trunc(options.maxRetries);
34
- })(),
35
- generationLimits
36
- };
37
- }
38
- function reasoningTokensForEffort(effort) {
39
- switch (effort) {
40
- case false:
41
- case "none": return 0;
42
- case "minimal": return 1024;
43
- case "low": return 2048;
44
- case "medium": return 4096;
45
- case "high": return 8192;
46
- default: return;
47
- }
48
- }
49
- function enforceLimit(requested, limit, behavior, label, provider, model) {
50
- if (!Number.isFinite(requested) || requested < 0) throw new AIError(`${label} must be a non-negative finite number`, "AI_LIMIT_INVALID", provider, model);
51
- const normalized = Math.trunc(requested);
52
- if (normalized <= limit) return normalized;
53
- if (behavior === "clamp") return limit;
54
- throw new AIError(`${label} ${normalized} exceeds configured ceiling ${limit}`, "AI_LIMIT_EXCEEDED", provider, model);
55
- }
56
- function normalizeChatOptions(providerOptions, options, provider, model) {
57
- const limits = normalizeBaseAIOptions(providerOptions).generationLimits;
58
- const requestedOutput = options.maxTokens ?? limits.defaultOutputTokens ?? limits.maxOutputTokens;
59
- const legacyEffort = options.thinkingLevel ?? providerOptions.thinkingLevel;
60
- const requestedReasoning = options.reasoning !== void 0 || legacyEffort !== void 0 || options.includeThoughts === true ? options.reasoning?.maxTokens ?? reasoningTokensForEffort(options.reasoning?.effort ?? legacyEffort) ?? limits.maxReasoningTokens : 0;
61
- return {
62
- ...options,
63
- maxTokens: enforceLimit(requestedOutput, limits.maxOutputTokens, limits.onExceeded, "maxTokens", provider, model),
64
- reasoning: {
65
- ...options.reasoning,
66
- maxTokens: enforceLimit(requestedReasoning, limits.maxReasoningTokens, limits.onExceeded, "reasoning.maxTokens", provider, model),
67
- includeThoughts: options.reasoning?.includeThoughts ?? options.includeThoughts
68
- }
69
- };
70
- }
71
- function normalizeImageGenerationOptions(providerOptions, options, provider, model) {
72
- const limits = normalizeBaseAIOptions(providerOptions).generationLimits;
73
- return {
74
- ...options,
75
- n: enforceLimit(options.n ?? 1, limits.maxImagesPerRequest, limits.onExceeded, "n", provider, model)
76
- };
77
- }
78
- function prepareRequestControls(providerOptions, requestOptions = {}) {
79
- const normalized = normalizeBaseAIOptions(providerOptions);
80
- const timeout = positiveInteger(requestOptions.timeout, normalized.timeout, "timeout");
81
- const controller = new AbortController();
82
- let timedOut = false;
83
- const abortFromCaller = () => controller.abort(requestOptions.signal?.reason);
84
- if (requestOptions.signal?.aborted) abortFromCaller();
85
- else requestOptions.signal?.addEventListener("abort", abortFromCaller, { once: true });
86
- const timer = setTimeout(() => {
87
- timedOut = true;
88
- controller.abort(/* @__PURE__ */ new Error(`AI request timed out after ${timeout}ms`));
89
- }, timeout);
90
- return {
91
- signal: controller.signal,
92
- timeout,
93
- didTimeout: () => timedOut,
94
- cleanup: () => {
95
- clearTimeout(timer);
96
- requestOptions.signal?.removeEventListener("abort", abortFromCaller);
97
- }
98
- };
99
- }
100
- function mergeTags(providerOptions, callTags) {
101
- return providerOptions.usageTags || callTags ? {
102
- ...providerOptions.usageTags,
103
- ...callTags
104
- } : void 0;
105
- }
106
- function emitRequestEvent(providerOptions, event) {
107
- if (!providerOptions.onRequest) return;
108
- try {
109
- providerOptions.onRequest({
110
- ...event,
111
- tags: mergeTags(providerOptions, event.tags)
112
- });
113
- } catch {}
114
- }
115
- function classifyRequestFailure(error, didTimeout = false) {
116
- const code = error instanceof AIError ? error.code : void 0;
117
- if (code === "AI_LIMIT_EXCEEDED" || code === "AI_LIMIT_INVALID") return {
118
- status: "rejected",
119
- errorCode: code
120
- };
121
- if (didTimeout || code === "AI_TIMEOUT" || code === "TIMEOUT" || code === "REQUEST_TIMEOUT") return {
122
- status: "timed_out",
123
- errorCode: code || "AI_TIMEOUT"
124
- };
125
- if (error instanceof Error && error.name === "AbortError") return {
126
- status: "aborted",
127
- errorCode: "ABORTED"
128
- };
129
- if (code === "AI_ABORTED" || code === "REQUEST_ABORTED") return {
130
- status: "aborted",
131
- errorCode: code
132
- };
133
- return {
134
- status: "failed",
135
- errorCode: code || (error instanceof Error ? error.name : void 0)
136
- };
137
- }
138
- function requestEventBase(options) {
139
- const normalized = normalizeBaseAIOptions(options.providerOptions);
140
- return {
141
- provider: options.provider,
142
- model: options.model,
143
- operation: options.operation,
144
- attempts: normalized.maxRetries + 1,
145
- requestedMaxOutputTokens: options.operation === "decide" ? void 0 : options.callOptions?.maxTokens,
146
- effectiveMaxOutputTokens: options.operation === "decide" || options.operation === "generateImage" || VIDEO_GENERATION_OPERATIONS.has(options.operation) ? void 0 : options.effectiveMaxOutputTokens ?? Math.min(options.callOptions?.maxTokens ?? normalized.generationLimits.defaultOutputTokens ?? normalized.generationLimits.maxOutputTokens, normalized.generationLimits.maxOutputTokens),
147
- tags: options.callOptions?.usageTags
148
- };
149
- }
150
- var OBSERVED_OPERATIONS = /* @__PURE__ */ new Set([
151
- "decide",
152
- "chat",
153
- "complete",
154
- "message",
155
- "describeImage",
156
- "generateImage",
157
- "stream",
158
- "submitVideoGenerationJob",
159
- "getVideoGenerationJob",
160
- "fetchVideoGenerationResult",
161
- "cancelVideoGenerationJob"
162
- ]);
163
- /**
164
- * `getVideoGenerationJob` / `fetchVideoGenerationResult` /
165
- * `cancelVideoGenerationJob` take a `VideoGenerationJob` handle as their
166
- * first (and only) argument rather than a chat-shaped `options` object as
167
- * the second argument. The handle still carries a `model` field, so
168
- * `callOptionsFor` reads it from the same position as `submitVideoGenerationJob`'s
169
- * `options` (index 0) rather than index 1.
170
- */
171
- var VIDEO_HANDLE_OPERATIONS = /* @__PURE__ */ new Set([
172
- "getVideoGenerationJob",
173
- "fetchVideoGenerationResult",
174
- "cancelVideoGenerationJob"
175
- ]);
176
- var VIDEO_GENERATION_OPERATIONS = /* @__PURE__ */ new Set(["submitVideoGenerationJob", ...VIDEO_HANDLE_OPERATIONS]);
177
- function callOptionsFor(operation, args) {
178
- const value = args[operation === "decide" ? 1 : operation === "describeImage" ? 2 : operation === "submitVideoGenerationJob" || VIDEO_HANDLE_OPERATIONS.has(operation) ? 0 : 1];
179
- return value && typeof value === "object" ? value : void 0;
180
- }
181
- function providerName(options) {
182
- return options.type || "openai";
183
- }
184
- function effectiveOutputTokens(operation, providerOptions, callOptions) {
185
- if (operation === "decide" || operation === "generateImage" || VIDEO_GENERATION_OPERATIONS.has(operation)) {
186
- if (operation === "generateImage") normalizeImageGenerationOptions(providerOptions, callOptions || {}, providerName(providerOptions), callOptions?.model);
187
- return;
188
- }
189
- return normalizeChatOptions(providerOptions, callOptions || {}, providerName(providerOptions), callOptions?.model || providerOptions.defaultModel).maxTokens;
190
- }
191
- /**
192
- * Wrap a public provider instance with prompt-free lifecycle observation.
193
- * Provider adapters still enforce limits internally so direct construction is
194
- * protected; this wrapper adds one terminal event to the public getAI() path.
195
- */
196
- function createObservedAI(client, providerOptions) {
197
- if (!providerOptions.onRequest) return client;
198
- return new Proxy(client, { get(target, property, receiver) {
199
- const value = Reflect.get(target, property, receiver);
200
- if (typeof property !== "string" || typeof value !== "function" || !OBSERVED_OPERATIONS.has(property)) return typeof value === "function" ? value.bind(target) : value;
201
- const operation = property;
202
- if (operation === "stream") return async function* (...args) {
203
- const startedAt = Date.now();
204
- const callOptions = callOptionsFor(operation, args);
205
- let base;
206
- try {
207
- base = requestEventBase({
208
- providerOptions,
209
- provider: providerName(providerOptions),
210
- model: callOptions?.model || providerOptions.defaultModel || "unknown",
211
- operation,
212
- callOptions,
213
- effectiveMaxOutputTokens: effectiveOutputTokens(operation, providerOptions, callOptions)
214
- });
215
- const iterable = Reflect.apply(value, target, args);
216
- for await (const chunk of iterable) yield chunk;
217
- emitRequestEvent(providerOptions, {
218
- ...base,
219
- status: "succeeded",
220
- duration: Date.now() - startedAt
221
- });
222
- } catch (error) {
223
- const failure = classifyRequestFailure(error);
224
- base ||= requestEventBase({
225
- providerOptions,
226
- provider: providerName(providerOptions),
227
- model: callOptions?.model || providerOptions.defaultModel || "unknown",
228
- operation,
229
- callOptions
230
- });
231
- emitRequestEvent(providerOptions, {
232
- ...base,
233
- ...failure,
234
- duration: Date.now() - startedAt
235
- });
236
- throw error;
237
- }
238
- };
239
- return async (...args) => {
240
- const startedAt = Date.now();
241
- const callOptions = callOptionsFor(operation, args);
242
- let base;
243
- try {
244
- base = requestEventBase({
245
- providerOptions,
246
- provider: providerName(providerOptions),
247
- model: callOptions?.model || providerOptions.defaultModel || "unknown",
248
- operation,
249
- callOptions,
250
- effectiveMaxOutputTokens: effectiveOutputTokens(operation, providerOptions, callOptions)
251
- });
252
- const result = await Reflect.apply(value, target, args);
253
- emitRequestEvent(providerOptions, {
254
- ...base,
255
- status: "succeeded",
256
- duration: Date.now() - startedAt
257
- });
258
- return result;
259
- } catch (error) {
260
- const failure = classifyRequestFailure(error);
261
- base ||= requestEventBase({
262
- providerOptions,
263
- provider: providerName(providerOptions),
264
- model: callOptions?.model || providerOptions.defaultModel || "unknown",
265
- operation,
266
- callOptions
267
- });
268
- emitRequestEvent(providerOptions, {
269
- ...base,
270
- ...failure,
271
- duration: Date.now() - startedAt
272
- });
273
- throw error;
274
- }
275
- };
276
- } });
277
- }
278
- //#endregion
1
+ import { _ as RateLimitError, h as DEFAULT_RATE_LIMIT_MAX_RETRY_DELAY_MS, u as AIError, x as isRateLimitRetryableSoon } from "./usage-BaQKo8bc.js";
279
2
  //#region src/shared/rate-limit.ts
280
3
  var RATE_LIMITED_METHODS = /* @__PURE__ */ new Set([
281
4
  "decide",
@@ -708,6 +431,6 @@ function positiveTimeout(value) {
708
431
  return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.trunc(value) : void 0;
709
432
  }
710
433
  //#endregion
711
- export { DEFAULT_AI_TIMEOUT_MS as a, normalizeChatOptions as c, DEFAULT_AI_MAX_RETRIES as i, normalizeImageGenerationOptions as l, rateLimitErrorFrom as n, createObservedAI as o, DEFAULT_AI_GENERATION_LIMITS as r, normalizeBaseAIOptions as s, createRateLimitedAI as t, prepareRequestControls as u };
434
+ export { rateLimitErrorFrom as n, createRateLimitedAI as t };
712
435
 
713
- //# sourceMappingURL=rate-limit-BzWfHA0e.js.map
436
+ //# sourceMappingURL=rate-limit-Bln_w0rH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit-Bln_w0rH.js","names":[],"sources":["../../src/shared/rate-limit.ts"],"sourcesContent":["import type { AIClientOptions } from './client';\nimport { DEFAULT_AI_TIMEOUT_MS } from './safety';\nimport type {\n AIInterface,\n AIRateLimitOptions,\n AIRequestControls,\n GetAIOptions,\n} from './types';\nimport {\n AIError,\n DEFAULT_RATE_LIMIT_MAX_RETRY_DELAY_MS,\n isRateLimitRetryableSoon,\n RateLimitError,\n} from './types';\n\nconst RATE_LIMITED_METHODS = new Set<keyof AIInterface>([\n 'decide',\n 'chat',\n 'complete',\n 'message',\n 'embed',\n 'embedImage',\n 'describeImage',\n 'generateImage',\n 'getModels',\n 'synthesizeSpeech',\n 'cloneVoice',\n 'designVoice',\n 'getVoices',\n 'submitVideoGenerationJob',\n]);\n\n/**\n * Where each paced method takes its request controls (`timeout`, `signal`).\n * For these, the timeout covers the whole call: time queued behind other calls\n * on the same key, pacing and retry waits, and the request itself.\n */\nconst REQUEST_CONTROLS_INDEX: Partial<Record<keyof AIInterface, number>> = {\n decide: 1,\n chat: 1,\n complete: 1,\n message: 1,\n describeImage: 2,\n generateImage: 1,\n submitVideoGenerationJob: 0,\n};\n\nconst MAX_BUDGET_COORDINATORS = 128;\nconst BUDGET_COORDINATOR_TTL_MS = 15 * 60 * 1000;\n\ninterface NormalizedRateLimitConfig {\n cooldownMs: number;\n initialDelayMs: number;\n key: string;\n maxAttempts: number;\n maxRetryDelayMs: number;\n}\n\n/** One call's limits while it waits for its turn on a budget key. */\ninterface CallBudget {\n provider: string;\n /** Epoch ms by which the whole call must finish; undefined = no limit. */\n deadline?: number;\n timeoutMs?: number;\n signal?: AbortSignal;\n}\n\nfunction queueTimeoutError(budget: CallBudget): AIError {\n return new AIError(\n `AI request timed out after ${budget.timeoutMs}ms, including time waiting for its rate-limit turn`,\n 'AI_TIMEOUT',\n budget.provider,\n );\n}\n\nfunction abortedError(budget: CallBudget): AIError {\n return new AIError(\n 'AI request aborted by caller',\n 'AI_ABORTED',\n budget.provider,\n );\n}\n\nclass BudgetCoordinator {\n private nextAvailableAt = 0;\n private pendingSchedules = 0;\n private tail: Promise<void> = Promise.resolve();\n private lastUsedAt = Date.now();\n /** The rate-limit error that holds the key closed until `blockedUntil`. */\n private blockedBy?: RateLimitError;\n private blockedUntil = 0;\n\n touch(): void {\n this.lastUsedAt = Date.now();\n }\n\n /**\n * Run `work` after every earlier call on this key. While the call is still\n * queued, its deadline or abort signal releases the caller, and the work is\n * skipped when its turn comes.\n */\n schedule<T>(work: () => Promise<T>, budget: CallBudget): Promise<T> {\n this.pendingSchedules += 1;\n this.touch();\n\n let gaveUp: AIError | undefined;\n let started: (() => void) | undefined;\n const guarded = () => {\n if (gaveUp) return Promise.reject(gaveUp);\n started?.();\n return work();\n };\n const run = this.tail.then(guarded, guarded);\n this.tail = run.then(\n () => undefined,\n () => undefined,\n );\n\n const result = run.finally(() => {\n this.pendingSchedules = Math.max(0, this.pendingSchedules - 1);\n this.touch();\n });\n if (budget.deadline === undefined && !budget.signal) return result;\n\n return new Promise<T>((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const stopWaiting = () => {\n if (timer) clearTimeout(timer);\n budget.signal?.removeEventListener('abort', onAbort);\n };\n const giveUp = (error: AIError) => {\n gaveUp = error;\n stopWaiting();\n reject(error);\n };\n const onAbort = () => giveUp(abortedError(budget));\n // Once the work starts, its own timeout and signal take over.\n started = stopWaiting;\n if (budget.deadline !== undefined) {\n timer = setTimeout(\n () => giveUp(queueTimeoutError(budget)),\n Math.max(0, budget.deadline - Date.now()),\n );\n }\n if (budget.signal?.aborted) {\n onAbort();\n } else {\n budget.signal?.addEventListener('abort', onAbort, { once: true });\n }\n result.then(\n (value) => {\n stopWaiting();\n resolve(value);\n },\n (error) => {\n stopWaiting();\n reject(error);\n },\n );\n });\n }\n\n /**\n * Wait out pacing before a request. When the wait would run past the call's\n * deadline, fail now: with a RateLimitError (reason and time until the key\n * reopens) when a rate limit closed the key, else with a timeout.\n */\n async waitUntilReady(\n budget: CallBudget,\n config: NormalizedRateLimitConfig,\n ): Promise<void> {\n this.touch();\n const now = Date.now();\n const delayMs = this.nextAvailableAt - now;\n if (delayMs > 0) {\n if (budget.deadline !== undefined && now + delayMs >= budget.deadline) {\n const blockedBy = this.blockedUntil > now ? this.blockedBy : undefined;\n if (blockedBy) {\n throw new RateLimitError(blockedBy.provider, undefined, {\n reason: blockedBy.reason,\n retryAfterMs: Math.max(0, this.blockedUntil - now),\n limitWindowMs: blockedBy.limitWindowMs,\n model: blockedBy.model,\n cause: blockedBy,\n maxRetryDelayMs: config.maxRetryDelayMs,\n });\n }\n throw queueTimeoutError(budget);\n }\n await sleep(delayMs, budget.signal);\n if (budget.signal?.aborted) throw abortedError(budget);\n }\n }\n\n delayFor(delayMs: number, cause?: RateLimitError): void {\n this.touch();\n if (delayMs <= 0) {\n return;\n }\n\n const until = Date.now() + delayMs;\n this.nextAvailableAt = Math.max(this.nextAvailableAt, until);\n if (cause && until >= this.blockedUntil) {\n this.blockedBy = cause;\n this.blockedUntil = until;\n }\n }\n\n isEvictable(now: number): boolean {\n return this.pendingSchedules === 0 && now >= this.nextAvailableAt;\n }\n\n isExpired(now: number): boolean {\n return (\n this.isEvictable(now) &&\n now - this.lastUsedAt >= BUDGET_COORDINATOR_TTL_MS\n );\n }\n\n getLastUsedAt(): number {\n return this.lastUsedAt;\n }\n}\n\nconst budgetCoordinators = new Map<string, BudgetCoordinator>();\n\n/** Sleep; an abort ends the sleep early (the caller checks the signal). */\nfunction sleep(delayMs: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n const done = () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', done);\n resolve();\n };\n const timer = setTimeout(done, delayMs);\n signal?.addEventListener('abort', done, { once: true });\n });\n}\n\nfunction pruneBudgetCoordinators(): void {\n const now = Date.now();\n\n for (const [key, coordinator] of budgetCoordinators.entries()) {\n if (coordinator.isExpired(now)) {\n budgetCoordinators.delete(key);\n }\n }\n\n while (budgetCoordinators.size > MAX_BUDGET_COORDINATORS) {\n const evictableEntries = [...budgetCoordinators.entries()]\n .filter(([, coordinator]) => coordinator.isEvictable(now))\n .sort(\n ([, leftCoordinator], [, rightCoordinator]) =>\n leftCoordinator.getLastUsedAt() - rightCoordinator.getLastUsedAt(),\n );\n\n if (evictableEntries.length === 0) {\n break;\n }\n\n budgetCoordinators.delete(evictableEntries[0][0]);\n }\n}\n\nfunction getBudgetCoordinator(key: string): BudgetCoordinator {\n pruneBudgetCoordinators();\n\n let coordinator = budgetCoordinators.get(key);\n if (!coordinator) {\n coordinator = new BudgetCoordinator();\n budgetCoordinators.set(key, coordinator);\n pruneBudgetCoordinators();\n }\n\n coordinator.touch();\n return coordinator;\n}\n\nfunction hasPacingConfig(rateLimit?: AIRateLimitOptions): boolean {\n if (!rateLimit || rateLimit.enabled === false) {\n return false;\n }\n\n return (\n rateLimit.enabled === true ||\n rateLimit.key !== undefined ||\n rateLimit.cooldownMs !== undefined ||\n rateLimit.initialDelayMs !== undefined ||\n rateLimit.maxAttempts !== undefined ||\n rateLimit.maxRetryDelayMs !== undefined\n );\n}\n\nfunction normalizeNonNegativeInteger(\n value: number | undefined,\n fallback: number,\n): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n return fallback;\n }\n\n return Math.max(0, Math.trunc(value));\n}\n\nfunction hashKey(value: string): string {\n let hash = 2166136261;\n\n for (let index = 0; index < value.length; index += 1) {\n hash ^= value.charCodeAt(index);\n hash = Math.imul(hash, 16777619);\n }\n\n return (hash >>> 0).toString(36);\n}\n\nfunction deriveBudgetKey(options: GetAIOptions | AIClientOptions): string {\n const type = (options as { type?: string }).type;\n const provider = typeof type === 'string' && type ? type : 'openai';\n\n const credentialLikeValues = [\n 'apiKey' in options ? options.apiKey : undefined,\n 'apiToken' in options ? options.apiToken : undefined,\n 'credentials' in options ? options.credentials?.accessKeyId : undefined,\n 'endpoint' in options ? options.endpoint : undefined,\n 'baseUrl' in options ? options.baseUrl : undefined,\n 'cliPath' in options ? options.cliPath : undefined,\n ];\n\n const seed = credentialLikeValues.find(\n (value): value is string => typeof value === 'string' && value.length > 0,\n );\n\n return seed ? `${provider}:${hashKey(seed)}` : `${provider}:default`;\n}\n\nfunction normalizeRateLimitConfig(\n options: GetAIOptions | AIClientOptions,\n): NormalizedRateLimitConfig | null {\n const rateLimit = 'rateLimit' in options ? options.rateLimit : undefined;\n\n if (!hasPacingConfig(rateLimit)) {\n return null;\n }\n\n return {\n cooldownMs: normalizeNonNegativeInteger(rateLimit?.cooldownMs, 0),\n initialDelayMs: normalizeNonNegativeInteger(\n rateLimit?.initialDelayMs,\n 5000,\n ),\n key: rateLimit?.key?.trim() || deriveBudgetKey(options),\n maxAttempts: Math.max(\n 1,\n normalizeNonNegativeInteger(rateLimit?.maxAttempts, 1),\n ),\n maxRetryDelayMs: normalizeNonNegativeInteger(\n rateLimit?.maxRetryDelayMs,\n DEFAULT_RATE_LIMIT_MAX_RETRY_DELAY_MS,\n ),\n };\n}\n\nfunction getRetryDelayMs(\n error: RateLimitError,\n config: NormalizedRateLimitConfig,\n): number {\n const hintedDelayMs =\n typeof error.retryAfterMs === 'number' &&\n Number.isFinite(error.retryAfterMs)\n ? Math.max(0, Math.ceil(error.retryAfterMs))\n : typeof error.retryAfter === 'number' &&\n Number.isFinite(error.retryAfter)\n ? Math.max(0, Math.ceil(error.retryAfter * 1000))\n : undefined;\n\n if (hintedDelayMs !== undefined) {\n return Math.max(config.cooldownMs, hintedDelayMs);\n }\n\n return Math.max(config.cooldownMs, config.initialDelayMs);\n}\n\nasync function invokeWithPacing<T>(\n execute: (remainingMs: number | undefined) => Promise<T>,\n coordinator: BudgetCoordinator,\n config: NormalizedRateLimitConfig,\n budget: CallBudget,\n allowRetry = true,\n): Promise<T> {\n let attempt = 1;\n\n while (true) {\n await coordinator.waitUntilReady(budget, config);\n\n const remainingMs =\n budget.deadline === undefined ? undefined : budget.deadline - Date.now();\n if (remainingMs !== undefined && remainingMs <= 0) {\n throw queueTimeoutError(budget);\n }\n\n try {\n const result = await execute(remainingMs);\n coordinator.delayFor(config.cooldownMs);\n return result;\n } catch (error) {\n if (error instanceof RateLimitError) {\n const retryDelayMs = getRetryDelayMs(error, config);\n coordinator.delayFor(retryDelayMs, error);\n // This client's threshold decides whether the reset is near enough\n // to retry; a far reset is surfaced as not retryable soon.\n error.retryable = isRateLimitRetryableSoon(\n error.retryAfterMs ?? error.limitWindowMs,\n config.maxRetryDelayMs,\n );\n\n const fitsDeadline =\n budget.deadline === undefined ||\n Date.now() + retryDelayMs < budget.deadline;\n if (\n allowRetry &&\n error.retryable &&\n fitsDeadline &&\n attempt < config.maxAttempts\n ) {\n attempt += 1;\n continue;\n }\n }\n\n throw error;\n }\n }\n}\n\nexport function parseRetryAfterSeconds(\n retryAfter: number | string | null | undefined,\n): number | undefined {\n if (typeof retryAfter === 'number' && Number.isFinite(retryAfter)) {\n return Math.max(0, retryAfter);\n }\n\n if (typeof retryAfter !== 'string') {\n return undefined;\n }\n\n const trimmed = retryAfter.trim();\n if (!trimmed) {\n return undefined;\n }\n\n const seconds = Number.parseFloat(trimmed);\n if (!Number.isNaN(seconds)) {\n return Math.max(0, seconds);\n }\n\n const retryAt = Date.parse(trimmed);\n if (Number.isNaN(retryAt)) {\n return undefined;\n }\n\n return Math.max(0, Math.ceil((retryAt - Date.now()) / 1000));\n}\n\nfunction getHeaderValue(\n headers: unknown,\n headerName: string,\n): number | string | undefined {\n if (!headers || typeof headers !== 'object') {\n return undefined;\n }\n\n if ('get' in headers && typeof headers.get === 'function') {\n return headers.get(headerName) ?? headers.get(headerName.toLowerCase());\n }\n\n const objectHeaders = headers as Record<string, number | string | undefined>;\n return objectHeaders[headerName] ?? objectHeaders[headerName.toLowerCase()];\n}\n\nexport function extractRetryAfterSeconds(error: unknown): number | undefined {\n if (!error || typeof error !== 'object') {\n return undefined;\n }\n\n if ('retryAfter' in error) {\n const retryAfter = parseRetryAfterSeconds(\n (error as { retryAfter?: number | string | null }).retryAfter,\n );\n if (retryAfter !== undefined) {\n return retryAfter;\n }\n }\n\n if ('headers' in error) {\n const retryAfter = parseRetryAfterSeconds(\n getHeaderValue((error as { headers?: unknown }).headers, 'retry-after'),\n );\n if (retryAfter !== undefined) {\n return retryAfter;\n }\n }\n\n const message =\n 'message' in error && typeof error.message === 'string'\n ? error.message\n : '';\n\n const retryAfterMatch =\n message.match(/retry after\\s+(\\d+(?:\\.\\d+)?)\\s*s?/i) ??\n message.match(/retryDelay[^\\d]*(\\d+(?:\\.\\d+)?)s/i);\n\n return retryAfterMatch\n ? parseRetryAfterSeconds(retryAfterMatch[1])\n : undefined;\n}\n\nconst DURATION_UNITS_MS: Record<string, number> = {\n ms: 1,\n millisecond: 1,\n milliseconds: 1,\n s: 1000,\n sec: 1000,\n secs: 1000,\n second: 1000,\n seconds: 1000,\n m: 60_000,\n min: 60_000,\n mins: 60_000,\n minute: 60_000,\n minutes: 60_000,\n h: 3_600_000,\n hr: 3_600_000,\n hrs: 3_600_000,\n hour: 3_600_000,\n hours: 3_600_000,\n d: 86_400_000,\n day: 86_400_000,\n days: 86_400_000,\n};\n\nconst DURATION_PART =\n '\\\\d+(?:\\\\.\\\\d+)?\\\\s*(?:milliseconds?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d)(?![a-z])';\nconst DURATION = `${DURATION_PART}(?:\\\\s*${DURATION_PART})*`;\n\n/**\n * Parse a duration such as `20s`, `6m0s`, `1h`, `250ms` or `2 minutes` into\n * milliseconds. Returns undefined for anything else.\n */\nexport function parseDurationMs(text: string): number | undefined {\n const trimmed = text.trim();\n if (!new RegExp(`^${DURATION}$`, 'i').test(trimmed)) return undefined;\n let total = 0;\n for (const match of trimmed.matchAll(/(\\d+(?:\\.\\d+)?)\\s*([a-z]+)/gi)) {\n total +=\n Number.parseFloat(match[1]) * DURATION_UNITS_MS[match[2].toLowerCase()];\n }\n return Number.isFinite(total) ? Math.ceil(total) : undefined;\n}\n\n/** Reset headers that name when a limit lifts, as a duration or a timestamp. */\nconst RESET_HEADERS = [\n 'x-ratelimit-reset-requests',\n 'x-ratelimit-reset-tokens',\n 'anthropic-ratelimit-requests-reset',\n 'anthropic-ratelimit-tokens-reset',\n 'anthropic-ratelimit-input-tokens-reset',\n 'anthropic-ratelimit-output-tokens-reset',\n];\n\nfunction resetHeaderMs(headers: unknown): number | undefined {\n let latest: number | undefined;\n for (const name of RESET_HEADERS) {\n const raw = getHeaderValue(headers, name);\n if (raw === undefined || raw === null || raw === '') continue;\n const text = String(raw).trim();\n let ms = parseDurationMs(text);\n if (ms === undefined && /\\d{4}-\\d{2}-\\d{2}T/.test(text)) {\n const at = Date.parse(text);\n if (!Number.isNaN(at)) ms = Math.max(0, at - Date.now());\n }\n if (ms !== undefined) latest = Math.max(latest ?? 0, ms);\n }\n return latest;\n}\n\nfunction stringAt(value: unknown, ...path: string[]): string | undefined {\n let current = value;\n for (const key of path) {\n if (!current || typeof current !== 'object') return undefined;\n current = (current as Record<string, unknown>)[key];\n }\n return typeof current === 'string' && current.trim() ? current : undefined;\n}\n\n/**\n * The provider's own reason text from an SDK error or response body, for\n * example `token limit exceeded (277867/250000, resets every 1h)`.\n */\nexport function extractRateLimitReason(error: unknown): string | undefined {\n const fromBody =\n stringAt(error, 'error', 'error', 'message') ?? // Anthropic SDK body\n stringAt(error, 'error', 'message') ?? // OpenAI SDK body.error\n stringAt(error, 'body', 'error', 'message') ??\n stringAt(error, 'body', 'message');\n if (fromBody) return fromBody;\n const message = stringAt(error, 'message');\n if (!message) return undefined;\n // A raw HTTP body handed over as the message: read the JSON error text.\n if (/^\\s*\\{/.test(message)) {\n try {\n const body: unknown = JSON.parse(message);\n const text =\n stringAt(body, 'error', 'message') ??\n stringAt(body, 'message') ??\n stringAt(body, 'error');\n if (text) return text;\n } catch {\n // Not JSON: use the text as-is below.\n }\n }\n // SDKs prefix the HTTP status (\"429 ...\"); a bare status line has no reason.\n const reason = message.replace(/^\\d{3}\\s+/, '').trim();\n return /^(?:status code \\(no body\\)|too many requests|rate limit(?:ed| exceeded)?)\\.?$/i.test(\n reason,\n )\n ? undefined\n : reason;\n}\n\n/**\n * Build a RateLimitError that keeps what the provider said: its reason text,\n * any `Retry-After` or reset hint (headers or text), and a named limit window.\n */\nexport function rateLimitErrorFrom(\n provider: string,\n error: unknown,\n extra: { reason?: string; model?: string } = {},\n): RateLimitError {\n const reason = extra.reason?.trim() || extractRateLimitReason(error);\n const retryAfter = extractRetryAfterSeconds(error);\n const headers =\n error && typeof error === 'object' && 'headers' in error\n ? (error as { headers?: unknown }).headers\n : undefined;\n let retryAfterMs =\n retryAfter !== undefined ? retryAfter * 1000 : resetHeaderMs(headers);\n let limitWindowMs: number | undefined;\n if (reason) {\n if (retryAfterMs === undefined) {\n const inMatch = reason.match(\n new RegExp(\n `(?:try again|retry|resets?|available)\\\\s+in\\\\s+(${DURATION})`,\n 'i',\n ),\n );\n if (inMatch) retryAfterMs = parseDurationMs(inMatch[1]);\n }\n const everyMatch = reason.match(\n new RegExp(`resets?\\\\s+(?:every|each)\\\\s+(${DURATION})`, 'i'),\n );\n if (everyMatch) limitWindowMs = parseDurationMs(everyMatch[1]);\n }\n return new RateLimitError(provider, retryAfter, {\n reason,\n retryAfterMs,\n limitWindowMs,\n model: extra.model,\n cause: error,\n });\n}\n\nexport function createRateLimitedAI<T extends AIInterface>(\n client: T,\n options: GetAIOptions | AIClientOptions,\n): T {\n const config = normalizeRateLimitConfig(options);\n if (!config) {\n return client;\n }\n\n const wrappedMethods = new Map<PropertyKey, unknown>();\n const provider =\n typeof options.type === 'string' && options.type ? options.type : 'openai';\n const clientTimeoutMs = positiveTimeout(\n 'timeout' in options ? options.timeout : undefined,\n );\n // Seevio does not document idempotency for billed video-task submission.\n // Existing providers retain their established pacing-retry behavior.\n const allowSeevioSubmitRetry = options.type !== 'seevio';\n\n return new Proxy(client, {\n get(target, property, receiver) {\n const value = Reflect.get(target, property, receiver);\n\n if (typeof value !== 'function') {\n return value;\n }\n\n if (!RATE_LIMITED_METHODS.has(property as keyof AIInterface)) {\n if (!wrappedMethods.has(property)) {\n wrappedMethods.set(property, value.bind(target));\n }\n\n return wrappedMethods.get(property);\n }\n\n if (!wrappedMethods.has(property)) {\n const controlsIndex =\n REQUEST_CONTROLS_INDEX[property as keyof AIInterface];\n wrappedMethods.set(property, (...args: unknown[]) => {\n const coordinator = getBudgetCoordinator(config.key);\n const controls =\n controlsIndex === undefined\n ? undefined\n : (args[controlsIndex] as AIRequestControls | undefined);\n // The timeout bounds the whole call from the caller's side. Methods\n // without request controls only use a client-level timeout.\n const timeoutMs =\n controlsIndex === undefined\n ? clientTimeoutMs\n : controls?.timeout !== undefined\n ? positiveTimeout(controls.timeout)\n : (clientTimeoutMs ?? DEFAULT_AI_TIMEOUT_MS);\n const budget: CallBudget = {\n provider,\n timeoutMs,\n deadline:\n timeoutMs === undefined ? undefined : Date.now() + timeoutMs,\n signal: controls?.signal,\n };\n return coordinator.schedule(\n () =>\n invokeWithPacing(\n (remainingMs) => {\n const callArgs = [...args];\n if (\n controlsIndex !== undefined &&\n remainingMs !== undefined\n ) {\n // The request gets only what is left of the call's timeout.\n callArgs[controlsIndex] = {\n ...controls,\n timeout: Math.max(1, Math.floor(remainingMs)),\n };\n }\n return Reflect.apply(\n value,\n target,\n callArgs,\n ) as Promise<unknown>;\n },\n coordinator,\n config,\n budget,\n property !== 'submitVideoGenerationJob' ||\n allowSeevioSubmitRetry,\n ),\n budget,\n );\n });\n }\n\n return wrappedMethods.get(property);\n },\n }) as T;\n}\n\n/** A usable timeout, or undefined so the provider reports a bad value itself. */\nfunction positiveTimeout(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) && value > 0\n ? Math.trunc(value)\n : undefined;\n}\n\nexport function __resetAIRateLimitStateForTests(): void {\n budgetCoordinators.clear();\n}\n\nexport function __getAIRateLimitStateForTests(): {\n count: number;\n maxBudgetCoordinators: number;\n ttlMs: number;\n} {\n return {\n count: budgetCoordinators.size,\n maxBudgetCoordinators: MAX_BUDGET_COORDINATORS,\n ttlMs: BUDGET_COORDINATOR_TTL_MS,\n };\n}\n\nexport function isRetryableAIError(error: unknown): error is AIError {\n return error instanceof AIError && error.retryable;\n}\n"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true
8
+ });
9
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
10
+ return target;
11
+ };
12
+ //#endregion
13
+ export { __exportAll as t };
@@ -1,6 +1,5 @@
1
- import { r as AuthenticationError, t as AIError } from "./types-DB5W6_F-.js";
2
- import { n as rateLimitErrorFrom, s as normalizeBaseAIOptions } from "./rate-limit-BzWfHA0e.js";
3
- import { t as emitUsage } from "./usage-C1Y1Nlg4.js";
1
+ import { f as AuthenticationError, o as normalizeBaseAIOptions, t as emitUsage, u as AIError } from "./usage-BaQKo8bc.js";
2
+ import { n as rateLimitErrorFrom } from "./rate-limit-Bln_w0rH.js";
4
3
  import { ValidationError } from "@happyvertical/utils";
5
4
  //#region src/shared/providers/seevio.ts
6
5
  /**
@@ -447,4 +446,4 @@ var SeevioProvider = class {
447
446
  //#endregion
448
447
  export { SeevioProvider };
449
448
 
450
- //# sourceMappingURL=seevio-D2y5Io7C.js.map
449
+ //# sourceMappingURL=seevio-CosohVa0.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"seevio-D2y5Io7C.js","names":[],"sources":["../../src/shared/providers/seevio.ts"],"sourcesContent":["/**\n * Seevio's native asynchronous Seedance 2.5 video-generation provider.\n *\n * Seevio is deliberately implemented as its own raw-HTTP adapter rather than\n * being shaped to ModelArk. Both services can run Seedance, but their task,\n * billing, and media contracts differ.\n *\n * @see https://seevio.ai/api-docs\n */\n\nimport { ValidationError } from '@happyvertical/utils';\nimport { rateLimitErrorFrom } from '../rate-limit';\nimport { normalizeBaseAIOptions } from '../safety';\nimport type {\n AICapabilities,\n AIInterface,\n AIMessage,\n AIModel,\n AIResponse,\n ChatOptions,\n CompletionOptions,\n EmbeddingOptions,\n EmbeddingResponse,\n ImageDescriptionOptions,\n ImageEmbeddingOptions,\n ImageGenerationOptions,\n ImageGenerationResponse,\n MessageOptions,\n SeevioOptions,\n TTSOptions,\n TTSResponse,\n VideoGenerationBillingMetadata,\n VideoGenerationJob,\n VideoGenerationOptions,\n VideoGenerationReferenceMedia,\n VideoGenerationResult,\n VideoGenerationStatusResult,\n Voice,\n VoiceCloneOptions,\n VoiceDesignOptions,\n VoiceListOptions,\n} from '../types';\nimport { AIError, AuthenticationError } from '../types';\nimport { emitUsage } from './usage';\n\nconst DEFAULT_BASE_URL = 'https://api.seevio.ai';\nconst DEFAULT_RESULT_ORIGIN = 'https://cdn.seevio.ai';\nconst MODEL = 'seedance-2-5';\nconst MIN_POLL_INTERVAL_MS = 10_000;\nconst MAX_REDIRECTS = 5;\nconst DEFAULT_MAX_RESULT_BYTES = 200 * 1024 * 1024;\nconst COMPLETED_SNAPSHOT_TTL_MS = MIN_POLL_INTERVAL_MS;\nconst MAX_COMPLETED_SNAPSHOTS = 128;\n\ninterface SeevioTask {\n id: string;\n status: string;\n model?: string;\n billing_status?: string;\n credits?: number;\n failed_reason?: string | null;\n data?: {\n results?: string[];\n video_expires_at?: string;\n last_frame_url?: string | null;\n processing_time?: number;\n };\n}\n\ninterface SeevioErrorResponse {\n error?: {\n code?: string;\n message?: string;\n required?: number;\n available?: number;\n };\n}\n\ninterface SeevioCreateResponse {\n taskId: string;\n credits?: number;\n}\n\ninterface SeevioInput {\n prompt: string;\n generation_type: 'text-to-video' | 'image-to-video' | 'reference-to-video';\n image_urls?: string[];\n video_urls?: string[];\n audio_urls?: string[];\n duration: number;\n aspect_ratio: 'adaptive' | '16:9' | '9:16' | '1:1' | '4:3' | '3:4' | '21:9';\n resolution: '480p' | '720p';\n generate_audio: boolean;\n return_last_frame: boolean;\n}\n\nfunction ensureOptions(options: SeevioOptions): SeevioOptions {\n const baseUrl = (options.baseUrl || DEFAULT_BASE_URL)\n .trim()\n .replace(/\\/+$/, '');\n const parsedBaseUrl = new URL(baseUrl);\n if (parsedBaseUrl.protocol !== 'https:') {\n throw new ValidationError('seevio baseUrl must use HTTPS', {\n provider: 'seevio',\n });\n }\n const origins = options.resultUrlOrigins?.length\n ? options.resultUrlOrigins\n : [DEFAULT_RESULT_ORIGIN];\n for (const origin of origins) {\n const parsed = new URL(origin);\n if (\n parsed.protocol !== 'https:' ||\n parsed.origin !== origin.replace(/\\/+$/, '')\n ) {\n throw new ValidationError(\n 'seevio resultUrlOrigins must contain HTTPS origins only',\n {\n provider: 'seevio',\n },\n );\n }\n }\n if (\n options.maxResultBytes !== undefined &&\n (!Number.isSafeInteger(options.maxResultBytes) ||\n options.maxResultBytes <= 0)\n ) {\n throw new ValidationError(\n 'seevio maxResultBytes must be a positive safe integer',\n { provider: 'seevio' },\n );\n }\n return {\n ...options,\n baseUrl,\n resultUrlOrigins: origins.map((origin) => origin.replace(/\\/+$/, '')),\n };\n}\n\nfunction validatedHttpsUrl(value: string, label: string): string {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new ValidationError(`${label} must be a valid public HTTPS URL`, {\n provider: 'seevio',\n });\n }\n if (url.protocol !== 'https:') {\n throw new ValidationError(`${label} must use HTTPS`, {\n provider: 'seevio',\n });\n }\n const host = url.hostname.toLowerCase();\n if (\n url.username ||\n url.password ||\n host === 'localhost' ||\n host.endsWith('.localhost') ||\n host.includes(':') ||\n /^\\d{1,3}(?:\\.\\d{1,3}){3}$/.test(host)\n ) {\n throw new ValidationError(\n `${label} must not use credentials, localhost, or an IP-literal host`,\n { provider: 'seevio' },\n );\n }\n return url.toString();\n}\n\nfunction normalizeBilling(\n task: SeevioTask,\n): VideoGenerationBillingMetadata | undefined {\n if (task.credits === undefined && !task.billing_status) return undefined;\n const normalized = [\n 'reserved',\n 'charged',\n 'refunded',\n 'refund_failed',\n ].includes(task.billing_status || '')\n ? (task.billing_status as VideoGenerationBillingMetadata['status'])\n : undefined;\n return {\n ...(task.credits !== undefined ? { credits: task.credits } : {}),\n ...(normalized ? { status: normalized } : {}),\n ...(!normalized && task.billing_status\n ? { rawStatus: task.billing_status }\n : {}),\n };\n}\n\n/** Native Seevio adapter for the pinned `seedance-2-5` model. */\nexport class SeevioProvider implements AIInterface {\n private readonly options: SeevioOptions;\n private readonly resultOrigins: Set<string>;\n private readonly nextPollAt = new Map<string, number>();\n private readonly completedSnapshots = new Map<\n string,\n { task: SeevioTask; recordedAt: number }\n >();\n\n /** Creates a Seevio task client using the documented HTTPS API root. */\n constructor(options: SeevioOptions) {\n this.options = normalizeBaseAIOptions(ensureOptions(options));\n this.resultOrigins = new Set(this.options.resultUrlOrigins);\n }\n\n private async request<T>(\n path: string,\n options: {\n method?: 'GET' | 'POST';\n body?: unknown;\n signal?: AbortSignal;\n timeout?: number;\n allowNotFound?: boolean;\n } = {},\n ): Promise<T> {\n const response = await this.rawRequest(path, options);\n const text = await response.text();\n return text ? (JSON.parse(text) as T) : ({} as T);\n }\n\n private async rawRequest(\n path: string,\n options: {\n method?: 'GET' | 'POST';\n body?: unknown;\n signal?: AbortSignal;\n timeout?: number;\n allowNotFound?: boolean;\n } = {},\n ): Promise<Response> {\n if (options.signal?.aborted)\n throw new AIError(\n 'Seevio request aborted by caller',\n 'AI_ABORTED',\n 'seevio',\n );\n const controller = new AbortController();\n const timeoutMs = options.timeout ?? this.options.timeout;\n let timedOut = false;\n const timer = setTimeout(() => {\n timedOut = true;\n controller.abort();\n }, timeoutMs);\n const abort = () => controller.abort(options.signal?.reason);\n options.signal?.addEventListener('abort', abort, { once: true });\n // An abort may occur between the preflight check and listener\n // registration. Re-check after registration so that race still reaches\n // the fetch signal rather than allowing a paid request to continue.\n if (options.signal?.aborted) abort();\n try {\n let response: Response;\n try {\n response = await fetch(`${this.options.baseUrl}${path}`, {\n method: options.method || 'GET',\n headers: {\n Authorization: `Bearer ${this.options.apiKey ?? ''}`,\n ...(options.body !== undefined\n ? { 'Content-Type': 'application/json' }\n : {}),\n ...(this.options.headers || {}),\n },\n body:\n options.body === undefined\n ? undefined\n : JSON.stringify(options.body),\n signal: controller.signal,\n });\n } catch (error) {\n if (timedOut)\n throw new AIError(\n `Seevio request to ${path} timed out after ${timeoutMs}ms`,\n 'AI_TIMEOUT',\n 'seevio',\n undefined,\n options.method !== 'POST',\n );\n if (options.signal?.aborted)\n throw new AIError(\n 'Seevio request aborted by caller',\n 'AI_ABORTED',\n 'seevio',\n );\n throw new AIError(\n `Network error calling Seevio ${path}: ${error instanceof Error ? error.message : String(error)}`,\n 'NETWORK_ERROR',\n 'seevio',\n undefined,\n options.method !== 'POST',\n );\n }\n if (response.status === 404 && options.allowNotFound) return response;\n if (response.ok) return response;\n const errorText = await response.text();\n let payload: SeevioErrorResponse = {};\n try {\n payload = JSON.parse(errorText) as SeevioErrorResponse;\n } catch {\n /* preserve status fallback below */\n }\n const message =\n payload.error?.message ||\n `Seevio request to ${path} failed with HTTP ${response.status}`;\n if (response.status === 401) throw new AuthenticationError('seevio');\n if (response.status === 403)\n throw new AIError(message, 'SEEVIO_FORBIDDEN', 'seevio');\n if (response.status === 402)\n throw new AIError(message, 'INSUFFICIENT_CREDITS', 'seevio');\n if (response.status === 429)\n throw rateLimitErrorFrom(\n 'seevio',\n { headers: response.headers },\n { reason: payload.error?.message },\n );\n throw new AIError(\n message,\n 'SEEVIO_REQUEST_FAILED',\n 'seevio',\n undefined,\n response.status >= 500 && options.method !== 'POST',\n );\n } finally {\n clearTimeout(timer);\n options.signal?.removeEventListener('abort', abort);\n }\n }\n\n private assertReviewedResultUrl(value: string): string {\n const url = validatedHttpsUrl(value, 'Seevio result URL');\n if (!this.resultOrigins.has(new URL(url).origin)) {\n throw new AIError(\n 'Seevio returned a result URL outside configured reviewed origins',\n 'UNTRUSTED_RESULT_URL',\n 'seevio',\n );\n }\n return url;\n }\n\n private async downloadReviewedResult(\n initialUrl: string,\n ): Promise<{ data: Buffer; mimeType: string; url: string }> {\n let current = this.assertReviewedResultUrl(initialUrl);\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.options.timeout);\n const maxBytes = this.options.maxResultBytes ?? DEFAULT_MAX_RESULT_BYTES;\n try {\n for (let redirects = 0; redirects <= MAX_REDIRECTS; redirects += 1) {\n const response = await fetch(current, {\n redirect: 'manual',\n signal: controller.signal,\n });\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get('location');\n if (!location)\n throw new AIError(\n 'Seevio result redirect omitted Location',\n 'SEEVIO_RESULT_DOWNLOAD_FAILED',\n 'seevio',\n );\n current = this.assertReviewedResultUrl(\n new URL(location, current).toString(),\n );\n continue;\n }\n if (!response.ok)\n throw new AIError(\n `Seevio result download failed with HTTP ${response.status}`,\n 'SEEVIO_RESULT_DOWNLOAD_FAILED',\n 'seevio',\n );\n const contentType = response.headers.get('content-type');\n if (!contentType?.toLowerCase().startsWith('video/'))\n throw new AIError(\n `Seevio result download returned non-video content type ${contentType}`,\n 'SEEVIO_RESULT_MIME_INVALID',\n 'seevio',\n );\n const contentLength = response.headers.get('content-length');\n if (contentLength && Number(contentLength) > maxBytes)\n throw new AIError(\n `Seevio result exceeds configured ${maxBytes}-byte download limit`,\n 'SEEVIO_RESULT_TOO_LARGE',\n 'seevio',\n );\n if (!response.body)\n throw new AIError(\n 'Seevio result download had no response body',\n 'SEEVIO_RESULT_DOWNLOAD_FAILED',\n 'seevio',\n );\n const chunks: Uint8Array[] = [];\n let size = 0;\n const reader = response.body.getReader();\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n size += value.byteLength;\n if (size > maxBytes) {\n await reader.cancel();\n throw new AIError(\n `Seevio result exceeds configured ${maxBytes}-byte download limit`,\n 'SEEVIO_RESULT_TOO_LARGE',\n 'seevio',\n );\n }\n chunks.push(value);\n }\n return {\n data: Buffer.concat(chunks.map((chunk) => Buffer.from(chunk))),\n mimeType: contentType,\n url: current,\n };\n }\n throw new AIError(\n 'Seevio result exceeded the maximum redirect count',\n 'SEEVIO_RESULT_DOWNLOAD_FAILED',\n 'seevio',\n );\n } catch (error) {\n if (controller.signal.aborted)\n throw new AIError(\n `Seevio result download timed out after ${this.options.timeout}ms`,\n 'AI_TIMEOUT',\n 'seevio',\n undefined,\n true,\n );\n throw error;\n } finally {\n clearTimeout(timer);\n }\n }\n\n private mediaUrls(options: VideoGenerationOptions): {\n images: string[];\n videos: string[];\n audio: string[];\n } {\n const images = (options.referenceImages ?? []).map((reference) => {\n if (\n typeof reference.image !== 'string' ||\n reference.image.startsWith('data:')\n ) {\n throw new ValidationError(\n 'Seevio referenceImages must be public HTTPS URLs; it cannot retrieve bytes or data URLs',\n { provider: 'seevio' },\n );\n }\n return validatedHttpsUrl(reference.image, 'Seevio reference image');\n });\n const references = options.referenceMedia ?? [];\n if (references.length + images.length > 50)\n throw new ValidationError(\n 'Seevio accepts at most 50 total reference assets',\n { provider: 'seevio' },\n );\n const collect = (type: VideoGenerationReferenceMedia['type']) =>\n references\n .filter((reference) => reference.type === type)\n .map((reference) =>\n validatedHttpsUrl(reference.url, `Seevio ${type} reference`),\n );\n const mediaImages = collect('image');\n const videos = collect('video');\n const audio = collect('audio');\n if (\n images.length + mediaImages.length > 30 ||\n videos.length > 10 ||\n audio.length > 10\n ) {\n throw new ValidationError(\n 'Seevio reference limits are 30 images, 10 videos, and 10 audio files',\n { provider: 'seevio' },\n );\n }\n for (const reference of references) {\n if (\n (reference.type === 'video' || reference.type === 'audio') &&\n reference.durationSeconds !== undefined &&\n (!Number.isFinite(reference.durationSeconds) ||\n reference.durationSeconds < 2 ||\n reference.durationSeconds > 30)\n ) {\n throw new ValidationError(\n 'Seevio video/audio reference durations must be 2-30 seconds when supplied',\n { provider: 'seevio' },\n );\n }\n }\n for (const [label, type] of [\n ['video', 'video'],\n ['audio', 'audio'],\n ] as const) {\n const durations = references\n .filter((reference) => reference.type === type)\n .flatMap((reference) =>\n reference.durationSeconds === undefined\n ? []\n : [reference.durationSeconds],\n );\n if (durations.reduce((total, duration) => total + duration, 0) > 30) {\n throw new ValidationError(\n `Seevio ${label} reference durations must total no more than 30 seconds`,\n { provider: 'seevio' },\n );\n }\n }\n return { images: [...images, ...mediaImages], videos, audio };\n }\n\n private async pollTask(jobId: string): Promise<SeevioTask> {\n const now = Date.now();\n for (const [knownJobId, expiry] of this.nextPollAt) {\n if (expiry <= now) this.nextPollAt.delete(knownJobId);\n }\n const next = this.nextPollAt.get(jobId);\n if (next && now < next)\n throw new AIError(\n `Seevio tasks may be polled no more than once every 10 seconds; retry after ${Math.ceil((next - now) / 1000)} seconds`,\n 'VIDEO_POLL_TOO_FREQUENT',\n 'seevio',\n );\n const expiry = now + MIN_POLL_INTERVAL_MS;\n this.nextPollAt.set(jobId, expiry);\n const cleanup = setTimeout(() => {\n if (this.nextPollAt.get(jobId) === expiry) this.nextPollAt.delete(jobId);\n }, MIN_POLL_INTERVAL_MS);\n // Let idle Node workers exit rather than keeping the process alive for a\n // cadence cleanup timer. Browser timer handles do not expose `unref`.\n if (typeof cleanup === 'object' && 'unref' in cleanup) cleanup.unref();\n const task = await this.request<SeevioTask>(\n `/v1/tasks/${encodeURIComponent(jobId)}`,\n );\n if (task.status === 'completed') {\n // This is a bounded, short-lived handoff cache, not task history. A\n // completed task can be fetched without another status request only\n // within the provider's ten-second cadence window.\n if (!this.completedSnapshots.has(jobId)) {\n const oldestJobId = this.completedSnapshots.keys().next().value;\n if (\n this.completedSnapshots.size >= MAX_COMPLETED_SNAPSHOTS &&\n oldestJobId !== undefined\n ) {\n this.completedSnapshots.delete(oldestJobId);\n }\n }\n this.completedSnapshots.set(jobId, { task, recordedAt: Date.now() });\n }\n return task;\n }\n\n private completedSnapshot(jobId: string): SeevioTask | undefined {\n const snapshot = this.completedSnapshots.get(jobId);\n if (!snapshot) return undefined;\n if (Date.now() - snapshot.recordedAt >= COMPLETED_SNAPSHOT_TTL_MS) {\n this.completedSnapshots.delete(jobId);\n return undefined;\n }\n return snapshot.task;\n }\n\n /** Submits one unambiguous, non-retried Seedance 2.5 task. */\n async submitVideoGenerationJob(\n options: VideoGenerationOptions,\n ): Promise<VideoGenerationJob> {\n const startTime = Date.now();\n const model = options.model || this.options.defaultModel || MODEL;\n if (model !== MODEL)\n throw new ValidationError(\n `Seevio provider supports the pinned model ${MODEL}`,\n { provider: 'seevio' },\n );\n if (!options.prompt?.trim())\n throw new ValidationError('Seevio requires a non-empty prompt', {\n provider: 'seevio',\n });\n if (options.seed !== undefined)\n throw new ValidationError(\n 'seed is not supported by Seevio Seedance 2.5',\n { provider: 'seevio' },\n );\n const duration = options.durationSeconds ?? 5;\n if (!Number.isInteger(duration) || duration < 4 || duration > 30)\n throw new ValidationError(\n 'Seevio durationSeconds must be an integer from 4 through 30',\n { provider: 'seevio' },\n );\n const resolution = options.resolution ?? '720p';\n if (resolution !== '480p' && resolution !== '720p')\n throw new ValidationError('Seevio resolution must be 480p or 720p', {\n provider: 'seevio',\n });\n const { images, videos, audio } = this.mediaUrls(options);\n const isImageToVideo =\n images.length >= 1 &&\n images.length <= 2 &&\n videos.length === 0 &&\n audio.length === 0;\n const generationType = isImageToVideo\n ? 'image-to-video'\n : images.length || videos.length || audio.length\n ? 'reference-to-video'\n : 'text-to-video';\n const aspectRatio = options.aspectRatio ?? 'adaptive';\n const supportedRatios: SeevioInput['aspect_ratio'][] = [\n 'adaptive',\n '16:9',\n '9:16',\n '1:1',\n '4:3',\n '3:4',\n '21:9',\n ];\n if (!supportedRatios.includes(aspectRatio as SeevioInput['aspect_ratio']))\n throw new ValidationError('Unsupported Seevio aspectRatio', {\n provider: 'seevio',\n });\n if (isImageToVideo && aspectRatio !== 'adaptive')\n throw new ValidationError(\n 'Seevio image-to-video requires aspectRatio: adaptive',\n { provider: 'seevio' },\n );\n const input: SeevioInput = {\n prompt: options.prompt.trim(),\n generation_type: generationType,\n duration,\n aspect_ratio: aspectRatio as SeevioInput['aspect_ratio'],\n resolution: resolution as '480p' | '720p',\n generate_audio: options.generateAudio ?? true,\n return_last_frame: options.returnLastFrame ?? false,\n ...(images.length ? { image_urls: images } : {}),\n ...(videos.length ? { video_urls: videos } : {}),\n ...(audio.length ? { audio_urls: audio } : {}),\n };\n const created = await this.request<SeevioCreateResponse>(\n '/v1/videos/generations',\n {\n method: 'POST',\n body: { model: MODEL, input },\n signal: options.signal,\n timeout: options.timeout,\n },\n );\n if (!created.taskId)\n throw new AIError(\n 'Seevio accepted submission without a taskId',\n 'SEEVIO_INVALID_RESPONSE',\n 'seevio',\n );\n emitUsage(\n this.options,\n 'seevio',\n 'submitVideoGenerationJob',\n MODEL,\n undefined,\n startTime,\n {\n durationSeconds: String(duration),\n resolution,\n aspectRatio,\n ...options.usageTags,\n },\n );\n return {\n jobId: created.taskId,\n provider: 'seevio',\n model: MODEL,\n createdAt: new Date().toISOString(),\n raw:\n created.credits === undefined\n ? undefined\n : { credits: created.credits, billingStatus: 'reserved' },\n };\n }\n\n /** Returns a normalized task snapshot, enforcing Seevio's 10-second poll cadence. */\n async getVideoGenerationJob(\n handle: VideoGenerationJob,\n ): Promise<VideoGenerationStatusResult> {\n return this.mapTask(await this.pollTask(handle.jobId));\n }\n\n /** Downloads a completed video while validating the initial URL and every redirect. */\n async fetchVideoGenerationResult(\n handle: VideoGenerationJob,\n ): Promise<VideoGenerationResult> {\n const task =\n this.completedSnapshot(handle.jobId) ??\n (await this.pollTask(handle.jobId));\n const status = this.mapTask(task);\n if (status.status !== 'succeeded' || !status.result?.url)\n throw new AIError(\n `Seevio job ${handle.jobId} has not succeeded (status: ${status.status})`,\n 'VIDEO_JOB_NOT_READY',\n 'seevio',\n handle.model,\n );\n try {\n const downloaded = await this.downloadReviewedResult(status.result.url);\n return { ...status.result, ...downloaded };\n } finally {\n // The handoff cache exists only to make an immediate status → fetch\n // flow cadence-safe. Do not retain expired signed URLs after any fetch\n // attempt; a later fetch will authenticate a fresh task snapshot.\n this.completedSnapshots.delete(handle.jobId);\n }\n }\n\n /** Reports cancellation as unsupported because Seevio documents no cancellation endpoint. */\n async cancelVideoGenerationJob(_handle: VideoGenerationJob): Promise<void> {\n throw new AIError(\n 'Seevio does not document a video-task cancellation endpoint',\n 'NOT_IMPLEMENTED',\n 'seevio',\n );\n }\n\n /** Performs an unbilled random task-id probe; an authenticated 404 is valid access. */\n async validateVideoGenerationAccess(): Promise<boolean> {\n const response = await this.rawRequest(\n `/v1/tasks/have-ai-access-probe-${crypto.randomUUID()}`,\n { allowNotFound: true },\n );\n return response.ok || response.status === 404;\n }\n\n private mapTask(task: SeevioTask): VideoGenerationStatusResult {\n const billing = normalizeBilling(task);\n if (task.status === 'queued')\n return { status: 'queued', ...(billing ? { billing } : {}) };\n if (task.status === 'generating')\n return { status: 'running', ...(billing ? { billing } : {}) };\n if (task.status === 'failed')\n return {\n status: 'failed',\n error: task.failed_reason || 'Seevio video generation failed',\n ...(billing ? { billing } : {}),\n };\n if (task.status !== 'completed')\n return {\n status: 'running',\n rawStatus: task.status,\n ...(billing ? { billing } : {}),\n };\n const url = task.data?.results?.[0];\n if (!url)\n return {\n status: 'failed',\n error: 'Seevio reported completion with no result URL',\n ...(billing ? { billing } : {}),\n };\n const result: VideoGenerationResult = {\n url: this.assertReviewedResultUrl(url),\n mimeType: 'video/mp4',\n ...(task.data?.video_expires_at\n ? { expiresAt: task.data.video_expires_at }\n : {}),\n ...(task.data?.last_frame_url\n ? {\n lastFrameUrl: this.assertReviewedResultUrl(\n task.data.last_frame_url,\n ),\n }\n : {}),\n };\n return { status: 'succeeded', result, ...(billing ? { billing } : {}) };\n }\n\n /** Lists the single intentional Seevio model selection. */\n async getModels(): Promise<AIModel[]> {\n return [\n {\n id: MODEL,\n name: 'Seedance 2.5',\n description: 'Seevio Seedance 2.5 async video generation',\n contextLength: 0,\n capabilities: ['video_generation'],\n supportsFunctions: false,\n supportsVision: true,\n },\n ];\n }\n /** Reports Seevio's video-only capability surface. */\n async getCapabilities(): Promise<AICapabilities> {\n return {\n chat: false,\n completion: false,\n embeddings: false,\n streaming: false,\n functions: false,\n vision: false,\n fineTuning: false,\n imageEmbeddings: false,\n imageGeneration: false,\n videoGeneration: true,\n tts: false,\n voiceCloning: false,\n voiceDesign: false,\n maxContextLength: 0,\n supportedOperations: [\n 'submitVideoGenerationJob',\n 'getVideoGenerationJob',\n 'fetchVideoGenerationResult',\n ],\n };\n }\n\n private unsupported(): never {\n throw new AIError(\n 'This operation is not supported by the Seevio video-only provider.',\n 'NOT_IMPLEMENTED',\n 'seevio',\n );\n }\n /** @inheritdoc */ async chat(\n _messages: AIMessage[],\n _options?: ChatOptions,\n ): Promise<AIResponse> {\n return this.unsupported();\n }\n /** @inheritdoc */ async complete(\n _prompt: string,\n _options?: CompletionOptions,\n ): Promise<AIResponse> {\n return this.unsupported();\n }\n /** @inheritdoc */ async message(\n _text: string,\n _options?: MessageOptions,\n ): Promise<string> {\n return this.unsupported();\n }\n /** @inheritdoc */ async embed(\n _text: string | string[],\n _options?: EmbeddingOptions,\n ): Promise<EmbeddingResponse> {\n return this.unsupported();\n }\n /** @inheritdoc */ async embedImage(\n _image: string | Buffer,\n _options?: ImageEmbeddingOptions,\n ): Promise<EmbeddingResponse> {\n return this.unsupported();\n }\n /** @inheritdoc */ async describeImage(\n _image: string | Buffer,\n _prompt?: string,\n _options?: ImageDescriptionOptions,\n ): Promise<string> {\n return this.unsupported();\n }\n /** @inheritdoc */ async generateImage(\n _prompt: string,\n _options?: ImageGenerationOptions,\n ): Promise<ImageGenerationResponse> {\n return this.unsupported();\n }\n /** @inheritdoc */ stream(\n _messages: AIMessage[],\n _options?: ChatOptions,\n ): AsyncIterable<string> {\n const error = new AIError(\n 'Chat streaming is not supported by the Seevio video-only provider.',\n 'NOT_IMPLEMENTED',\n 'seevio',\n );\n return {\n [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(error) }),\n };\n }\n /** @inheritdoc */ async countTokens(_text: string): Promise<number> {\n return this.unsupported();\n }\n /** @inheritdoc */ async synthesizeSpeech(\n _text: string,\n _options?: TTSOptions,\n ): Promise<TTSResponse> {\n return this.unsupported();\n }\n /** @inheritdoc */ streamSpeech(\n _text: string,\n _options?: TTSOptions,\n ): AsyncIterable<Buffer> {\n const error = new AIError(\n 'TTS streaming is not supported by the Seevio video-only provider.',\n 'NOT_IMPLEMENTED',\n 'seevio',\n );\n return {\n [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(error) }),\n };\n }\n /** @inheritdoc */ async cloneVoice(\n _options: VoiceCloneOptions,\n ): Promise<Voice> {\n return this.unsupported();\n }\n /** @inheritdoc */ async designVoice(\n _options: VoiceDesignOptions,\n ): Promise<Voice> {\n return this.unsupported();\n }\n /** @inheritdoc */ async getVoices(\n _options?: VoiceListOptions,\n ): Promise<Voice[]> {\n return this.unsupported();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"seevio-CosohVa0.js","names":[],"sources":["../../src/shared/providers/seevio.ts"],"sourcesContent":["/**\n * Seevio's native asynchronous Seedance 2.5 video-generation provider.\n *\n * Seevio is deliberately implemented as its own raw-HTTP adapter rather than\n * being shaped to ModelArk. Both services can run Seedance, but their task,\n * billing, and media contracts differ.\n *\n * @see https://seevio.ai/api-docs\n */\n\nimport { ValidationError } from '@happyvertical/utils';\nimport { rateLimitErrorFrom } from '../rate-limit';\nimport { normalizeBaseAIOptions } from '../safety';\nimport type {\n AICapabilities,\n AIInterface,\n AIMessage,\n AIModel,\n AIResponse,\n ChatOptions,\n CompletionOptions,\n EmbeddingOptions,\n EmbeddingResponse,\n ImageDescriptionOptions,\n ImageEmbeddingOptions,\n ImageGenerationOptions,\n ImageGenerationResponse,\n MessageOptions,\n SeevioOptions,\n TTSOptions,\n TTSResponse,\n VideoGenerationBillingMetadata,\n VideoGenerationJob,\n VideoGenerationOptions,\n VideoGenerationReferenceMedia,\n VideoGenerationResult,\n VideoGenerationStatusResult,\n Voice,\n VoiceCloneOptions,\n VoiceDesignOptions,\n VoiceListOptions,\n} from '../types';\nimport { AIError, AuthenticationError } from '../types';\nimport { emitUsage } from './usage';\n\nconst DEFAULT_BASE_URL = 'https://api.seevio.ai';\nconst DEFAULT_RESULT_ORIGIN = 'https://cdn.seevio.ai';\nconst MODEL = 'seedance-2-5';\nconst MIN_POLL_INTERVAL_MS = 10_000;\nconst MAX_REDIRECTS = 5;\nconst DEFAULT_MAX_RESULT_BYTES = 200 * 1024 * 1024;\nconst COMPLETED_SNAPSHOT_TTL_MS = MIN_POLL_INTERVAL_MS;\nconst MAX_COMPLETED_SNAPSHOTS = 128;\n\ninterface SeevioTask {\n id: string;\n status: string;\n model?: string;\n billing_status?: string;\n credits?: number;\n failed_reason?: string | null;\n data?: {\n results?: string[];\n video_expires_at?: string;\n last_frame_url?: string | null;\n processing_time?: number;\n };\n}\n\ninterface SeevioErrorResponse {\n error?: {\n code?: string;\n message?: string;\n required?: number;\n available?: number;\n };\n}\n\ninterface SeevioCreateResponse {\n taskId: string;\n credits?: number;\n}\n\ninterface SeevioInput {\n prompt: string;\n generation_type: 'text-to-video' | 'image-to-video' | 'reference-to-video';\n image_urls?: string[];\n video_urls?: string[];\n audio_urls?: string[];\n duration: number;\n aspect_ratio: 'adaptive' | '16:9' | '9:16' | '1:1' | '4:3' | '3:4' | '21:9';\n resolution: '480p' | '720p';\n generate_audio: boolean;\n return_last_frame: boolean;\n}\n\nfunction ensureOptions(options: SeevioOptions): SeevioOptions {\n const baseUrl = (options.baseUrl || DEFAULT_BASE_URL)\n .trim()\n .replace(/\\/+$/, '');\n const parsedBaseUrl = new URL(baseUrl);\n if (parsedBaseUrl.protocol !== 'https:') {\n throw new ValidationError('seevio baseUrl must use HTTPS', {\n provider: 'seevio',\n });\n }\n const origins = options.resultUrlOrigins?.length\n ? options.resultUrlOrigins\n : [DEFAULT_RESULT_ORIGIN];\n for (const origin of origins) {\n const parsed = new URL(origin);\n if (\n parsed.protocol !== 'https:' ||\n parsed.origin !== origin.replace(/\\/+$/, '')\n ) {\n throw new ValidationError(\n 'seevio resultUrlOrigins must contain HTTPS origins only',\n {\n provider: 'seevio',\n },\n );\n }\n }\n if (\n options.maxResultBytes !== undefined &&\n (!Number.isSafeInteger(options.maxResultBytes) ||\n options.maxResultBytes <= 0)\n ) {\n throw new ValidationError(\n 'seevio maxResultBytes must be a positive safe integer',\n { provider: 'seevio' },\n );\n }\n return {\n ...options,\n baseUrl,\n resultUrlOrigins: origins.map((origin) => origin.replace(/\\/+$/, '')),\n };\n}\n\nfunction validatedHttpsUrl(value: string, label: string): string {\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n throw new ValidationError(`${label} must be a valid public HTTPS URL`, {\n provider: 'seevio',\n });\n }\n if (url.protocol !== 'https:') {\n throw new ValidationError(`${label} must use HTTPS`, {\n provider: 'seevio',\n });\n }\n const host = url.hostname.toLowerCase();\n if (\n url.username ||\n url.password ||\n host === 'localhost' ||\n host.endsWith('.localhost') ||\n host.includes(':') ||\n /^\\d{1,3}(?:\\.\\d{1,3}){3}$/.test(host)\n ) {\n throw new ValidationError(\n `${label} must not use credentials, localhost, or an IP-literal host`,\n { provider: 'seevio' },\n );\n }\n return url.toString();\n}\n\nfunction normalizeBilling(\n task: SeevioTask,\n): VideoGenerationBillingMetadata | undefined {\n if (task.credits === undefined && !task.billing_status) return undefined;\n const normalized = [\n 'reserved',\n 'charged',\n 'refunded',\n 'refund_failed',\n ].includes(task.billing_status || '')\n ? (task.billing_status as VideoGenerationBillingMetadata['status'])\n : undefined;\n return {\n ...(task.credits !== undefined ? { credits: task.credits } : {}),\n ...(normalized ? { status: normalized } : {}),\n ...(!normalized && task.billing_status\n ? { rawStatus: task.billing_status }\n : {}),\n };\n}\n\n/** Native Seevio adapter for the pinned `seedance-2-5` model. */\nexport class SeevioProvider implements AIInterface {\n private readonly options: SeevioOptions;\n private readonly resultOrigins: Set<string>;\n private readonly nextPollAt = new Map<string, number>();\n private readonly completedSnapshots = new Map<\n string,\n { task: SeevioTask; recordedAt: number }\n >();\n\n /** Creates a Seevio task client using the documented HTTPS API root. */\n constructor(options: SeevioOptions) {\n this.options = normalizeBaseAIOptions(ensureOptions(options));\n this.resultOrigins = new Set(this.options.resultUrlOrigins);\n }\n\n private async request<T>(\n path: string,\n options: {\n method?: 'GET' | 'POST';\n body?: unknown;\n signal?: AbortSignal;\n timeout?: number;\n allowNotFound?: boolean;\n } = {},\n ): Promise<T> {\n const response = await this.rawRequest(path, options);\n const text = await response.text();\n return text ? (JSON.parse(text) as T) : ({} as T);\n }\n\n private async rawRequest(\n path: string,\n options: {\n method?: 'GET' | 'POST';\n body?: unknown;\n signal?: AbortSignal;\n timeout?: number;\n allowNotFound?: boolean;\n } = {},\n ): Promise<Response> {\n if (options.signal?.aborted)\n throw new AIError(\n 'Seevio request aborted by caller',\n 'AI_ABORTED',\n 'seevio',\n );\n const controller = new AbortController();\n const timeoutMs = options.timeout ?? this.options.timeout;\n let timedOut = false;\n const timer = setTimeout(() => {\n timedOut = true;\n controller.abort();\n }, timeoutMs);\n const abort = () => controller.abort(options.signal?.reason);\n options.signal?.addEventListener('abort', abort, { once: true });\n // An abort may occur between the preflight check and listener\n // registration. Re-check after registration so that race still reaches\n // the fetch signal rather than allowing a paid request to continue.\n if (options.signal?.aborted) abort();\n try {\n let response: Response;\n try {\n response = await fetch(`${this.options.baseUrl}${path}`, {\n method: options.method || 'GET',\n headers: {\n Authorization: `Bearer ${this.options.apiKey ?? ''}`,\n ...(options.body !== undefined\n ? { 'Content-Type': 'application/json' }\n : {}),\n ...(this.options.headers || {}),\n },\n body:\n options.body === undefined\n ? undefined\n : JSON.stringify(options.body),\n signal: controller.signal,\n });\n } catch (error) {\n if (timedOut)\n throw new AIError(\n `Seevio request to ${path} timed out after ${timeoutMs}ms`,\n 'AI_TIMEOUT',\n 'seevio',\n undefined,\n options.method !== 'POST',\n );\n if (options.signal?.aborted)\n throw new AIError(\n 'Seevio request aborted by caller',\n 'AI_ABORTED',\n 'seevio',\n );\n throw new AIError(\n `Network error calling Seevio ${path}: ${error instanceof Error ? error.message : String(error)}`,\n 'NETWORK_ERROR',\n 'seevio',\n undefined,\n options.method !== 'POST',\n );\n }\n if (response.status === 404 && options.allowNotFound) return response;\n if (response.ok) return response;\n const errorText = await response.text();\n let payload: SeevioErrorResponse = {};\n try {\n payload = JSON.parse(errorText) as SeevioErrorResponse;\n } catch {\n /* preserve status fallback below */\n }\n const message =\n payload.error?.message ||\n `Seevio request to ${path} failed with HTTP ${response.status}`;\n if (response.status === 401) throw new AuthenticationError('seevio');\n if (response.status === 403)\n throw new AIError(message, 'SEEVIO_FORBIDDEN', 'seevio');\n if (response.status === 402)\n throw new AIError(message, 'INSUFFICIENT_CREDITS', 'seevio');\n if (response.status === 429)\n throw rateLimitErrorFrom(\n 'seevio',\n { headers: response.headers },\n { reason: payload.error?.message },\n );\n throw new AIError(\n message,\n 'SEEVIO_REQUEST_FAILED',\n 'seevio',\n undefined,\n response.status >= 500 && options.method !== 'POST',\n );\n } finally {\n clearTimeout(timer);\n options.signal?.removeEventListener('abort', abort);\n }\n }\n\n private assertReviewedResultUrl(value: string): string {\n const url = validatedHttpsUrl(value, 'Seevio result URL');\n if (!this.resultOrigins.has(new URL(url).origin)) {\n throw new AIError(\n 'Seevio returned a result URL outside configured reviewed origins',\n 'UNTRUSTED_RESULT_URL',\n 'seevio',\n );\n }\n return url;\n }\n\n private async downloadReviewedResult(\n initialUrl: string,\n ): Promise<{ data: Buffer; mimeType: string; url: string }> {\n let current = this.assertReviewedResultUrl(initialUrl);\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.options.timeout);\n const maxBytes = this.options.maxResultBytes ?? DEFAULT_MAX_RESULT_BYTES;\n try {\n for (let redirects = 0; redirects <= MAX_REDIRECTS; redirects += 1) {\n const response = await fetch(current, {\n redirect: 'manual',\n signal: controller.signal,\n });\n if (response.status >= 300 && response.status < 400) {\n const location = response.headers.get('location');\n if (!location)\n throw new AIError(\n 'Seevio result redirect omitted Location',\n 'SEEVIO_RESULT_DOWNLOAD_FAILED',\n 'seevio',\n );\n current = this.assertReviewedResultUrl(\n new URL(location, current).toString(),\n );\n continue;\n }\n if (!response.ok)\n throw new AIError(\n `Seevio result download failed with HTTP ${response.status}`,\n 'SEEVIO_RESULT_DOWNLOAD_FAILED',\n 'seevio',\n );\n const contentType = response.headers.get('content-type');\n if (!contentType?.toLowerCase().startsWith('video/'))\n throw new AIError(\n `Seevio result download returned non-video content type ${contentType}`,\n 'SEEVIO_RESULT_MIME_INVALID',\n 'seevio',\n );\n const contentLength = response.headers.get('content-length');\n if (contentLength && Number(contentLength) > maxBytes)\n throw new AIError(\n `Seevio result exceeds configured ${maxBytes}-byte download limit`,\n 'SEEVIO_RESULT_TOO_LARGE',\n 'seevio',\n );\n if (!response.body)\n throw new AIError(\n 'Seevio result download had no response body',\n 'SEEVIO_RESULT_DOWNLOAD_FAILED',\n 'seevio',\n );\n const chunks: Uint8Array[] = [];\n let size = 0;\n const reader = response.body.getReader();\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n size += value.byteLength;\n if (size > maxBytes) {\n await reader.cancel();\n throw new AIError(\n `Seevio result exceeds configured ${maxBytes}-byte download limit`,\n 'SEEVIO_RESULT_TOO_LARGE',\n 'seevio',\n );\n }\n chunks.push(value);\n }\n return {\n data: Buffer.concat(chunks.map((chunk) => Buffer.from(chunk))),\n mimeType: contentType,\n url: current,\n };\n }\n throw new AIError(\n 'Seevio result exceeded the maximum redirect count',\n 'SEEVIO_RESULT_DOWNLOAD_FAILED',\n 'seevio',\n );\n } catch (error) {\n if (controller.signal.aborted)\n throw new AIError(\n `Seevio result download timed out after ${this.options.timeout}ms`,\n 'AI_TIMEOUT',\n 'seevio',\n undefined,\n true,\n );\n throw error;\n } finally {\n clearTimeout(timer);\n }\n }\n\n private mediaUrls(options: VideoGenerationOptions): {\n images: string[];\n videos: string[];\n audio: string[];\n } {\n const images = (options.referenceImages ?? []).map((reference) => {\n if (\n typeof reference.image !== 'string' ||\n reference.image.startsWith('data:')\n ) {\n throw new ValidationError(\n 'Seevio referenceImages must be public HTTPS URLs; it cannot retrieve bytes or data URLs',\n { provider: 'seevio' },\n );\n }\n return validatedHttpsUrl(reference.image, 'Seevio reference image');\n });\n const references = options.referenceMedia ?? [];\n if (references.length + images.length > 50)\n throw new ValidationError(\n 'Seevio accepts at most 50 total reference assets',\n { provider: 'seevio' },\n );\n const collect = (type: VideoGenerationReferenceMedia['type']) =>\n references\n .filter((reference) => reference.type === type)\n .map((reference) =>\n validatedHttpsUrl(reference.url, `Seevio ${type} reference`),\n );\n const mediaImages = collect('image');\n const videos = collect('video');\n const audio = collect('audio');\n if (\n images.length + mediaImages.length > 30 ||\n videos.length > 10 ||\n audio.length > 10\n ) {\n throw new ValidationError(\n 'Seevio reference limits are 30 images, 10 videos, and 10 audio files',\n { provider: 'seevio' },\n );\n }\n for (const reference of references) {\n if (\n (reference.type === 'video' || reference.type === 'audio') &&\n reference.durationSeconds !== undefined &&\n (!Number.isFinite(reference.durationSeconds) ||\n reference.durationSeconds < 2 ||\n reference.durationSeconds > 30)\n ) {\n throw new ValidationError(\n 'Seevio video/audio reference durations must be 2-30 seconds when supplied',\n { provider: 'seevio' },\n );\n }\n }\n for (const [label, type] of [\n ['video', 'video'],\n ['audio', 'audio'],\n ] as const) {\n const durations = references\n .filter((reference) => reference.type === type)\n .flatMap((reference) =>\n reference.durationSeconds === undefined\n ? []\n : [reference.durationSeconds],\n );\n if (durations.reduce((total, duration) => total + duration, 0) > 30) {\n throw new ValidationError(\n `Seevio ${label} reference durations must total no more than 30 seconds`,\n { provider: 'seevio' },\n );\n }\n }\n return { images: [...images, ...mediaImages], videos, audio };\n }\n\n private async pollTask(jobId: string): Promise<SeevioTask> {\n const now = Date.now();\n for (const [knownJobId, expiry] of this.nextPollAt) {\n if (expiry <= now) this.nextPollAt.delete(knownJobId);\n }\n const next = this.nextPollAt.get(jobId);\n if (next && now < next)\n throw new AIError(\n `Seevio tasks may be polled no more than once every 10 seconds; retry after ${Math.ceil((next - now) / 1000)} seconds`,\n 'VIDEO_POLL_TOO_FREQUENT',\n 'seevio',\n );\n const expiry = now + MIN_POLL_INTERVAL_MS;\n this.nextPollAt.set(jobId, expiry);\n const cleanup = setTimeout(() => {\n if (this.nextPollAt.get(jobId) === expiry) this.nextPollAt.delete(jobId);\n }, MIN_POLL_INTERVAL_MS);\n // Let idle Node workers exit rather than keeping the process alive for a\n // cadence cleanup timer. Browser timer handles do not expose `unref`.\n if (typeof cleanup === 'object' && 'unref' in cleanup) cleanup.unref();\n const task = await this.request<SeevioTask>(\n `/v1/tasks/${encodeURIComponent(jobId)}`,\n );\n if (task.status === 'completed') {\n // This is a bounded, short-lived handoff cache, not task history. A\n // completed task can be fetched without another status request only\n // within the provider's ten-second cadence window.\n if (!this.completedSnapshots.has(jobId)) {\n const oldestJobId = this.completedSnapshots.keys().next().value;\n if (\n this.completedSnapshots.size >= MAX_COMPLETED_SNAPSHOTS &&\n oldestJobId !== undefined\n ) {\n this.completedSnapshots.delete(oldestJobId);\n }\n }\n this.completedSnapshots.set(jobId, { task, recordedAt: Date.now() });\n }\n return task;\n }\n\n private completedSnapshot(jobId: string): SeevioTask | undefined {\n const snapshot = this.completedSnapshots.get(jobId);\n if (!snapshot) return undefined;\n if (Date.now() - snapshot.recordedAt >= COMPLETED_SNAPSHOT_TTL_MS) {\n this.completedSnapshots.delete(jobId);\n return undefined;\n }\n return snapshot.task;\n }\n\n /** Submits one unambiguous, non-retried Seedance 2.5 task. */\n async submitVideoGenerationJob(\n options: VideoGenerationOptions,\n ): Promise<VideoGenerationJob> {\n const startTime = Date.now();\n const model = options.model || this.options.defaultModel || MODEL;\n if (model !== MODEL)\n throw new ValidationError(\n `Seevio provider supports the pinned model ${MODEL}`,\n { provider: 'seevio' },\n );\n if (!options.prompt?.trim())\n throw new ValidationError('Seevio requires a non-empty prompt', {\n provider: 'seevio',\n });\n if (options.seed !== undefined)\n throw new ValidationError(\n 'seed is not supported by Seevio Seedance 2.5',\n { provider: 'seevio' },\n );\n const duration = options.durationSeconds ?? 5;\n if (!Number.isInteger(duration) || duration < 4 || duration > 30)\n throw new ValidationError(\n 'Seevio durationSeconds must be an integer from 4 through 30',\n { provider: 'seevio' },\n );\n const resolution = options.resolution ?? '720p';\n if (resolution !== '480p' && resolution !== '720p')\n throw new ValidationError('Seevio resolution must be 480p or 720p', {\n provider: 'seevio',\n });\n const { images, videos, audio } = this.mediaUrls(options);\n const isImageToVideo =\n images.length >= 1 &&\n images.length <= 2 &&\n videos.length === 0 &&\n audio.length === 0;\n const generationType = isImageToVideo\n ? 'image-to-video'\n : images.length || videos.length || audio.length\n ? 'reference-to-video'\n : 'text-to-video';\n const aspectRatio = options.aspectRatio ?? 'adaptive';\n const supportedRatios: SeevioInput['aspect_ratio'][] = [\n 'adaptive',\n '16:9',\n '9:16',\n '1:1',\n '4:3',\n '3:4',\n '21:9',\n ];\n if (!supportedRatios.includes(aspectRatio as SeevioInput['aspect_ratio']))\n throw new ValidationError('Unsupported Seevio aspectRatio', {\n provider: 'seevio',\n });\n if (isImageToVideo && aspectRatio !== 'adaptive')\n throw new ValidationError(\n 'Seevio image-to-video requires aspectRatio: adaptive',\n { provider: 'seevio' },\n );\n const input: SeevioInput = {\n prompt: options.prompt.trim(),\n generation_type: generationType,\n duration,\n aspect_ratio: aspectRatio as SeevioInput['aspect_ratio'],\n resolution: resolution as '480p' | '720p',\n generate_audio: options.generateAudio ?? true,\n return_last_frame: options.returnLastFrame ?? false,\n ...(images.length ? { image_urls: images } : {}),\n ...(videos.length ? { video_urls: videos } : {}),\n ...(audio.length ? { audio_urls: audio } : {}),\n };\n const created = await this.request<SeevioCreateResponse>(\n '/v1/videos/generations',\n {\n method: 'POST',\n body: { model: MODEL, input },\n signal: options.signal,\n timeout: options.timeout,\n },\n );\n if (!created.taskId)\n throw new AIError(\n 'Seevio accepted submission without a taskId',\n 'SEEVIO_INVALID_RESPONSE',\n 'seevio',\n );\n emitUsage(\n this.options,\n 'seevio',\n 'submitVideoGenerationJob',\n MODEL,\n undefined,\n startTime,\n {\n durationSeconds: String(duration),\n resolution,\n aspectRatio,\n ...options.usageTags,\n },\n );\n return {\n jobId: created.taskId,\n provider: 'seevio',\n model: MODEL,\n createdAt: new Date().toISOString(),\n raw:\n created.credits === undefined\n ? undefined\n : { credits: created.credits, billingStatus: 'reserved' },\n };\n }\n\n /** Returns a normalized task snapshot, enforcing Seevio's 10-second poll cadence. */\n async getVideoGenerationJob(\n handle: VideoGenerationJob,\n ): Promise<VideoGenerationStatusResult> {\n return this.mapTask(await this.pollTask(handle.jobId));\n }\n\n /** Downloads a completed video while validating the initial URL and every redirect. */\n async fetchVideoGenerationResult(\n handle: VideoGenerationJob,\n ): Promise<VideoGenerationResult> {\n const task =\n this.completedSnapshot(handle.jobId) ??\n (await this.pollTask(handle.jobId));\n const status = this.mapTask(task);\n if (status.status !== 'succeeded' || !status.result?.url)\n throw new AIError(\n `Seevio job ${handle.jobId} has not succeeded (status: ${status.status})`,\n 'VIDEO_JOB_NOT_READY',\n 'seevio',\n handle.model,\n );\n try {\n const downloaded = await this.downloadReviewedResult(status.result.url);\n return { ...status.result, ...downloaded };\n } finally {\n // The handoff cache exists only to make an immediate status → fetch\n // flow cadence-safe. Do not retain expired signed URLs after any fetch\n // attempt; a later fetch will authenticate a fresh task snapshot.\n this.completedSnapshots.delete(handle.jobId);\n }\n }\n\n /** Reports cancellation as unsupported because Seevio documents no cancellation endpoint. */\n async cancelVideoGenerationJob(_handle: VideoGenerationJob): Promise<void> {\n throw new AIError(\n 'Seevio does not document a video-task cancellation endpoint',\n 'NOT_IMPLEMENTED',\n 'seevio',\n );\n }\n\n /** Performs an unbilled random task-id probe; an authenticated 404 is valid access. */\n async validateVideoGenerationAccess(): Promise<boolean> {\n const response = await this.rawRequest(\n `/v1/tasks/have-ai-access-probe-${crypto.randomUUID()}`,\n { allowNotFound: true },\n );\n return response.ok || response.status === 404;\n }\n\n private mapTask(task: SeevioTask): VideoGenerationStatusResult {\n const billing = normalizeBilling(task);\n if (task.status === 'queued')\n return { status: 'queued', ...(billing ? { billing } : {}) };\n if (task.status === 'generating')\n return { status: 'running', ...(billing ? { billing } : {}) };\n if (task.status === 'failed')\n return {\n status: 'failed',\n error: task.failed_reason || 'Seevio video generation failed',\n ...(billing ? { billing } : {}),\n };\n if (task.status !== 'completed')\n return {\n status: 'running',\n rawStatus: task.status,\n ...(billing ? { billing } : {}),\n };\n const url = task.data?.results?.[0];\n if (!url)\n return {\n status: 'failed',\n error: 'Seevio reported completion with no result URL',\n ...(billing ? { billing } : {}),\n };\n const result: VideoGenerationResult = {\n url: this.assertReviewedResultUrl(url),\n mimeType: 'video/mp4',\n ...(task.data?.video_expires_at\n ? { expiresAt: task.data.video_expires_at }\n : {}),\n ...(task.data?.last_frame_url\n ? {\n lastFrameUrl: this.assertReviewedResultUrl(\n task.data.last_frame_url,\n ),\n }\n : {}),\n };\n return { status: 'succeeded', result, ...(billing ? { billing } : {}) };\n }\n\n /** Lists the single intentional Seevio model selection. */\n async getModels(): Promise<AIModel[]> {\n return [\n {\n id: MODEL,\n name: 'Seedance 2.5',\n description: 'Seevio Seedance 2.5 async video generation',\n contextLength: 0,\n capabilities: ['video_generation'],\n supportsFunctions: false,\n supportsVision: true,\n },\n ];\n }\n /** Reports Seevio's video-only capability surface. */\n async getCapabilities(): Promise<AICapabilities> {\n return {\n chat: false,\n completion: false,\n embeddings: false,\n streaming: false,\n functions: false,\n vision: false,\n fineTuning: false,\n imageEmbeddings: false,\n imageGeneration: false,\n videoGeneration: true,\n tts: false,\n voiceCloning: false,\n voiceDesign: false,\n maxContextLength: 0,\n supportedOperations: [\n 'submitVideoGenerationJob',\n 'getVideoGenerationJob',\n 'fetchVideoGenerationResult',\n ],\n };\n }\n\n private unsupported(): never {\n throw new AIError(\n 'This operation is not supported by the Seevio video-only provider.',\n 'NOT_IMPLEMENTED',\n 'seevio',\n );\n }\n /** @inheritdoc */ async chat(\n _messages: AIMessage[],\n _options?: ChatOptions,\n ): Promise<AIResponse> {\n return this.unsupported();\n }\n /** @inheritdoc */ async complete(\n _prompt: string,\n _options?: CompletionOptions,\n ): Promise<AIResponse> {\n return this.unsupported();\n }\n /** @inheritdoc */ async message(\n _text: string,\n _options?: MessageOptions,\n ): Promise<string> {\n return this.unsupported();\n }\n /** @inheritdoc */ async embed(\n _text: string | string[],\n _options?: EmbeddingOptions,\n ): Promise<EmbeddingResponse> {\n return this.unsupported();\n }\n /** @inheritdoc */ async embedImage(\n _image: string | Buffer,\n _options?: ImageEmbeddingOptions,\n ): Promise<EmbeddingResponse> {\n return this.unsupported();\n }\n /** @inheritdoc */ async describeImage(\n _image: string | Buffer,\n _prompt?: string,\n _options?: ImageDescriptionOptions,\n ): Promise<string> {\n return this.unsupported();\n }\n /** @inheritdoc */ async generateImage(\n _prompt: string,\n _options?: ImageGenerationOptions,\n ): Promise<ImageGenerationResponse> {\n return this.unsupported();\n }\n /** @inheritdoc */ stream(\n _messages: AIMessage[],\n _options?: ChatOptions,\n ): AsyncIterable<string> {\n const error = new AIError(\n 'Chat streaming is not supported by the Seevio video-only provider.',\n 'NOT_IMPLEMENTED',\n 'seevio',\n );\n return {\n [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(error) }),\n };\n }\n /** @inheritdoc */ async countTokens(_text: string): Promise<number> {\n return this.unsupported();\n }\n /** @inheritdoc */ async synthesizeSpeech(\n _text: string,\n _options?: TTSOptions,\n ): Promise<TTSResponse> {\n return this.unsupported();\n }\n /** @inheritdoc */ streamSpeech(\n _text: string,\n _options?: TTSOptions,\n ): AsyncIterable<Buffer> {\n const error = new AIError(\n 'TTS streaming is not supported by the Seevio video-only provider.',\n 'NOT_IMPLEMENTED',\n 'seevio',\n );\n return {\n [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(error) }),\n };\n }\n /** @inheritdoc */ async cloneVoice(\n _options: VoiceCloneOptions,\n ): Promise<Voice> {\n return this.unsupported();\n }\n /** @inheritdoc */ async designVoice(\n _options: VoiceDesignOptions,\n ): Promise<Voice> {\n return this.unsupported();\n }\n /** @inheritdoc */ async getVoices(\n _options?: VoiceListOptions,\n ): Promise<Voice[]> {\n return this.unsupported();\n }\n}\n"],"mappings":"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"}