@adaptic/lumic-utils 1.0.23 → 1.0.24

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 (35) hide show
  1. package/dist/{apollo-client.client-DrSy1wz-.js → apollo-client.client-9wJcufhf.js} +4 -4
  2. package/dist/{apollo-client.client-DrSy1wz-.js.map → apollo-client.client-9wJcufhf.js.map} +1 -1
  3. package/dist/{apollo-client.client-FeVPHV0i.js → apollo-client.client-CyxU1hTu.js} +3 -3
  4. package/dist/{apollo-client.client-FeVPHV0i.js.map → apollo-client.client-CyxU1hTu.js.map} +1 -1
  5. package/dist/{apollo-client.server-CJ6iRLa2.js → apollo-client.server-CbagxkmK.js} +3 -3
  6. package/dist/{apollo-client.server-CJ6iRLa2.js.map → apollo-client.server-CbagxkmK.js.map} +1 -1
  7. package/dist/{apollo-client.server-BEGHAF48.js → apollo-client.server-DB3jLbBx.js} +3 -3
  8. package/dist/{apollo-client.server-BEGHAF48.js.map → apollo-client.server-DB3jLbBx.js.map} +1 -1
  9. package/dist/{index-Dz0wKyTF.js → index-B4yVKGNR.js} +2 -2
  10. package/dist/{index-Dz0wKyTF.js.map → index-B4yVKGNR.js.map} +1 -1
  11. package/dist/{index-vRskhk1H.js → index-CL79JTWc.js} +2 -2
  12. package/dist/{index-vRskhk1H.js.map → index-CL79JTWc.js.map} +1 -1
  13. package/dist/{index-CWoI2dXN.js → index-EMQ1uJMh.js} +365 -274
  14. package/dist/{index-WGzi__C5.js.map → index-EMQ1uJMh.js.map} +1 -1
  15. package/dist/{index-WGzi__C5.js → index-KzQOh2uu.js} +365 -274
  16. package/dist/{index-CWoI2dXN.js.map → index-KzQOh2uu.js.map} +1 -1
  17. package/dist/index.cjs +1 -1
  18. package/dist/index.mjs +1 -1
  19. package/dist/test.cjs +21 -17
  20. package/dist/test.cjs.map +1 -1
  21. package/dist/test.mjs +21 -17
  22. package/dist/test.mjs.map +1 -1
  23. package/dist/types/functions/get-weather.d.ts +1 -1
  24. package/dist/types/functions/google-sheets.d.ts +2 -2
  25. package/dist/types/functions/json-llm-tools.d.ts +1 -1
  26. package/dist/types/functions/llm-anthropic.d.ts +1 -1
  27. package/dist/types/functions/llm-deepseek.d.ts +2 -2
  28. package/dist/types/functions/llm-openai-compatible.d.ts +2 -2
  29. package/dist/types/functions/llm-openai.d.ts +3 -3
  30. package/dist/types/functions/llm-utils.d.ts +1 -1
  31. package/dist/types/test-llm-functions-archive.d.ts +1 -1
  32. package/dist/types/test.d.ts +1 -1
  33. package/dist/types/types/openai-types.d.ts +10 -1
  34. package/dist/types/utils/aws-initialise.d.ts +4 -4
  35. package/package.json +2 -2
@@ -551,10 +551,19 @@ function getModelProvider(model) {
551
551
  return SUPPORTED_MODELS[model].provider;
552
552
  }
553
553
  /**
554
- * Default model tiers per provider for use with LLM_MODEL_MINI/NORMAL/ADVANCED env vars
554
+ * Default model tiers per provider for use with LLM_MODEL_MINI/NORMAL/ADVANCED env vars.
555
+ *
556
+ * OpenAI `advanced` was reverted from `gpt-5.5` back to `gpt-5.4` on 2026-05-30:
557
+ * the heavy tool-call prompt in adaptic-engine's trading-decision path was
558
+ * timing out even after the engine raised `LLM_CALL_TIMEOUT_MS` to 90s (5+
559
+ * tickers per loop still exceeded the budget). `gpt-5.5`'s 1M-context window
560
+ * is not required on that path — the prompt fits comfortably inside `gpt-5.4`'s
561
+ * envelope and `gpt-5.4` returns inside the original 25-30s p95. `gpt-5.5`
562
+ * remains registered in OPENAI_MODELS and reachable by explicit model id;
563
+ * only the `advanced` tier default is rolled back.
555
564
  */
556
565
  const PROVIDER_DEFAULT_MODELS = {
557
- openai: { mini: 'gpt-5.4-nano', normal: 'gpt-5.4-mini', advanced: 'gpt-5.5' },
566
+ openai: { mini: 'gpt-5.4-nano', normal: 'gpt-5.4-mini', advanced: 'gpt-5.4' },
558
567
  anthropic: { mini: 'claude-haiku-4-5', normal: 'claude-sonnet-4-6', advanced: 'claude-opus-4-7' },
559
568
  deepseek: { mini: 'deepseek-v4-flash', normal: 'deepseek-v4-flash', advanced: 'deepseek-v4-pro' },
560
569
  kimi: { mini: 'kimi-k2-0905-preview', normal: 'kimi-k2.5', advanced: 'kimi-k2.6' },
@@ -1508,11 +1517,13 @@ let openai;
1508
1517
  function initializeOpenAI(apiKey) {
1509
1518
  const key = apiKey || getSecrets().openai.apiKey;
1510
1519
  if (!key) {
1511
- throw new Error('OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set');
1520
+ throw new Error("OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set");
1512
1521
  }
1513
1522
  return new OpenAI({
1514
1523
  apiKey: key,
1515
- defaultHeaders: { 'User-Agent': 'My Server-side Application (compatible; OpenAI API Client)' },
1524
+ defaultHeaders: {
1525
+ "User-Agent": "My Server-side Application (compatible; OpenAI API Client)",
1526
+ },
1516
1527
  });
1517
1528
  }
1518
1529
  /**
@@ -1530,9 +1541,7 @@ function initializeOpenAI(apiKey) {
1530
1541
  */
1531
1542
  async function fixJsonWithAI(jsonStr, options) {
1532
1543
  // Backward compatibility: handle string apiKey as first positional param
1533
- const opts = typeof options === 'string'
1534
- ? { apiKey: options }
1535
- : (options ?? {});
1544
+ const opts = typeof options === "string" ? { apiKey: options } : (options ?? {});
1536
1545
  const apiKey = opts.apiKey;
1537
1546
  const maxDepth = opts.maxDepth ?? 2;
1538
1547
  const depth = opts._depth ?? 0;
@@ -1545,18 +1554,18 @@ async function fixJsonWithAI(jsonStr, options) {
1545
1554
  openai = initializeOpenAI(apiKey);
1546
1555
  }
1547
1556
  const completion = await openai.chat.completions.create({
1548
- model: 'gpt-5-mini',
1557
+ model: "gpt-5-mini",
1549
1558
  messages: [
1550
1559
  {
1551
- role: 'system',
1552
- content: 'You are a JSON fixer. Return only valid JSON without any additional text or explanation.'
1560
+ role: "system",
1561
+ content: "You are a JSON fixer. Return only valid JSON without any additional text or explanation.",
1553
1562
  },
1554
1563
  {
1555
- role: 'user',
1556
- content: `Fix this broken JSON:\n${jsonStr}`
1557
- }
1564
+ role: "user",
1565
+ content: `Fix this broken JSON:\n${jsonStr}`,
1566
+ },
1558
1567
  ],
1559
- response_format: { type: 'json_object' }
1568
+ response_format: { type: "json_object" },
1560
1569
  });
1561
1570
  const fixedJson = completion.choices[0]?.message?.content;
1562
1571
  if (fixedJson && isValidJson(fixedJson)) {
@@ -1570,23 +1579,32 @@ async function fixJsonWithAI(jsonStr, options) {
1570
1579
  _depth: depth + 1,
1571
1580
  });
1572
1581
  }
1573
- throw new JsonParseError('Failed to fix JSON with AI: returned invalid JSON');
1582
+ throw new JsonParseError("Failed to fix JSON with AI: returned invalid JSON");
1574
1583
  }
1575
1584
  catch (err) {
1576
1585
  // Re-throw JsonParseError as-is (e.g. max depth exceeded)
1577
1586
  if (err instanceof JsonParseError) {
1578
1587
  throw err;
1579
1588
  }
1580
- const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
1589
+ const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
1581
1590
  throw new JsonParseError(`Error fixing JSON with AI: ${errorMessage}`);
1582
1591
  }
1583
1592
  }
1584
1593
 
1585
1594
  // llm-utils.ts
1586
1595
  function normalizeModelName(model) {
1587
- return model.replace(/_/g, '-').toLowerCase();
1588
- }
1589
- const CODE_BLOCK_TYPES = ['javascript', 'js', 'graphql', 'json', 'typescript', 'python', 'markdown', 'yaml'];
1596
+ return model.replace(/_/g, "-").toLowerCase();
1597
+ }
1598
+ const CODE_BLOCK_TYPES = [
1599
+ "javascript",
1600
+ "js",
1601
+ "graphql",
1602
+ "json",
1603
+ "typescript",
1604
+ "python",
1605
+ "markdown",
1606
+ "yaml",
1607
+ ];
1590
1608
  /**
1591
1609
  * Tries to parse JSON from the given content string according to the specified
1592
1610
  * response format. If the response format is 'json' or a JSON schema object, it
@@ -1610,7 +1628,9 @@ async function parseResponse(content, responseFormat, options = {}) {
1610
1628
  if (recursionDepth > maxRetries) {
1611
1629
  throw new Error(`Maximum recursion depth (${maxRetries}) exceeded while parsing JSON. AI fixing may have returned broken JSON.`);
1612
1630
  }
1613
- if (responseFormat === 'json' || (typeof responseFormat === 'object' && responseFormat?.type === 'json_schema')) {
1631
+ if (responseFormat === "json" ||
1632
+ (typeof responseFormat === "object" &&
1633
+ responseFormat?.type === "json_schema")) {
1614
1634
  let cleanedContent = content.trim();
1615
1635
  let detectedType = null;
1616
1636
  // Remove code block markers if present
@@ -1621,8 +1641,8 @@ async function parseResponse(content, responseFormat, options = {}) {
1621
1641
  }
1622
1642
  return false;
1623
1643
  });
1624
- if (startsWithCodeBlock && cleanedContent.endsWith('```')) {
1625
- const firstLineEndIndex = cleanedContent.indexOf('\n');
1644
+ if (startsWithCodeBlock && cleanedContent.endsWith("```")) {
1645
+ const firstLineEndIndex = cleanedContent.indexOf("\n");
1626
1646
  if (firstLineEndIndex !== -1) {
1627
1647
  cleanedContent = cleanedContent.slice(firstLineEndIndex + 1, -3).trim();
1628
1648
  getLumicLogger().info(`Code block for type ${detectedType} detected and removed. Cleaned content: ${cleanedContent}`);
@@ -1655,7 +1675,7 @@ async function parseResponse(content, responseFormat, options = {}) {
1655
1675
  },
1656
1676
  // Strategy 3: Remove leading/trailing text and try parsing
1657
1677
  () => {
1658
- const jsonMatch = cleanedContent.replace(/^[^{[]*|[^}\]]*$/g, '');
1678
+ const jsonMatch = cleanedContent.replace(/^[^{[]*|[^}\]]*$/g, "");
1659
1679
  try {
1660
1680
  return JSON.parse(jsonMatch);
1661
1681
  }
@@ -1677,7 +1697,7 @@ async function parseResponse(content, responseFormat, options = {}) {
1677
1697
  }
1678
1698
  // Strategy 5: Use AI fixing (only if explicitly enabled)
1679
1699
  if (enableAiFix) {
1680
- getLumicLogger().warn('Using AI-powered JSON fixing. This adds cost and latency. Consider improving JSON generation instead.');
1700
+ getLumicLogger().warn("Using AI-powered JSON fixing. This adds cost and latency. Consider improving JSON generation instead.");
1681
1701
  try {
1682
1702
  const aiFixedJson = await fixJsonWithAI(cleanedContent);
1683
1703
  if (aiFixedJson !== null) {
@@ -1690,7 +1710,7 @@ async function parseResponse(content, responseFormat, options = {}) {
1690
1710
  catch {
1691
1711
  // AI returned something that looks like JSON but isn't valid
1692
1712
  // Increment recursion depth and try parsing the AI response
1693
- getLumicLogger().warn('AI fixing returned invalid JSON, attempting recursive parse...');
1713
+ getLumicLogger().warn("AI fixing returned invalid JSON, attempting recursive parse...");
1694
1714
  return parseResponse(JSON.stringify(aiFixedJson), responseFormat, {
1695
1715
  ...options,
1696
1716
  _recursionDepth: recursionDepth + 1,
@@ -1699,14 +1719,14 @@ async function parseResponse(content, responseFormat, options = {}) {
1699
1719
  }
1700
1720
  }
1701
1721
  catch (error) {
1702
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
1722
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
1703
1723
  getLumicLogger().error(`AI JSON fixing failed: ${errorMessage}`);
1704
1724
  // Continue to final error below
1705
1725
  }
1706
1726
  }
1707
1727
  // If all strategies fail, throw an error
1708
1728
  getLumicLogger().error(`Failed to parse JSON from content: ${cleanedContent}. Original JSON: ${content}`);
1709
- throw new Error('Unable to parse JSON response');
1729
+ throw new Error("Unable to parse JSON response");
1710
1730
  }
1711
1731
  else {
1712
1732
  return content;
@@ -2300,13 +2320,15 @@ const isRetryableLLMError = (error) => {
2300
2320
  if (error instanceof Error) {
2301
2321
  const message = error.message;
2302
2322
  // Retry on rate limits (429)
2303
- if (message.includes('429') || message.includes('rate limit') || message.includes('Rate limit')) {
2323
+ if (message.includes("429") ||
2324
+ message.includes("rate limit") ||
2325
+ message.includes("Rate limit")) {
2304
2326
  return true;
2305
2327
  }
2306
2328
  // Retry on transient body-corruption 400s. Match the exact OpenAI error
2307
2329
  // string to avoid retrying genuine client-side validation 400s (which
2308
2330
  // would re-fail forever and waste retry budget).
2309
- if (message.includes('could not parse the JSON body of your request')) {
2331
+ if (message.includes("could not parse the JSON body of your request")) {
2310
2332
  return true;
2311
2333
  }
2312
2334
  }
@@ -2375,23 +2397,26 @@ function isReasoningModel(model) {
2375
2397
  * @throws Error if the response format is invalid or incompatible.
2376
2398
  */
