@umituz/web-ai 1.0.11 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +29 -3
  2. package/dist/{cancellation-error-_39nYWwz.d.cts → cancellation-error-BWb59Wkj.d.cts} +1 -1
  3. package/dist/{cancellation-error-hYcE9AS9.d.ts → cancellation-error-D9LETLCD.d.ts} +1 -1
  4. package/dist/chat/index.cjs +1 -0
  5. package/dist/chat/index.cjs.map +1 -1
  6. package/dist/chat/index.js +1 -0
  7. package/dist/chat/index.js.map +1 -1
  8. package/dist/content/index.cjs +622 -8
  9. package/dist/content/index.cjs.map +1 -1
  10. package/dist/content/index.d.cts +2 -2
  11. package/dist/content/index.d.ts +2 -2
  12. package/dist/content/index.js +622 -8
  13. package/dist/content/index.js.map +1 -1
  14. package/dist/context-manager-CuZz0vnC.d.cts +104 -0
  15. package/dist/context-manager-CuZz0vnC.d.ts +104 -0
  16. package/dist/core/index.cjs +147 -10
  17. package/dist/core/index.cjs.map +1 -1
  18. package/dist/core/index.d.cts +91 -73
  19. package/dist/core/index.d.ts +91 -73
  20. package/dist/core/index.js +141 -11
  21. package/dist/core/index.js.map +1 -1
  22. package/dist/{create-ai-D-oEWzf9.d.ts → create-ai-Cq3HkJxd.d.ts} +61 -1
  23. package/dist/{create-ai-DRysRImc.d.cts → create-ai-DDyTVzef.d.cts} +61 -1
  24. package/dist/hooks/index.cjs +747 -15
  25. package/dist/hooks/index.cjs.map +1 -1
  26. package/dist/hooks/index.d.cts +57 -4
  27. package/dist/hooks/index.d.ts +57 -4
  28. package/dist/hooks/index.js +746 -16
  29. package/dist/hooks/index.js.map +1 -1
  30. package/dist/index.cjs +1180 -242
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +7 -6
  33. package/dist/index.d.ts +7 -6
  34. package/dist/index.js +1140 -243
  35. package/dist/index.js.map +1 -1
  36. package/dist/providers/index.cjs +1212 -362
  37. package/dist/providers/index.cjs.map +1 -1
  38. package/dist/providers/index.d.cts +422 -10
  39. package/dist/providers/index.d.ts +422 -10
  40. package/dist/providers/index.js +1179 -363
  41. package/dist/providers/index.js.map +1 -1
  42. package/dist/remote-chat-client-LrNlew4n.d.cts +70 -0
  43. package/dist/remote-chat-client-LrNlew4n.d.ts +70 -0
  44. package/dist/{requestQueue-D89wx91Q.d.cts → requestQueue--h2uZ-Q3.d.cts} +1 -1
  45. package/dist/{requestQueue-AP6n_bRH.d.ts → requestQueue-BGeCy4Fd.d.ts} +1 -1
  46. package/package.json +1 -1
  47. package/dist/tool-call-accumulator-C7KhaXZA.d.cts +0 -69
  48. package/dist/tool-call-accumulator-C7KhaXZA.d.ts +0 -69
package/dist/index.cjs CHANGED
@@ -305,6 +305,23 @@ function errorFromUnknown(err) {
305
305
  return new AiError("upstream_error");
306
306
  }
307
307
 
308
+ // src/core/errors/error-status.ts
309
+ var AI_ERROR_STATUS = {
310
+ invalid_key: 502,
311
+ missing_key: 503,
312
+ rate_limited: 429,
313
+ capacity: 503,
314
+ timeout: 504,
315
+ invalid_request: 400,
316
+ model_unavailable: 503,
317
+ upstream_error: 502,
318
+ network: 502,
319
+ cancelled: 400
320
+ };
321
+ function aiErrorStatus(code) {
322
+ return AI_ERROR_STATUS[code];
323
+ }
324
+
308
325
  // src/core/executor/retry-executor.strategy.ts