2377
2399
  function getResponseFormatOption(responseFormat, normalizedModel) {
2378
- if (responseFormat === 'text') {
2379
- return { type: 'text' };
2400
+ if (responseFormat === "text") {
2401
+ return { type: "text" };
2380
2402
  }
2381
- if (responseFormat === 'json') {
2382
- return supportsJsonMode(normalizedModel) ? { type: 'json_object' } : { type: 'text' };
2403
+ if (responseFormat === "json") {
2404
+ return supportsJsonMode(normalizedModel)
2405
+ ? { type: "json_object" }
2406
+ : { type: "text" };
2383
2407
  }
2384
- if (typeof responseFormat === 'object' && responseFormat.type === 'json_schema') {
2408
+ if (typeof responseFormat === "object" &&
2409
+ responseFormat.type === "json_schema") {
2385
2410
  if (!isStructuredOutputCompatibleModel(normalizedModel)) {
2386
2411
  throw new Error(`${normalizedModel} is not compatible with structured outputs / json object.`);
2387
2412
  }
2388
2413
  return {
2389
- type: 'json_schema',
2414
+ type: "json_schema",
2390
2415
  json_schema: {
2391
- type: 'object',
2416
+ type: "object",
2392
2417
  properties: responseFormat.schema.properties,
2393
2418
  required: responseFormat.schema.required || [],
2394
- name: 'Response',
2419
+ name: "Response",
2395
2420
  },
2396
2421
  };
2397
2422
  }
@@ -2450,7 +2475,7 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2450
2475
  const normalizedModel = normalizeModelName(options.model || DEFAULT_MODEL);
2451
2476
  const apiKey = options.apiKey || getSecrets().openai.apiKey;
2452
2477
  if (!apiKey) {
2453
- throw new Error('OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set');
2478
+ throw new Error("OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set");
2454
2479
  }
2455
2480
  const openai = new OpenAI({
2456
2481
  apiKey: apiKey,
@@ -2460,7 +2485,7 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2460
2485
  // Add developer prompt if present
2461
2486
  if (options.developerPrompt && supportsDeveloperPrompt(normalizedModel)) {
2462
2487
  messages.push({
2463
- role: 'developer',
2488
+ role: "developer",
2464
2489
  content: options.developerPrompt,
2465
2490
  });
2466
2491
  }
@@ -2469,15 +2494,15 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2469
2494
  messages.push(...options.context);
2470
2495
  }
2471
2496
  // Add user content
2472
- if (typeof content === 'string') {
2497
+ if (typeof content === "string") {
2473
2498
  messages.push({
2474
- role: 'user',
2499
+ role: "user",
2475
2500
  content,
2476
2501
  });
2477
2502
  }
2478
2503
  else {
2479
2504
  messages.push({
2480
- role: 'user',
2505
+ role: "user",
2481
2506
  content,
2482
2507
  });
2483
2508
  }
@@ -2491,7 +2516,8 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2491
2516
  queryOptions.tools = options.tools;
2492
2517
  }
2493
2518
  // Only include temperature if the model supports it
2494
- if (options.temperature !== undefined && supportsTemperature(normalizedModel)) {
2519
+ if (options.temperature !== undefined &&
2520
+ supportsTemperature(normalizedModel)) {
2495
2521
  queryOptions.temperature = options.temperature;
2496
2522
  }
2497
2523
  // Only include max_completion_tokens when specified
@@ -2501,7 +2527,7 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2501
2527
  // Only set response_format when it's not the default 'text' type
2502
2528
  // (sending response_format: {type: 'text'} is redundant and may cause issues)
2503
2529
  const responseFormatOption = getResponseFormatOption(responseFormat, normalizedModel);
2504
- if (responseFormatOption.type !== 'text') {
2530
+ if (responseFormatOption.type !== "text") {
2505
2531
  queryOptions.response_format = responseFormatOption;
2506
2532
  }
2507
2533
  let completion;
@@ -2522,15 +2548,19 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2522
2548
  // for production prompts containing sensitive context.
2523
2549
  const errorMessage = error instanceof Error ? error.message : String(error);
2524
2550
  const totalContentChars = messages.reduce((sum, msg) => {
2525
- if (typeof msg.content === 'string')
2551
+ if (typeof msg.content === "string")
2526
2552
  return sum + msg.content.length;
2527
2553
  if (Array.isArray(msg.content)) {
2528
- return sum + msg.content.reduce((s, part) => {
2529
- if (typeof part === 'object' && part !== null && 'text' in part && typeof part.text === 'string') {
2530
- return s + part.text.length;
2531
- }
2532
- return s;
2533
- }, 0);
2554
+ return (sum +
2555
+ msg.content.reduce((s, part) => {
2556
+ if (typeof part === "object" &&
2557
+ part !== null &&
2558
+ "text" in part &&
2559
+ typeof part.text === "string") {
2560
+ return s + part.text.length;
2561
+ }
2562
+ return s;
2563
+ }, 0));
2534
2564
  }
2535
2565
  return sum;
2536
2566
  }, 0);
@@ -2557,7 +2587,7 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2557
2587
  const cachedTokens = completion.usage?.prompt_tokens_details?.cached_tokens ?? 0;
2558
2588
  const response = {
2559
2589
  id: completion.id,
2560
- content: completion.choices[0]?.message?.content || '',
2590
+ content: completion.choices[0]?.message?.content || "",
2561
2591
  tool_calls: completion.choices[0]?.message?.tool_calls,
2562
2592
  usage: {
2563
2593
  prompt_tokens: completion.usage?.prompt_tokens ?? 0,
@@ -2567,7 +2597,7 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2567
2597
  },
2568
2598
  system_fingerprint: completion.system_fingerprint,
2569
2599
  service_tier: options.service_tier,
2570
- provider: 'openai',
2600
+ provider: "openai",
2571
2601
  model: normalizedModel,
2572
2602
  };
2573
2603
  return response;
@@ -2580,7 +2610,7 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2580
2610
  * @param options The options for the LLM call. Defaults to an empty object.
2581
2611
  * @return A promise that resolves to the response from the LLM.
2582
2612
  */
2583
- const makeOpenAIChatCompletionCall = async (content, responseFormat = 'text', options = {}) => {
2613
+ const makeOpenAIChatCompletionCall = async (content, responseFormat = "text", options = {}) => {
2584
2614
  const mergedOptions = {
2585
2615
  ...DEFAULT_OPTIONS$1,
2586
2616
  ...options,
@@ -2589,7 +2619,7 @@ const makeOpenAIChatCompletionCall = async (content, responseFormat = 'text', op
2589
2619
  // Track cost in the global cost tracker. Pass cached tokens through so the
2590
2620
  // tracker applies the discounted cached-input rate (typically ~50% of the
2591
2621
  // standard input rate) instead of billing every input token at full price.
2592
- getLLMCostTracker().trackUsage('openai', completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens);
2622
+ getLLMCostTracker().trackUsage("openai", completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens);
2593
2623
  // Handle tool calls differently
2594
2624
  if (completion.tool_calls && completion.tool_calls.length > 0) {
2595
2625
  const toolCallResponse = {
@@ -2605,10 +2635,10 @@ const makeOpenAIChatCompletionCall = async (content, responseFormat = 'text', op
2605
2635
  prompt_tokens: completion.usage.prompt_tokens,
2606
2636
  completion_tokens: completion.usage.completion_tokens,
2607
2637
  reasoning_tokens: 0,
2608
- provider: 'openai',
2638
+ provider: "openai",
2609
2639
  model: completion.model,
2610
2640
  cached_tokens: completion.usage.cached_tokens,
2611
- cost: calculateCost('openai', completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens),
2641
+ cost: calculateCost("openai", completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens),
2612
2642
  },
2613
2643
  tool_calls: completion.tool_calls,
2614
2644
  };
@@ -2616,7 +2646,7 @@ const makeOpenAIChatCompletionCall = async (content, responseFormat = 'text', op
2616
2646
  // Handle regular responses
2617
2647
  const parsedResponse = await parseResponse(completion.content, responseFormat);
2618
2648
  if (parsedResponse === null) {
2619
- throw new Error('Failed to parse response');
2649
+ throw new Error("Failed to parse response");
2620
2650
  }
2621
2651
  return {
2622
2652
  response: parsedResponse,
@@ -2624,10 +2654,10 @@ const makeOpenAIChatCompletionCall = async (content, responseFormat = 'text', op
2624
2654
  prompt_tokens: completion.usage.prompt_tokens,
2625
2655
  completion_tokens: completion.usage.completion_tokens,
2626
2656
  reasoning_tokens: 0,
2627
- provider: 'openai',
2657
+ provider: "openai",
2628
2658
  model: completion.model,
2629
2659
  cached_tokens: completion.usage.cached_tokens,
2630
- cost: calculateCost('openai', completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens),
2660
+ cost: calculateCost("openai", completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens),
2631
2661
  },
2632
2662
  tool_calls: completion.tool_calls,
2633
2663
  };
@@ -2662,7 +2692,7 @@ const makeResponsesAPICall = async (input, options = {}) => {
2662
2692
  const normalizedModel = normalizeModelName(options.model || DEFAULT_MODEL);
2663
2693
  const apiKey = options.apiKey || getSecrets().openai.apiKey;
2664
2694
  if (!apiKey) {
2665
- throw new Error('OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set');
2695
+ throw new Error("OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set");
2666
2696
  }
2667
2697
  const openai = new OpenAI({
2668
2698
  apiKey: apiKey,
@@ -2686,20 +2716,20 @@ const makeResponsesAPICall = async (input, options = {}) => {
2686
2716
  // (the equivalent of Chat Completions' `prompt_tokens_details.cached_tokens`).
2687
2717
  const responsesCachedTokens = response.usage?.input_tokens_details?.cached_tokens || 0;
2688
2718
  // Track cost in the global cost tracker
2689
- getLLMCostTracker().trackUsage('openai', normalizedModel, response.usage?.input_tokens || 0, response.usage?.output_tokens || 0, response.usage?.output_tokens_details?.reasoning_tokens || 0, responsesCachedTokens);
2719
+ getLLMCostTracker().trackUsage("openai", normalizedModel, response.usage?.input_tokens || 0, response.usage?.output_tokens || 0, response.usage?.output_tokens_details?.reasoning_tokens || 0, responsesCachedTokens);
2690
2720
  // Extract tool calls from the output
2691
2721
  const toolCalls = response.output
2692
- ?.filter((item) => item.type === 'function_call')
2722
+ ?.filter((item) => item.type === "function_call")
2693
2723
  .map((toolCall) => ({
2694
2724
  id: toolCall.call_id,
2695
- type: 'function',
2725
+ type: "function",
2696
2726
  function: {
2697
2727
  name: toolCall.name,
2698
2728
  arguments: toolCall.arguments,
2699
2729
  },
2700
2730
  }));
2701
2731
  // Extract code interpreter outputs if present
2702
- const codeInterpreterCalls = response.output?.filter((item) => item.type === 'code_interpreter_call');
2732
+ const codeInterpreterCalls = response.output?.filter((item) => item.type === "code_interpreter_call");
2703
2733
  let codeInterpreterOutputs = undefined;
2704
2734
  if (codeInterpreterCalls && codeInterpreterCalls.length > 0) {
2705
2735
  // Each code_interpreter_call has an 'outputs' array property
@@ -2725,32 +2755,34 @@ const makeResponsesAPICall = async (input, options = {}) => {
2725
2755
  prompt_tokens: response.usage?.input_tokens || 0,
2726
2756
  completion_tokens: response.usage?.output_tokens || 0,
2727
2757
  reasoning_tokens: response.usage?.output_tokens_details?.reasoning_tokens || 0,
2728
- provider: 'openai',
2758
+ provider: "openai",
2729
2759
  model: normalizedModel,
2730
2760
  cached_tokens: responsesCachedTokens,
2731
- cost: calculateCost('openai', normalizedModel, response.usage?.input_tokens || 0, response.usage?.output_tokens || 0, response.usage?.output_tokens_details?.reasoning_tokens || 0, responsesCachedTokens),
2761
+ cost: calculateCost("openai", normalizedModel, response.usage?.input_tokens || 0, response.usage?.output_tokens || 0, response.usage?.output_tokens_details?.reasoning_tokens || 0, responsesCachedTokens),
2732
2762
  },
2733
2763
  tool_calls: toolCalls,
2734
- ...(codeInterpreterOutputs ? { code_interpreter_outputs: codeInterpreterOutputs } : {}),
2764
+ ...(codeInterpreterOutputs
2765
+ ? { code_interpreter_outputs: codeInterpreterOutputs }
2766
+ : {}),
2735
2767
  };
2736
2768
  }
2737
2769
  // Extract text content from the response output
2738
2770
  const textContent = response.output
2739
- ?.filter((item) => item.type === 'message')
2771
+ ?.filter((item) => item.type === "message")
2740
2772
  .map((item) => item.content
2741
- .filter((content) => content.type === 'output_text')
2773
+ .filter((content) => content.type === "output_text")
2742
2774
  .map((content) => content.text)
2743
- .join(''))
2744
- .join('') || '';
2775
+ .join(""))
2776
+ .join("") || "";
2745
2777
  // Determine the format for parsing the response
2746
- let parsingFormat = 'text';
2747
- if (requestBody.text?.format?.type === 'json_object') {
2748
- parsingFormat = 'json';
2778
+ let parsingFormat = "text";
2779
+ if (requestBody.text?.format?.type === "json_object") {
2780
+ parsingFormat = "json";
2749
2781
  }
2750
2782
  // Handle regular responses
2751
2783
  const parsedResponse = await parseResponse(textContent, parsingFormat);
2752
2784
  if (parsedResponse === null) {
2753
- throw new Error('Failed to parse response from Responses API');
2785
+ throw new Error("Failed to parse response from Responses API");
2754
2786
  }
2755
2787
  return {
2756
2788
  response: parsedResponse,
@@ -2758,13 +2790,15 @@ const makeResponsesAPICall = async (input, options = {}) => {
2758
2790
  prompt_tokens: response.usage?.input_tokens || 0,
2759
2791
  completion_tokens: response.usage?.output_tokens || 0,
2760
2792
  reasoning_tokens: response.usage?.output_tokens_details?.reasoning_tokens || 0,
2761
- provider: 'openai',
2793
+ provider: "openai",
2762
2794
  model: normalizedModel,
2763
2795
  cached_tokens: responsesCachedTokens,
2764
- cost: calculateCost('openai', normalizedModel, response.usage?.input_tokens || 0, response.usage?.output_tokens || 0, response.usage?.output_tokens_details?.reasoning_tokens || 0, responsesCachedTokens),
2796
+ cost: calculateCost("openai", normalizedModel, response.usage?.input_tokens || 0, response.usage?.output_tokens || 0, response.usage?.output_tokens_details?.reasoning_tokens || 0, responsesCachedTokens),
2765
2797
  },
2766
2798
  tool_calls: toolCalls,
2767
- ...(codeInterpreterOutputs ? { code_interpreter_outputs: codeInterpreterOutputs } : {}),
2799
+ ...(codeInterpreterOutputs
2800
+ ? { code_interpreter_outputs: codeInterpreterOutputs }
2801
+ : {}),
2768
2802
  };
2769
2803
  };
2770
2804
 
@@ -8074,12 +8108,12 @@ function sanitizeObject(obj, sensitiveFields = ['apiKey', 'token', 'secret', 'pa
8074
8108
  const isRetryableAnthropicError = (error) => {
8075
8109
  if (error instanceof Error) {
8076
8110
  const message = error.message;
8077
- if (message.includes('429') ||
8078
- message.includes('500') ||
8079
- message.includes('503') ||
8080
- message.includes('529') ||
8081
- message.includes('rate limit') ||
8082
- message.includes('overloaded')) {
8111
+ if (message.includes("429") ||
8112
+ message.includes("500") ||
8113
+ message.includes("503") ||
8114
+ message.includes("529") ||
8115
+ message.includes("rate limit") ||
8116
+ message.includes("overloaded")) {
8083
8117
  return true;
8084
8118
  }
8085
8119
  }
@@ -8094,8 +8128,11 @@ const isRetryableAnthropicError = (error) => {
8094
8128
  function translateToolsToAnthropic(tools) {
8095
8129
  return tools.map((tool) => ({
8096
8130
  name: tool.function.name,
8097
- description: tool.function.description || '',
8098
- input_schema: (tool.function.parameters || { type: 'object', properties: {} }),
8131
+ description: tool.function.description || "",
8132
+ input_schema: (tool.function.parameters || {
8133
+ type: "object",
8134
+ properties: {},
8135
+ }),
8099
8136
  }));
8100
8137
  }
8101
8138
  /**
@@ -8108,27 +8145,31 @@ function translateContextToAnthropic(context) {
8108
8145
  const systemParts = [];
8109
8146
  const messages = [];
8110
8147
  for (const msg of context) {
8111
- if (msg.role === 'system' || msg.role === 'developer') {
8112
- if (typeof msg.content === 'string') {
8148
+ if (msg.role === "system" || msg.role === "developer") {
8149
+ if (typeof msg.content === "string") {
8113
8150
  systemParts.push(msg.content);
8114
8151
  }
8115
8152
  continue;
8116
8153
  }
8117
- if (msg.role === 'user') {
8118
- const content = typeof msg.content === 'string'
8154
+ if (msg.role === "user") {
8155
+ const content = typeof msg.content === "string"
8119
8156
  ? msg.content
8120
8157
  : JSON.stringify(msg.content);
8121
- messages.push({ role: 'user', content });
8158
+ messages.push({ role: "user", content });
8122
8159
  continue;
8123
8160
  }
8124
- if (msg.role === 'assistant') {
8161
+ if (msg.role === "assistant") {
8125
8162
  const assistantMsg = msg;
8126
8163
  // If the assistant message has tool_calls, translate to Anthropic tool_use blocks
8127
8164
  if (assistantMsg.tool_calls && assistantMsg.tool_calls.length > 0) {
8128
8165
  const contentBlocks = [];
8129
8166
  // Include text content if present
8130
- if (typeof assistantMsg.content === 'string' && assistantMsg.content.trim()) {
8131
- contentBlocks.push({ type: 'text', text: assistantMsg.content });
8167
+ if (typeof assistantMsg.content === "string" &&
8168
+ assistantMsg.content.trim()) {
8169
+ contentBlocks.push({
8170
+ type: "text",
8171
+ text: assistantMsg.content,
8172
+ });
8132
8173
  }
8133
8174
  // Translate each tool_call to a tool_use block
8134
8175
  for (const tc of assistantMsg.tool_calls) {
@@ -8140,32 +8181,36 @@ function translateContextToAnthropic(context) {
8140
8181
  input = { raw: tc.function.arguments };
8141
8182
  }
8142
8183
  contentBlocks.push({
8143
- type: 'tool_use',
8184
+ type: "tool_use",
8144
8185
  id: tc.id,
8145
8186
  name: tc.function.name,
8146
8187
  input,
8147
8188
  });
8148
8189
  }
8149
- messages.push({ role: 'assistant', content: contentBlocks });
8190
+ messages.push({ role: "assistant", content: contentBlocks });
8150
8191
  }
8151
8192
  else {
8152
- const content = typeof assistantMsg.content === 'string'
8193
+ const content = typeof assistantMsg.content === "string"
8153
8194
  ? assistantMsg.content
8154
8195
  : JSON.stringify(assistantMsg.content);
8155
- messages.push({ role: 'assistant', content });
8196
+ messages.push({ role: "assistant", content });
8156
8197
  }
8157
8198
  continue;
8158
8199
  }
8159
- if (msg.role === 'tool') {
8200
+ if (msg.role === "tool") {
8160
8201
  // Anthropic expects tool results as user messages with tool_result content blocks
8161
8202
  const toolMsg = msg;
8162
8203
  messages.push({
8163
- role: 'user',
8164
- content: [{
8165
- type: 'tool_result',
8204
+ role: "user",
8205
+ content: [
8206
+ {
8207
+ type: "tool_result",
8166
8208
  tool_use_id: toolMsg.tool_call_id,
8167
- content: typeof toolMsg.content === 'string' ? toolMsg.content : JSON.stringify(toolMsg.content),
8168
- }],
8209
+ content: typeof toolMsg.content === "string"
8210
+ ? toolMsg.content
8211
+ : JSON.stringify(toolMsg.content),
8212
+ },
8213
+ ],
8169
8214
  });
8170
8215
  continue;
8171
8216
  }
@@ -8186,13 +8231,13 @@ function translateContextToAnthropic(context) {
8186
8231
  merged.push({ role: msg.role, content: toContentBlocks(msg.content) });
8187
8232
  }
8188
8233
  }
8189
- return { messages: merged, systemText: systemParts.join('\n\n') };
8234
+ return { messages: merged, systemText: systemParts.join("\n\n") };
8190
8235
  }
8191
8236
  /** Convert string or content block array to a uniform content block array. */
8192
8237
  function toContentBlocks(content) {
8193
- if (typeof content === 'string') {
8238
+ if (typeof content === "string") {
8194
8239
  const textBlock = {
8195
- type: 'text',
8240
+ type: "text",
8196
8241
  text: content,
8197
8242
  citations: null,
8198
8243
  };
@@ -8212,11 +8257,11 @@ function toContentBlocks(content) {
8212
8257
  * @param options The options for the LLM call.
8213
8258
  * @return A promise that resolves to the response from the Anthropic API.
8214
8259
  */
8215
- async function makeAnthropicCall(content, responseFormat = 'text', options = {}) {
8216
- const model = (options.model || 'claude-sonnet-4-6');
8260
+ async function makeAnthropicCall(content, responseFormat = "text", options = {}) {
8261
+ const model = (options.model || "claude-sonnet-4-6");
8217
8262
  const apiKey = options.apiKey || getSecrets().anthropic.apiKey;
8218
8263
  if (!apiKey) {
8219
- throw new Error('Anthropic API key is not provided and ANTHROPIC_API_KEY environment variable is not set');
8264
+ throw new Error("Anthropic API key is not provided and ANTHROPIC_API_KEY environment variable is not set");
8220
8265
  }
8221
8266
  const client = new Anthropic({
8222
8267
  apiKey,
@@ -8228,8 +8273,10 @@ async function makeAnthropicCall(content, responseFormat = 'text', options = {})
8228
8273
  systemParts.push(options.developerPrompt);
8229
8274
  }
8230
8275
  // If JSON response is requested, instruct the model via system prompt
8231
- if (responseFormat === 'json' || (typeof responseFormat === 'object' && responseFormat.type === 'json_schema')) {
8232
- systemParts.push('You MUST respond with valid JSON only. No markdown, no code blocks, no explanatory text — just the raw JSON object or array.');
8276
+ if (responseFormat === "json" ||
8277
+ (typeof responseFormat === "object" &&
8278
+ responseFormat.type === "json_schema")) {
8279
+ systemParts.push("You MUST respond with valid JSON only. No markdown, no code blocks, no explanatory text — just the raw JSON object or array.");
8233
8280
  }
8234
8281
  // Build messages array
8235
8282
  const messages = [];
@@ -8242,7 +8289,7 @@ async function makeAnthropicCall(content, responseFormat = 'text', options = {})
8242
8289
  messages.push(...translated.messages);
8243
8290
  }
8244
8291
  // Add user content
8245
- messages.push({ role: 'user', content });
8292
+ messages.push({ role: "user", content });
8246
8293
  // Build request params
8247
8294
  const requestParams = {
8248
8295
  model,
@@ -8251,7 +8298,7 @@ async function makeAnthropicCall(content, responseFormat = 'text', options = {})
8251
8298
  };
8252
8299
  // Add system prompt if present
8253
8300
  if (systemParts.length > 0) {
8254
- requestParams.system = systemParts.join('\n\n');
8301
+ requestParams.system = systemParts.join("\n\n");
8255
8302
  }
8256
8303
  // Add temperature if specified
8257
8304
  if (options.temperature !== undefined) {
@@ -8274,14 +8321,14 @@ async function makeAnthropicCall(content, responseFormat = 'text', options = {})
8274
8321
  const inputTokens = response.usage.input_tokens;
8275
8322
  const outputTokens = response.usage.output_tokens;
8276
8323
  // Track cost
8277
- getLLMCostTracker().trackUsage('anthropic', model, inputTokens, outputTokens);
8324
+ getLLMCostTracker().trackUsage("anthropic", model, inputTokens, outputTokens);
8278
8325
  // Extract tool use blocks
8279
- const toolUseBlocks = response.content.filter((block) => block.type === 'tool_use');
8326
+ const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
8280
8327
  if (toolUseBlocks.length > 0) {
8281
8328
  // Translate Anthropic tool_use to OpenAI tool_calls format
8282
8329
  const toolCalls = toolUseBlocks.map((block) => ({
8283
8330
  id: block.id,
8284
- type: 'function',
8331
+ type: "function",
8285
8332
  function: {
8286
8333
  name: block.name,
8287
8334
  arguments: JSON.stringify(block.input),
@@ -8300,22 +8347,22 @@ async function makeAnthropicCall(content, responseFormat = 'text', options = {})
8300
8347
  prompt_tokens: inputTokens,
8301
8348
  completion_tokens: outputTokens,
8302
8349
  reasoning_tokens: 0,
8303
- provider: 'anthropic',
8350
+ provider: "anthropic",
8304
8351
  model,
8305
- cost: calculateCost('anthropic', model, inputTokens, outputTokens),
8352
+ cost: calculateCost("anthropic", model, inputTokens, outputTokens),
8306
8353
  },
8307
8354
  tool_calls: toolCalls,
8308
8355
  };
8309
8356
  }
8310
8357
  // Extract text content
8311
8358
  const textContent = response.content
8312
- .filter((block) => block.type === 'text')
8359
+ .filter((block) => block.type === "text")
8313
8360
  .map((block) => block.text)
8314
- .join('');
8361
+ .join("");
8315
8362
  // Parse response
8316
8363
  const parsedResponse = await parseResponse(textContent, responseFormat);
8317
8364
  if (parsedResponse === null) {
8318
- throw new Error('Failed to parse Anthropic response');
8365
+ throw new Error("Failed to parse Anthropic response");
8319
8366
  }
8320
8367
  return {
8321
8368
  response: parsedResponse,
@@ -8323,9 +8370,9 @@ async function makeAnthropicCall(content, responseFormat = 'text', options = {})
8323
8370
  prompt_tokens: inputTokens,
8324
8371
  completion_tokens: outputTokens,
8325
8372
  reasoning_tokens: 0,
8326
- provider: 'anthropic',
8373
+ provider: "anthropic",
8327
8374
  model,
8328
- cost: calculateCost('anthropic', model, inputTokens, outputTokens),
8375
+ cost: calculateCost("anthropic", model, inputTokens, outputTokens),
8329
8376
  },
8330
8377
  };
8331
8378
  }
@@ -8347,7 +8394,9 @@ async function makeAnthropicCall(content, responseFormat = 'text', options = {})
8347
8394
  const isRetryableError = (error) => {
8348
8395
  if (error instanceof Error) {
8349
8396
  const message = error.message;
8350
- if (message.includes('429') || message.includes('rate limit') || message.includes('Rate limit')) {
8397
+ if (message.includes("429") ||
8398
+ message.includes("rate limit") ||
8399
+ message.includes("Rate limit")) {
8351
8400
  return true;
8352
8401
  }
8353
8402
  }
@@ -8361,14 +8410,16 @@ function resolveApiKey(provider, optionsApiKey) {
8361
8410
  if (optionsApiKey)
8362
8411
  return optionsApiKey;
8363
8412
  const secrets = getSecrets();
8364
- const pathParts = provider.apiKeySecretPath.split('.');
8413
+ const pathParts = provider.apiKeySecretPath.split(".");
8365
8414
  let current = secrets;
8366
8415
  for (const part of pathParts) {
8367
- if (current === null || current === undefined || typeof current !== 'object')
8368
- return '';
8416
+ if (current === null ||
8417
+ current === undefined ||
8418
+ typeof current !== "object")
8419
+ return "";
8369
8420
  current = current[part];
8370
8421
  }
8371
- return (typeof current === 'string' ? current : '') || '';
8422
+ return (typeof current === "string" ? current : "") || "";
8372
8423
  }
8373
8424
  /**
8374
8425
  * Makes a call to an OpenAI-compatible provider (Kimi, Qwen, or any future provider).
@@ -8382,12 +8433,12 @@ function resolveApiKey(provider, optionsApiKey) {
8382
8433
  * @param providerName The provider key in OPENAI_COMPATIBLE_PROVIDERS.
8383
8434
  * @return A promise that resolves to the response from the provider.
8384
8435
  */
8385
- async function makeOpenAICompatibleCall(content, responseFormat = 'text', options = {}, providerName) {
8436
+ async function makeOpenAICompatibleCall(content, responseFormat = "text", options = {}, providerName) {
8386
8437
  const providerConfig = OPENAI_COMPATIBLE_PROVIDERS[providerName];
8387
8438
  if (!providerConfig) {
8388
8439
  throw new Error(`Unknown OpenAI-compatible provider: ${providerName}`);
8389
8440
  }
8390
- const model = normalizeModelName(options.model || '');
8441
+ const model = normalizeModelName(options.model || "");
8391
8442
  const apiKey = resolveApiKey(providerConfig, options.apiKey);
8392
8443
  if (!apiKey) {
8393
8444
  throw new Error(`${providerConfig.name} API key is not provided and ${providerConfig.apiKeyEnvVar} environment variable is not set`);
@@ -8400,31 +8451,36 @@ async function makeOpenAICompatibleCall(content, responseFormat = 'text', option
8400
8451
  const messages = [];
8401
8452
  // Add system message with developer prompt if present
8402
8453
  if (options.developerPrompt) {
8403
- messages.push({ role: 'system', content: options.developerPrompt });
8454
+ messages.push({ role: "system", content: options.developerPrompt });
8404
8455
  }
8405
8456
  // Add context if present
8406
8457
  if (options.context) {
8407
8458
  messages.push(...options.context);
8408
8459
  }
8409
8460
  // Add user content
8410
- if (typeof content === 'string') {
8411
- messages.push({ role: 'user', content });
8461
+ if (typeof content === "string") {
8462
+ messages.push({ role: "user", content });
8412
8463
  }
8413
8464
  else {
8414
- messages.push({ role: 'user', content });
8465
+ messages.push({ role: "user", content });
8415
8466
  }
8416
8467
  // Determine if the model supports JSON mode
8417
8468
  const supportsJson = isValidModel(model) && getModelCapabilities(model).supportsJson;
8418
8469
  // If JSON response format, add hint to system prompt
8419
- if ((responseFormat === 'json' || (typeof responseFormat === 'object' && responseFormat.type === 'json_schema')) &&
8470
+ if ((responseFormat === "json" ||
8471
+ (typeof responseFormat === "object" &&
8472
+ responseFormat.type === "json_schema")) &&
8420
8473
  supportsJson) {
8421
- if (!messages.some((m) => m.role === 'system')) {
8422
- messages.unshift({ role: 'system', content: 'Please respond in valid JSON format.' });
8474
+ if (!messages.some((m) => m.role === "system")) {
8475
+ messages.unshift({
8476
+ role: "system",
8477
+ content: "Please respond in valid JSON format.",
8478
+ });
8423
8479
  }
8424
8480
  else {
8425
- const systemMsgIndex = messages.findIndex((m) => m.role === 'system');
8481
+ const systemMsgIndex = messages.findIndex((m) => m.role === "system");
8426
8482
  const systemMsg = messages[systemMsgIndex];
8427
- if (typeof systemMsg.content === 'string') {
8483
+ if (typeof systemMsg.content === "string") {
8428
8484
  messages[systemMsgIndex] = {
8429
8485
  ...systemMsg,
8430
8486
  content: `${systemMsg.content} Please respond in valid JSON format.`,
@@ -8437,8 +8493,8 @@ async function makeOpenAICompatibleCall(content, responseFormat = 'text', option
8437
8493
  messages,
8438
8494
  };
8439
8495
  // Add response format if JSON is supported
8440
- if (responseFormat !== 'text' && supportsJson) {
8441
- queryOptions.response_format = { type: 'json_object' };
8496
+ if (responseFormat !== "text" && supportsJson) {
8497
+ queryOptions.response_format = { type: "json_object" };
8442
8498
  }
8443
8499
  // Temperature
8444
8500
  if (options.temperature !== undefined) {
@@ -8496,7 +8552,7 @@ async function makeOpenAICompatibleCall(content, responseFormat = 'text', option
8496
8552
  };
8497
8553
  }
8498
8554
  // Handle regular responses
8499
- const textContent = completion.choices[0]?.message?.content || '';
8555
+ const textContent = completion.choices[0]?.message?.content || "";
8500
8556
  const parsedResponse = await parseResponse(textContent, responseFormat);
8501
8557
  if (parsedResponse === null) {
8502
8558
  throw new Error(`Failed to parse ${providerConfig.name} response`);
@@ -8788,7 +8844,9 @@ const isRetryableDeepseekError = (error) => {
8788
8844
  if (error instanceof Error) {
8789
8845
  const message = error.message;
8790
8846
  // Retry only on rate limits (429)
8791
- if (message.includes('429') || message.includes('rate limit') || message.includes('Rate limit')) {
8847
+ if (message.includes("429") ||
8848
+ message.includes("rate limit") ||
8849
+ message.includes("Rate limit")) {
8792
8850
  return true;
8793
8851
  }
8794
8852
  }
@@ -8798,7 +8856,7 @@ const isRetryableDeepseekError = (error) => {
8798
8856
  * Default options for Deepseek API calls
8799
8857
  */
8800
8858
  const DEFAULT_DEEPSEEK_OPTIONS = {
8801
- defaultModel: 'deepseek-chat',
8859
+ defaultModel: "deepseek-chat",
8802
8860
  };
8803
8861
  /**
8804
8862
  * Checks if the given model is a supported Deepseek model
@@ -8810,7 +8868,7 @@ const isSupportedDeepseekModel = (model) => {
8810
8868
  return false;
8811
8869
  }
8812
8870
  const capabilities = getModelCapabilities(model);
8813
- return capabilities.provider === 'deepseek';
8871
+ return capabilities.provider === "deepseek";
8814
8872
  };
8815
8873
  /**
8816
8874
  * Checks if the given Deepseek model supports JSON output format
@@ -8843,17 +8901,19 @@ const supportsToolCalling = (model) => {
8843
8901
  */
8844
8902
  function getDeepseekResponseFormatOption(responseFormat, model) {
8845
8903
  // Check if the model supports JSON output
8846
- if (responseFormat !== 'text' && !supportsJsonOutput(model)) {
8904
+ if (responseFormat !== "text" && !supportsJsonOutput(model)) {
8847
8905
  getLumicLogger().warn(`Model ${model} does not support JSON output. Using text format instead.`);
8848
- return { type: 'text' };
8906
+ return { type: "text" };
8849
8907
  }
8850
- if (responseFormat === 'text') {
8851
- return { type: 'text' };
8908
+ if (responseFormat === "text") {
8909
+ return { type: "text" };
8852
8910
  }
8853
- if (responseFormat === 'json' || (typeof responseFormat === 'object' && responseFormat.type === 'json_schema')) {
8854
- return { type: 'json_object' };
8911
+ if (responseFormat === "json" ||
8912
+ (typeof responseFormat === "object" &&
8913
+ responseFormat.type === "json_schema")) {
8914
+ return { type: "json_object" };
8855
8915
  }
8856
- return { type: 'text' };
8916
+ return { type: "text" };
8857
8917
  }
8858
8918
  /**
8859
8919
  * Creates a completion using the Deepseek API
@@ -8872,24 +8932,26 @@ async function createDeepseekCompletion(content, responseFormat, options = {}) {
8872
8932
  throw new Error(`Unsupported Deepseek model: ${normalizedModel}. Please use 'deepseek-chat' or 'deepseek-reasoner'.`);
8873
8933
  }
8874
8934
  // Check if tools are requested with a model that doesn't support them
8875
- if (options.tools && options.tools.length > 0 && !supportsToolCalling(normalizedModel)) {
8935
+ if (options.tools &&
8936
+ options.tools.length > 0 &&
8937
+ !supportsToolCalling(normalizedModel)) {
8876
8938
  throw new Error(`Model ${normalizedModel} does not support tool calling.`);
8877
8939
  }
8878
8940
  const apiKey = options.apiKey || getSecrets().deepseek.apiKey;
8879
8941
  if (!apiKey) {
8880
- throw new Error('Deepseek API key is not provided and DEEPSEEK_API_KEY environment variable is not set');
8942
+ throw new Error("Deepseek API key is not provided and DEEPSEEK_API_KEY environment variable is not set");
8881
8943
  }
8882
8944
  // Initialize OpenAI client with Deepseek API URL
8883
8945
  const openai = new OpenAI({
8884
8946
  apiKey,
8885
- baseURL: 'https://api.deepseek.com',
8947
+ baseURL: "https://api.deepseek.com",
8886
8948
  timeout: options.timeout ?? LLM_TIMEOUT_MS,
8887
8949
  });
8888
8950
  const messages = [];
8889
8951
  // Add system message with developer prompt if present
8890
8952
  if (options.developerPrompt) {
8891
8953
  messages.push({
8892
- role: 'system',
8954
+ role: "system",
8893
8955
  content: options.developerPrompt,
8894
8956
  });
8895
8957
  }
@@ -8898,33 +8960,35 @@ async function createDeepseekCompletion(content, responseFormat, options = {}) {
8898
8960
  messages.push(...options.context);
8899
8961
  }
8900
8962
  // Add user content
8901
- if (typeof content === 'string') {
8963
+ if (typeof content === "string") {
8902
8964
  messages.push({
8903
- role: 'user',
8965
+ role: "user",
8904
8966
  content,
8905
8967
  });
8906
8968
  }
8907
8969
  else {
8908
8970
  messages.push({
8909
- role: 'user',
8971
+ role: "user",
8910
8972
  content,
8911
8973
  });
8912
8974
  }
8913
8975
  // If JSON response format, include a hint in the system prompt
8914
- if ((responseFormat === 'json' || (typeof responseFormat === 'object' && responseFormat.type === 'json_schema'))
8915
- && supportsJsonOutput(normalizedModel)) {
8976
+ if ((responseFormat === "json" ||
8977
+ (typeof responseFormat === "object" &&
8978
+ responseFormat.type === "json_schema")) &&
8979
+ supportsJsonOutput(normalizedModel)) {
8916
8980
  // If there's no system message yet, add one
8917
- if (!messages.some(m => m.role === 'system')) {
8981
+ if (!messages.some((m) => m.role === "system")) {
8918
8982
  messages.unshift({
8919
- role: 'system',
8920
- content: 'Please respond in valid JSON format.',
8983
+ role: "system",
8984
+ content: "Please respond in valid JSON format.",
8921
8985
  });
8922
8986
  }
8923
8987
  else {
8924
8988
  // Append to existing system message
8925
- const systemMsgIndex = messages.findIndex(m => m.role === 'system');
8989
+ const systemMsgIndex = messages.findIndex((m) => m.role === "system");
8926
8990
  const systemMsg = messages[systemMsgIndex];
8927
- if (typeof systemMsg.content === 'string') {
8991
+ if (typeof systemMsg.content === "string") {
8928
8992
  messages[systemMsgIndex] = {
8929
8993
  ...systemMsg,
8930
8994
  content: `${systemMsg.content} Please respond in valid JSON format.`,
@@ -8965,7 +9029,7 @@ async function createDeepseekCompletion(content, responseFormat, options = {}) {
8965
9029
  0;
8966
9030
  return {
8967
9031
  id: completion.id,
8968
- content: completion.choices[0]?.message?.content || '',
9032
+ content: completion.choices[0]?.message?.content || "",
8969
9033
  tool_calls: completion.choices[0]?.message?.tool_calls,
8970
9034
  usage: {
8971
9035
  prompt_tokens: completion.usage?.prompt_tokens ?? 0,
@@ -8974,7 +9038,7 @@ async function createDeepseekCompletion(content, responseFormat, options = {}) {
8974
9038
  cached_tokens: cachedTokens,
8975
9039
  },
8976
9040
  system_fingerprint: completion.system_fingerprint,
8977
- provider: 'deepseek',
9041
+ provider: "deepseek",
8978
9042
  model: normalizedModel,
8979
9043
  };
8980
9044
  }
@@ -8991,7 +9055,7 @@ async function createDeepseekCompletion(content, responseFormat, options = {}) {
8991
9055
  * @param options Configuration options including model ('deepseek-chat' or 'deepseek-reasoner'), tools, and apiKey.
8992
9056
  * @return A promise that resolves to the response from the Deepseek API.
8993
9057
  */
8994
- const makeDeepseekCall = async (content, responseFormat = 'json', options = {}) => {
9058
+ const makeDeepseekCall = async (content, responseFormat = "json", options = {}) => {
8995
9059
  // Set default model if not provided
8996
9060
  const mergedOptions = {
8997
9061
  ...options,
@@ -9001,17 +9065,17 @@ const makeDeepseekCall = async (content, responseFormat = 'json', options = {})
9001
9065
  }
9002
9066
  const modelName = normalizeModelName(mergedOptions.model);
9003
9067
  // Check if the requested response format is compatible with the model
9004
- if (responseFormat !== 'text' && !supportsJsonOutput(modelName)) {
9068
+ if (responseFormat !== "text" && !supportsJsonOutput(modelName)) {
9005
9069
  getLumicLogger().warn(`Model ${modelName} does not support JSON output. Will return error in the response.`);
9006
9070
  return {
9007
9071
  response: {
9008
- error: `Model ${modelName} does not support JSON output format.`
9072
+ error: `Model ${modelName} does not support JSON output format.`,
9009
9073
  },
9010
9074
  usage: {
9011
9075
  prompt_tokens: 0,
9012
9076
  completion_tokens: 0,
9013
9077
  reasoning_tokens: 0,
9014
- provider: 'deepseek',
9078
+ provider: "deepseek",
9015
9079
  model: modelName,
9016
9080
  cached_tokens: 0,
9017
9081
  cost: 0,
@@ -9020,17 +9084,19 @@ const makeDeepseekCall = async (content, responseFormat = 'json', options = {})
9020
9084
  };
9021
9085
  }
9022
9086
  // Check if tools are requested with a model that doesn't support them
9023
- if (mergedOptions.tools && mergedOptions.tools.length > 0 && !supportsToolCalling(modelName)) {
9087
+ if (mergedOptions.tools &&
9088
+ mergedOptions.tools.length > 0 &&
9089
+ !supportsToolCalling(modelName)) {
9024
9090
  getLumicLogger().warn(`Model ${modelName} does not support tool calling. Will return error in the response.`);
9025
9091
  return {
9026
9092
  response: {
9027
- error: `Model ${modelName} does not support tool calling.`
9093
+ error: `Model ${modelName} does not support tool calling.`,
9028
9094
  },
9029
9095
  usage: {
9030
9096
  prompt_tokens: 0,
9031
9097
  completion_tokens: 0,
9032
9098
  reasoning_tokens: 0,
9033
- provider: 'deepseek',
9099
+ provider: "deepseek",
9034
9100
  model: modelName,
9035
9101
  cached_tokens: 0,
9036
9102
  cost: 0,
@@ -9042,7 +9108,7 @@ const makeDeepseekCall = async (content, responseFormat = 'json', options = {})
9042
9108
  const completion = await createDeepseekCompletion(content, responseFormat, mergedOptions);
9043
9109
  // Track cost in the global cost tracker. Pass cached tokens through so the
9044
9110
  // discounted cached-input pricing tier is applied.
9045
- getLLMCostTracker().trackUsage('deepseek', completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens);
9111
+ getLLMCostTracker().trackUsage("deepseek", completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens);
9046
9112
  // Handle tool calls similarly to OpenAI
9047
9113
  if (completion.tool_calls && completion.tool_calls.length > 0) {
9048
9114
  const toolCallResponse = {
@@ -9058,10 +9124,10 @@ const makeDeepseekCall = async (content, responseFormat = 'json', options = {})
9058
9124
  prompt_tokens: completion.usage.prompt_tokens,
9059
9125
  completion_tokens: completion.usage.completion_tokens,
9060
9126
  reasoning_tokens: 0, // Deepseek doesn't provide reasoning tokens separately
9061
- provider: 'deepseek',
9127
+ provider: "deepseek",
9062
9128
  model: completion.model,
9063
9129
  cached_tokens: completion.usage.cached_tokens,
9064
- cost: calculateCost('deepseek', completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens),
9130
+ cost: calculateCost("deepseek", completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens),
9065
9131
  },
9066
9132
  tool_calls: completion.tool_calls,
9067
9133
  };
@@ -9069,7 +9135,7 @@ const makeDeepseekCall = async (content, responseFormat = 'json', options = {})
9069
9135
  // Handle regular responses
9070
9136
  const parsedResponse = await parseResponse(completion.content, responseFormat);
9071
9137
  if (parsedResponse === null) {
9072
- throw new Error('Failed to parse Deepseek response');
9138
+ throw new Error("Failed to parse Deepseek response");
9073
9139
  }
9074
9140
  return {
9075
9141
  response: parsedResponse,
@@ -9077,10 +9143,10 @@ const makeDeepseekCall = async (content, responseFormat = 'json', options = {})
9077
9143
  prompt_tokens: completion.usage.prompt_tokens,
9078
9144
  completion_tokens: completion.usage.completion_tokens,
9079
9145
  reasoning_tokens: 0, // Deepseek doesn't provide reasoning tokens separately
9080
- provider: 'deepseek',
9146
+ provider: "deepseek",
9081
9147
  model: completion.model,
9082
9148
  cached_tokens: completion.usage.cached_tokens,
9083
- cost: calculateCost('deepseek', completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens),
9149
+ cost: calculateCost("deepseek", completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens),
9084
9150
  },
9085
9151
  tool_calls: completion.tool_calls,
9086
9152
  };
@@ -9090,13 +9156,13 @@ const makeDeepseekCall = async (content, responseFormat = 'json', options = {})
9090
9156
  getLumicLogger().error(`Error in Deepseek API call: ${sanitizeError(error)}`);
9091
9157
  return {
9092
9158
  response: {
9093
- error: sanitizeError(error)
9159
+ error: sanitizeError(error),
9094
9160
  },
9095
9161
  usage: {
9096
9162
  prompt_tokens: 0,
9097
9163
  completion_tokens: 0,
9098
9164
  reasoning_tokens: 0,
9099
- provider: 'deepseek',
9165
+ provider: "deepseek",
9100
9166
  model: modelName,
9101
9167
  cached_tokens: 0,
9102
9168
  cost: 0,
@@ -9205,15 +9271,15 @@ const generateCacheKey = (auth, envVarsCheck = null) => {
9205
9271
  if (auth) {
9206
9272
  return `${auth.AWS_ACCESS_KEY_ID}:${auth.AWS_SECRET_ACCESS_KEY}:${auth.AWS_REGION}`;
9207
9273
  }
9208
- if (envVarsCheck?.source === 'lambda') {
9274
+ if (envVarsCheck?.source === "lambda") {
9209
9275
  // In Lambda, use function name as cache key since it uses IAM role
9210
9276
  const secrets = getSecrets();
9211
- return `lambda:${secrets.aws.lambdaFunctionName || 'default'}`;
9277
+ return `lambda:${secrets.aws.lambdaFunctionName || "default"}`;
9212
9278
  }
9213
9279
  if (envVarsCheck?.vars) {
9214
9280
  return `${envVarsCheck.vars.accessKeyId}:${envVarsCheck.vars.secretAccessKey}:${envVarsCheck.vars.region}`;
9215
9281
  }
9216
- return 'default';
9282
+ return "default";
9217
9283
  };
9218
9284
  const validateEnvironmentVars = () => {
9219
9285
  const secrets = getSecrets();
@@ -9226,37 +9292,37 @@ const validateEnvironmentVars = () => {
9226
9292
  // We're in a Lambda environment
9227
9293
  return {
9228
9294
  isValid: true,
9229
- source: 'lambda',
9230
- vars: { accessKeyId: '', secretAccessKey: '', region: '' } // No need for explicit credentials in Lambda
9295
+ source: "lambda",
9296
+ vars: { accessKeyId: "", secretAccessKey: "", region: "" }, // No need for explicit credentials in Lambda
9231
9297
  };
9232
9298
  }
9233
9299
  else if (areVarsComplete(secrets.aws.myAccessKeyId, secrets.aws.mySecretAccessKey, secrets.aws.myRegion)) {
9234
9300
  return {
9235
9301
  isValid: true,
9236
- source: 'my_prefix',
9302
+ source: "my_prefix",
9237
9303
  vars: {
9238
- accessKeyId: secrets.aws.myAccessKeyId,
9239
- secretAccessKey: secrets.aws.mySecretAccessKey,
9240
- region: secrets.aws.myRegion
9241
- }
9304
+ accessKeyId: secrets.aws.myAccessKeyId ?? "",
9305
+ secretAccessKey: secrets.aws.mySecretAccessKey ?? "",
9306
+ region: secrets.aws.myRegion ?? "",
9307
+ },
9242
9308
  };
9243
9309
  }
9244
9310
  else if (areVarsComplete(secrets.aws.accessKeyId, secrets.aws.secretAccessKey, secrets.aws.region)) {
9245
9311
  return {
9246
9312
  isValid: true,
9247
- source: 'standard',
9313
+ source: "standard",
9248
9314
  vars: {
9249
- accessKeyId: secrets.aws.accessKeyId,
9250
- secretAccessKey: secrets.aws.secretAccessKey,
9251
- region: secrets.aws.region
9252
- }
9315
+ accessKeyId: secrets.aws.accessKeyId ?? "",
9316
+ secretAccessKey: secrets.aws.secretAccessKey ?? "",
9317
+ region: secrets.aws.region ?? "",
9318
+ },
9253
9319
  };
9254
9320
  }
9255
9321
  // If we get here, no complete set of variables was found
9256
9322
  return {
9257
9323
  isValid: false,
9258
9324
  source: null,
9259
- missingVars: []
9325
+ missingVars: [],
9260
9326
  };
9261
9327
  };
9262
9328
  const initialiseAWSClient = (ClientClass, auth = null) => {
@@ -9265,48 +9331,52 @@ const initialiseAWSClient = (ClientClass, auth = null) => {
9265
9331
  const requestTimeout = ClientClass === S3Client ? AWS_S3_TIMEOUT_MS : AWS_LAMBDA_TIMEOUT_MS;
9266
9332
  // Case 1: Explicit auth provided
9267
9333
  if (auth) {
9268
- if (typeof auth !== 'object' || auth === null) {
9269
- throw new Error('Auth parameter must be an object');
9334
+ if (typeof auth !== "object" || auth === null) {
9335
+ throw new Error("Auth parameter must be an object");
9270
9336
  }
9271
- const requiredAuthFields = ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'AWS_REGION'];
9272
- const missingFields = requiredAuthFields.filter(field => !auth[field]);
9337
+ const requiredAuthFields = [
9338
+ "AWS_ACCESS_KEY_ID",
9339
+ "AWS_SECRET_ACCESS_KEY",
9340
+ "AWS_REGION",
9341
+ ];
9342
+ const missingFields = requiredAuthFields.filter((field) => !auth[field]);
9273
9343
  if (missingFields.length > 0) {
9274
- throw new Error(`Auth object is missing required fields: ${missingFields.join(', ')}`);
9344
+ throw new Error(`Auth object is missing required fields: ${missingFields.join(", ")}`);
9275
9345
  }
9276
9346
  return new ClientClass({
9277
9347
  region: auth.AWS_REGION,
9278
9348
  credentials: {
9279
9349
  accessKeyId: auth.AWS_ACCESS_KEY_ID,
9280
- secretAccessKey: auth.AWS_SECRET_ACCESS_KEY
9350
+ secretAccessKey: auth.AWS_SECRET_ACCESS_KEY,
9281
9351
  },
9282
9352
  requestHandler: {
9283
- requestTimeout
9284
- }
9353
+ requestTimeout,
9354
+ },
9285
9355
  });
9286
9356
  }
9287
9357
  // Case 2: Check environment variables
9288
9358
  const envVarsCheck = validateEnvironmentVars();
9289
9359
  if (!envVarsCheck.isValid) {
9290
- throw new Error('No valid AWS credentials found in environment variables');
9360
+ throw new Error("No valid AWS credentials found in environment variables");
9291
9361
  }
9292
9362
  // Case 2a: Lambda execution environment
9293
- if (envVarsCheck.source === 'lambda') {
9363
+ if (envVarsCheck.source === "lambda") {
9294
9364
  return new ClientClass({
9295
9365
  requestHandler: {
9296
- requestTimeout
9297
- }
9366
+ requestTimeout,
9367
+ },
9298
9368
  }); // AWS SDK will automatically use Lambda role credentials
9299
9369
  }
9300
9370
  // Case 2b: MY_ prefixed vars or standard AWS vars
9301
9371
  return new ClientClass({
9302
- region: envVarsCheck.vars.region,
9372
+ region: envVarsCheck.vars?.region ?? "",
9303
9373
  credentials: {
9304
- accessKeyId: envVarsCheck.vars.accessKeyId,
9305
- secretAccessKey: envVarsCheck.vars.secretAccessKey
9374
+ accessKeyId: envVarsCheck.vars?.accessKeyId ?? "",
9375
+ secretAccessKey: envVarsCheck.vars?.secretAccessKey ?? "",
9306
9376
  },
9307
9377
  requestHandler: {
9308
- requestTimeout
9309
- }
9378
+ requestTimeout,
9379
+ },
9310
9380
  });
9311
9381
  }
9312
9382
  catch (error) {
@@ -9319,7 +9389,9 @@ const initialiseS3Client = (auth = null) => {
9319
9389
  const envVarsCheck = auth ? null : validateEnvironmentVars();
9320
9390
  const cacheKey = generateCacheKey(auth, envVarsCheck);
9321
9391
  if (s3ClientCache.has(cacheKey)) {
9322
- return s3ClientCache.get(cacheKey);
9392
+ const cached = s3ClientCache.get(cacheKey);
9393
+ if (cached)
9394
+ return cached;
9323
9395
  }
9324
9396
  // Create new client and cache it
9325
9397
  const client = initialiseAWSClient(S3Client, auth);
@@ -9331,7 +9403,9 @@ const initialiseLambdaClient = (auth = null) => {
9331
9403
  const envVarsCheck = auth ? null : validateEnvironmentVars();
9332
9404
  const cacheKey = generateCacheKey(auth, envVarsCheck);
9333
9405
  if (lambdaClientCache.has(cacheKey)) {
9334
- return lambdaClientCache.get(cacheKey);
9406
+ const cached = lambdaClientCache.get(cacheKey);
9407
+ if (cached)
9408
+ return cached;
9335
9409
  }
9336
9410
  // Create new client and cache it
9337
9411
  const client = initialiseAWSClient(Lambda, auth);
@@ -9831,15 +9905,17 @@ const isRetryableS3Error = (error) => {
9831
9905
  if (error instanceof Error) {
9832
9906
  const message = error.message;
9833
9907
  // Retry on throttling
9834
- if (message.includes('SlowDown') || message.includes('RequestTimeout')) {
9908
+ if (message.includes("SlowDown") || message.includes("RequestTimeout")) {
9835
9909
  return true;
9836
9910
  }
9837
9911
  // Retry on 5xx server errors
9838
- if (message.includes('InternalError') || message.includes('ServiceUnavailable')) {
9912
+ if (message.includes("InternalError") ||
9913
+ message.includes("ServiceUnavailable")) {
9839
9914
  return true;
9840
9915
  }
9841
9916
  // Retry on connection errors
9842
- if (message.includes('RequestTimeTooSkewed') || message.includes('NetworkingError')) {
9917
+ if (message.includes("RequestTimeTooSkewed") ||
9918
+ message.includes("NetworkingError")) {
9843
9919
  return true;
9844
9920
  }
9845
9921
  }
@@ -9853,10 +9929,11 @@ const generateRandomHash = (length) => {
9853
9929
  };
9854
9930
  function generateDateTimeStamp() {
9855
9931
  const now = new Date();
9856
- return now.toISOString()
9857
- .replace(/T/, '-')
9858
- .replace(/\..+/, '')
9859
- .replace(/:/g, '-');
9932
+ return now
9933
+ .toISOString()
9934
+ .replace(/T/, "-")
9935
+ .replace(/\..+/, "")
9936
+ .replace(/:/g, "-");
9860
9937
  }
9861
9938
  const isValidBucketName = (name) => {
9862
9939
  const regex = /^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;
@@ -9887,7 +9964,7 @@ async function uploadFile(s3Client, bucketName, filePath, destinationPath, isPub
9887
9964
  Bucket: bucketName,
9888
9965
  Key: s3Key,
9889
9966
  Body: fileContent,
9890
- ACL: isPublic ? 'public-read' : undefined
9967
+ ACL: isPublic ? "public-read" : undefined,
9891
9968
  });
9892
9969
  await withRetry(() => s3Client.send(command), {
9893
9970
  maxRetries: 3,
@@ -9907,7 +9984,7 @@ async function uploadDirectory(s3Client, bucketName, dirPath, destinationPath, i
9907
9984
  Bucket: bucketName,
9908
9985
  Key: s3Key,
9909
9986
  Body: fileContent,
9910
- ACL: isPublic ? 'public-read' : undefined
9987
+ ACL: isPublic ? "public-read" : undefined,
9911
9988
  });
9912
9989
  await withRetry(() => s3Client.send(command), {
9913
9990
  maxRetries: 3,
@@ -9923,7 +10000,7 @@ async function zipDirectory(sourceDir, outPath) {
9923
10000
  const zip = new AdmZip();
9924
10001
  let fileCount = 0;
9925
10002
  try {
9926
- async function addFilesToZip(currentPath, relativePath = '') {
10003
+ async function addFilesToZip(currentPath, relativePath = "") {
9927
10004
  const files = await fs$1.readdir(currentPath, { withFileTypes: true });
9928
10005
  for (const file of files) {
9929
10006
  const filePath = path__default.join(currentPath, file.name);
@@ -9966,27 +10043,33 @@ async function downloadFromS3Helper(s3Client, bucketName, s3Path, localPath) {
9966
10043
  Prefix: s3Path,
9967
10044
  ContinuationToken: continuationToken,
9968
10045
  });
9969
- const listResponse = await withRetry(() => s3Client.send(listCommand), {
10046
+ const listResponse = (await withRetry(() => s3Client.send(listCommand), {
9970
10047
  maxRetries: 3,
9971
10048
  baseDelayMs: 1000,
9972
10049
  maxDelayMs: 15000,
9973
10050
  retryableErrors: isRetryableS3Error,
9974
- }, `S3:ListObjects:${bucketName}`);
10051
+ }, `S3:ListObjects:${bucketName}`));
9975
10052
  const objects = listResponse.Contents || [];
9976
10053
  if (objects.length === 0) {
9977
10054
  return { fileCount: 0, folderCount: 0, totalSize: 0, fileList: [] };
9978
10055
  }
9979
- if (objects.length === 1 && objects[0].Key?.endsWith('.zip')) {
10056
+ if (objects.length === 1 && objects[0].Key?.endsWith(".zip")) {
9980
10057
  // It's a zip file, download and extract it
9981
10058
  const zipPath = path__default.join(localPath, path__default.basename(objects[0].Key));
9982
10059
  await downloadFile(s3Client, bucketName, objects[0].Key, zipPath);
9983
- const { totalFiles, totalFolders, totalSize: extractedSize, fileList: extractedFileList } = await unzipFile(zipPath, localPath);
10060
+ const { totalFiles, totalFolders, totalSize: extractedSize, fileList: extractedFileList, } = await unzipFile(zipPath, localPath);
9984
10061
  await fs$1.unlink(zipPath);
9985
- return { fileCount: totalFiles, folderCount: totalFolders, totalSize: extractedSize, fileList: extractedFileList };
10062
+ return {
10063
+ fileCount: totalFiles,
10064
+ folderCount: totalFolders,
10065
+ totalSize: extractedSize,
10066
+ fileList: extractedFileList,
10067
+ };
9986
10068
  }
9987
10069
  else {
9988
10070
  // Non-zip files. Download files in batches.
9989
- for (let i = 0; i < objects.length; i += 1000) { // AWS allows up to 1000 per request
10071
+ for (let i = 0; i < objects.length; i += 1000) {
10072
+ // AWS allows up to 1000 per request
9990
10073
  const batch = objects.slice(i, i + 1000);
9991
10074
  await Promise.all(batch.map(async (obj) => {
9992
10075
  if (!obj.Key)
@@ -10002,7 +10085,9 @@ async function downloadFromS3Helper(s3Client, bucketName, s3Path, localPath) {
10002
10085
  }
10003
10086
  // Count folders
10004
10087
  const relativePath = path__default.relative(localPath, path__default.dirname(localFilePath));
10005
- if (relativePath && !relativePath.startsWith('..') && relativePath !== '.') {
10088
+ if (relativePath &&
10089
+ !relativePath.startsWith("..") &&
10090
+ relativePath !== ".") {
10006
10091
  folderCount++;
10007
10092
  }
10008
10093
  }));
@@ -10023,7 +10108,7 @@ async function downloadFile(s3Client, bucketName, s3Key, localFilePath) {
10023
10108
  await withRetry(async () => {
10024
10109
  const { Body } = await s3Client.send(getCommand);
10025
10110
  if (!Body)
10026
- throw new Error('No body returned from S3');
10111
+ throw new Error("No body returned from S3");
10027
10112
  const writeStream = createWriteStream(localFilePath);
10028
10113
  await pipeline(Body, writeStream);
10029
10114
  }, {
@@ -10079,17 +10164,19 @@ async function emptyBucket(s3Client, bucketName) {
10079
10164
  Bucket: bucketName,
10080
10165
  ContinuationToken: continuationToken,
10081
10166
  });
10082
- const response = await withRetry(() => s3Client.send(listCommand), {
10167
+ const response = (await withRetry(() => s3Client.send(listCommand), {
10083
10168
  maxRetries: 3,
10084
10169
  baseDelayMs: 1000,
10085
10170
  maxDelayMs: 15000,
10086
10171
  retryableErrors: isRetryableS3Error,
10087
- }, `S3:ListObjects:${bucketName}`);
10172
+ }, `S3:ListObjects:${bucketName}`));
10088
10173
  const { Contents, IsTruncated, NextContinuationToken } = response;
10089
10174
  if (Contents && Contents.length > 0) {
10090
10175
  const deleteCommand = new DeleteObjectsCommand({
10091
10176
  Bucket: bucketName,
10092
- Delete: { Objects: Contents.map(({ Key }) => ({ Key: Key })) },
10177
+ Delete: {
10178
+ Objects: Contents.filter((c) => c.Key).map((c) => ({ Key: c.Key })),
10179
+ },
10093
10180
  });
10094
10181
  await withRetry(() => s3Client.send(deleteCommand), {
10095
10182
  maxRetries: 3,
@@ -22997,11 +23084,11 @@ let poolConfig = DEFAULT_POOL_CONFIG;
22997
23084
  async function loadApolloModules() {
22998
23085
  if (typeof window === "undefined" || process.env.AWS_EXECUTION_ENV) {
22999
23086
  // Server-side (or Lambda): load the CommonJS‑based implementation.
23000
- return (await import('./apollo-client.server-CJ6iRLa2.js'));
23087
+ return (await import('./apollo-client.server-CbagxkmK.js'));
23001
23088
  }
23002
23089
  else {
23003
23090
  // Client-side: load the ESM‑based implementation.
23004
- return (await import('./apollo-client.client-DrSy1wz-.js'));
23091
+ return (await import('./apollo-client.client-9wJcufhf.js'));
23005
23092
  }
23006
23093
  }
23007
23094
  /**
@@ -79028,7 +79115,7 @@ const RETRY_CONFIG = {
79028
79115
  BASE_DELAY: 2000, // Increased base delay to 2 seconds
79029
79116
  MAX_DELAY: 64000,
79030
79117
  MAX_RETRIES: 5,
79031
- MAX_RANDOM_DELAY: 1000
79118
+ MAX_RANDOM_DELAY: 1000,
79032
79119
  };
79033
79120
  /**
79034
79121
  * Determines if an error is related to Google Sheets API quotas or rate limits.
@@ -79054,10 +79141,10 @@ const RETRY_CONFIG = {
79054
79141
  */
79055
79142
  function isQuotaError(error) {
79056
79143
  const message = error.message.toLowerCase();
79057
- return message.includes('quota exceeded') ||
79058
- message.includes('rate limit') ||
79059
- message.includes('429') ||
79060
- message.includes('too many requests');
79144
+ return (message.includes("quota exceeded") ||
79145
+ message.includes("rate limit") ||
79146
+ message.includes("429") ||
79147
+ message.includes("too many requests"));
79061
79148
  }
79062
79149
  /**
79063
79150
  * Implements exponential backoff retry mechanism for Google Sheets API calls.
@@ -79116,14 +79203,14 @@ async function withExponentialBackoff(operation) {
79116
79203
  const exponentialDelay = Math.min(Math.pow(2, retries) * RETRY_CONFIG.BASE_DELAY + randomDelay, RETRY_CONFIG.MAX_DELAY);
79117
79204
  logIfDebug(`Quota/Rate limit exceeded. Error: ${error.message}`);
79118
79205
  logIfDebug(`Retrying in ${exponentialDelay}ms (attempt ${retries}/${RETRY_CONFIG.MAX_RETRIES})`);
79119
- await new Promise(resolve => setTimeout(resolve, exponentialDelay));
79206
+ await new Promise((resolve) => setTimeout(resolve, exponentialDelay));
79120
79207
  }
79121
79208
  }
79122
79209
  }
79123
79210
  function checkEnvVars() {
79124
79211
  const secrets = getSecrets();
79125
79212
  if (!secrets.googleSheets.clientEmail || !secrets.googleSheets.privateKey) {
79126
- throw new Error('GOOGLE_SHEETS_CLIENT_EMAIL or GOOGLE_SHEETS_PRIVATE_KEY is not defined in environment variables.');
79213
+ throw new Error("GOOGLE_SHEETS_CLIENT_EMAIL or GOOGLE_SHEETS_PRIVATE_KEY is not defined in environment variables.");
79127
79214
  }
79128
79215
  }
79129
79216
  /**
@@ -79138,16 +79225,16 @@ async function getAuthClient() {
79138
79225
  const secrets = getSecrets();
79139
79226
  const credentials = {
79140
79227
  client_email: secrets.googleSheets.clientEmail,
79141
- private_key: secrets.googleSheets.privateKey?.replace(/\\n/g, '\n'),
79228
+ private_key: secrets.googleSheets.privateKey?.replace(/\\n/g, "\n"),
79142
79229
  };
79143
79230
  const auth = new GoogleAuth({
79144
79231
  credentials,
79145
- scopes: ['https://www.googleapis.com/auth/spreadsheets'],
79232
+ scopes: ["https://www.googleapis.com/auth/spreadsheets"],
79146
79233
  });
79147
79234
  return auth.getClient();
79148
79235
  }
79149
79236
  catch (error) {
79150
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
79237
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
79151
79238
  logIfDebug(`Error initializing Google Sheets auth: ${errorMessage}`);
79152
79239
  throw new Error(`Failed to initialize Google Sheets auth: ${errorMessage}`);
79153
79240
  }
@@ -79159,7 +79246,7 @@ async function getSheetsClient() {
79159
79246
  const auth = await getAuthClient();
79160
79247
  return new buildExports.sheets_v4.Sheets({
79161
79248
  auth,
79162
- timeout: GOOGLE_SHEETS_TIMEOUT_MS
79249
+ timeout: GOOGLE_SHEETS_TIMEOUT_MS,
79163
79250
  });
79164
79251
  }
79165
79252
  /**
@@ -79192,7 +79279,7 @@ function escapeSheetName(sheetName) {
79192
79279
  * @param startColumn Optional starting column (defaults to 'A')
79193
79280
  * @returns Promise resolving to response with success status and row details
79194
79281
  */
79195
- async function addRow(config, values, startColumn = 'A') {
79282
+ async function addRow(config, values, startColumn = "A") {
79196
79283
  try {
79197
79284
  const sheets = await getSheetsClient();
79198
79285
  const escapedSheetName = escapeSheetName(config.sheetName);
@@ -79200,7 +79287,7 @@ async function addRow(config, values, startColumn = 'A') {
79200
79287
  const response = await withExponentialBackoff(() => sheets.spreadsheets.values.append({
79201
79288
  spreadsheetId: config.spreadsheetId,
79202
79289
  range,
79203
- valueInputOption: 'USER_ENTERED',
79290
+ valueInputOption: "USER_ENTERED",
79204
79291
  requestBody: {
79205
79292
  values: [values],
79206
79293
  },
@@ -79208,9 +79295,9 @@ async function addRow(config, values, startColumn = 'A') {
79208
79295
  //logIfDebug(`Added row to sheet ${config.sheetName}: ${values.join(', ')}`);
79209
79296
  const rowNumber = response.data.updates?.updatedRange
79210
79297
  ? parseInt(response.data.updates.updatedRange
79211
- .split('!')[1]
79212
- .split(':')[0]
79213
- .replace(/[^0-9]/g, ''))
79298
+ .split("!")[1]
79299
+ .split(":")[0]
79300
+ .replace(/[^0-9]/g, ""))
79214
79301
  : 0;
79215
79302
  return {
79216
79303
  success: true,
@@ -79221,7 +79308,7 @@ async function addRow(config, values, startColumn = 'A') {
79221
79308
  };
79222
79309
  }
79223
79310
  catch (error) {
79224
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
79311
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
79225
79312
  logIfDebug(`Error adding row to sheet: ${errorMessage}`);
79226
79313
  return {
79227
79314
  success: false,
@@ -79263,7 +79350,7 @@ async function addSheet(spreadsheetId, sheetTitle) {
79263
79350
  };
79264
79351
  }
79265
79352
  catch (error) {
79266
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
79353
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
79267
79354
  logIfDebug(`Error adding sheet: ${errorMessage}`);
79268
79355
  return {
79269
79356
  success: false,
@@ -79287,7 +79374,7 @@ async function writeCell(config, cell, value) {
79287
79374
  await withExponentialBackoff(() => sheets.spreadsheets.values.update({
79288
79375
  spreadsheetId: config.spreadsheetId,
79289
79376
  range,
79290
- valueInputOption: 'USER_ENTERED',
79377
+ valueInputOption: "USER_ENTERED",
79291
79378
  requestBody: {
79292
79379
  values: [[value]],
79293
79380
  },
@@ -79301,7 +79388,7 @@ async function writeCell(config, cell, value) {
79301
79388
  };
79302
79389
  }
79303
79390
  catch (error) {
79304
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
79391
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
79305
79392
  logIfDebug(`Error writing to cell: ${errorMessage}`);
79306
79393
  return {
79307
79394
  success: false,
@@ -79325,8 +79412,11 @@ async function getCell(config, cell) {
79325
79412
  spreadsheetId: config.spreadsheetId,
79326
79413
  range,
79327
79414
  }));
79328
- const value = response.data.values?.[0]?.[0];
79329
- logIfDebug(`Read value from cell ${range}: ${value}`);
79415
+ const rawValue = response.data.values?.[0]?.[0];
79416
+ const value = rawValue === undefined || rawValue === null
79417
+ ? null
79418
+ : rawValue;
79419
+ logIfDebug(`Read value from cell ${range}: ${String(value)}`);
79330
79420
  return {
79331
79421
  success: true,
79332
79422
  data: {
@@ -79335,7 +79425,7 @@ async function getCell(config, cell) {
79335
79425
  };
79336
79426
  }
79337
79427
  catch (error) {
79338
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
79428
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
79339
79429
  logIfDebug(`Error reading from cell: ${errorMessage}`);
79340
79430
  return {
79341
79431
  success: false,
@@ -79368,10 +79458,11 @@ function convertA1ToRowCol(a1Notation) {
79368
79458
  * @returns Padded array of arrays
79369
79459
  */
79370
79460
  function padArrays(arrays) {
79371
- const maxLength = Math.max(...arrays.map(arr => arr.length));
79372
- return arrays.map(arr => {
79461
+ const maxLength = Math.max(...arrays.map((arr) => arr.length));
79462
+ return arrays.map((arr) => {
79373
79463
  if (arr.length < maxLength) {
79374
- return [...arr, ...Array(maxLength - arr.length).fill('')];
79464
+ const padding = Array(maxLength - arr.length).fill("");
79465
+ return [...arr, ...padding];
79375
79466
  }
79376
79467
  return arr;
79377
79468
  });
@@ -79383,10 +79474,10 @@ function padArrays(arrays) {
79383
79474
  * @param startCell Optional starting cell in A1 notation (defaults to 'A1')
79384
79475
  * @returns Promise resolving to response with success status and update details
79385
79476
  */
79386
- async function writeArray(config, data, startCell = 'A1') {
79477
+ async function writeArray(config, data, startCell = "A1") {
79387
79478
  try {
79388
79479
  if (!data.length) {
79389
- throw new Error('Data array is empty');
79480
+ throw new Error("Data array is empty");
79390
79481
  }
79391
79482
  const sheets = await getSheetsClient();
79392
79483
  const { row: startRow, column: startCol } = convertA1ToRowCol(startCell);
@@ -79402,7 +79493,7 @@ async function writeArray(config, data, startCell = 'A1') {
79402
79493
  const response = await withExponentialBackoff(() => sheets.spreadsheets.values.update({
79403
79494
  spreadsheetId: config.spreadsheetId,
79404
79495
  range,
79405
- valueInputOption: 'USER_ENTERED',
79496
+ valueInputOption: "USER_ENTERED",
79406
79497
  requestBody: {
79407
79498
  values: paddedData,
79408
79499
  },
@@ -79418,7 +79509,7 @@ async function writeArray(config, data, startCell = 'A1') {
79418
79509
  };
79419
79510
  }
79420
79511
  catch (error) {
79421
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
79512
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
79422
79513
  logIfDebug(`Error writing array to sheet: ${errorMessage}`);
79423
79514
  return {
79424
79515
  success: false,
@@ -81525,4 +81616,4 @@ const lumic = {
81525
81616
  };
81526
81617
 
81527
81618
  export { GraphQLInterfaceType as $, print as A, getNamedType as B, isInputType as C, isRequiredArgument as D, isNamedType as E, GraphQLError as F, GraphQLNonNull as G, isOutputType as H, isRequiredInputField as I, isCompositeType as J, Kind as K, getNullableType as L, getEnterLeaveForKind as M, isNode as N, OperationTypeNode as O, didYouMean as P, naturalCompare as Q, suggestionList as R, specifiedScalarTypes as S, keyMap as T, isType as U, isNullableType as V, visit as W, visitInParallel as X, keyValMap as Y, assertObjectType as Z, GraphQLScalarType as _, isListType as a, validateGoogleSheetsRange as a$, GraphQLUnionType as a0, GraphQLInputObjectType as a1, assertNullableType as a2, assertInterfaceType as a3, mapValue as a4, isSpecifiedScalarType as a5, isPrintableAsBlockString as a6, printBlockString as a7, BREAK as a8, GRAPHQL_MAX_INT as a9, printSourceLocation as aA, resolveObjMapThunk as aB, resolveReadonlyArrayThunk as aC, valueFromASTUntyped as aD, version$4 as aE, versionInfo as aF, getAugmentedNamespace as aG, isDigit$1 as aH, isNameStart as aI, dedentBlockStringLines as aJ, isNameContinue as aK, setLumicLogger as aL, getLumicLogger as aM, sanitizeForLog as aN, sanitizeError as aO, sanitizeAWSAuth as aP, sanitizeObject as aQ, getSecrets as aR, resetSecrets as aS, requireSecret as aT, withRetry as aU, CircuitBreaker as aV, CircuitBreakerState as aW, CircuitBreakerOpenError as aX, DEFAULT_CIRCUIT_BREAKER_CONFIG as aY, validateSlackChannel as aZ, validateS3Key as a_, GRAPHQL_MIN_INT as aa, GraphQLFloat as ab, GraphQLInt as ac, Location as ad, Token as ae, assertAbstractType as af, assertCompositeType as ag, assertEnumType as ah, assertEnumValueName as ai, assertInputObjectType as aj, assertInputType as ak, assertLeafType as al, assertListType as am, assertNamedType as an, assertNonNullType as ao, assertOutputType as ap, assertScalarType as aq, assertType as ar, assertUnionType as as, assertWrappingType as at, formatError as au, getLocation as av, getVisitFn as aw, isWrappingType as ax, printError as ay, printLocation as az, isAbstractType as b, PDFError as b$, LLMCostTracker as b0, getLLMCostTracker as b1, setLLMCostTracker as b2, resetLLMCostTracker as b3, setMetricsCollector as b4, getMetricsCollector as b5, resetMetricsCollector as b6, withMetrics as b7, generateCorrelationId as b8, getCorrelationId as b9, openAIChatCompletionSchema as bA, openAIImageResponseSchema as bB, validateOpenAIChatCompletion as bC, safeValidateOpenAIChatCompletion as bD, perplexityResponseSchema as bE, validatePerplexityResponse as bF, safeValidatePerplexityResponse as bG, googleSheetsValueRangeSchema as bH, validateGoogleSheetsResponse as bI, safeValidateGoogleSheetsResponse as bJ, s3ListObjectsSchema as bK, s3GetObjectSchema as bL, lambdaInvokeResponseSchema as bM, validateS3ListObjects as bN, safeValidateS3ListObjects as bO, validateLambdaResponse as bP, safeValidateLambdaResponse as bQ, createValidator as bR, createSafeValidator as bS, LumicError as bT, SlackError as bU, LLMError as bV, AWSLambdaError as bW, AWSS3Error as bX, GoogleSheetsError as bY, PerplexityError as bZ, JsonParseError as b_, getCorrelationContext as ba, withCorrelationId as bb, getCorrelationHeaders as bc, TokenBucketRateLimiter as bd, RATE_LIMIT_PROFILES as be, getRateLimiter as bf, resetAllRateLimiters as bg, withRateLimit as bh, checkIntegrationHealth as bi, SUPPORTED_MODELS as bj, isValidModel as bk, getModelCapabilities as bl, getModelProvider as bm, MODEL_ALIASES as bn, OPENAI_COMPATIBLE_PROVIDERS as bo, PROVIDER_DEFAULT_MODELS as bp, LLM_DEFAULT_PROVIDER as bq, LLM_MINI_PROVIDER as br, LLM_NORMAL_PROVIDER as bs, LLM_ADVANCED_PROVIDER as bt, LLM_PROVIDER as bu, LLM_MODEL_MINI as bv, LLM_MODEL_NORMAL as bw, LLM_MODEL_ADVANCED as bx, makeAnthropicCall as by, makeOpenAICompatibleCall as bz, isInterfaceType as c, ZipError as c0, SLACK_TIMEOUT_MS as c1, PERPLEXITY_TIMEOUT_MS as c2, GOOGLE_SHEETS_TIMEOUT_MS as c3, LLM_TIMEOUT_MS as c4, AWS_LAMBDA_TIMEOUT_MS as c5, AWS_S3_TIMEOUT_MS as c6, OPENWEATHER_TIMEOUT_MS as c7, GENERIC_FETCH_TIMEOUT_MS as c8, isObjectType as d, assertName as e, devAssert as f, isObjectLike as g, defineArguments as h, isNonNullType as i, argsToArgsConfig as j, GraphQLBoolean as k, lumic as l, GraphQLString as m, instanceOf as n, inspect as o, isInputObjectType as p, isLeafType as q, isEnumType as r, GraphQLID as s, toObjMap as t, invariant as u, GraphQLObjectType as v, GraphQLEnumType as w, GraphQLList as x, isScalarType as y, isUnionType as z };
81528
- //# sourceMappingURL=index-CWoI2dXN.js.map
81619
+ //# sourceMappingURL=index-EMQ1uJMh.js.map