309
326
  var RetryExecutor = class {
310
327
  constructor(retryManager2, options) {
@@ -1428,13 +1445,14 @@ function buildContext(history, systemPrompt, budget) {
1428
1445
  const selected = [];
1429
1446
  for (let i = history.length - 1; i >= 0; i -= 1) {
1430
1447
  const message = history[i];
1448
+ if (!message) continue;
1431
1449
  const cost = estimateMessageTokens(message);
1432
1450
  if (used + cost > available && selected.length > 0) break;
1433
1451
  used += cost;
1434
1452
  selected.push(message);
1435
1453
  }
1436
1454
  selected.reverse();
1437
- while (selected.length > 1 && (selected[0].role === "assistant" || selected[0].role === "tool")) {
1455
+ while (selected.length > 1 && (selected[0]?.role === "assistant" || selected[0]?.role === "tool")) {
1438
1456
  selected.shift();
1439
1457
  }
1440
1458
  return [{ role: "system", content: systemPrompt }, ...selected];
@@ -1637,7 +1655,10 @@ function diffLines(before, after) {
1637
1655
  const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
1638
1656
  for (let i2 = m - 1; i2 >= 0; i2 -= 1) {
1639
1657
  for (let j2 = n - 1; j2 >= 0; j2 -= 1) {
1640
- dp[i2][j2] = a[i2] === b[j2] ? dp[i2 + 1][j2 + 1] + 1 : Math.max(dp[i2 + 1][j2], dp[i2][j2 + 1]);
1658
+ const row = dp[i2];
1659
+ if (row) {
1660
+ row[j2] = a[i2] === b[j2] ? (dp[i2 + 1]?.[j2 + 1] ?? 0) + 1 : Math.max(dp[i2 + 1]?.[j2] ?? 0, row[j2 + 1] ?? 0);
1661
+ }
1641
1662
  }
1642
1663
  }
1643
1664
  const out = [];
@@ -1645,23 +1666,23 @@ function diffLines(before, after) {
1645
1666
  let j = 0;
1646
1667
  while (i < m && j < n) {
1647
1668
  if (a[i] === b[j]) {
1648
- out.push({ type: "same", text: a[i] });
1669
+ out.push({ type: "same", text: a[i] ?? "" });
1649
1670
  i += 1;
1650
1671
  j += 1;
1651
- } else if (dp[i + 1][j] >= dp[i][j + 1]) {
1652
- out.push({ type: "remove", text: a[i] });
1672
+ } else if ((dp[i + 1]?.[j] ?? 0) >= (dp[i]?.[j + 1] ?? 0)) {
1673
+ out.push({ type: "remove", text: a[i] ?? "" });
1653
1674
  i += 1;
1654
1675
  } else {
1655
- out.push({ type: "add", text: b[j] });
1676
+ out.push({ type: "add", text: b[j] ?? "" });
1656
1677
  j += 1;
1657
1678
  }
1658
1679
  }
1659
1680
  while (i < m) {
1660
- out.push({ type: "remove", text: a[i] });
1681
+ out.push({ type: "remove", text: a[i] ?? "" });
1661
1682
  i += 1;
1662
1683
  }
1663
1684
  while (j < n) {
1664
- out.push({ type: "add", text: b[j] });
1685
+ out.push({ type: "add", text: b[j] ?? "" });
1665
1686
  j += 1;
1666
1687
  }
1667
1688
  return out;
@@ -1776,14 +1797,14 @@ function dotProduct(a, b) {
1776
1797
  const length = Math.min(a.length, b.length);
1777
1798
  let sum = 0;
1778
1799
  for (let i = 0; i < length; i += 1) {
1779
- sum += a[i] * b[i];
1800
+ sum += (a[i] ?? 0) * (b[i] ?? 0);
1780
1801
  }
1781
1802
  return sum;
1782
1803
  }
1783
1804
  function magnitude(v) {
1784
1805
  let sum = 0;
1785
1806
  for (let i = 0; i < v.length; i += 1) {
1786
- sum += v[i] * v[i];
1807
+ sum += (v[i] ?? 0) * (v[i] ?? 0);
1787
1808
  }
1788
1809
  return Math.sqrt(sum);
1789
1810
  }
@@ -1928,6 +1949,115 @@ function validateToolArgs(toolKey, args, schemas) {
1928
1949
  return { ok: false, error: `Invalid schema definition for tool: ${toolKey}` };
1929
1950
  }
1930
1951
 
1952
+ // src/core/analytics/usage-series.ts
1953
+ function num(value) {
1954
+ const parsed = typeof value === "number" ? value : Number(value ?? 0);
1955
+ return Number.isFinite(parsed) ? parsed : 0;
1956
+ }
1957
+ function utcDateKey(base, offsetDays) {
1958
+ const shifted = new Date(base.getTime() - offsetDays * 864e5);
1959
+ return shifted.toISOString().slice(0, 10);
1960
+ }
1961
+ function buildUsageDailySeries(days, usageRows, messageRows, today = /* @__PURE__ */ new Date()) {
1962
+ const usageByDate = new Map(usageRows.map((row) => [row.date, row]));
1963
+ const messageByDate = new Map(messageRows.map((row) => [row.date, row]));
1964
+ const series = [];
1965
+ for (let offset = days - 1; offset >= 0; offset -= 1) {
1966
+ const date = utcDateKey(today, offset);
1967
+ const usage = usageByDate.get(date);
1968
+ const message = messageByDate.get(date);
1969
+ series.push({
1970
+ date,
1971
+ requests: num(usage?.requests),
1972
+ attempts: num(message?.attempts),
1973
+ errors: num(message?.errors),
1974
+ inputTokens: num(usage?.inputTokens),
1975
+ outputTokens: num(usage?.outputTokens),
1976
+ reasoningTokens: num(usage?.reasoningTokens),
1977
+ costMicros: num(usage?.costMicros)
1978
+ });
1979
+ }
1980
+ return series;
1981
+ }
1982
+ function usageWindowTotals(series, from, to) {
1983
+ const slice = series.slice(from, to);
1984
+ return slice.reduce(
1985
+ (acc, day) => ({
1986
+ requests: acc.requests + day.requests,
1987
+ attempts: acc.attempts + day.attempts,
1988
+ errors: acc.errors + day.errors,
1989
+ inputTokens: acc.inputTokens + day.inputTokens,
1990
+ outputTokens: acc.outputTokens + day.outputTokens,
1991
+ costMicros: acc.costMicros + day.costMicros
1992
+ }),
1993
+ { requests: 0, attempts: 0, errors: 0, inputTokens: 0, outputTokens: 0, costMicros: 0 }
1994
+ );
1995
+ }
1996
+ function usageTrendOf(current, previous) {
1997
+ return {
1998
+ current,
1999
+ previous,
2000
+ deltaPct: previous > 0 ? (current - previous) / previous * 100 : null
2001
+ };
2002
+ }
2003
+ function errorRatePct(errors, attempts) {
2004
+ if (attempts <= 0) return 0;
2005
+ return errors / attempts * 100;
2006
+ }
2007
+
2008
+ // src/core/remote/remote-chat-client.ts
2009
+ async function surfaceHttpError(response, callbacks) {
2010
+ const payload = await response.json().catch(() => null);
2011
+ callbacks.onError?.(payload?.code ?? "request_failed", payload?.error ?? "Request failed");
2012
+ }
2013
+ function createRemoteChatClient(options) {
2014
+ const doFetch = options.fetchImpl ?? fetch;
2015
+ const { urls } = options;
2016
+ return {
2017
+ streamChat(conversationId, body, callbacks) {
2018
+ const controller = new AbortController();
2019
+ const promise = (async () => {
2020
+ const response = await doFetch(urls.stream(conversationId), {
2021
+ method: "POST",
2022
+ headers: { "content-type": "application/json" },
2023
+ body: JSON.stringify(body),
2024
+ signal: controller.signal
2025
+ });
2026
+ if (!response.ok) {
2027
+ await surfaceHttpError(response, callbacks);
2028
+ return;
2029
+ }
2030
+ if (!response.body) {
2031
+ callbacks.onError?.("request_failed", "The server returned an empty stream.");
2032
+ return;
2033
+ }
2034
+ await readSseResponse(response, callbacks);
2035
+ })();
2036
+ return {
2037
+ promise,
2038
+ abort: () => controller.abort()
2039
+ };
2040
+ },
2041
+ async resolveToolCall(conversationId, toolCallId, approved, callbacks) {
2042
+ const response = await doFetch(urls.resolveToolCall(conversationId, toolCallId), {
2043
+ method: "POST",
2044
+ headers: { "content-type": "application/json" },
2045
+ body: JSON.stringify({ approved })
2046
+ });
2047
+ if (!response.ok) {
2048
+ await surfaceHttpError(response, callbacks);
2049
+ return false;
2050
+ }
2051
+ const contentType = response.headers.get("content-type") ?? "";
2052
+ if (!contentType.includes("text/event-stream") || !response.body) {
2053
+ return false;
2054
+ }
2055
+ await readSseResponse(response, callbacks);
2056
+ return true;
2057
+ }
2058
+ };
2059
+ }
2060
+
1931
2061
  // src/providers/base/provider.types.ts
1932
2062
  function isTextProvider(provider) {
1933
2063
  return provider.capabilities.includes("text");
@@ -2658,7 +2788,7 @@ var AnthropicProvider = class {
2658
2788
  );
2659
2789
  }
2660
2790
  const structuredPrompt = new StructuredPromptBuilder(
2661
- messages[lastUserIndex].content
2791
+ messages[lastUserIndex]?.content ?? ""
2662
2792
  ).withSchema(request.schema).build();
2663
2793
  messages[lastUserIndex] = { role: "user", content: structuredPrompt };
2664
2794
  const wireRequest = new AnthropicRequestBuilder(model).withRequest({ ...request, messages }).withEffort(this.config.effort).build();
@@ -2738,7 +2868,8 @@ function mapAnthropicUsage(usage) {
2738
2868
  }
2739
2869
  function findLastIndex(items, predicate) {
2740
2870
  for (let i = items.length - 1; i >= 0; i--) {
2741
- if (predicate(items[i])) return i;
2871
+ const item = items[i];
2872
+ if (item !== void 0 && predicate(item)) return i;
2742
2873
  }
2743
2874
  return -1;
2744
2875
  }
@@ -3238,7 +3369,7 @@ var GroqProvider = class {
3238
3369
  );
3239
3370
  }
3240
3371
  const structuredPrompt = new StructuredPromptBuilder(
3241
- messages[lastUserIndex].content
3372
+ messages[lastUserIndex]?.content ?? ""
3242
3373
  ).withSchema(request.schema).build();
3243
3374
  messages[lastUserIndex] = { role: "user", content: structuredPrompt };
3244
3375
  const wireRequest = GroqChatRequestBuilder.for(model).withMessages(messages).withConfig(this.generationConfig(request, STRUCTURED_TEMPERATURE)).withJsonResponse(true).build();
@@ -3335,7 +3466,8 @@ function createGroqProvider(config) {
3335
3466
  }
3336
3467
  function findLastIndex2(items, predicate) {
3337
3468
  for (let i = items.length - 1; i >= 0; i--) {
3338
- if (predicate(items[i])) return i;
3469
+ const item = items[i];
3470
+ if (item !== void 0 && predicate(item)) return i;
3339
3471
  }
3340
3472
  return -1;
3341
3473
  }
@@ -3485,7 +3617,7 @@ var GeminiProvider = class extends BaseProvider {
3485
3617
  }
3486
3618
  messages[lastUserIndex] = {
3487
3619
  role: "user",
3488
- content: new StructuredPromptBuilder(messages[lastUserIndex].content).withSchema(request.schema).build()
3620
+ content: new StructuredPromptBuilder(messages[lastUserIndex]?.content ?? "").withSchema(request.schema).build()
3489
3621
  };
3490
3622
  const result = await this.generate({ ...request, messages, temperature: 0.1 });
3491
3623
  return { value: this.jsonParser.parse(result.text), result };
@@ -3591,7 +3723,8 @@ function mapGeminiFinishReason(reason) {
3591
3723
  }
3592
3724
  function findLastIndex3(items, predicate) {
3593
3725
  for (let i = items.length - 1; i >= 0; i--) {
3594
- if (predicate(items[i])) return i;
3726
+ const item = items[i];
3727
+ if (item !== void 0 && predicate(item)) return i;
3595
3728
  }
3596
3729
  return -1;
3597
3730
  }
@@ -4809,98 +4942,636 @@ function createPrunaProvider(config) {
4809
4942
  return new PrunaProvider(config);
4810
4943
  }
4811
4944
 
4812
- // src/providers/factory/create-ai.ts
4813
- function createAI(config = {}) {
4814
- const factory = new ProviderFactory({
4815
- priority: config.priority,
4816
- fallbackEnabled: config.fallbackEnabled,
4817
- defaultTier: config.defaultTier
4818
- });
4819
- if (config.anthropic?.apiKey) {
4820
- factory.register(new AnthropicProvider(config.anthropic));
4945
+ // src/providers/adapters/openai-compatible.adapter.ts
4946
+ function toWireMessage(message) {
4947
+ if (message.role === "tool") {
4948
+ return { role: "tool", content: message.content, tool_call_id: message.toolCallId ?? "" };
4821
4949
  }
4822
- if (config.groq?.apiKey) {
4823
- factory.register(new GroqProvider(config.groq));
4950
+ if (message.role === "assistant" && message.toolCalls && message.toolCalls.length > 0) {
4951
+ return {
4952
+ role: "assistant",
4953
+ content: message.content,
4954
+ tool_calls: message.toolCalls.map((call) => ({
4955
+ id: call.id,
4956
+ type: "function",
4957
+ function: { name: call.name, arguments: call.arguments }
4958
+ }))
4959
+ };
4824
4960
  }
4825
- if (config.gemini?.apiKey) {
4826
- factory.register(new GeminiProvider({ ...config.gemini, enabled: true }));
4961
+ if (message.role === "user") return { role: "user", content: message.content };
4962
+ return { role: message.role, content: message.content };
4963
+ }
4964
+ function mergeImages(messages, images) {
4965
+ if (images.length === 0) return [...messages];
4966
+ const parts = images.map((image) => ({
4967
+ type: "image_url",
4968
+ image_url: { url: `data:${image.mimeType};base64,${image.dataBase64}` }
4969
+ }));
4970
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
4971
+ const message = messages[index];
4972
+ if (!message || message.role !== "user") continue;
4973
+ const textParts = typeof message.content === "string" ? message.content.length > 0 ? [{ type: "text", text: message.content }] : [] : message.content;
4974
+ return [
4975
+ ...messages.slice(0, index),
4976
+ { role: "user", content: [...textParts, ...parts] },
4977
+ ...messages.slice(index + 1)
4978
+ ];
4827
4979
  }
4828
- if (config.fal?.apiKey) {
4829
- factory.register(new FalProvider({ ...config.fal, enabled: true }));
4980
+ return [...messages, { role: "user", content: [...parts] }];
4981
+ }
4982
+ async function extractErrorDetail(response) {
4983
+ try {
4984
+ const body = await response.json();
4985
+ return body.error;
4986
+ } catch {
4987
+ return void 0;
4830
4988
  }
4831
- if (config.pruna?.apiKey) {
4832
- factory.register(new PrunaProvider({ ...config.pruna, enabled: true }));
4989
+ }
4990
+ async function* parseSseEvent2(rawEvent, toolCallAccumulator) {
4991
+ for (const line of rawEvent.split("\n")) {
4992
+ if (!line.startsWith("data:")) continue;
4993
+ const payload = line.slice(5).trim();
4994
+ if (payload.length === 0 || payload === "[DONE]") continue;
4995
+ let chunk;
4996
+ try {
4997
+ chunk = JSON.parse(payload);
4998
+ } catch {
4999
+ continue;
5000
+ }
5001
+ const delta = chunk.choices?.[0]?.delta;
5002
+ if (delta?.reasoning) {
5003
+ yield { type: "delta", channel: "reasoning", text: delta.reasoning };
5004
+ }
5005
+ if (delta?.content) {
5006
+ yield { type: "delta", channel: "answer", text: delta.content };
5007
+ }
5008
+ if (delta?.tool_calls) {
5009
+ for (const toolCallDelta of delta.tool_calls) toolCallAccumulator.push(toolCallDelta);
5010
+ }
5011
+ if (chunk.usage) {
5012
+ yield {
5013
+ type: "usage",
5014
+ usage: {
5015
+ inputTokens: chunk.usage.prompt_tokens ?? 0,
5016
+ outputTokens: chunk.usage.completion_tokens ?? 0,
5017
+ reasoningTokens: chunk.usage.completion_tokens_details?.reasoning_tokens
5018
+ }
5019
+ };
5020
+ }
4833
5021
  }
4834
- return factory;
4835
5022
  }
4836
-
4837
- // src/providers/groq/groq-messages.ts
4838
- var createUserMessage = (content) => ({
4839
- role: "user",
4840
- content
4841
- });
4842
- var createAssistantMessage = (content) => ({
4843
- role: "assistant",
4844
- content
4845
- });
4846
- var createSystemMessage = (content) => ({
4847
- role: "system",
4848
- content
4849
- });
4850
- var createMessage = (role, content) => ({
4851
- role,
4852
- content
4853
- });
4854
- var promptToMessages = (prompt) => [
4855
- createUserMessage(prompt)
4856
- ];
4857
- var extractTextFromMessages = (messages) => messages.map((m) => m.content).join("\n\n");
4858
- var formatMessagesForDisplay = (messages) => messages.map((m) => `[${m.role.toUpperCase()}]: ${m.content}`).join("\n\n---\n\n");
4859
-
4860
- // src/providers/groq/groq-structured-json.ts
4861
- async function requestStructuredJson(client, request) {
4862
- const chatRequest = {
4863
- model: request.model,
4864
- messages: [createUserMessage(request.instructions)],
4865
- temperature: request.temperature,
4866
- max_tokens: request.maxTokens,
4867
- response_format: { type: "json_object" },
4868
- ...request.reasoningEffort !== void 0 ? { reasoning_effort: request.reasoningEffort } : {}
4869
- };
4870
- const response = await client.postChatCompletion(chatRequest);
4871
- const content = response.choices[0]?.message?.content ?? "";
4872
- const candidate = extractJsonCandidate(content);
5023
+ async function* parseSseStream(body) {
5024
+ const reader = body.getReader();
5025
+ const decoder = new TextDecoder();
5026
+ const toolCallAccumulator = new ToolCallAccumulator();
5027
+ let buffer = "";
4873
5028
  try {
4874
- return JSON.parse(candidate);
5029
+ while (true) {
5030
+ const { done, value } = await reader.read();
5031
+ if (done) break;
5032
+ buffer += decoder.decode(value, { stream: true });
5033
+ let separator = buffer.indexOf("\n\n");
5034
+ while (separator !== -1) {
5035
+ const rawEvent = buffer.slice(0, separator);
5036
+ buffer = buffer.slice(separator + 2);
5037
+ separator = buffer.indexOf("\n\n");
5038
+ yield* parseSseEvent2(rawEvent, toolCallAccumulator);
5039
+ }
5040
+ }
4875
5041
  } catch (err) {
4876
- throw new GroqError(
4877
- "UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
4878
- "model response contained no parsable json object",
4879
- err instanceof Error ? err : void 0
4880
- );
5042
+ throw errorFromUnknown(err);
5043
+ } finally {
5044
+ reader.releaseLock();
5045
+ }
5046
+ const calls = toolCallAccumulator.finish();
5047
+ if (calls.length > 0) yield { type: "tool_calls", calls };
5048
+ }
5049
+ function createOpenAiCompatibleAdapter(config) {
5050
+ if (!config.baseUrl && !config.endpointUrl) {
5051
+ throw new Error("createOpenAiCompatibleAdapter requires baseUrl or endpointUrl");
4881
5052
  }
5053
+ const endpoint = config.endpointUrl ?? `${config.baseUrl}/chat/completions`;
5054
+ return {
5055
+ async *stream(req) {
5056
+ const timeout = AbortSignal.timeout(config.timeoutMs);
5057
+ const signal = req.signal ? AbortSignal.any([req.signal, timeout]) : timeout;
5058
+ let response;
5059
+ try {
5060
+ response = await fetch(endpoint, {
5061
+ method: "POST",
5062
+ headers: {
5063
+ Authorization: `Bearer ${config.apiKey}`,
5064
+ "Content-Type": "application/json"
5065
+ },
5066
+ body: JSON.stringify({
5067
+ model: req.externalModelId,
5068
+ messages: mergeImages(req.messages.map(toWireMessage), req.images ?? []),
5069
+ temperature: req.temperature,
5070
+ max_completion_tokens: req.maxOutputTokens,
5071
+ top_p: req.topP,
5072
+ stream: true,
5073
+ stream_options: { include_usage: true },
5074
+ ...req.tools && req.tools.length > 0 ? {
5075
+ tools: req.tools.map((tool) => ({ type: "function", function: tool })),
5076
+ tool_choice: "auto"
5077
+ } : {}
5078
+ }),
5079
+ signal
5080
+ });
5081
+ } catch (err) {
5082
+ throw errorFromUnknown(err);
5083
+ }
5084
+ if (!response.ok || !response.body) {
5085
+ const detail = await extractErrorDetail(response);
5086
+ throw errorFromStatus(response.status, detail?.message, detail);
5087
+ }
5088
+ yield* parseSseStream(response.body);
5089
+ }
5090
+ };
4882
5091
  }
4883
5092
 
4884
- // src/providers/groq/text-generation.service.ts
4885
- var STRUCTURED_OUTPUT_TEMPERATURE = 0.1;
4886
- var TextGenerationService = class {
4887
- constructor(httpClient, cache = new CacheManager(), defaultModel = DEFAULT_MODELS.TEXT) {
4888
- this.httpClient = httpClient;
4889
- this.cache = cache;
4890
- this.defaultModel = defaultModel;
5093
+ // src/providers/openai-compatible/openai-compatible.provider.ts
5094
+ var DEFAULT_TIMEOUT_MS = 3e4;
5095
+ var STRUCTURED_TEMPERATURE2 = 0.1;
5096
+ var OpenAiCompatibleProvider = class {
5097
+ constructor(config) {
5098
+ this.config = config;
5099
+ if (!config.baseUrl && !config.endpointUrl) {
5100
+ throw new AIError(
5101
+ "MISSING_CONFIG" /* MISSING_CONFIG */,
5102
+ "OpenAiCompatibleProvider requires baseUrl or endpointUrl"
5103
+ );
5104
+ }
5105
+ this.adapter = createOpenAiCompatibleAdapter({
5106
+ baseUrl: config.baseUrl,
5107
+ endpointUrl: config.endpointUrl,
5108
+ apiKey: config.apiKey,
5109
+ timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS
5110
+ });
5111
+ this.tiers = mergeTierOverrides(
5112
+ config.model ? { fast: config.model, balanced: config.model, powerful: config.model } : {},
5113
+ config.models
5114
+ );
4891
5115
  }
4892
- httpClient;
4893
- cache;
4894
- defaultModel;
4895
- id = "groq-text-generation";
4896
- name = "Groq Text Generation";
5116
+ config;
5117
+ id = "openai-compatible";
5118
+ name = "OpenAI-compatible";
4897
5119
  capabilities = ["text"];
5120
+ adapter;
5121
+ tiers;
4898
5122
  jsonParser = new JsonResponseParser();
4899
- generateCompletion(prompt, options = {}) {
4900
- const model = options.model ?? this.defaultModel;
4901
- return this.executeWithCache(
4902
- {
4903
- type: CACHE_KEY_TYPE_COMPLETION,
5123
+ resolveModel(tier) {
5124
+ return resolveModel(this.tiers, tier, this.id);
5125
+ }
5126
+ async healthCheck() {
5127
+ return this.config.apiKey && (this.config.baseUrl || this.config.endpointUrl) ? "healthy" : "unavailable";
5128
+ }
5129
+ async estimateCost() {
5130
+ return 0;
5131
+ }
5132
+ async generate(request) {
5133
+ const model = this.modelFor(request);
5134
+ const outcome = await this.consume(this.toAdapterRequest(model, request));
5135
+ if (outcome.text.length === 0) {
5136
+ throw this.noContentError(model);
5137
+ }
5138
+ return {
5139
+ text: outcome.text,
5140
+ usage: outcome.usage,
5141
+ model,
5142
+ providerId: this.id,
5143
+ finishReason: "stop"
5144
+ };
5145
+ }
5146
+ async generateStructured(request) {
5147
+ const model = this.modelFor(request);
5148
+ const messages = this.toWireMessages(request.messages, request.systemPrompt);
5149
+ const lastUserIndex = findLastIndex4(messages, (m) => m.role === "user");
5150
+ if (lastUserIndex === -1) {
5151
+ throw new AIError(
5152
+ "UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
5153
+ "generateStructured requires at least one user message"
5154
+ );
5155
+ }
5156
+ const structuredPrompt = new StructuredPromptBuilder(
5157
+ messages[lastUserIndex]?.content ?? ""
5158
+ ).withSchema(request.schema).build();
5159
+ messages[lastUserIndex] = { role: "user", content: structuredPrompt };
5160
+ const outcome = await this.consume({
5161
+ externalModelId: model,
5162
+ messages,
5163
+ temperature: STRUCTURED_TEMPERATURE2,
5164
+ signal: request.signal
5165
+ });
5166
+ if (outcome.text.length === 0) {
5167
+ throw this.noContentError(model);
5168
+ }
5169
+ return {
5170
+ value: this.jsonParser.parse(outcome.text),
5171
+ result: {
5172
+ text: outcome.text,
5173
+ usage: outcome.usage,
5174
+ model,
5175
+ providerId: this.id,
5176
+ finishReason: "stop"
5177
+ }
5178
+ };
5179
+ }
5180
+ async stream(request, callbacks) {
5181
+ const model = this.modelFor(request);
5182
+ try {
5183
+ const outcome = await this.consume(this.toAdapterRequest(model, request), (text) => {
5184
+ callbacks.onChunk?.(text);
5185
+ });
5186
+ if (outcome.text.length === 0) {
5187
+ throw this.noContentError(model);
5188
+ }
5189
+ const result = {
5190
+ text: outcome.text,
5191
+ usage: outcome.usage,
5192
+ model,
5193
+ providerId: this.id,
5194
+ finishReason: "stop"
5195
+ };
5196
+ callbacks.onComplete?.(result);
5197
+ return result;
5198
+ } catch (error) {
5199
+ callbacks.onError?.(error instanceof Error ? error : new Error(String(error)));
5200
+ throw error;
5201
+ }
5202
+ }
5203
+ /* ---------- internals ---------- */
5204
+ /** Drain one adapter stream to its end. `onChunk`, when given, sees answer
5205
+ * deltas as they arrive — the streaming surface is this same drain. */
5206
+ async consume(req, onChunk) {
5207
+ let text = "";
5208
+ let usage;
5209
+ for await (const event of this.adapter.stream(req)) {
5210
+ if (event.type === "delta" && event.channel === "answer") {
5211
+ text += event.text;
5212
+ onChunk?.(event.text);
5213
+ } else if (event.type === "usage") {
5214
+ usage = event.usage;
5215
+ }
5216
+ }
5217
+ return { text, usage };
5218
+ }
5219
+ modelFor(request) {
5220
+ return request.model ?? this.resolveModel(request.tier ?? "balanced");
5221
+ }
5222
+ noContentError(model) {
5223
+ return new AIError(
5224
+ "SERVER_ERROR" /* SERVER_ERROR */,
5225
+ "No content generated from the OpenAI-compatible endpoint",
5226
+ void 0,
5227
+ { model }
5228
+ );
5229
+ }
5230
+ toAdapterRequest(model, request) {
5231
+ return {
5232
+ externalModelId: model,
5233
+ messages: this.toWireMessages(request.messages, request.systemPrompt),
5234
+ ...request.temperature !== void 0 ? { temperature: request.temperature } : {},
5235
+ ...request.maxTokens !== void 0 ? { maxOutputTokens: request.maxTokens } : {},
5236
+ ...request.topP !== void 0 ? { topP: request.topP } : {},
5237
+ ...request.signal ? { signal: request.signal } : {}
5238
+ };
5239
+ }
5240
+ /** Neutral messages onto the adapter's shape; systemPrompt becomes the
5241
+ * leading system message (in-band, the OpenAI way). */
5242
+ toWireMessages(messages, systemPrompt) {
5243
+ const wire = [];
5244
+ if (systemPrompt && systemPrompt.length > 0) {
5245
+ wire.push({ role: "system", content: systemPrompt });
5246
+ }
5247
+ for (const message of messages) {
5248
+ wire.push({ role: message.role, content: message.content });
5249
+ }
5250
+ return wire;
5251
+ }
5252
+ };
5253
+ function createOpenAiCompatibleProvider(config) {
5254
+ return new OpenAiCompatibleProvider(config);
5255
+ }
5256
+ function findLastIndex4(items, predicate) {
5257
+ for (let index = items.length - 1; index >= 0; index -= 1) {
5258
+ if (predicate(items[index])) return index;
5259
+ }
5260
+ return -1;
5261
+ }
5262
+
5263
+ // src/providers/workers-ai/workers-ai.entities.ts
5264
+ var WorkersAIError = class extends Error {
5265
+ status;
5266
+ constructor(message, status) {
5267
+ super(message);
5268
+ this.name = "WorkersAIError";
5269
+ this.status = status;
5270
+ }
5271
+ };
5272
+
5273
+ // src/providers/workers-ai/workers-ai.text.ts
5274
+ var WORKERS_AI_LLM_MODEL = "@cf/meta/llama-3.3-70b-instruct-fp8-fast";
5275
+ var WORKERS_AI_TEXT_TIMEOUT_MS = 25e3;
5276
+ function workersAIConfigured(env) {
5277
+ return typeof env.AI?.run === "function";
5278
+ }
5279
+ function requireAi(env) {
5280
+ const ai = env.AI;
5281
+ if (!ai || typeof ai.run !== "function") throw new WorkersAIError("Workers AI is not configured");
5282
+ return ai;
5283
+ }
5284
+ async function runWorkersAIText(env, messages, opts = {}) {
5285
+ const ai = requireAi(env);
5286
+ const model = opts.model ?? WORKERS_AI_LLM_MODEL;
5287
+ let result;
5288
+ try {
5289
+ result = await Promise.race([
5290
+ ai.run(model, {
5291
+ messages: messages.map((m) => ({ role: m.role, content: m.content })),
5292
+ max_tokens: opts.maxTokens ?? 900,
5293
+ temperature: opts.temperature ?? 0.7
5294
+ }),
5295
+ new Promise(
5296
+ (_, reject) => setTimeout(() => reject(new WorkersAIError("Workers AI timed out")), WORKERS_AI_TEXT_TIMEOUT_MS)
5297
+ )
5298
+ ]);
5299
+ } catch (err) {
5300
+ throw err instanceof WorkersAIError ? err : new WorkersAIError(err instanceof Error ? err.message : "Workers AI request failed");
5301
+ }
5302
+ const response = result ?? {};
5303
+ let text = response.response;
5304
+ if (typeof text !== "string" || text.length === 0) {
5305
+ text = response.choices?.[0]?.message?.content;
5306
+ }
5307
+ if (typeof text !== "string" || text.length === 0) {
5308
+ throw new WorkersAIError("Workers AI returned no text");
5309
+ }
5310
+ return text;
5311
+ }
5312
+ async function* streamWorkersAIText(env, messages, opts = {}) {
5313
+ const ai = requireAi(env);
5314
+ const model = opts.model ?? WORKERS_AI_LLM_MODEL;
5315
+ let body;
5316
+ try {
5317
+ body = await Promise.race([
5318
+ ai.run(model, {
5319
+ messages: messages.map((m) => ({ role: m.role, content: m.content })),
5320
+ stream: true,
5321
+ max_tokens: opts.maxTokens ?? 600,
5322
+ temperature: opts.temperature ?? 0.7
5323
+ }),
5324
+ new Promise(
5325
+ (_, reject) => setTimeout(() => reject(new WorkersAIError("Workers AI timed out")), WORKERS_AI_TEXT_TIMEOUT_MS)
5326
+ )
5327
+ ]);
5328
+ } catch (err) {
5329
+ throw err instanceof WorkersAIError ? err : new WorkersAIError(err instanceof Error ? err.message : "Workers AI request failed");
5330
+ }
5331
+ const stream = body;
5332
+ const getReader = typeof stream === "object" && stream !== null && "getReader" in stream && typeof stream.getReader === "function" ? stream.getReader : void 0;
5333
+ if (!getReader) throw new WorkersAIError("Workers AI stream was not readable");
5334
+ const reader = getReader.call(stream);
5335
+ const decoder = new TextDecoder();
5336
+ let buffer = "";
5337
+ try {
5338
+ for (; ; ) {
5339
+ const { done, value } = await reader.read();
5340
+ if (done) break;
5341
+ buffer += decoder.decode(value, { stream: true });
5342
+ let newlineAt;
5343
+ while ((newlineAt = buffer.indexOf("\n")) !== -1) {
5344
+ let line = buffer.slice(0, newlineAt);
5345
+ buffer = buffer.slice(newlineAt + 1);
5346
+ if (line.endsWith("\r")) line = line.slice(0, -1);
5347
+ if (line.startsWith(":") || line.trim() === "") continue;
5348
+ if (!line.startsWith("data: ")) continue;
5349
+ const payload = line.slice(6).trim();
5350
+ if (payload === "[DONE]") return;
5351
+ try {
5352
+ const parsed = JSON.parse(payload);
5353
+ if (typeof parsed.response === "string" && parsed.response.length > 0) yield parsed.response;
5354
+ } catch {
5355
+ buffer = `${line}
5356
+ ${buffer}`;
5357
+ break;
5358
+ }
5359
+ }
5360
+ }
5361
+ } finally {
5362
+ reader.releaseLock();
5363
+ }
5364
+ }
5365
+
5366
+ // src/providers/workers-ai/workers-ai.provider.ts
5367
+ var WORKERS_AI_TIERS = {
5368
+ fast: "@cf/meta/llama-3.1-8b-instruct-fp8-fast",
5369
+ balanced: WORKERS_AI_LLM_MODEL,
5370
+ powerful: WORKERS_AI_LLM_MODEL
5371
+ };
5372
+ var WorkersAIProvider = class {
5373
+ id = "workers-ai";
5374
+ name = "Cloudflare Workers AI";
5375
+ capabilities = ["text"];
5376
+ binding;
5377
+ tiers;
5378
+ jsonParser = new JsonResponseParser();
5379
+ constructor(config) {
5380
+ this.binding = config.binding;
5381
+ this.tiers = mergeTierOverrides(WORKERS_AI_TIERS, config.models);
5382
+ }
5383
+ resolveModel(tier) {
5384
+ return resolveModel(this.tiers, tier, this.id);
5385
+ }
5386
+ async healthCheck() {
5387
+ return typeof this.binding?.run === "function" ? "healthy" : "unavailable";
5388
+ }
5389
+ /** Workers AI is allocation-priced (neurons per deployment), not per
5390
+ * request — there is no per-call cost to estimate. */
5391
+ async estimateCost(_request) {
5392
+ return 0;
5393
+ }
5394
+ async generate(request) {
5395
+ const model = request.model ?? this.resolveModel(request.tier ?? "balanced");
5396
+ const messages = withSystemPrompt(request);
5397
+ try {
5398
+ const text = await runWorkersAIText(
5399
+ { AI: this.binding },
5400
+ messages,
5401
+ {
5402
+ model,
5403
+ maxTokens: request.maxTokens,
5404
+ temperature: request.temperature
5405
+ }
5406
+ );
5407
+ return { text, model, providerId: this.id, finishReason: "stop" };
5408
+ } catch (error) {
5409
+ throw toAIError(error);
5410
+ }
5411
+ }
5412
+ async generateStructured(request) {
5413
+ const messages = [...request.messages];
5414
+ const lastUserIndex = findLastIndex5(messages, (m) => m.role === "user");
5415
+ if (lastUserIndex === -1) {
5416
+ throw new AIError("UNKNOWN_ERROR" /* UNKNOWN_ERROR */, "generateStructured requires at least one user message");
5417
+ }
5418
+ messages[lastUserIndex] = {
5419
+ role: "user",
5420
+ content: new StructuredPromptBuilder(messages[lastUserIndex]?.content ?? "").withSchema(request.schema).build()
5421
+ };
5422
+ const result = await this.generate({ ...request, messages, temperature: 0.1 });
5423
+ return { value: this.jsonParser.parse(result.text), result };
5424
+ }
5425
+ async stream(request, callbacks) {
5426
+ const model = request.model ?? this.resolveModel(request.tier ?? "balanced");
5427
+ const messages = withSystemPrompt(request);
5428
+ let text = "";
5429
+ try {
5430
+ for await (const chunk of streamWorkersAIText({ AI: this.binding }, messages, {
5431
+ model,
5432
+ maxTokens: request.maxTokens,
5433
+ temperature: request.temperature
5434
+ })) {
5435
+ text += chunk;
5436
+ callbacks.onChunk?.(chunk);
5437
+ }
5438
+ } catch (error) {
5439
+ const aiError = toAIError(error);
5440
+ callbacks.onError?.(aiError);
5441
+ throw aiError;
5442
+ }
5443
+ const result = { text, model, providerId: this.id, finishReason: "stop" };
5444
+ callbacks.onComplete?.(result);
5445
+ return result;
5446
+ }
5447
+ };
5448
+ function withSystemPrompt(request) {
5449
+ if (request.systemPrompt && request.systemPrompt.length > 0) {
5450
+ return [
5451
+ { role: "system", content: request.systemPrompt },
5452
+ ...request.messages.filter((m) => m.role !== "system")
5453
+ ];
5454
+ }
5455
+ return request.messages;
5456
+ }
5457
+ function toAIError(error) {
5458
+ if (error instanceof AIError) return error;
5459
+ const message = error instanceof Error ? error.message : "Workers AI request failed";
5460
+ const type = error instanceof WorkersAIError && error.message.includes("not configured") ? "INVALID_API_KEY" /* INVALID_API_KEY */ : "SERVER_ERROR" /* SERVER_ERROR */;
5461
+ return new AIError(type, message, error instanceof Error ? error : void 0);
5462
+ }
5463
+ function findLastIndex5(items, predicate) {
5464
+ for (let i = items.length - 1; i >= 0; i--) {
5465
+ const item = items[i];
5466
+ if (item !== void 0 && predicate(item)) return i;
5467
+ }
5468
+ return -1;
5469
+ }
5470
+ function createWorkersAIProvider(config) {
5471
+ return new WorkersAIProvider(config);
5472
+ }
5473
+
5474
+ // src/providers/factory/create-ai.ts
5475
+ function createAI(config = {}) {
5476
+ const factory = new ProviderFactory({
5477
+ priority: config.priority,
5478
+ fallbackEnabled: config.fallbackEnabled,
5479
+ defaultTier: config.defaultTier
5480
+ });
5481
+ if (config.anthropic?.apiKey) {
5482
+ factory.register(new AnthropicProvider(config.anthropic));
5483
+ }
5484
+ if (config.groq?.apiKey) {
5485
+ factory.register(new GroqProvider(config.groq));
5486
+ }
5487
+ if (config.gemini?.apiKey) {
5488
+ factory.register(new GeminiProvider({ ...config.gemini, enabled: true }));
5489
+ }
5490
+ if (config.fal?.apiKey) {
5491
+ factory.register(new FalProvider({ ...config.fal, enabled: true }));
5492
+ }
5493
+ if (config.pruna?.apiKey) {
5494
+ factory.register(new PrunaProvider({ ...config.pruna, enabled: true }));
5495
+ }
5496
+ const openaiCompatible = config.openaiCompatible;
5497
+ if (openaiCompatible?.apiKey && (openaiCompatible.baseUrl || openaiCompatible.endpointUrl)) {
5498
+ factory.register(
5499
+ new OpenAiCompatibleProvider({ ...openaiCompatible, apiKey: openaiCompatible.apiKey })
5500
+ );
5501
+ }
5502
+ if (config.workersAI?.binding) {
5503
+ factory.register(new WorkersAIProvider(config.workersAI));
5504
+ }
5505
+ return factory;
5506
+ }
5507
+
5508
+ // src/providers/groq/groq-messages.ts
5509
+ var createUserMessage = (content) => ({
5510
+ role: "user",
5511
+ content
5512
+ });
5513
+ var createAssistantMessage = (content) => ({
5514
+ role: "assistant",
5515
+ content
5516
+ });
5517
+ var createSystemMessage = (content) => ({
5518
+ role: "system",
5519
+ content
5520
+ });
5521
+ var createMessage = (role, content) => ({
5522
+ role,
5523
+ content
5524
+ });
5525
+ var promptToMessages = (prompt) => [
5526
+ createUserMessage(prompt)
5527
+ ];
5528
+ var extractTextFromMessages = (messages) => messages.map((m) => m.content).join("\n\n");
5529
+ var formatMessagesForDisplay = (messages) => messages.map((m) => `[${m.role.toUpperCase()}]: ${m.content}`).join("\n\n---\n\n");
5530
+
5531
+ // src/providers/groq/groq-structured-json.ts
5532
+ async function requestStructuredJson(client, request) {
5533
+ const chatRequest = {
5534
+ model: request.model,
5535
+ messages: [createUserMessage(request.instructions)],
5536
+ temperature: request.temperature,
5537
+ max_tokens: request.maxTokens,
5538
+ response_format: { type: "json_object" },
5539
+ ...request.reasoningEffort !== void 0 ? { reasoning_effort: request.reasoningEffort } : {}
5540
+ };
5541
+ const response = await client.postChatCompletion(chatRequest);
5542
+ const content = response.choices[0]?.message?.content ?? "";
5543
+ const candidate = extractJsonCandidate(content);
5544
+ try {
5545
+ return JSON.parse(candidate);
5546
+ } catch (err) {
5547
+ throw new GroqError(
5548
+ "UNKNOWN_ERROR" /* UNKNOWN_ERROR */,
5549
+ "model response contained no parsable json object",
5550
+ err instanceof Error ? err : void 0
5551
+ );
5552
+ }
5553
+ }
5554
+
5555
+ // src/providers/groq/text-generation.service.ts
5556
+ var STRUCTURED_OUTPUT_TEMPERATURE = 0.1;
5557
+ var TextGenerationService = class {
5558
+ constructor(httpClient, cache = new CacheManager(), defaultModel = DEFAULT_MODELS.TEXT) {
5559
+ this.httpClient = httpClient;
5560
+ this.cache = cache;
5561
+ this.defaultModel = defaultModel;
5562
+ }
5563
+ httpClient;
5564
+ cache;
5565
+ defaultModel;
5566
+ id = "groq-text-generation";
5567
+ name = "Groq Text Generation";
5568
+ capabilities = ["text"];
5569
+ jsonParser = new JsonResponseParser();
5570
+ generateCompletion(prompt, options = {}) {
5571
+ const model = options.model ?? this.defaultModel;
5572
+ return this.executeWithCache(
5573
+ {
5574
+ type: CACHE_KEY_TYPE_COMPLETION,
4904
5575
  model,
4905
5576
  prompt,
4906
5577
  config: options.generationConfig
@@ -5200,6 +5871,7 @@ var ChatService = class {
5200
5871
  if (messages.length === 0) return null;
5201
5872
  const last = messages[messages.length - 1];
5202
5873
  const first = messages[0];
5874
+ if (!last || !first) return null;
5203
5875
  const companionId = String(first.metadata?.["companionId"] ?? "unknown");
5204
5876
  const companionName = String(first.metadata?.["companionName"] ?? "Unknown");
5205
5877
  return {
@@ -5343,6 +6015,211 @@ function resetProvider() {
5343
6015
  container = null;
5344
6016
  }
5345
6017
 
6018
+ // src/providers/workers-ai/workers-ai.speech.ts
6019
+ var WORKERS_AI_SPEECH_TIMEOUT_MS = 45e3;
6020
+ async function readAll(stream) {
6021
+ const reader = stream.getReader();
6022
+ const chunks = [];
6023
+ try {
6024
+ for (; ; ) {
6025
+ const { done, value } = await reader.read();
6026
+ if (done) break;
6027
+ if (value) chunks.push(value);
6028
+ }
6029
+ } finally {
6030
+ reader.releaseLock();
6031
+ }
6032
+ const combined = new Uint8Array(chunks.reduce((acc, chunk) => acc + chunk.length, 0));
6033
+ let offset = 0;
6034
+ for (const chunk of chunks) {
6035
+ combined.set(chunk, offset);
6036
+ offset += chunk.length;
6037
+ }
6038
+ return combined;
6039
+ }
6040
+ function base64ToBytes2(base64) {
6041
+ const binary = atob(base64);
6042
+ const bytes = new Uint8Array(binary.length);
6043
+ for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i);
6044
+ return bytes;
6045
+ }
6046
+ async function speakWithWorkersAI(env, engine, text) {
6047
+ const ai = env.AI;
6048
+ if (!ai || typeof ai.run !== "function") throw new WorkersAIError("Workers AI is not configured");
6049
+ const input = engine.langParam ? { prompt: text, lang: engine.langParam } : { text };
6050
+ let result;
6051
+ try {
6052
+ result = await Promise.race([
6053
+ ai.run(engine.model, input),
6054
+ new Promise(
6055
+ (_, reject) => setTimeout(() => reject(new WorkersAIError("The speech engine timed out")), WORKERS_AI_SPEECH_TIMEOUT_MS)
6056
+ )
6057
+ ]);
6058
+ } catch (err) {
6059
+ throw err instanceof WorkersAIError ? err : new WorkersAIError(err instanceof Error ? err.message : "Workers AI speech request failed");
6060
+ }
6061
+ if (result instanceof ReadableStream) {
6062
+ const bytes = await readAll(result);
6063
+ if (bytes.length === 0) throw new WorkersAIError("The speech engine returned no audio");
6064
+ return { bytes };
6065
+ }
6066
+ const audio = result ?? {};
6067
+ if (typeof audio.audio === "string" && audio.audio.length > 0) {
6068
+ return { bytes: base64ToBytes2(audio.audio) };
6069
+ }
6070
+ throw new WorkersAIError("The speech engine returned no audio");
6071
+ }
6072
+
6073
+ // src/providers/fal/queue/fal-queue.entities.ts
6074
+ var FalQueueError = class extends Error {
6075
+ status;
6076
+ constructor(message, status) {
6077
+ super(message);
6078
+ this.name = "FalQueueError";
6079
+ this.status = status;
6080
+ }
6081
+ };
6082
+ var FAL_ASPECT_IMAGE_SIZES = {
6083
+ "1:1": "square_hd",
6084
+ "16:9": "landscape_16_9",
6085
+ "9:16": "portrait_16_9"
6086
+ };
6087
+
6088
+ // src/providers/fal/queue/fal-queue.client.ts
6089
+ var FAL_QUEUE_BASE = "https://queue.fal.run";
6090
+ var FAL_SUBMIT_TIMEOUT_MS = 15e3;
6091
+ var FAL_POLL_TIMEOUT_MS = 1e4;
6092
+ function falQueueConfigured(env) {
6093
+ return Boolean(env.FAL_KEY);
6094
+ }
6095
+ async function falFetch(env, url, timeoutMs, body) {
6096
+ if (!falQueueConfigured(env)) throw new FalQueueError("fal.ai is not configured");
6097
+ const request = async () => fetch(url, {
6098
+ method: body !== void 0 ? "POST" : "GET",
6099
+ headers: {
6100
+ Authorization: `Key ${env.FAL_KEY}`,
6101
+ ...body !== void 0 ? { "Content-Type": "application/json" } : {}
6102
+ },
6103
+ body: body !== void 0 ? JSON.stringify(body) : void 0,
6104
+ signal: AbortSignal.timeout(timeoutMs)
6105
+ });
6106
+ let res;
6107
+ try {
6108
+ res = await request();
6109
+ if (res.status >= 500) res = await request();
6110
+ } catch (err) {
6111
+ throw new FalQueueError(err instanceof Error ? err.message : "fal.ai request failed");
6112
+ }
6113
+ if (!res.ok) {
6114
+ const text = await res.text().catch(() => "");
6115
+ throw new FalQueueError(`fal ${res.status}: ${text.slice(0, 200)}`, res.status);
6116
+ }
6117
+ return await res.json();
6118
+ }
6119
+ function createFalQueue(env) {
6120
+ return {
6121
+ async submit(model, input) {
6122
+ const res = await falFetch(env, `${FAL_QUEUE_BASE}/${model}`, FAL_SUBMIT_TIMEOUT_MS, input);
6123
+ return { requestId: res.request_id, statusUrl: res.status_url, responseUrl: res.response_url };
6124
+ },
6125
+ async checkStatus(statusUrl) {
6126
+ const res = await falFetch(env, statusUrl, FAL_POLL_TIMEOUT_MS);
6127
+ return {
6128
+ status: res.status,
6129
+ queuePosition: res.queue_position,
6130
+ logs: res.logs?.map((l) => l.message ?? "").filter(Boolean)
6131
+ };
6132
+ },
6133
+ fetchResult(responseUrl) {
6134
+ return falFetch(env, responseUrl, FAL_POLL_TIMEOUT_MS);
6135
+ }
6136
+ };
6137
+ }
6138
+
6139
+ // src/providers/fal/queue/fal-wire.ts
6140
+ function buildFalImageInput(model, input) {
6141
+ const base = { prompt: input.prompt, num_images: input.numImages };
6142
+ if (model.includes("flux")) {
6143
+ const imageSize = input.aspectRatio ? FAL_ASPECT_IMAGE_SIZES[input.aspectRatio] : void 0;
6144
+ if (imageSize) base.image_size = imageSize;
6145
+ }
6146
+ return base;
6147
+ }
6148
+ function parseFalImageOutput(raw) {
6149
+ const obj = raw ?? {};
6150
+ const entries = Array.isArray(obj.images) ? obj.images : obj.image && typeof obj.image === "object" ? [obj.image] : [];
6151
+ const imageUrls = entries.map((e) => typeof e.url === "string" ? e.url : "").filter((url) => url.length > 0);
6152
+ const first = entries.find((e) => typeof e.width === "number" || typeof e.height === "number");
6153
+ return {
6154
+ imageUrls,
6155
+ ...typeof obj.seed === "number" ? { seed: obj.seed } : {},
6156
+ ...typeof first?.width === "number" ? { width: first.width } : {},
6157
+ ...typeof first?.height === "number" ? { height: first.height } : {}
6158
+ };
6159
+ }
6160
+ function buildFalVideoInput(spec, input) {
6161
+ const base = { prompt: input.prompt };
6162
+ if (spec.durationFormat !== "none" && typeof input.durationSeconds === "number") {
6163
+ base.duration = spec.durationFormat === "s-suffix" ? `${input.durationSeconds}s` : String(input.durationSeconds);
6164
+ }
6165
+ if (spec.aspectRatios && input.aspectRatio) base.aspect_ratio = input.aspectRatio;
6166
+ if (spec.resolutions && input.resolution) base.resolution = input.resolution;
6167
+ if (input.imageUrl) base.image_url = input.imageUrl;
6168
+ if (spec.supportsNegativePrompt && input.negativePrompt) base.negative_prompt = input.negativePrompt;
6169
+ if (spec.generateAudio) base.generate_audio = true;
6170
+ return base;
6171
+ }
6172
+ function parseFalVideoOutput(raw) {
6173
+ const obj = raw ?? {};
6174
+ const video = obj.video && typeof obj.video === "object" ? obj.video : void 0;
6175
+ if (!video || typeof video.url !== "string" || video.url.length === 0) return null;
6176
+ return {
6177
+ videoUrl: video.url,
6178
+ ...typeof video.content_type === "string" ? { contentType: video.content_type } : {},
6179
+ ...typeof video.file_size === "number" ? { fileSize: video.file_size } : {}
6180
+ };
6181
+ }
6182
+ function buildFalTagPrompt(prompt) {
6183
+ return prompt.toLowerCase().split(/[,\s]+/).filter((word) => word.length > 3).slice(0, 5).join(", ");
6184
+ }
6185
+ function buildFalAudioLyrics(input) {
6186
+ if (input.instrumental) return "[inst]";
6187
+ const lyrics = input.lyrics?.trim();
6188
+ if (!lyrics) return void 0;
6189
+ if (lyrics.includes("[verse]") || lyrics.includes("[chorus]")) return lyrics;
6190
+ return `[verse]
6191
+ ${lyrics}
6192
+ [/verse]`;
6193
+ }
6194
+ function buildFalAudioInput(spec, input) {
6195
+ const tags = buildFalTagPrompt(input.prompt);
6196
+ const base = { prompt: tags, duration: input.durationSeconds };
6197
+ if (spec.supportsLyrics) {
6198
+ const lyrics = buildFalAudioLyrics(input);
6199
+ if (lyrics) base.lyrics = lyrics;
6200
+ }
6201
+ if (spec.supportsInstrumental && input.instrumental !== void 0) {
6202
+ base.instrumental = input.instrumental;
6203
+ }
6204
+ return base;
6205
+ }
6206
+ function parseFalAudioOutput(raw) {
6207
+ const obj = raw ?? {};
6208
+ const nested = (key) => {
6209
+ const value = obj[key];
6210
+ if (!value || typeof value !== "object") return void 0;
6211
+ const url = value.url;
6212
+ return typeof url === "string" && url.length > 0 ? url : void 0;
6213
+ };
6214
+ const flat = (key) => {
6215
+ const value = obj[key];
6216
+ return typeof value === "string" && value.length > 0 ? value : void 0;
6217
+ };
6218
+ const audioUrl = nested("audio_url") ?? nested("audio_file") ?? nested("audio") ?? flat("audio_url") ?? flat("audio");
6219
+ if (!audioUrl) return null;
6220
+ return { audioUrl };
6221
+ }
6222
+
5346
6223
  // src/providers/embeddings/openai-embeddings.ts
5347
6224
  var DEFAULT_EMBED_TIMEOUT_MS = 6e4;
5348
6225
  function createOpenAiEmbeddingsAdapter(config) {
@@ -5530,150 +6407,6 @@ function createOpenAiImageAdapter(config) {
5530
6407
  };
5531
6408
  }
5532
6409
 
5533
- // src/providers/adapters/openai-compatible.adapter.ts
5534
- function toWireMessage(message) {
5535
- if (message.role === "tool") {
5536
- return { role: "tool", content: message.content, tool_call_id: message.toolCallId ?? "" };
5537
- }
5538
- if (message.role === "assistant" && message.toolCalls && message.toolCalls.length > 0) {
5539
- return {
5540
- role: "assistant",
5541
- content: message.content,
5542
- tool_calls: message.toolCalls.map((call) => ({
5543
- id: call.id,
5544
- type: "function",
5545
- function: { name: call.name, arguments: call.arguments }
5546
- }))
5547
- };
5548
- }
5549
- if (message.role === "user") return { role: "user", content: message.content };
5550
- return { role: message.role, content: message.content };
5551
- }
5552
- function mergeImages(messages, images) {
5553
- if (images.length === 0) return [...messages];
5554
- const parts = images.map((image) => ({
5555
- type: "image_url",
5556
- image_url: { url: `data:${image.mimeType};base64,${image.dataBase64}` }
5557
- }));
5558
- for (let index = messages.length - 1; index >= 0; index -= 1) {
5559
- const message = messages[index];
5560
- if (message.role !== "user") continue;
5561
- const textParts = typeof message.content === "string" ? message.content.length > 0 ? [{ type: "text", text: message.content }] : [] : message.content;
5562
- return [
5563
- ...messages.slice(0, index),
5564
- { role: "user", content: [...textParts, ...parts] },
5565
- ...messages.slice(index + 1)
5566
- ];
5567
- }
5568
- return [...messages, { role: "user", content: [...parts] }];
5569
- }
5570
- async function extractErrorDetail(response) {
5571
- try {
5572
- const body = await response.json();
5573
- return body.error;
5574
- } catch {
5575
- return void 0;
5576
- }
5577
- }
5578
- async function* parseSseEvent2(rawEvent, toolCallAccumulator) {
5579
- for (const line of rawEvent.split("\n")) {
5580
- if (!line.startsWith("data:")) continue;
5581
- const payload = line.slice(5).trim();
5582
- if (payload.length === 0 || payload === "[DONE]") continue;
5583
- let chunk;
5584
- try {
5585
- chunk = JSON.parse(payload);
5586
- } catch {
5587
- continue;
5588
- }
5589
- const delta = chunk.choices?.[0]?.delta;
5590
- if (delta?.reasoning) {
5591
- yield { type: "delta", channel: "reasoning", text: delta.reasoning };
5592
- }
5593
- if (delta?.content) {
5594
- yield { type: "delta", channel: "answer", text: delta.content };
5595
- }
5596
- if (delta?.tool_calls) {
5597
- for (const toolCallDelta of delta.tool_calls) toolCallAccumulator.push(toolCallDelta);
5598
- }
5599
- if (chunk.usage) {
5600
- yield {
5601
- type: "usage",
5602
- usage: {
5603
- inputTokens: chunk.usage.prompt_tokens ?? 0,
5604
- outputTokens: chunk.usage.completion_tokens ?? 0,
5605
- reasoningTokens: chunk.usage.completion_tokens_details?.reasoning_tokens
5606
- }
5607
- };
5608
- }
5609
- }
5610
- }
5611
- async function* parseSseStream(body) {
5612
- const reader = body.getReader();
5613
- const decoder = new TextDecoder();
5614
- const toolCallAccumulator = new ToolCallAccumulator();
5615
- let buffer = "";
5616
- try {
5617
- while (true) {
5618
- const { done, value } = await reader.read();
5619
- if (done) break;
5620
- buffer += decoder.decode(value, { stream: true });
5621
- let separator = buffer.indexOf("\n\n");
5622
- while (separator !== -1) {
5623
- const rawEvent = buffer.slice(0, separator);
5624
- buffer = buffer.slice(separator + 2);
5625
- separator = buffer.indexOf("\n\n");
5626
- yield* parseSseEvent2(rawEvent, toolCallAccumulator);
5627
- }
5628
- }
5629
- } catch (err) {
5630
- throw errorFromUnknown(err);
5631
- } finally {
5632
- reader.releaseLock();
5633
- }
5634
- const calls = toolCallAccumulator.finish();
5635
- if (calls.length > 0) yield { type: "tool_calls", calls };
5636
- }
5637
- function createOpenAiCompatibleAdapter(config) {
5638
- return {
5639
- async *stream(req) {
5640
- const timeout = AbortSignal.timeout(config.timeoutMs);
5641
- const signal = req.signal ? AbortSignal.any([req.signal, timeout]) : timeout;
5642
- let response;
5643
- try {
5644
- response = await fetch(`${config.baseUrl}/chat/completions`, {
5645
- method: "POST",
5646
- headers: {
5647
- Authorization: `Bearer ${config.apiKey}`,
5648
- "Content-Type": "application/json"
5649
- },
5650
- body: JSON.stringify({
5651
- model: req.externalModelId,
5652
- messages: mergeImages(req.messages.map(toWireMessage), req.images ?? []),
5653
- temperature: req.temperature,
5654
- max_completion_tokens: req.maxOutputTokens,
5655
- top_p: req.topP,
5656
- stream: true,
5657
- stream_options: { include_usage: true },
5658
- ...req.tools && req.tools.length > 0 ? {
5659
- tools: req.tools.map((tool) => ({ type: "function", function: tool })),
5660
- tool_choice: "auto"
5661
- } : {}
5662
- }),
5663
- signal
5664
- });
5665
- } catch (err) {
5666
- throw errorFromUnknown(err);
5667
- }
5668
- if (!response.ok || !response.body) {
5669
- const detail = await extractErrorDetail(response);
5670
- throw errorFromStatus(response.status, detail?.message, detail);
5671
- }
5672
- yield* parseSseStream(response.body);
5673
- }
5674
- };
5675
- }
5676
-
5677
6410
  // src/providers/adapters/anthropic.adapter.ts
5678
6411
  var ANTHROPIC_VERSION = "2023-06-01";
5679
6412
  var ERROR_TYPE_TO_CODE = {
@@ -5694,7 +6427,7 @@ function mergeImages2(messages, images) {
5694
6427
  }));
5695
6428
  for (let index = messages.length - 1; index >= 0; index -= 1) {
5696
6429
  const message = messages[index];
5697
- if (message.role !== "user") continue;
6430
+ if (!message || message.role !== "user") continue;
5698
6431
  const textBlocks = typeof message.content === "string" ? message.content.length > 0 ? [{ type: "text", text: message.content }] : [] : message.content;
5699
6432
  return [
5700
6433
  ...messages.slice(0, index),
@@ -5810,7 +6543,7 @@ function createAnthropicAdapter(config) {
5810
6543
  model: req.externalModelId,
5811
6544
  messages,
5812
6545
  ...system.length > 0 ? { system } : {},
5813
- max_tokens: req.maxOutputTokens,
6546
+ max_tokens: req.maxOutputTokens ?? 4096,
5814
6547
  stream: true
5815
6548
  }),
5816
6549
  signal
@@ -5827,6 +6560,170 @@ function createAnthropicAdapter(config) {
5827
6560
  };
5828
6561
  }
5829
6562
 
6563
+ // src/providers/adapters/adapter-resolver.ts
6564
+ var ADAPTER_TIMEOUT_MS = 6e4;
6565
+ var ADAPTER_MEDIA_TIMEOUT_MS = 12e4;
6566
+ function resolveApiKey(env, apiKeyEnv) {
6567
+ const value = env[apiKeyEnv];
6568
+ if (typeof value !== "string" || value.trim().length === 0) {
6569
+ throw new AiError("missing_key");
6570
+ }
6571
+ return value.trim();
6572
+ }
6573
+ function apiKeyAvailable(env, apiKeyEnv) {
6574
+ try {
6575
+ resolveApiKey(env, apiKeyEnv);
6576
+ return true;
6577
+ } catch {
6578
+ return false;
6579
+ }
6580
+ }
6581
+ function normalizeBaseUrl(url) {
6582
+ return url.replace(/\/$/, "");
6583
+ }
6584
+ function openAiApiKey(binding, capability) {
6585
+ if (binding.adapter !== "openai-compatible") {
6586
+ throw new AiError(
6587
+ "model_unavailable",
6588
+ `Adapter kind does not support ${capability}: ${binding.adapter}`
6589
+ );
6590
+ }
6591
+ return binding.apiKey;
6592
+ }
6593
+ function chatAdapterFor(binding, timing = {}) {
6594
+ const timeoutMs = timing.timeoutMs ?? ADAPTER_TIMEOUT_MS;
6595
+ if (binding.adapter === "openai-compatible") {
6596
+ return createOpenAiCompatibleAdapter({
6597
+ baseUrl: normalizeBaseUrl(binding.baseUrl),
6598
+ apiKey: binding.apiKey,
6599
+ timeoutMs
6600
+ });
6601
+ }
6602
+ if (binding.adapter === "anthropic") {
6603
+ return createAnthropicAdapter({
6604
+ baseUrl: normalizeBaseUrl(binding.baseUrl),
6605
+ apiKey: binding.apiKey,
6606
+ timeoutMs
6607
+ });
6608
+ }
6609
+ throw new AiError("model_unavailable", `Unsupported adapter kind: ${binding.adapter}`);
6610
+ }
6611
+ function imageAdapterFor(binding, timing = {}) {
6612
+ return createOpenAiImageAdapter({
6613
+ baseUrl: normalizeBaseUrl(binding.baseUrl),
6614
+ apiKey: openAiApiKey(binding, "images"),
6615
+ timeoutMs: timing.mediaTimeoutMs ?? ADAPTER_MEDIA_TIMEOUT_MS
6616
+ });
6617
+ }
6618
+ function embeddingsAdapterFor(binding, timing = {}) {
6619
+ return createOpenAiEmbeddingsAdapter({
6620
+ baseUrl: normalizeBaseUrl(binding.baseUrl),
6621
+ apiKey: openAiApiKey(binding, "embeddings"),
6622
+ timeoutMs: timing.timeoutMs ?? ADAPTER_TIMEOUT_MS
6623
+ });
6624
+ }
6625
+ function audioTranscriptionAdapterFor(binding, timing = {}) {
6626
+ return createOpenAiAudioTranscriptionAdapter({
6627
+ baseUrl: normalizeBaseUrl(binding.baseUrl),
6628
+ apiKey: openAiApiKey(binding, "audio transcription"),
6629
+ timeoutMs: timing.timeoutMs ?? ADAPTER_TIMEOUT_MS
6630
+ });
6631
+ }
6632
+ function speechAdapterFor(binding, timing = {}) {
6633
+ return createOpenAiSpeechAdapter({
6634
+ baseUrl: normalizeBaseUrl(binding.baseUrl),
6635
+ apiKey: openAiApiKey(binding, "speech synthesis"),
6636
+ timeoutMs: timing.mediaTimeoutMs ?? ADAPTER_MEDIA_TIMEOUT_MS
6637
+ });
6638
+ }
6639
+ function createAdapterResolver(env, timing = {}) {
6640
+ const toProviderBinding = (binding) => ({
6641
+ adapter: binding.adapter,
6642
+ baseUrl: binding.baseUrl,
6643
+ apiKey: resolveApiKey(env, binding.apiKeyEnv)
6644
+ });
6645
+ return {
6646
+ chat: (binding) => chatAdapterFor(toProviderBinding(binding), timing),
6647
+ image: (binding) => imageAdapterFor(toProviderBinding(binding), timing),
6648
+ embeddings: (binding) => embeddingsAdapterFor(toProviderBinding(binding), timing),
6649
+ audioTranscription: (binding) => audioTranscriptionAdapterFor(toProviderBinding(binding), timing),
6650
+ speech: (binding) => speechAdapterFor(toProviderBinding(binding), timing),
6651
+ available: (binding) => apiKeyAvailable(env, binding.apiKeyEnv)
6652
+ };
6653
+ }
6654
+
6655
+ // src/providers/execution/run-conversation.ts
6656
+ async function* runConversation(input) {
6657
+ const tools = input.tools && input.tools.length > 0 ? { tools: input.tools } : {};
6658
+ const images = input.images && input.images.length > 0 ? { images: input.images } : {};
6659
+ for (const [index, attempt] of input.attempts.entries()) {
6660
+ let answer = "";
6661
+ let reasoning = "";
6662
+ let usage = null;
6663
+ let toolCalls = [];
6664
+ const startedAt = Date.now();
6665
+ const context = buildContext(input.history, input.systemPrompt, {
6666
+ contextWindow: attempt.model.contextWindow,
6667
+ // No explicit output reservation → keep the whole window for input.
6668
+ maxOutputTokens: attempt.settings.maxOutputTokens ?? 0
6669
+ });
6670
+ yield { type: "attempt", index };
6671
+ try {
6672
+ for await (const event of attempt.adapter.stream({
6673
+ externalModelId: attempt.model.externalModelId,
6674
+ messages: context,
6675
+ temperature: attempt.settings.temperature,
6676
+ maxOutputTokens: attempt.settings.maxOutputTokens,
6677
+ topP: attempt.settings.topP,
6678
+ ...tools,
6679
+ ...images,
6680
+ signal: input.signal
6681
+ })) {
6682
+ if (event.type === "delta") {
6683
+ if (event.channel === "reasoning") reasoning += event.text;
6684
+ else answer += event.text;
6685
+ yield { type: "delta", channel: event.channel, text: event.text };
6686
+ } else if (event.type === "tool_calls") {
6687
+ toolCalls = [...event.calls];
6688
+ } else {
6689
+ usage = event.usage;
6690
+ }
6691
+ }
6692
+ } catch (err) {
6693
+ const result2 = {
6694
+ answer,
6695
+ reasoning,
6696
+ usage,
6697
+ toolCalls,
6698
+ durationMs: Date.now() - startedAt
6699
+ };
6700
+ if (input.signal?.aborted === true) {
6701
+ yield { type: "stopped", result: result2 };
6702
+ return;
6703
+ }
6704
+ if (index + 1 < input.attempts.length && canFailover(err, answer.length + reasoning.length)) {
6705
+ continue;
6706
+ }
6707
+ const aiError = err instanceof AiError ? err : errorFromUnknown(err);
6708
+ yield { type: "failed", code: aiError.code, message: aiError.userMessage, result: result2 };
6709
+ return;
6710
+ }
6711
+ const result = {
6712
+ answer,
6713
+ reasoning,
6714
+ usage,
6715
+ toolCalls,
6716
+ durationMs: Date.now() - startedAt
6717
+ };
6718
+ if (toolCalls.length > 0 && input.tools && input.tools.length > 0) {
6719
+ yield { type: "tool_calls", result };
6720
+ return;
6721
+ }
6722
+ yield { type: "done", result };
6723
+ return;
6724
+ }
6725
+ }
6726
+
5830
6727
  // src/content/domain/calculations/ContentCreditCost.ts
5831
6728
  var CREDIT_COSTS = {
5832
6729
  "text-to-image": { standard: 1, hd: 2, "4k": 4 },
@@ -6461,7 +7358,7 @@ async function batchRequest(requests, options = {}) {
6461
7358
  errors.push(result.reason);
6462
7359
  if (stopOnError) {
6463
7360
  throw new Error(
6464
- `Batch request failed: ${errors[0].message}`
7361
+ `Batch request failed: ${errors[0]?.message}`
6465
7362
  );
6466
7363
  }
6467
7364
  }
@@ -6923,7 +7820,7 @@ function safeJSONParse(text, fallback, onError) {
6923
7820
  }
6924
7821
  if (error instanceof SyntaxError) {
6925
7822
  const positionMatch = error.message.match(/position (\d+)/);
6926
- const position = positionMatch ? parseInt(positionMatch[1], 10) : -1;
7823
+ const position = positionMatch ? parseInt(positionMatch[1] ?? "", 10) : -1;
6927
7824
  if (position > 0) {
6928
7825
  const context = text.substring(Math.max(0, position - 50), position + 50);
6929
7826
  onError?.(`JSON parse error at position ${position}: "${context}"`);
@@ -7422,9 +8319,12 @@ function buildVideoRequest(data) {
7422
8319
  }
7423
8320
 
7424
8321
  exports.ABTestService = ABTestService;
8322
+ exports.ADAPTER_MEDIA_TIMEOUT_MS = ADAPTER_MEDIA_TIMEOUT_MS;
8323
+ exports.ADAPTER_TIMEOUT_MS = ADAPTER_TIMEOUT_MS;
7425
8324
  exports.AIContentService = AIContentService;
7426
8325
  exports.AIError = AIError;
7427
8326
  exports.AIErrorType = AIErrorType;
8327
+ exports.AI_ERROR_STATUS = AI_ERROR_STATUS;
7428
8328
  exports.ANTHROPIC_API_VERSION = ANTHROPIC_API_VERSION;
7429
8329
  exports.ANTHROPIC_DEFAULT_MAX_TOKENS = ANTHROPIC_DEFAULT_MAX_TOKENS;
7430
8330
  exports.ANTHROPIC_MODELS = ANTHROPIC_MODELS;
@@ -7470,7 +8370,9 @@ exports.DEFAULT_RETRY_MAX_DELAY_MS = DEFAULT_RETRY_MAX_DELAY_MS;
7470
8370
  exports.DEFAULT_TASK_POLICIES = DEFAULT_TASK_POLICIES;
7471
8371
  exports.DebounceManager = DebounceManager;
7472
8372
  exports.DedupeExecutor = DedupeExecutor;
8373
+ exports.FAL_ASPECT_IMAGE_SIZES = FAL_ASPECT_IMAGE_SIZES;
7473
8374
  exports.FalProvider = FalProvider;
8375
+ exports.FalQueueError = FalQueueError;
7474
8376
  exports.GEMINI_TIERS = GEMINI_TIERS;
7475
8377
  exports.GENERATION_BOUNDS = GENERATION_BOUNDS;
7476
8378
  exports.GENERATION_COSTS = CREDIT_COSTS;
@@ -7501,6 +8403,7 @@ exports.MEMORY_TOTAL_LIMIT = MEMORY_TOTAL_LIMIT;
7501
8403
  exports.MICROS_PER_UNIT = MICROS_PER_UNIT;
7502
8404
  exports.MOTION_OPTIONS = MOTION_OPTIONS;
7503
8405
  exports.MediaGenerationService = MediaGenerationService;
8406
+ exports.OpenAiCompatibleProvider = OpenAiCompatibleProvider;
7504
8407
  exports.PromptBuilder = PromptBuilder;
7505
8408
  exports.ProviderError = ProviderError;
7506
8409
  exports.ProviderFactory = ProviderFactory;
@@ -7549,21 +8452,34 @@ exports.VIDEO_QUALITY_VALUES = VIDEO_QUALITY_VALUES;
7549
8452
  exports.VIDEO_WIZARD_STEPS = VIDEO_WIZARD_STEPS;
7550
8453
  exports.ValidationError = ValidationError2;
7551
8454
  exports.VideoScriptService = VideoScriptService;
8455
+ exports.WORKERS_AI_LLM_MODEL = WORKERS_AI_LLM_MODEL;
8456
+ exports.WORKERS_AI_TIERS = WORKERS_AI_TIERS;
8457
+ exports.WorkersAIError = WorkersAIError;
8458
+ exports.WorkersAIProvider = WorkersAIProvider;
7552
8459
  exports.accumulateReport = accumulateReport;
7553
8460
  exports.aiErrorMessage = aiErrorMessage;
8461
+ exports.aiErrorStatus = aiErrorStatus;
8462
+ exports.apiKeyAvailable = apiKeyAvailable;
7554
8463
  exports.asObjectArray = asObjectArray;
7555
8464
  exports.asRecord = asRecord;
7556
8465
  exports.asStringArray = asStringArray;
7557
8466
  exports.asTrimmedOptionalString = asTrimmedOptionalString;
8467
+ exports.audioTranscriptionAdapterFor = audioTranscriptionAdapterFor;
7558
8468
  exports.batchEmbed = batchEmbed;
7559
8469
  exports.batchRequest = batchRequest;
7560
8470
  exports.buildCacheKey = buildCacheKey;
7561
8471
  exports.buildContentRequest = buildContentRequest;
7562
8472
  exports.buildContext = buildContext;
8473
+ exports.buildFalAudioInput = buildFalAudioInput;
8474
+ exports.buildFalAudioLyrics = buildFalAudioLyrics;
8475
+ exports.buildFalImageInput = buildFalImageInput;
8476
+ exports.buildFalTagPrompt = buildFalTagPrompt;
8477
+ exports.buildFalVideoInput = buildFalVideoInput;
7563
8478
  exports.buildHttpStatusFallback = buildHttpStatusFallback;
7564
8479
  exports.buildImageRequest = buildImageRequest;
7565
8480
  exports.buildResearchMessages = buildResearchMessages;
7566
8481
  exports.buildSystemPrompt = buildSystemPrompt;
8482
+ exports.buildUsageDailySeries = buildUsageDailySeries;
7567
8483
  exports.buildUsageData = buildUsageData;
7568
8484
  exports.buildVideoRequest = buildVideoRequest;
7569
8485
  exports.cacheManager = cacheManager;
@@ -7574,6 +8490,7 @@ exports.calculateTrailingDelay = calculateTrailingDelay;
7574
8490
  exports.canFailover = canFailover;
7575
8491
  exports.canStartTask = canStartTask;
7576
8492
  exports.capText = capText;
8493
+ exports.chatAdapterFor = chatAdapterFor;
7577
8494
  exports.chatIdGenerator = chatIdGenerator;
7578
8495
  exports.chunkText = chunkText;
7579
8496
  exports.clampScore = clampScore;
@@ -7585,22 +8502,27 @@ exports.consumeGroqStream = consumeGroqStream;
7585
8502
  exports.cosineSimilarity = cosineSimilarity;
7586
8503
  exports.countChanges = countChanges;
7587
8504
  exports.createAI = createAI;
8505
+ exports.createAdapterResolver = createAdapterResolver;
7588
8506
  exports.createAnthropicAdapter = createAnthropicAdapter;
7589
8507
  exports.createAssistantMessage = createAssistantMessage;
7590
8508
  exports.createFalProvider = createFalProvider;
8509
+ exports.createFalQueue = createFalQueue;
7591
8510
  exports.createGeminiProvider = createGeminiProvider;
7592
8511
  exports.createGroqProvider = createGroqProvider;
7593
8512
  exports.createMessage = createMessage;
7594
8513
  exports.createOpenAiAudioTranscriptionAdapter = createOpenAiAudioTranscriptionAdapter;
7595
8514
  exports.createOpenAiCompatibleAdapter = createOpenAiCompatibleAdapter;
8515
+ exports.createOpenAiCompatibleProvider = createOpenAiCompatibleProvider;
7596
8516
  exports.createOpenAiEmbeddingsAdapter = createOpenAiEmbeddingsAdapter;
7597
8517
  exports.createOpenAiImageAdapter = createOpenAiImageAdapter;
7598
8518
  exports.createOpenAiSpeechAdapter = createOpenAiSpeechAdapter;
7599
8519
  exports.createProviderFactory = createProviderFactory;
7600
8520
  exports.createPrunaProvider = createPrunaProvider;
8521
+ exports.createRemoteChatClient = createRemoteChatClient;
7601
8522
  exports.createSseResponse = createSseResponse;
7602
8523
  exports.createSystemMessage = createSystemMessage;
7603
8524
  exports.createUserMessage = createUserMessage;
8525
+ exports.createWorkersAIProvider = createWorkersAIProvider;
7604
8526
  exports.debounce = debounce;
7605
8527
  exports.debounceManager = debounceManager;
7606
8528
  exports.defaultEffortForModel = defaultEffortForModel;
@@ -7609,8 +8531,10 @@ exports.deriveSnippetTitle = deriveSnippetTitle;
7609
8531
  exports.describeAIErrorType = describeAIErrorType;
7610
8532
  exports.diffLines = diffLines;
7611
8533
  exports.dotProduct = dotProduct;
8534
+ exports.embeddingsAdapterFor = embeddingsAdapterFor;
7612
8535
  exports.errorFromStatus = errorFromStatus;
7613
8536
  exports.errorFromUnknown = errorFromUnknown;
8537
+ exports.errorRatePct = errorRatePct;
7614
8538
  exports.estimateMessageTokens = estimateMessageTokens;
7615
8539
  exports.estimateTokens = estimateTokens;
7616
8540
  exports.extractContentFromSsePayload = extractContentFromSsePayload;
@@ -7626,6 +8550,7 @@ exports.extractText = extractText;
7626
8550
  exports.extractTextFromMessages = extractTextFromMessages;
7627
8551
  exports.extractTokenUsage = extractTokenUsage;
7628
8552
  exports.failoverCandidate = failoverCandidate;
8553
+ exports.falQueueConfigured = falQueueConfigured;
7629
8554
  exports.findTopKSimilar = findTopKSimilar;
7630
8555
  exports.formatCost = formatCost;
7631
8556
  exports.formatErrorForLogging = formatErrorForLogging;
@@ -7638,6 +8563,7 @@ exports.generateWithPruna = generateWithPruna;
7638
8563
  exports.getDimensionsForAspectRatio = getDimensionsForAspectRatio;
7639
8564
  exports.getProvider = getProvider;
7640
8565
  exports.getRecommendedQuality = getRecommendedQuality;
8566
+ exports.imageAdapterFor = imageAdapterFor;
7641
8567
  exports.isAuthErrorType = isAuthErrorType;
7642
8568
  exports.isMediaProvider = isMediaProvider;
7643
8569
  exports.isRetryableErrorType = isRetryableErrorType;
@@ -7660,6 +8586,9 @@ exports.normalizeSources = normalizeSources;
7660
8586
  exports.normalizeSseChunk = normalizeSseChunk;
7661
8587
  exports.oneOfCatalog = oneOfCatalog;
7662
8588
  exports.parseAIResponse = parseAIResponse;
8589
+ exports.parseFalAudioOutput = parseFalAudioOutput;
8590
+ exports.parseFalImageOutput = parseFalImageOutput;
8591
+ exports.parseFalVideoOutput = parseFalVideoOutput;
7663
8592
  exports.parseSseEvent = parseSseEvent;
7664
8593
  exports.planTaskFailure = planTaskFailure;
7665
8594
  exports.pollForResult = pollForResult;
@@ -7671,25 +8600,34 @@ exports.requestDeduplicator = requestDeduplicator;
7671
8600
  exports.requestQueue = requestQueue;
7672
8601
  exports.requestStructuredJson = requestStructuredJson;
7673
8602
  exports.resetProvider = resetProvider;
8603
+ exports.resolveApiKey = resolveApiKey;
7674
8604
  exports.resolveModel = resolveModel;
7675
8605
  exports.resolveUserFriendlyErrorMessage = resolveUserFriendlyErrorMessage;
7676
8606
  exports.resolveUserFriendlyMessage = resolveUserFriendlyMessage;
7677
8607
  exports.retryManager = retryManager;
8608
+ exports.runConversation = runConversation;
8609
+ exports.runWorkersAIText = runWorkersAIText;
7678
8610
  exports.safeJSONParse = safeJSONParse;
7679
8611
  exports.searchWeb = searchWeb;
7680
8612
  exports.selectLeastRecentlyUsedKey = selectLeastRecentlyUsedKey;
7681
8613
  exports.selectMemories = selectMemories;
7682
8614
  exports.shouldCallOnLeadingEdge = shouldCallOnLeadingEdge;
8615
+ exports.speakWithWorkersAI = speakWithWorkersAI;
8616
+ exports.speechAdapterFor = speechAdapterFor;
7683
8617
  exports.splitMarkdown = splitMarkdown;
7684
8618
  exports.splitSseLines = splitSseLines;
7685
8619
  exports.sseStreamResponse = sseStreamResponse;
8620
+ exports.streamWorkersAIText = streamWorkersAIText;
7686
8621
  exports.submitPrediction = submitPrediction;
7687
8622
  exports.throttle = throttle;
7688
8623
  exports.throttleManager = throttleManager;
7689
8624
  exports.toGroqMessages = toGroqMessages;
7690
8625
  exports.uploadImage = uploadImage;
8626
+ exports.usageTrendOf = usageTrendOf;
8627
+ exports.usageWindowTotals = usageWindowTotals;
7691
8628
  exports.validateApiKey = validateApiKey;
7692
8629
  exports.validateToolArgs = validateToolArgs;
7693
8630
  exports.withRetry = withRetry;
8631
+ exports.workersAIConfigured = workersAIConfigured;
7694
8632
  //# sourceMappingURL=index.cjs.map
7695
8633
  //# sourceMappingURL=index.cjs.map