@adaptic/lumic-utils 1.0.22 → 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-Bu5mc2I8.js → apollo-client.client-9wJcufhf.js} +4 -4
  2. package/dist/{apollo-client.client-Bu5mc2I8.js.map → apollo-client.client-9wJcufhf.js.map} +1 -1
  3. package/dist/{apollo-client.client-YzlpL7kf.js → apollo-client.client-CyxU1hTu.js} +3 -3
  4. package/dist/{apollo-client.client-YzlpL7kf.js.map → apollo-client.client-CyxU1hTu.js.map} +1 -1
  5. package/dist/{apollo-client.server-sD1QteQO.js → apollo-client.server-CbagxkmK.js} +3 -3
  6. package/dist/{apollo-client.server-sD1QteQO.js.map → apollo-client.server-CbagxkmK.js.map} +1 -1
  7. package/dist/{apollo-client.server-BTHAQqYl.js → apollo-client.server-DB3jLbBx.js} +3 -3
  8. package/dist/{apollo-client.server-BTHAQqYl.js.map → apollo-client.server-DB3jLbBx.js.map} +1 -1
  9. package/dist/{index-CWx6sW9a.js → index-B4yVKGNR.js} +2 -2
  10. package/dist/{index-CWx6sW9a.js.map → index-B4yVKGNR.js.map} +1 -1
  11. package/dist/{index-B_4Q2noT.js → index-CL79JTWc.js} +2 -2
  12. package/dist/{index-B_4Q2noT.js.map → index-CL79JTWc.js.map} +1 -1
  13. package/dist/{index-DPaCMqua.js → index-EMQ1uJMh.js} +380 -281
  14. package/dist/{index-DPaCMqua.js.map → index-EMQ1uJMh.js.map} +1 -1
  15. package/dist/{index-DfuMX-MS.js → index-KzQOh2uu.js} +380 -281
  16. package/dist/{index-DfuMX-MS.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 +17 -8
  34. package/dist/types/utils/aws-initialise.d.ts +4 -4
  35. package/package.json +2 -2
@@ -100,13 +100,21 @@ const OPENAI_COMPATIBLE_PROVIDERS = {
100
100
  */
101
101
  const SUPPORTED_MODELS = {
102
102
  // ── OpenAI GPT-5.5 series (current flagship) ─────────────────────────
103
+ // GPT-5.x series: OpenAI's 2026 API constraint — only the default
104
+ // temperature value (1.0) is accepted. Passing any other value returns
105
+ // HTTP 400: "Unsupported value: 'temperature' does not support 0.2 with
106
+ // this model. Only the default (1) value is supported." Mark
107
+ // supportsTemperature=false so the lumic-utils gate at llm-call.ts:194
108
+ // OMITS the parameter entirely (OpenAI then uses its default of 1.0).
109
+ // Ref: community.openai.com/t/temperature-in-gpt-5-models/1337133
110
+ // Ref: developers.openai.com/api/docs/models/gpt-5.4-nano
103
111
  'gpt-5.5': {
104
112
  provider: 'openai',
105
113
  supportsTools: true,
106
114
  supportsJson: true,
107
115
  supportsStructuredOutput: true,
108
116
  supportsDeveloperPrompt: true,
109
- supportsTemperature: true,
117
+ supportsTemperature: false,
110
118
  isReasoningModel: false,
111
119
  },
112
120
  'gpt-5.5-pro': {
@@ -115,7 +123,7 @@ const SUPPORTED_MODELS = {
115
123
  supportsJson: true,
116
124
  supportsStructuredOutput: true,
117
125
  supportsDeveloperPrompt: true,
118
- supportsTemperature: true,
126
+ supportsTemperature: false,
119
127
  isReasoningModel: false,
120
128
  },
121
129
  // ── OpenAI GPT-5.4 series ────────────────────────────────────────────
@@ -125,7 +133,7 @@ const SUPPORTED_MODELS = {
125
133
  supportsJson: true,
126
134
  supportsStructuredOutput: true,
127
135
  supportsDeveloperPrompt: true,
128
- supportsTemperature: true,
136
+ supportsTemperature: false,
129
137
  isReasoningModel: false,
130
138
  },
131
139
  'gpt-5.4-mini': {
@@ -134,7 +142,7 @@ const SUPPORTED_MODELS = {
134
142
  supportsJson: true,
135
143
  supportsStructuredOutput: true,
136
144
  supportsDeveloperPrompt: true,
137
- supportsTemperature: true,
145
+ supportsTemperature: false,
138
146
  isReasoningModel: false,
139
147
  },
140
148
  'gpt-5.4-nano': {
@@ -143,7 +151,7 @@ const SUPPORTED_MODELS = {
143
151
  supportsJson: true,
144
152
  supportsStructuredOutput: true,
145
153
  supportsDeveloperPrompt: true,
146
- supportsTemperature: true,
154
+ supportsTemperature: false,
147
155
  isReasoningModel: false,
148
156
  },
149
157
  // ── OpenAI GPT-5 series ──────────────────────────────────────────────
@@ -153,7 +161,7 @@ const SUPPORTED_MODELS = {
153
161
  supportsJson: true,
154
162
  supportsStructuredOutput: true,
155
163
  supportsDeveloperPrompt: true,
156
- supportsTemperature: true,
164
+ supportsTemperature: false,
157
165
  isReasoningModel: false,
158
166
  },
159
167
  'gpt-5-mini': {
@@ -162,7 +170,7 @@ const SUPPORTED_MODELS = {
162
170
  supportsJson: true,
163
171
  supportsStructuredOutput: true,
164
172
  supportsDeveloperPrompt: true,
165
- supportsTemperature: true,
173
+ supportsTemperature: false,
166
174
  isReasoningModel: false,
167
175
  },
168
176
  // ── OpenAI GPT-4.1 series ────────────────────────────────────────────
@@ -563,10 +571,19 @@ function getModelProvider(model) {
563
571
  return SUPPORTED_MODELS[model].provider;
564
572
  }
565
573
  /**
566
- * Default model tiers per provider for use with LLM_MODEL_MINI/NORMAL/ADVANCED env vars
574
+ * Default model tiers per provider for use with LLM_MODEL_MINI/NORMAL/ADVANCED env vars.
575
+ *
576
+ * OpenAI `advanced` was reverted from `gpt-5.5` back to `gpt-5.4` on 2026-05-30:
577
+ * the heavy tool-call prompt in adaptic-engine's trading-decision path was
578
+ * timing out even after the engine raised `LLM_CALL_TIMEOUT_MS` to 90s (5+
579
+ * tickers per loop still exceeded the budget). `gpt-5.5`'s 1M-context window
580
+ * is not required on that path — the prompt fits comfortably inside `gpt-5.4`'s
581
+ * envelope and `gpt-5.4` returns inside the original 25-30s p95. `gpt-5.5`
582
+ * remains registered in OPENAI_MODELS and reachable by explicit model id;
583
+ * only the `advanced` tier default is rolled back.
567
584
  */
568
585
  const PROVIDER_DEFAULT_MODELS = {
569
- openai: { mini: 'gpt-5.4-nano', normal: 'gpt-5.4-mini', advanced: 'gpt-5.5' },
586
+ openai: { mini: 'gpt-5.4-nano', normal: 'gpt-5.4-mini', advanced: 'gpt-5.4' },
570
587
  anthropic: { mini: 'claude-haiku-4-5', normal: 'claude-sonnet-4-6', advanced: 'claude-opus-4-7' },
571
588
  deepseek: { mini: 'deepseek-v4-flash', normal: 'deepseek-v4-flash', advanced: 'deepseek-v4-pro' },
572
589
  kimi: { mini: 'kimi-k2-0905-preview', normal: 'kimi-k2.5', advanced: 'kimi-k2.6' },
@@ -1520,11 +1537,13 @@ let openai;
1520
1537
  function initializeOpenAI(apiKey) {
1521
1538
  const key = apiKey || getSecrets().openai.apiKey;
1522
1539
  if (!key) {
1523
- throw new Error('OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set');
1540
+ throw new Error("OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set");
1524
1541
  }
1525
1542
  return new OpenAI({
1526
1543
  apiKey: key,
1527
- defaultHeaders: { 'User-Agent': 'My Server-side Application (compatible; OpenAI API Client)' },
1544
+ defaultHeaders: {
1545
+ "User-Agent": "My Server-side Application (compatible; OpenAI API Client)",
1546
+ },
1528
1547
  });
1529
1548
  }
1530
1549
  /**
@@ -1542,9 +1561,7 @@ function initializeOpenAI(apiKey) {
1542
1561
  */
1543
1562
  async function fixJsonWithAI(jsonStr, options) {
1544
1563
  // Backward compatibility: handle string apiKey as first positional param
1545
- const opts = typeof options === 'string'
1546
- ? { apiKey: options }
1547
- : (options ?? {});
1564
+ const opts = typeof options === "string" ? { apiKey: options } : (options ?? {});
1548
1565
  const apiKey = opts.apiKey;
1549
1566
  const maxDepth = opts.maxDepth ?? 2;
1550
1567
  const depth = opts._depth ?? 0;
@@ -1557,18 +1574,18 @@ async function fixJsonWithAI(jsonStr, options) {
1557
1574
  openai = initializeOpenAI(apiKey);
1558
1575
  }
1559
1576
  const completion = await openai.chat.completions.create({
1560
- model: 'gpt-5-mini',
1577
+ model: "gpt-5-mini",
1561
1578
  messages: [
1562
1579
  {
1563
- role: 'system',
1564
- content: 'You are a JSON fixer. Return only valid JSON without any additional text or explanation.'
1580
+ role: "system",
1581
+ content: "You are a JSON fixer. Return only valid JSON without any additional text or explanation.",
1565
1582
  },
1566
1583
  {
1567
- role: 'user',
1568
- content: `Fix this broken JSON:\n${jsonStr}`
1569
- }
1584
+ role: "user",
1585
+ content: `Fix this broken JSON:\n${jsonStr}`,
1586
+ },
1570
1587
  ],
1571
- response_format: { type: 'json_object' }
1588
+ response_format: { type: "json_object" },
1572
1589
  });
1573
1590
  const fixedJson = completion.choices[0]?.message?.content;
1574
1591
  if (fixedJson && isValidJson(fixedJson)) {
@@ -1582,23 +1599,32 @@ async function fixJsonWithAI(jsonStr, options) {
1582
1599
  _depth: depth + 1,
1583
1600
  });
1584
1601
  }
1585
- throw new JsonParseError('Failed to fix JSON with AI: returned invalid JSON');
1602
+ throw new JsonParseError("Failed to fix JSON with AI: returned invalid JSON");
1586
1603
  }
1587
1604
  catch (err) {
1588
1605
  // Re-throw JsonParseError as-is (e.g. max depth exceeded)
1589
1606
  if (err instanceof JsonParseError) {
1590
1607
  throw err;
1591
1608
  }
1592
- const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
1609
+ const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
1593
1610
  throw new JsonParseError(`Error fixing JSON with AI: ${errorMessage}`);
1594
1611
  }
1595
1612
  }
1596
1613
 
1597
1614
  // llm-utils.ts
1598
1615
  function normalizeModelName(model) {
1599
- return model.replace(/_/g, '-').toLowerCase();
1600
- }
1601
- const CODE_BLOCK_TYPES = ['javascript', 'js', 'graphql', 'json', 'typescript', 'python', 'markdown', 'yaml'];
1616
+ return model.replace(/_/g, "-").toLowerCase();
1617
+ }
1618
+ const CODE_BLOCK_TYPES = [
1619
+ "javascript",
1620
+ "js",
1621
+ "graphql",
1622
+ "json",
1623
+ "typescript",
1624
+ "python",
1625
+ "markdown",
1626
+ "yaml",
1627
+ ];
1602
1628
  /**
1603
1629
  * Tries to parse JSON from the given content string according to the specified
1604
1630
  * response format. If the response format is 'json' or a JSON schema object, it
@@ -1622,7 +1648,9 @@ async function parseResponse(content, responseFormat, options = {}) {
1622
1648
  if (recursionDepth > maxRetries) {
1623
1649
  throw new Error(`Maximum recursion depth (${maxRetries}) exceeded while parsing JSON. AI fixing may have returned broken JSON.`);
1624
1650
  }
1625
- if (responseFormat === 'json' || (typeof responseFormat === 'object' && responseFormat?.type === 'json_schema')) {
1651
+ if (responseFormat === "json" ||
1652
+ (typeof responseFormat === "object" &&
1653
+ responseFormat?.type === "json_schema")) {
1626
1654
  let cleanedContent = content.trim();
1627
1655
  let detectedType = null;
1628
1656
  // Remove code block markers if present
@@ -1633,8 +1661,8 @@ async function parseResponse(content, responseFormat, options = {}) {
1633
1661
  }
1634
1662
  return false;
1635
1663
  });
1636
- if (startsWithCodeBlock && cleanedContent.endsWith('```')) {
1637
- const firstLineEndIndex = cleanedContent.indexOf('\n');
1664
+ if (startsWithCodeBlock && cleanedContent.endsWith("```")) {
1665
+ const firstLineEndIndex = cleanedContent.indexOf("\n");
1638
1666
  if (firstLineEndIndex !== -1) {
1639
1667
  cleanedContent = cleanedContent.slice(firstLineEndIndex + 1, -3).trim();
1640
1668
  getLumicLogger().info(`Code block for type ${detectedType} detected and removed. Cleaned content: ${cleanedContent}`);
@@ -1667,7 +1695,7 @@ async function parseResponse(content, responseFormat, options = {}) {
1667
1695
  },
1668
1696
  // Strategy 3: Remove leading/trailing text and try parsing
1669
1697
  () => {
1670
- const jsonMatch = cleanedContent.replace(/^[^{[]*|[^}\]]*$/g, '');
1698
+ const jsonMatch = cleanedContent.replace(/^[^{[]*|[^}\]]*$/g, "");
1671
1699
  try {
1672
1700
  return JSON.parse(jsonMatch);
1673
1701
  }
@@ -1689,7 +1717,7 @@ async function parseResponse(content, responseFormat, options = {}) {
1689
1717
  }
1690
1718
  // Strategy 5: Use AI fixing (only if explicitly enabled)
1691
1719
  if (enableAiFix) {
1692
- getLumicLogger().warn('Using AI-powered JSON fixing. This adds cost and latency. Consider improving JSON generation instead.');
1720
+ getLumicLogger().warn("Using AI-powered JSON fixing. This adds cost and latency. Consider improving JSON generation instead.");
1693
1721
  try {
1694
1722
  const aiFixedJson = await fixJsonWithAI(cleanedContent);
1695
1723
  if (aiFixedJson !== null) {
@@ -1702,7 +1730,7 @@ async function parseResponse(content, responseFormat, options = {}) {
1702
1730
  catch {
1703
1731
  // AI returned something that looks like JSON but isn't valid
1704
1732
  // Increment recursion depth and try parsing the AI response
1705
- getLumicLogger().warn('AI fixing returned invalid JSON, attempting recursive parse...');
1733
+ getLumicLogger().warn("AI fixing returned invalid JSON, attempting recursive parse...");
1706
1734
  return parseResponse(JSON.stringify(aiFixedJson), responseFormat, {
1707
1735
  ...options,
1708
1736
  _recursionDepth: recursionDepth + 1,
@@ -1711,14 +1739,14 @@ async function parseResponse(content, responseFormat, options = {}) {
1711
1739
  }
1712
1740
  }
1713
1741
  catch (error) {
1714
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
1742
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
1715
1743
  getLumicLogger().error(`AI JSON fixing failed: ${errorMessage}`);
1716
1744
  // Continue to final error below
1717
1745
  }
1718
1746
  }
1719
1747
  // If all strategies fail, throw an error
1720
1748
  getLumicLogger().error(`Failed to parse JSON from content: ${cleanedContent}. Original JSON: ${content}`);
1721
- throw new Error('Unable to parse JSON response');
1749
+ throw new Error("Unable to parse JSON response");
1722
1750
  }
1723
1751
  else {
1724
1752
  return content;
@@ -2312,13 +2340,15 @@ const isRetryableLLMError = (error) => {
2312
2340
  if (error instanceof Error) {
2313
2341
  const message = error.message;
2314
2342
  // Retry on rate limits (429)
2315
- if (message.includes('429') || message.includes('rate limit') || message.includes('Rate limit')) {
2343
+ if (message.includes("429") ||
2344
+ message.includes("rate limit") ||
2345
+ message.includes("Rate limit")) {
2316
2346
  return true;
2317
2347
  }
2318
2348
  // Retry on transient body-corruption 400s. Match the exact OpenAI error
2319
2349
  // string to avoid retrying genuine client-side validation 400s (which
2320
2350
  // would re-fail forever and waste retry budget).
2321
- if (message.includes('could not parse the JSON body of your request')) {
2351
+ if (message.includes("could not parse the JSON body of your request")) {
2322
2352
  return true;
2323
2353
  }
2324
2354
  }
@@ -2387,23 +2417,26 @@ function isReasoningModel(model) {
2387
2417
  * @throws Error if the response format is invalid or incompatible.
2388
2418
  */
2389
2419
  function getResponseFormatOption(responseFormat, normalizedModel) {
2390
- if (responseFormat === 'text') {
2391
- return { type: 'text' };
2420
+ if (responseFormat === "text") {
2421
+ return { type: "text" };
2392
2422
  }
2393
- if (responseFormat === 'json') {
2394
- return supportsJsonMode(normalizedModel) ? { type: 'json_object' } : { type: 'text' };
2423
+ if (responseFormat === "json") {
2424
+ return supportsJsonMode(normalizedModel)
2425
+ ? { type: "json_object" }
2426
+ : { type: "text" };
2395
2427
  }
2396
- if (typeof responseFormat === 'object' && responseFormat.type === 'json_schema') {
2428
+ if (typeof responseFormat === "object" &&
2429
+ responseFormat.type === "json_schema") {
2397
2430
  if (!isStructuredOutputCompatibleModel(normalizedModel)) {
2398
2431
  throw new Error(`${normalizedModel} is not compatible with structured outputs / json object.`);
2399
2432
  }
2400
2433
  return {
2401
- type: 'json_schema',
2434
+ type: "json_schema",
2402
2435
  json_schema: {
2403
- type: 'object',
2436
+ type: "object",
2404
2437
  properties: responseFormat.schema.properties,
2405
2438
  required: responseFormat.schema.required || [],
2406
- name: 'Response',
2439
+ name: "Response",
2407
2440
  },
2408
2441
  };
2409
2442
  }
@@ -2462,7 +2495,7 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2462
2495
  const normalizedModel = normalizeModelName(options.model || DEFAULT_MODEL);
2463
2496
  const apiKey = options.apiKey || getSecrets().openai.apiKey;
2464
2497
  if (!apiKey) {
2465
- throw new Error('OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set');
2498
+ throw new Error("OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set");
2466
2499
  }
2467
2500
  const openai = new OpenAI({
2468
2501
  apiKey: apiKey,
@@ -2472,7 +2505,7 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2472
2505
  // Add developer prompt if present
2473
2506
  if (options.developerPrompt && supportsDeveloperPrompt(normalizedModel)) {
2474
2507
  messages.push({
2475
- role: 'developer',
2508
+ role: "developer",
2476
2509
  content: options.developerPrompt,
2477
2510
  });
2478
2511
  }
@@ -2481,15 +2514,15 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2481
2514
  messages.push(...options.context);
2482
2515
  }
2483
2516
  // Add user content
2484
- if (typeof content === 'string') {
2517
+ if (typeof content === "string") {
2485
2518
  messages.push({
2486
- role: 'user',
2519
+ role: "user",
2487
2520
  content,
2488
2521
  });
2489
2522
  }
2490
2523
  else {
2491
2524
  messages.push({
2492
- role: 'user',
2525
+ role: "user",
2493
2526
  content,
2494
2527
  });
2495
2528
  }
@@ -2503,7 +2536,8 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2503
2536
  queryOptions.tools = options.tools;
2504
2537
  }
2505
2538
  // Only include temperature if the model supports it
2506
- if (options.temperature !== undefined && supportsTemperature(normalizedModel)) {
2539
+ if (options.temperature !== undefined &&
2540
+ supportsTemperature(normalizedModel)) {
2507
2541
  queryOptions.temperature = options.temperature;
2508
2542
  }
2509
2543
  // Only include max_completion_tokens when specified
@@ -2513,7 +2547,7 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2513
2547
  // Only set response_format when it's not the default 'text' type
2514
2548
  // (sending response_format: {type: 'text'} is redundant and may cause issues)
2515
2549
  const responseFormatOption = getResponseFormatOption(responseFormat, normalizedModel);
2516
- if (responseFormatOption.type !== 'text') {
2550
+ if (responseFormatOption.type !== "text") {
2517
2551
  queryOptions.response_format = responseFormatOption;
2518
2552
  }
2519
2553
  let completion;
@@ -2534,15 +2568,19 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2534
2568
  // for production prompts containing sensitive context.
2535
2569
  const errorMessage = error instanceof Error ? error.message : String(error);
2536
2570
  const totalContentChars = messages.reduce((sum, msg) => {
2537
- if (typeof msg.content === 'string')
2571
+ if (typeof msg.content === "string")
2538
2572
  return sum + msg.content.length;
2539
2573
  if (Array.isArray(msg.content)) {
2540
- return sum + msg.content.reduce((s, part) => {
2541
- if (typeof part === 'object' && part !== null && 'text' in part && typeof part.text === 'string') {
2542
- return s + part.text.length;
2543
- }
2544
- return s;
2545
- }, 0);
2574
+ return (sum +
2575
+ msg.content.reduce((s, part) => {
2576
+ if (typeof part === "object" &&
2577
+ part !== null &&
2578
+ "text" in part &&
2579
+ typeof part.text === "string") {
2580
+ return s + part.text.length;
2581
+ }
2582
+ return s;
2583
+ }, 0));
2546
2584
  }
2547
2585
  return sum;
2548
2586
  }, 0);
@@ -2569,7 +2607,7 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2569
2607
  const cachedTokens = completion.usage?.prompt_tokens_details?.cached_tokens ?? 0;
2570
2608
  const response = {
2571
2609
  id: completion.id,
2572
- content: completion.choices[0]?.message?.content || '',
2610
+ content: completion.choices[0]?.message?.content || "",
2573
2611
  tool_calls: completion.choices[0]?.message?.tool_calls,
2574
2612
  usage: {
2575
2613
  prompt_tokens: completion.usage?.prompt_tokens ?? 0,
@@ -2579,7 +2617,7 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2579
2617
  },
2580
2618
  system_fingerprint: completion.system_fingerprint,
2581
2619
  service_tier: options.service_tier,
2582
- provider: 'openai',
2620
+ provider: "openai",
2583
2621
  model: normalizedModel,
2584
2622
  };
2585
2623
  return response;
@@ -2592,7 +2630,7 @@ async function createCompletion(content, responseFormat, options = DEFAULT_OPTIO
2592
2630
  * @param options The options for the LLM call. Defaults to an empty object.
2593
2631
  * @return A promise that resolves to the response from the LLM.
2594
2632
  */
2595
- const makeOpenAIChatCompletionCall = async (content, responseFormat = 'text', options = {}) => {
2633
+ const makeOpenAIChatCompletionCall = async (content, responseFormat = "text", options = {}) => {
2596
2634
  const mergedOptions = {
2597
2635
  ...DEFAULT_OPTIONS$1,
2598
2636
  ...options,
@@ -2601,7 +2639,7 @@ const makeOpenAIChatCompletionCall = async (content, responseFormat = 'text', op
2601
2639
  // Track cost in the global cost tracker. Pass cached tokens through so the
2602
2640
  // tracker applies the discounted cached-input rate (typically ~50% of the
2603
2641
  // standard input rate) instead of billing every input token at full price.
2604
- getLLMCostTracker().trackUsage('openai', completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens);
2642
+ getLLMCostTracker().trackUsage("openai", completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens);
2605
2643
  // Handle tool calls differently
2606
2644
  if (completion.tool_calls && completion.tool_calls.length > 0) {
2607
2645
  const toolCallResponse = {
@@ -2617,10 +2655,10 @@ const makeOpenAIChatCompletionCall = async (content, responseFormat = 'text', op
2617
2655
  prompt_tokens: completion.usage.prompt_tokens,
2618
2656
  completion_tokens: completion.usage.completion_tokens,
2619
2657
  reasoning_tokens: 0,
2620
- provider: 'openai',
2658
+ provider: "openai",
2621
2659
  model: completion.model,
2622
2660
  cached_tokens: completion.usage.cached_tokens,
2623
- cost: calculateCost('openai', completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens),
2661
+ cost: calculateCost("openai", completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens),
2624
2662
  },
2625
2663
  tool_calls: completion.tool_calls,
2626
2664
  };
@@ -2628,7 +2666,7 @@ const makeOpenAIChatCompletionCall = async (content, responseFormat = 'text', op
2628
2666
  // Handle regular responses
2629
2667
  const parsedResponse = await parseResponse(completion.content, responseFormat);
2630
2668
  if (parsedResponse === null) {
2631
- throw new Error('Failed to parse response');
2669
+ throw new Error("Failed to parse response");
2632
2670
  }
2633
2671
  return {
2634
2672
  response: parsedResponse,
@@ -2636,10 +2674,10 @@ const makeOpenAIChatCompletionCall = async (content, responseFormat = 'text', op
2636
2674
  prompt_tokens: completion.usage.prompt_tokens,
2637
2675
  completion_tokens: completion.usage.completion_tokens,
2638
2676
  reasoning_tokens: 0,
2639
- provider: 'openai',
2677
+ provider: "openai",
2640
2678
  model: completion.model,
2641
2679
  cached_tokens: completion.usage.cached_tokens,
2642
- cost: calculateCost('openai', completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens),
2680
+ cost: calculateCost("openai", completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens),
2643
2681
  },
2644
2682
  tool_calls: completion.tool_calls,
2645
2683
  };
@@ -2674,7 +2712,7 @@ const makeResponsesAPICall = async (input, options = {}) => {
2674
2712
  const normalizedModel = normalizeModelName(options.model || DEFAULT_MODEL);
2675
2713
  const apiKey = options.apiKey || getSecrets().openai.apiKey;
2676
2714
  if (!apiKey) {
2677
- throw new Error('OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set');
2715
+ throw new Error("OpenAI API key is not provided and OPENAI_API_KEY environment variable is not set");
2678
2716
  }
2679
2717
  const openai = new OpenAI({
2680
2718
  apiKey: apiKey,
@@ -2698,20 +2736,20 @@ const makeResponsesAPICall = async (input, options = {}) => {
2698
2736
  // (the equivalent of Chat Completions' `prompt_tokens_details.cached_tokens`).
2699
2737
  const responsesCachedTokens = response.usage?.input_tokens_details?.cached_tokens || 0;
2700
2738
  // Track cost in the global cost tracker
2701
- getLLMCostTracker().trackUsage('openai', normalizedModel, response.usage?.input_tokens || 0, response.usage?.output_tokens || 0, response.usage?.output_tokens_details?.reasoning_tokens || 0, responsesCachedTokens);
2739
+ getLLMCostTracker().trackUsage("openai", normalizedModel, response.usage?.input_tokens || 0, response.usage?.output_tokens || 0, response.usage?.output_tokens_details?.reasoning_tokens || 0, responsesCachedTokens);
2702
2740
  // Extract tool calls from the output
2703
2741
  const toolCalls = response.output
2704
- ?.filter((item) => item.type === 'function_call')
2742
+ ?.filter((item) => item.type === "function_call")
2705
2743
  .map((toolCall) => ({
2706
2744
  id: toolCall.call_id,
2707
- type: 'function',
2745
+ type: "function",
2708
2746
  function: {
2709
2747
  name: toolCall.name,
2710
2748
  arguments: toolCall.arguments,
2711
2749
  },
2712
2750
  }));
2713
2751
  // Extract code interpreter outputs if present
2714
- const codeInterpreterCalls = response.output?.filter((item) => item.type === 'code_interpreter_call');
2752
+ const codeInterpreterCalls = response.output?.filter((item) => item.type === "code_interpreter_call");
2715
2753
  let codeInterpreterOutputs = undefined;
2716
2754
  if (codeInterpreterCalls && codeInterpreterCalls.length > 0) {
2717
2755
  // Each code_interpreter_call has an 'outputs' array property
@@ -2737,32 +2775,34 @@ const makeResponsesAPICall = async (input, options = {}) => {
2737
2775
  prompt_tokens: response.usage?.input_tokens || 0,
2738
2776
  completion_tokens: response.usage?.output_tokens || 0,
2739
2777
  reasoning_tokens: response.usage?.output_tokens_details?.reasoning_tokens || 0,
2740
- provider: 'openai',
2778
+ provider: "openai",
2741
2779
  model: normalizedModel,
2742
2780
  cached_tokens: responsesCachedTokens,
2743
- cost: calculateCost('openai', normalizedModel, response.usage?.input_tokens || 0, response.usage?.output_tokens || 0, response.usage?.output_tokens_details?.reasoning_tokens || 0, responsesCachedTokens),
2781
+ cost: calculateCost("openai", normalizedModel, response.usage?.input_tokens || 0, response.usage?.output_tokens || 0, response.usage?.output_tokens_details?.reasoning_tokens || 0, responsesCachedTokens),
2744
2782
  },
2745
2783
  tool_calls: toolCalls,
2746
- ...(codeInterpreterOutputs ? { code_interpreter_outputs: codeInterpreterOutputs } : {}),
2784
+ ...(codeInterpreterOutputs
2785
+ ? { code_interpreter_outputs: codeInterpreterOutputs }
2786
+ : {}),
2747
2787
  };
2748
2788
  }
2749
2789
  // Extract text content from the response output
2750
2790
  const textContent = response.output
2751
- ?.filter((item) => item.type === 'message')
2791
+ ?.filter((item) => item.type === "message")
2752
2792
  .map((item) => item.content
2753
- .filter((content) => content.type === 'output_text')
2793
+ .filter((content) => content.type === "output_text")
2754
2794
  .map((content) => content.text)
2755
- .join(''))
2756
- .join('') || '';
2795
+ .join(""))
2796
+ .join("") || "";
2757
2797
  // Determine the format for parsing the response
2758
- let parsingFormat = 'text';
2759
- if (requestBody.text?.format?.type === 'json_object') {
2760
- parsingFormat = 'json';
2798
+ let parsingFormat = "text";
2799
+ if (requestBody.text?.format?.type === "json_object") {
2800
+ parsingFormat = "json";
2761
2801
  }
2762
2802
  // Handle regular responses
2763
2803
  const parsedResponse = await parseResponse(textContent, parsingFormat);
2764
2804
  if (parsedResponse === null) {
2765
- throw new Error('Failed to parse response from Responses API');
2805
+ throw new Error("Failed to parse response from Responses API");
2766
2806
  }
2767
2807
  return {
2768
2808
  response: parsedResponse,
@@ -2770,13 +2810,15 @@ const makeResponsesAPICall = async (input, options = {}) => {
2770
2810
  prompt_tokens: response.usage?.input_tokens || 0,
2771
2811
  completion_tokens: response.usage?.output_tokens || 0,
2772
2812
  reasoning_tokens: response.usage?.output_tokens_details?.reasoning_tokens || 0,
2773
- provider: 'openai',
2813
+ provider: "openai",
2774
2814
  model: normalizedModel,
2775
2815
  cached_tokens: responsesCachedTokens,
2776
- cost: calculateCost('openai', normalizedModel, response.usage?.input_tokens || 0, response.usage?.output_tokens || 0, response.usage?.output_tokens_details?.reasoning_tokens || 0, responsesCachedTokens),
2816
+ cost: calculateCost("openai", normalizedModel, response.usage?.input_tokens || 0, response.usage?.output_tokens || 0, response.usage?.output_tokens_details?.reasoning_tokens || 0, responsesCachedTokens),
2777
2817
  },
2778
2818
  tool_calls: toolCalls,
2779
- ...(codeInterpreterOutputs ? { code_interpreter_outputs: codeInterpreterOutputs } : {}),
2819
+ ...(codeInterpreterOutputs
2820
+ ? { code_interpreter_outputs: codeInterpreterOutputs }
2821
+ : {}),
2780
2822
  };
2781
2823
  };
2782
2824
 
@@ -8086,12 +8128,12 @@ function sanitizeObject(obj, sensitiveFields = ['apiKey', 'token', 'secret', 'pa
8086
8128
  const isRetryableAnthropicError = (error) => {
8087
8129
  if (error instanceof Error) {
8088
8130
  const message = error.message;
8089
- if (message.includes('429') ||
8090
- message.includes('500') ||
8091
- message.includes('503') ||
8092
- message.includes('529') ||
8093
- message.includes('rate limit') ||
8094
- message.includes('overloaded')) {
8131
+ if (message.includes("429") ||
8132
+ message.includes("500") ||
8133
+ message.includes("503") ||
8134
+ message.includes("529") ||
8135
+ message.includes("rate limit") ||
8136
+ message.includes("overloaded")) {
8095
8137
  return true;
8096
8138
  }
8097
8139
  }
@@ -8106,8 +8148,11 @@ const isRetryableAnthropicError = (error) => {
8106
8148
  function translateToolsToAnthropic(tools) {
8107
8149
  return tools.map((tool) => ({
8108
8150
  name: tool.function.name,
8109
- description: tool.function.description || '',
8110
- input_schema: (tool.function.parameters || { type: 'object', properties: {} }),
8151
+ description: tool.function.description || "",
8152
+ input_schema: (tool.function.parameters || {
8153
+ type: "object",
8154
+ properties: {},
8155
+ }),
8111
8156
  }));
8112
8157
  }
8113
8158
  /**
@@ -8120,27 +8165,31 @@ function translateContextToAnthropic(context) {
8120
8165
  const systemParts = [];
8121
8166
  const messages = [];
8122
8167
  for (const msg of context) {
8123
- if (msg.role === 'system' || msg.role === 'developer') {
8124
- if (typeof msg.content === 'string') {
8168
+ if (msg.role === "system" || msg.role === "developer") {
8169
+ if (typeof msg.content === "string") {
8125
8170
  systemParts.push(msg.content);
8126
8171
  }
8127
8172
  continue;
8128
8173
  }
8129
- if (msg.role === 'user') {
8130
- const content = typeof msg.content === 'string'
8174
+ if (msg.role === "user") {
8175
+ const content = typeof msg.content === "string"
8131
8176
  ? msg.content
8132
8177
  : JSON.stringify(msg.content);
8133
- messages.push({ role: 'user', content });
8178
+ messages.push({ role: "user", content });
8134
8179
  continue;
8135
8180
  }
8136
- if (msg.role === 'assistant') {
8181
+ if (msg.role === "assistant") {
8137
8182
  const assistantMsg = msg;
8138
8183
  // If the assistant message has tool_calls, translate to Anthropic tool_use blocks
8139
8184
  if (assistantMsg.tool_calls && assistantMsg.tool_calls.length > 0) {
8140
8185
  const contentBlocks = [];
8141
8186
  // Include text content if present
8142
- if (typeof assistantMsg.content === 'string' && assistantMsg.content.trim()) {
8143
- contentBlocks.push({ type: 'text', text: assistantMsg.content });
8187
+ if (typeof assistantMsg.content === "string" &&
8188
+ assistantMsg.content.trim()) {
8189
+ contentBlocks.push({
8190
+ type: "text",
8191
+ text: assistantMsg.content,
8192
+ });
8144
8193
  }
8145
8194
  // Translate each tool_call to a tool_use block
8146
8195
  for (const tc of assistantMsg.tool_calls) {
@@ -8152,32 +8201,36 @@ function translateContextToAnthropic(context) {
8152
8201
  input = { raw: tc.function.arguments };
8153
8202
  }
8154
8203
  contentBlocks.push({
8155
- type: 'tool_use',
8204
+ type: "tool_use",
8156
8205
  id: tc.id,
8157
8206
  name: tc.function.name,
8158
8207
  input,
8159
8208
  });
8160
8209
  }
8161
- messages.push({ role: 'assistant', content: contentBlocks });
8210
+ messages.push({ role: "assistant", content: contentBlocks });
8162
8211
  }
8163
8212
  else {
8164
- const content = typeof assistantMsg.content === 'string'
8213
+ const content = typeof assistantMsg.content === "string"
8165
8214
  ? assistantMsg.content
8166
8215
  : JSON.stringify(assistantMsg.content);
8167
- messages.push({ role: 'assistant', content });
8216
+ messages.push({ role: "assistant", content });
8168
8217
  }
8169
8218
  continue;
8170
8219
  }
8171
- if (msg.role === 'tool') {
8220
+ if (msg.role === "tool") {
8172
8221
  // Anthropic expects tool results as user messages with tool_result content blocks
8173
8222
  const toolMsg = msg;
8174
8223
  messages.push({
8175
- role: 'user',
8176
- content: [{
8177
- type: 'tool_result',
8224
+ role: "user",
8225
+ content: [
8226
+ {
8227
+ type: "tool_result",
8178
8228
  tool_use_id: toolMsg.tool_call_id,
8179
- content: typeof toolMsg.content === 'string' ? toolMsg.content : JSON.stringify(toolMsg.content),
8180
- }],
8229
+ content: typeof toolMsg.content === "string"
8230
+ ? toolMsg.content
8231
+ : JSON.stringify(toolMsg.content),
8232
+ },
8233
+ ],
8181
8234
  });
8182
8235
  continue;
8183
8236
  }
@@ -8198,13 +8251,13 @@ function translateContextToAnthropic(context) {
8198
8251
  merged.push({ role: msg.role, content: toContentBlocks(msg.content) });
8199
8252
  }
8200
8253
  }
8201
- return { messages: merged, systemText: systemParts.join('\n\n') };
8254
+ return { messages: merged, systemText: systemParts.join("\n\n") };
8202
8255
  }
8203
8256
  /** Convert string or content block array to a uniform content block array. */
8204
8257
  function toContentBlocks(content) {
8205
- if (typeof content === 'string') {
8258
+ if (typeof content === "string") {
8206
8259
  const textBlock = {
8207
- type: 'text',
8260
+ type: "text",
8208
8261
  text: content,
8209
8262
  citations: null,
8210
8263
  };
@@ -8224,11 +8277,11 @@ function toContentBlocks(content) {
8224
8277
  * @param options The options for the LLM call.
8225
8278
  * @return A promise that resolves to the response from the Anthropic API.
8226
8279
  */
8227
- async function makeAnthropicCall(content, responseFormat = 'text', options = {}) {
8228
- const model = (options.model || 'claude-sonnet-4-6');
8280
+ async function makeAnthropicCall(content, responseFormat = "text", options = {}) {
8281
+ const model = (options.model || "claude-sonnet-4-6");
8229
8282
  const apiKey = options.apiKey || getSecrets().anthropic.apiKey;
8230
8283
  if (!apiKey) {
8231
- throw new Error('Anthropic API key is not provided and ANTHROPIC_API_KEY environment variable is not set');
8284
+ throw new Error("Anthropic API key is not provided and ANTHROPIC_API_KEY environment variable is not set");
8232
8285
  }
8233
8286
  const client = new Anthropic({
8234
8287
  apiKey,
@@ -8240,8 +8293,10 @@ async function makeAnthropicCall(content, responseFormat = 'text', options = {})
8240
8293
  systemParts.push(options.developerPrompt);
8241
8294
  }
8242
8295
  // If JSON response is requested, instruct the model via system prompt
8243
- if (responseFormat === 'json' || (typeof responseFormat === 'object' && responseFormat.type === 'json_schema')) {
8244
- systemParts.push('You MUST respond with valid JSON only. No markdown, no code blocks, no explanatory text — just the raw JSON object or array.');
8296
+ if (responseFormat === "json" ||
8297
+ (typeof responseFormat === "object" &&
8298
+ responseFormat.type === "json_schema")) {
8299
+ systemParts.push("You MUST respond with valid JSON only. No markdown, no code blocks, no explanatory text — just the raw JSON object or array.");
8245
8300
  }
8246
8301
  // Build messages array
8247
8302
  const messages = [];
@@ -8254,7 +8309,7 @@ async function makeAnthropicCall(content, responseFormat = 'text', options = {})
8254
8309
  messages.push(...translated.messages);
8255
8310
  }
8256
8311
  // Add user content
8257
- messages.push({ role: 'user', content });
8312
+ messages.push({ role: "user", content });
8258
8313
  // Build request params
8259
8314
  const requestParams = {
8260
8315
  model,
@@ -8263,7 +8318,7 @@ async function makeAnthropicCall(content, responseFormat = 'text', options = {})
8263
8318
  };
8264
8319
  // Add system prompt if present
8265
8320
  if (systemParts.length > 0) {
8266
- requestParams.system = systemParts.join('\n\n');
8321
+ requestParams.system = systemParts.join("\n\n");
8267
8322
  }
8268
8323
  // Add temperature if specified
8269
8324
  if (options.temperature !== undefined) {
@@ -8286,14 +8341,14 @@ async function makeAnthropicCall(content, responseFormat = 'text', options = {})
8286
8341
  const inputTokens = response.usage.input_tokens;
8287
8342
  const outputTokens = response.usage.output_tokens;
8288
8343
  // Track cost
8289
- getLLMCostTracker().trackUsage('anthropic', model, inputTokens, outputTokens);
8344
+ getLLMCostTracker().trackUsage("anthropic", model, inputTokens, outputTokens);
8290
8345
  // Extract tool use blocks
8291
- const toolUseBlocks = response.content.filter((block) => block.type === 'tool_use');
8346
+ const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
8292
8347
  if (toolUseBlocks.length > 0) {
8293
8348
  // Translate Anthropic tool_use to OpenAI tool_calls format
8294
8349
  const toolCalls = toolUseBlocks.map((block) => ({
8295
8350
  id: block.id,
8296
- type: 'function',
8351
+ type: "function",
8297
8352
  function: {
8298
8353
  name: block.name,
8299
8354
  arguments: JSON.stringify(block.input),
@@ -8312,22 +8367,22 @@ async function makeAnthropicCall(content, responseFormat = 'text', options = {})
8312
8367
  prompt_tokens: inputTokens,
8313
8368
  completion_tokens: outputTokens,
8314
8369
  reasoning_tokens: 0,
8315
- provider: 'anthropic',
8370
+ provider: "anthropic",
8316
8371
  model,
8317
- cost: calculateCost('anthropic', model, inputTokens, outputTokens),
8372
+ cost: calculateCost("anthropic", model, inputTokens, outputTokens),
8318
8373
  },
8319
8374
  tool_calls: toolCalls,
8320
8375
  };
8321
8376
  }
8322
8377
  // Extract text content
8323
8378
  const textContent = response.content
8324
- .filter((block) => block.type === 'text')
8379
+ .filter((block) => block.type === "text")
8325
8380
  .map((block) => block.text)
8326
- .join('');
8381
+ .join("");
8327
8382
  // Parse response
8328
8383
  const parsedResponse = await parseResponse(textContent, responseFormat);
8329
8384
  if (parsedResponse === null) {
8330
- throw new Error('Failed to parse Anthropic response');
8385
+ throw new Error("Failed to parse Anthropic response");
8331
8386
  }
8332
8387
  return {
8333
8388
  response: parsedResponse,
@@ -8335,9 +8390,9 @@ async function makeAnthropicCall(content, responseFormat = 'text', options = {})
8335
8390
  prompt_tokens: inputTokens,
8336
8391
  completion_tokens: outputTokens,
8337
8392
  reasoning_tokens: 0,
8338
- provider: 'anthropic',
8393
+ provider: "anthropic",
8339
8394
  model,
8340
- cost: calculateCost('anthropic', model, inputTokens, outputTokens),
8395
+ cost: calculateCost("anthropic", model, inputTokens, outputTokens),
8341
8396
  },
8342
8397
  };
8343
8398
  }
@@ -8359,7 +8414,9 @@ async function makeAnthropicCall(content, responseFormat = 'text', options = {})
8359
8414
  const isRetryableError = (error) => {
8360
8415
  if (error instanceof Error) {
8361
8416
  const message = error.message;
8362
- if (message.includes('429') || message.includes('rate limit') || message.includes('Rate limit')) {
8417
+ if (message.includes("429") ||
8418
+ message.includes("rate limit") ||
8419
+ message.includes("Rate limit")) {
8363
8420
  return true;
8364
8421
  }
8365
8422
  }
@@ -8373,14 +8430,16 @@ function resolveApiKey(provider, optionsApiKey) {
8373
8430
  if (optionsApiKey)
8374
8431
  return optionsApiKey;
8375
8432
  const secrets = getSecrets();
8376
- const pathParts = provider.apiKeySecretPath.split('.');
8433
+ const pathParts = provider.apiKeySecretPath.split(".");
8377
8434
  let current = secrets;
8378
8435
  for (const part of pathParts) {
8379
- if (current === null || current === undefined || typeof current !== 'object')
8380
- return '';
8436
+ if (current === null ||
8437
+ current === undefined ||
8438
+ typeof current !== "object")
8439
+ return "";
8381
8440
  current = current[part];
8382
8441
  }
8383
- return (typeof current === 'string' ? current : '') || '';
8442
+ return (typeof current === "string" ? current : "") || "";
8384
8443
  }
8385
8444
  /**
8386
8445
  * Makes a call to an OpenAI-compatible provider (Kimi, Qwen, or any future provider).
@@ -8394,12 +8453,12 @@ function resolveApiKey(provider, optionsApiKey) {
8394
8453
  * @param providerName The provider key in OPENAI_COMPATIBLE_PROVIDERS.
8395
8454
  * @return A promise that resolves to the response from the provider.
8396
8455
  */
8397
- async function makeOpenAICompatibleCall(content, responseFormat = 'text', options = {}, providerName) {
8456
+ async function makeOpenAICompatibleCall(content, responseFormat = "text", options = {}, providerName) {
8398
8457
  const providerConfig = OPENAI_COMPATIBLE_PROVIDERS[providerName];
8399
8458
  if (!providerConfig) {
8400
8459
  throw new Error(`Unknown OpenAI-compatible provider: ${providerName}`);
8401
8460
  }
8402
- const model = normalizeModelName(options.model || '');
8461
+ const model = normalizeModelName(options.model || "");
8403
8462
  const apiKey = resolveApiKey(providerConfig, options.apiKey);
8404
8463
  if (!apiKey) {
8405
8464
  throw new Error(`${providerConfig.name} API key is not provided and ${providerConfig.apiKeyEnvVar} environment variable is not set`);
@@ -8412,31 +8471,36 @@ async function makeOpenAICompatibleCall(content, responseFormat = 'text', option
8412
8471
  const messages = [];
8413
8472
  // Add system message with developer prompt if present
8414
8473
  if (options.developerPrompt) {
8415
- messages.push({ role: 'system', content: options.developerPrompt });
8474
+ messages.push({ role: "system", content: options.developerPrompt });
8416
8475
  }
8417
8476
  // Add context if present
8418
8477
  if (options.context) {
8419
8478
  messages.push(...options.context);
8420
8479
  }
8421
8480
  // Add user content
8422
- if (typeof content === 'string') {
8423
- messages.push({ role: 'user', content });
8481
+ if (typeof content === "string") {
8482
+ messages.push({ role: "user", content });
8424
8483
  }
8425
8484
  else {
8426
- messages.push({ role: 'user', content });
8485
+ messages.push({ role: "user", content });
8427
8486
  }
8428
8487
  // Determine if the model supports JSON mode
8429
8488
  const supportsJson = isValidModel(model) && getModelCapabilities(model).supportsJson;
8430
8489
  // If JSON response format, add hint to system prompt
8431
- if ((responseFormat === 'json' || (typeof responseFormat === 'object' && responseFormat.type === 'json_schema')) &&
8490
+ if ((responseFormat === "json" ||
8491
+ (typeof responseFormat === "object" &&
8492
+ responseFormat.type === "json_schema")) &&
8432
8493
  supportsJson) {
8433
- if (!messages.some((m) => m.role === 'system')) {
8434
- messages.unshift({ role: 'system', content: 'Please respond in valid JSON format.' });
8494
+ if (!messages.some((m) => m.role === "system")) {
8495
+ messages.unshift({
8496
+ role: "system",
8497
+ content: "Please respond in valid JSON format.",
8498
+ });
8435
8499
  }
8436
8500
  else {
8437
- const systemMsgIndex = messages.findIndex((m) => m.role === 'system');
8501
+ const systemMsgIndex = messages.findIndex((m) => m.role === "system");
8438
8502
  const systemMsg = messages[systemMsgIndex];
8439
- if (typeof systemMsg.content === 'string') {
8503
+ if (typeof systemMsg.content === "string") {
8440
8504
  messages[systemMsgIndex] = {
8441
8505
  ...systemMsg,
8442
8506
  content: `${systemMsg.content} Please respond in valid JSON format.`,
@@ -8449,8 +8513,8 @@ async function makeOpenAICompatibleCall(content, responseFormat = 'text', option
8449
8513
  messages,
8450
8514
  };
8451
8515
  // Add response format if JSON is supported
8452
- if (responseFormat !== 'text' && supportsJson) {
8453
- queryOptions.response_format = { type: 'json_object' };
8516
+ if (responseFormat !== "text" && supportsJson) {
8517
+ queryOptions.response_format = { type: "json_object" };
8454
8518
  }
8455
8519
  // Temperature
8456
8520
  if (options.temperature !== undefined) {
@@ -8508,7 +8572,7 @@ async function makeOpenAICompatibleCall(content, responseFormat = 'text', option
8508
8572
  };
8509
8573
  }
8510
8574
  // Handle regular responses
8511
- const textContent = completion.choices[0]?.message?.content || '';
8575
+ const textContent = completion.choices[0]?.message?.content || "";
8512
8576
  const parsedResponse = await parseResponse(textContent, responseFormat);
8513
8577
  if (parsedResponse === null) {
8514
8578
  throw new Error(`Failed to parse ${providerConfig.name} response`);
@@ -8800,7 +8864,9 @@ const isRetryableDeepseekError = (error) => {
8800
8864
  if (error instanceof Error) {
8801
8865
  const message = error.message;
8802
8866
  // Retry only on rate limits (429)
8803
- if (message.includes('429') || message.includes('rate limit') || message.includes('Rate limit')) {
8867
+ if (message.includes("429") ||
8868
+ message.includes("rate limit") ||
8869
+ message.includes("Rate limit")) {
8804
8870
  return true;
8805
8871
  }
8806
8872
  }
@@ -8810,7 +8876,7 @@ const isRetryableDeepseekError = (error) => {
8810
8876
  * Default options for Deepseek API calls
8811
8877
  */
8812
8878
  const DEFAULT_DEEPSEEK_OPTIONS = {
8813
- defaultModel: 'deepseek-chat',
8879
+ defaultModel: "deepseek-chat",
8814
8880
  };
8815
8881
  /**
8816
8882
  * Checks if the given model is a supported Deepseek model
@@ -8822,7 +8888,7 @@ const isSupportedDeepseekModel = (model) => {
8822
8888
  return false;
8823
8889
  }
8824
8890
  const capabilities = getModelCapabilities(model);
8825
- return capabilities.provider === 'deepseek';
8891
+ return capabilities.provider === "deepseek";
8826
8892
  };
8827
8893
  /**
8828
8894
  * Checks if the given Deepseek model supports JSON output format
@@ -8855,17 +8921,19 @@ const supportsToolCalling = (model) => {
8855
8921
  */
8856
8922
  function getDeepseekResponseFormatOption(responseFormat, model) {
8857
8923
  // Check if the model supports JSON output
8858
- if (responseFormat !== 'text' && !supportsJsonOutput(model)) {
8924
+ if (responseFormat !== "text" && !supportsJsonOutput(model)) {
8859
8925
  getLumicLogger().warn(`Model ${model} does not support JSON output. Using text format instead.`);
8860
- return { type: 'text' };
8926
+ return { type: "text" };
8861
8927
  }
8862
- if (responseFormat === 'text') {
8863
- return { type: 'text' };
8928
+ if (responseFormat === "text") {
8929
+ return { type: "text" };
8864
8930
  }
8865
- if (responseFormat === 'json' || (typeof responseFormat === 'object' && responseFormat.type === 'json_schema')) {
8866
- return { type: 'json_object' };
8931
+ if (responseFormat === "json" ||
8932
+ (typeof responseFormat === "object" &&
8933
+ responseFormat.type === "json_schema")) {
8934
+ return { type: "json_object" };
8867
8935
  }
8868
- return { type: 'text' };
8936
+ return { type: "text" };
8869
8937
  }
8870
8938
  /**
8871
8939
  * Creates a completion using the Deepseek API
@@ -8884,24 +8952,26 @@ async function createDeepseekCompletion(content, responseFormat, options = {}) {
8884
8952
  throw new Error(`Unsupported Deepseek model: ${normalizedModel}. Please use 'deepseek-chat' or 'deepseek-reasoner'.`);
8885
8953
  }
8886
8954
  // Check if tools are requested with a model that doesn't support them
8887
- if (options.tools && options.tools.length > 0 && !supportsToolCalling(normalizedModel)) {
8955
+ if (options.tools &&
8956
+ options.tools.length > 0 &&
8957
+ !supportsToolCalling(normalizedModel)) {
8888
8958
  throw new Error(`Model ${normalizedModel} does not support tool calling.`);
8889
8959
  }
8890
8960
  const apiKey = options.apiKey || getSecrets().deepseek.apiKey;
8891
8961
  if (!apiKey) {
8892
- throw new Error('Deepseek API key is not provided and DEEPSEEK_API_KEY environment variable is not set');
8962
+ throw new Error("Deepseek API key is not provided and DEEPSEEK_API_KEY environment variable is not set");
8893
8963
  }
8894
8964
  // Initialize OpenAI client with Deepseek API URL
8895
8965
  const openai = new OpenAI({
8896
8966
  apiKey,
8897
- baseURL: 'https://api.deepseek.com',
8967
+ baseURL: "https://api.deepseek.com",
8898
8968
  timeout: options.timeout ?? LLM_TIMEOUT_MS,
8899
8969
  });
8900
8970
  const messages = [];
8901
8971
  // Add system message with developer prompt if present
8902
8972
  if (options.developerPrompt) {
8903
8973
  messages.push({
8904
- role: 'system',
8974
+ role: "system",
8905
8975
  content: options.developerPrompt,
8906
8976
  });
8907
8977
  }
@@ -8910,33 +8980,35 @@ async function createDeepseekCompletion(content, responseFormat, options = {}) {
8910
8980
  messages.push(...options.context);
8911
8981
  }
8912
8982
  // Add user content
8913
- if (typeof content === 'string') {
8983
+ if (typeof content === "string") {
8914
8984
  messages.push({
8915
- role: 'user',
8985
+ role: "user",
8916
8986
  content,
8917
8987
  });
8918
8988
  }
8919
8989
  else {
8920
8990
  messages.push({
8921
- role: 'user',
8991
+ role: "user",
8922
8992
  content,
8923
8993
  });
8924
8994
  }
8925
8995
  // If JSON response format, include a hint in the system prompt
8926
- if ((responseFormat === 'json' || (typeof responseFormat === 'object' && responseFormat.type === 'json_schema'))
8927
- && supportsJsonOutput(normalizedModel)) {
8996
+ if ((responseFormat === "json" ||
8997
+ (typeof responseFormat === "object" &&
8998
+ responseFormat.type === "json_schema")) &&
8999
+ supportsJsonOutput(normalizedModel)) {
8928
9000
  // If there's no system message yet, add one
8929
- if (!messages.some(m => m.role === 'system')) {
9001
+ if (!messages.some((m) => m.role === "system")) {
8930
9002
  messages.unshift({
8931
- role: 'system',
8932
- content: 'Please respond in valid JSON format.',
9003
+ role: "system",
9004
+ content: "Please respond in valid JSON format.",
8933
9005
  });
8934
9006
  }
8935
9007
  else {
8936
9008
  // Append to existing system message
8937
- const systemMsgIndex = messages.findIndex(m => m.role === 'system');
9009
+ const systemMsgIndex = messages.findIndex((m) => m.role === "system");
8938
9010
  const systemMsg = messages[systemMsgIndex];
8939
- if (typeof systemMsg.content === 'string') {
9011
+ if (typeof systemMsg.content === "string") {
8940
9012
  messages[systemMsgIndex] = {
8941
9013
  ...systemMsg,
8942
9014
  content: `${systemMsg.content} Please respond in valid JSON format.`,
@@ -8977,7 +9049,7 @@ async function createDeepseekCompletion(content, responseFormat, options = {}) {
8977
9049
  0;
8978
9050
  return {
8979
9051
  id: completion.id,
8980
- content: completion.choices[0]?.message?.content || '',
9052
+ content: completion.choices[0]?.message?.content || "",
8981
9053
  tool_calls: completion.choices[0]?.message?.tool_calls,
8982
9054
  usage: {
8983
9055
  prompt_tokens: completion.usage?.prompt_tokens ?? 0,
@@ -8986,7 +9058,7 @@ async function createDeepseekCompletion(content, responseFormat, options = {}) {
8986
9058
  cached_tokens: cachedTokens,
8987
9059
  },
8988
9060
  system_fingerprint: completion.system_fingerprint,
8989
- provider: 'deepseek',
9061
+ provider: "deepseek",
8990
9062
  model: normalizedModel,
8991
9063
  };
8992
9064
  }
@@ -9003,7 +9075,7 @@ async function createDeepseekCompletion(content, responseFormat, options = {}) {
9003
9075
  * @param options Configuration options including model ('deepseek-chat' or 'deepseek-reasoner'), tools, and apiKey.
9004
9076
  * @return A promise that resolves to the response from the Deepseek API.
9005
9077
  */
9006
- const makeDeepseekCall = async (content, responseFormat = 'json', options = {}) => {
9078
+ const makeDeepseekCall = async (content, responseFormat = "json", options = {}) => {
9007
9079
  // Set default model if not provided
9008
9080
  const mergedOptions = {
9009
9081
  ...options,
@@ -9013,17 +9085,17 @@ const makeDeepseekCall = async (content, responseFormat = 'json', options = {})
9013
9085
  }
9014
9086
  const modelName = normalizeModelName(mergedOptions.model);
9015
9087
  // Check if the requested response format is compatible with the model
9016
- if (responseFormat !== 'text' && !supportsJsonOutput(modelName)) {
9088
+ if (responseFormat !== "text" && !supportsJsonOutput(modelName)) {
9017
9089
  getLumicLogger().warn(`Model ${modelName} does not support JSON output. Will return error in the response.`);
9018
9090
  return {
9019
9091
  response: {
9020
- error: `Model ${modelName} does not support JSON output format.`
9092
+ error: `Model ${modelName} does not support JSON output format.`,
9021
9093
  },
9022
9094
  usage: {
9023
9095
  prompt_tokens: 0,
9024
9096
  completion_tokens: 0,
9025
9097
  reasoning_tokens: 0,
9026
- provider: 'deepseek',
9098
+ provider: "deepseek",
9027
9099
  model: modelName,
9028
9100
  cached_tokens: 0,
9029
9101
  cost: 0,
@@ -9032,17 +9104,19 @@ const makeDeepseekCall = async (content, responseFormat = 'json', options = {})
9032
9104
  };
9033
9105
  }
9034
9106
  // Check if tools are requested with a model that doesn't support them
9035
- if (mergedOptions.tools && mergedOptions.tools.length > 0 && !supportsToolCalling(modelName)) {
9107
+ if (mergedOptions.tools &&
9108
+ mergedOptions.tools.length > 0 &&
9109
+ !supportsToolCalling(modelName)) {
9036
9110
  getLumicLogger().warn(`Model ${modelName} does not support tool calling. Will return error in the response.`);
9037
9111
  return {
9038
9112
  response: {
9039
- error: `Model ${modelName} does not support tool calling.`
9113
+ error: `Model ${modelName} does not support tool calling.`,
9040
9114
  },
9041
9115
  usage: {
9042
9116
  prompt_tokens: 0,
9043
9117
  completion_tokens: 0,
9044
9118
  reasoning_tokens: 0,
9045
- provider: 'deepseek',
9119
+ provider: "deepseek",
9046
9120
  model: modelName,
9047
9121
  cached_tokens: 0,
9048
9122
  cost: 0,
@@ -9054,7 +9128,7 @@ const makeDeepseekCall = async (content, responseFormat = 'json', options = {})
9054
9128
  const completion = await createDeepseekCompletion(content, responseFormat, mergedOptions);
9055
9129
  // Track cost in the global cost tracker. Pass cached tokens through so the
9056
9130
  // discounted cached-input pricing tier is applied.
9057
- getLLMCostTracker().trackUsage('deepseek', completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens);
9131
+ getLLMCostTracker().trackUsage("deepseek", completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens);
9058
9132
  // Handle tool calls similarly to OpenAI
9059
9133
  if (completion.tool_calls && completion.tool_calls.length > 0) {
9060
9134
  const toolCallResponse = {
@@ -9070,10 +9144,10 @@ const makeDeepseekCall = async (content, responseFormat = 'json', options = {})
9070
9144
  prompt_tokens: completion.usage.prompt_tokens,
9071
9145
  completion_tokens: completion.usage.completion_tokens,
9072
9146
  reasoning_tokens: 0, // Deepseek doesn't provide reasoning tokens separately
9073
- provider: 'deepseek',
9147
+ provider: "deepseek",
9074
9148
  model: completion.model,
9075
9149
  cached_tokens: completion.usage.cached_tokens,
9076
- cost: calculateCost('deepseek', completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens),
9150
+ cost: calculateCost("deepseek", completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens),
9077
9151
  },
9078
9152
  tool_calls: completion.tool_calls,
9079
9153
  };
@@ -9081,7 +9155,7 @@ const makeDeepseekCall = async (content, responseFormat = 'json', options = {})
9081
9155
  // Handle regular responses
9082
9156
  const parsedResponse = await parseResponse(completion.content, responseFormat);
9083
9157
  if (parsedResponse === null) {
9084
- throw new Error('Failed to parse Deepseek response');
9158
+ throw new Error("Failed to parse Deepseek response");
9085
9159
  }
9086
9160
  return {
9087
9161
  response: parsedResponse,
@@ -9089,10 +9163,10 @@ const makeDeepseekCall = async (content, responseFormat = 'json', options = {})
9089
9163
  prompt_tokens: completion.usage.prompt_tokens,
9090
9164
  completion_tokens: completion.usage.completion_tokens,
9091
9165
  reasoning_tokens: 0, // Deepseek doesn't provide reasoning tokens separately
9092
- provider: 'deepseek',
9166
+ provider: "deepseek",
9093
9167
  model: completion.model,
9094
9168
  cached_tokens: completion.usage.cached_tokens,
9095
- cost: calculateCost('deepseek', completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens),
9169
+ cost: calculateCost("deepseek", completion.model, completion.usage.prompt_tokens, completion.usage.completion_tokens, 0, completion.usage.cached_tokens),
9096
9170
  },
9097
9171
  tool_calls: completion.tool_calls,
9098
9172
  };
@@ -9102,13 +9176,13 @@ const makeDeepseekCall = async (content, responseFormat = 'json', options = {})
9102
9176
  getLumicLogger().error(`Error in Deepseek API call: ${sanitizeError(error)}`);
9103
9177
  return {
9104
9178
  response: {
9105
- error: sanitizeError(error)
9179
+ error: sanitizeError(error),
9106
9180
  },
9107
9181
  usage: {
9108
9182
  prompt_tokens: 0,
9109
9183
  completion_tokens: 0,
9110
9184
  reasoning_tokens: 0,
9111
- provider: 'deepseek',
9185
+ provider: "deepseek",
9112
9186
  model: modelName,
9113
9187
  cached_tokens: 0,
9114
9188
  cost: 0,
@@ -9217,15 +9291,15 @@ const generateCacheKey = (auth, envVarsCheck = null) => {
9217
9291
  if (auth) {
9218
9292
  return `${auth.AWS_ACCESS_KEY_ID}:${auth.AWS_SECRET_ACCESS_KEY}:${auth.AWS_REGION}`;
9219
9293
  }
9220
- if (envVarsCheck?.source === 'lambda') {
9294
+ if (envVarsCheck?.source === "lambda") {
9221
9295
  // In Lambda, use function name as cache key since it uses IAM role
9222
9296
  const secrets = getSecrets();
9223
- return `lambda:${secrets.aws.lambdaFunctionName || 'default'}`;
9297
+ return `lambda:${secrets.aws.lambdaFunctionName || "default"}`;
9224
9298
  }
9225
9299
  if (envVarsCheck?.vars) {
9226
9300
  return `${envVarsCheck.vars.accessKeyId}:${envVarsCheck.vars.secretAccessKey}:${envVarsCheck.vars.region}`;
9227
9301
  }
9228
- return 'default';
9302
+ return "default";
9229
9303
  };
9230
9304
  const validateEnvironmentVars = () => {
9231
9305
  const secrets = getSecrets();
@@ -9238,37 +9312,37 @@ const validateEnvironmentVars = () => {
9238
9312
  // We're in a Lambda environment
9239
9313
  return {
9240
9314
  isValid: true,
9241
- source: 'lambda',
9242
- vars: { accessKeyId: '', secretAccessKey: '', region: '' } // No need for explicit credentials in Lambda
9315
+ source: "lambda",
9316
+ vars: { accessKeyId: "", secretAccessKey: "", region: "" }, // No need for explicit credentials in Lambda
9243
9317
  };
9244
9318
  }
9245
9319
  else if (areVarsComplete(secrets.aws.myAccessKeyId, secrets.aws.mySecretAccessKey, secrets.aws.myRegion)) {
9246
9320
  return {
9247
9321
  isValid: true,
9248
- source: 'my_prefix',
9322
+ source: "my_prefix",
9249
9323
  vars: {
9250
- accessKeyId: secrets.aws.myAccessKeyId,
9251
- secretAccessKey: secrets.aws.mySecretAccessKey,
9252
- region: secrets.aws.myRegion
9253
- }
9324
+ accessKeyId: secrets.aws.myAccessKeyId ?? "",
9325
+ secretAccessKey: secrets.aws.mySecretAccessKey ?? "",
9326
+ region: secrets.aws.myRegion ?? "",
9327
+ },
9254
9328
  };
9255
9329
  }
9256
9330
  else if (areVarsComplete(secrets.aws.accessKeyId, secrets.aws.secretAccessKey, secrets.aws.region)) {
9257
9331
  return {
9258
9332
  isValid: true,
9259
- source: 'standard',
9333
+ source: "standard",
9260
9334
  vars: {
9261
- accessKeyId: secrets.aws.accessKeyId,
9262
- secretAccessKey: secrets.aws.secretAccessKey,
9263
- region: secrets.aws.region
9264
- }
9335
+ accessKeyId: secrets.aws.accessKeyId ?? "",
9336
+ secretAccessKey: secrets.aws.secretAccessKey ?? "",
9337
+ region: secrets.aws.region ?? "",
9338
+ },
9265
9339
  };
9266
9340
  }
9267
9341
  // If we get here, no complete set of variables was found
9268
9342
  return {
9269
9343
  isValid: false,
9270
9344
  source: null,
9271
- missingVars: []
9345
+ missingVars: [],
9272
9346
  };
9273
9347
  };
9274
9348
  const initialiseAWSClient = (ClientClass, auth = null) => {
@@ -9277,48 +9351,52 @@ const initialiseAWSClient = (ClientClass, auth = null) => {
9277
9351
  const requestTimeout = ClientClass === clientS3.S3Client ? AWS_S3_TIMEOUT_MS : AWS_LAMBDA_TIMEOUT_MS;
9278
9352
  // Case 1: Explicit auth provided
9279
9353
  if (auth) {
9280
- if (typeof auth !== 'object' || auth === null) {
9281
- throw new Error('Auth parameter must be an object');
9354
+ if (typeof auth !== "object" || auth === null) {
9355
+ throw new Error("Auth parameter must be an object");
9282
9356
  }
9283
- const requiredAuthFields = ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY', 'AWS_REGION'];
9284
- const missingFields = requiredAuthFields.filter(field => !auth[field]);
9357
+ const requiredAuthFields = [
9358
+ "AWS_ACCESS_KEY_ID",
9359
+ "AWS_SECRET_ACCESS_KEY",
9360
+ "AWS_REGION",
9361
+ ];
9362
+ const missingFields = requiredAuthFields.filter((field) => !auth[field]);
9285
9363
  if (missingFields.length > 0) {
9286
- throw new Error(`Auth object is missing required fields: ${missingFields.join(', ')}`);
9364
+ throw new Error(`Auth object is missing required fields: ${missingFields.join(", ")}`);
9287
9365
  }
9288
9366
  return new ClientClass({
9289
9367
  region: auth.AWS_REGION,
9290
9368
  credentials: {
9291
9369
  accessKeyId: auth.AWS_ACCESS_KEY_ID,
9292
- secretAccessKey: auth.AWS_SECRET_ACCESS_KEY
9370
+ secretAccessKey: auth.AWS_SECRET_ACCESS_KEY,
9293
9371
  },
9294
9372
  requestHandler: {
9295
- requestTimeout
9296
- }
9373
+ requestTimeout,
9374
+ },
9297
9375
  });
9298
9376
  }
9299
9377
  // Case 2: Check environment variables
9300
9378
  const envVarsCheck = validateEnvironmentVars();
9301
9379
  if (!envVarsCheck.isValid) {
9302
- throw new Error('No valid AWS credentials found in environment variables');
9380
+ throw new Error("No valid AWS credentials found in environment variables");
9303
9381
  }
9304
9382
  // Case 2a: Lambda execution environment
9305
- if (envVarsCheck.source === 'lambda') {
9383
+ if (envVarsCheck.source === "lambda") {
9306
9384
  return new ClientClass({
9307
9385
  requestHandler: {
9308
- requestTimeout
9309
- }
9386
+ requestTimeout,
9387
+ },
9310
9388
  }); // AWS SDK will automatically use Lambda role credentials
9311
9389
  }
9312
9390
  // Case 2b: MY_ prefixed vars or standard AWS vars
9313
9391
  return new ClientClass({
9314
- region: envVarsCheck.vars.region,
9392
+ region: envVarsCheck.vars?.region ?? "",
9315
9393
  credentials: {
9316
- accessKeyId: envVarsCheck.vars.accessKeyId,
9317
- secretAccessKey: envVarsCheck.vars.secretAccessKey
9394
+ accessKeyId: envVarsCheck.vars?.accessKeyId ?? "",
9395
+ secretAccessKey: envVarsCheck.vars?.secretAccessKey ?? "",
9318
9396
  },
9319
9397
  requestHandler: {
9320
- requestTimeout
9321
- }
9398
+ requestTimeout,
9399
+ },
9322
9400
  });
9323
9401
  }
9324
9402
  catch (error) {
@@ -9331,7 +9409,9 @@ const initialiseS3Client = (auth = null) => {
9331
9409
  const envVarsCheck = auth ? null : validateEnvironmentVars();
9332
9410
  const cacheKey = generateCacheKey(auth, envVarsCheck);
9333
9411
  if (s3ClientCache.has(cacheKey)) {
9334
- return s3ClientCache.get(cacheKey);
9412
+ const cached = s3ClientCache.get(cacheKey);
9413
+ if (cached)
9414
+ return cached;
9335
9415
  }
9336
9416
  // Create new client and cache it
9337
9417
  const client = initialiseAWSClient(clientS3.S3Client, auth);
@@ -9343,7 +9423,9 @@ const initialiseLambdaClient = (auth = null) => {
9343
9423
  const envVarsCheck = auth ? null : validateEnvironmentVars();
9344
9424
  const cacheKey = generateCacheKey(auth, envVarsCheck);
9345
9425
  if (lambdaClientCache.has(cacheKey)) {
9346
- return lambdaClientCache.get(cacheKey);
9426
+ const cached = lambdaClientCache.get(cacheKey);
9427
+ if (cached)
9428
+ return cached;
9347
9429
  }
9348
9430
  // Create new client and cache it
9349
9431
  const client = initialiseAWSClient(clientLambda.Lambda, auth);
@@ -9843,15 +9925,17 @@ const isRetryableS3Error = (error) => {
9843
9925
  if (error instanceof Error) {
9844
9926
  const message = error.message;
9845
9927
  // Retry on throttling
9846
- if (message.includes('SlowDown') || message.includes('RequestTimeout')) {
9928
+ if (message.includes("SlowDown") || message.includes("RequestTimeout")) {
9847
9929
  return true;
9848
9930
  }
9849
9931
  // Retry on 5xx server errors
9850
- if (message.includes('InternalError') || message.includes('ServiceUnavailable')) {
9932
+ if (message.includes("InternalError") ||
9933
+ message.includes("ServiceUnavailable")) {
9851
9934
  return true;
9852
9935
  }
9853
9936
  // Retry on connection errors
9854
- if (message.includes('RequestTimeTooSkewed') || message.includes('NetworkingError')) {
9937
+ if (message.includes("RequestTimeTooSkewed") ||
9938
+ message.includes("NetworkingError")) {
9855
9939
  return true;
9856
9940
  }
9857
9941
  }
@@ -9865,10 +9949,11 @@ const generateRandomHash = (length) => {
9865
9949
  };
9866
9950
  function generateDateTimeStamp() {
9867
9951
  const now = new Date();
9868
- return now.toISOString()
9869
- .replace(/T/, '-')
9870
- .replace(/\..+/, '')
9871
- .replace(/:/g, '-');
9952
+ return now
9953
+ .toISOString()
9954
+ .replace(/T/, "-")
9955
+ .replace(/\..+/, "")
9956
+ .replace(/:/g, "-");
9872
9957
  }
9873
9958
  const isValidBucketName = (name) => {
9874
9959
  const regex = /^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;
@@ -9899,7 +9984,7 @@ async function uploadFile(s3Client, bucketName, filePath, destinationPath, isPub
9899
9984
  Bucket: bucketName,
9900
9985
  Key: s3Key,
9901
9986
  Body: fileContent,
9902
- ACL: isPublic ? 'public-read' : undefined
9987
+ ACL: isPublic ? "public-read" : undefined,
9903
9988
  });
9904
9989
  await withRetry(() => s3Client.send(command), {
9905
9990
  maxRetries: 3,
@@ -9919,7 +10004,7 @@ async function uploadDirectory(s3Client, bucketName, dirPath, destinationPath, i
9919
10004
  Bucket: bucketName,
9920
10005
  Key: s3Key,
9921
10006
  Body: fileContent,
9922
- ACL: isPublic ? 'public-read' : undefined
10007
+ ACL: isPublic ? "public-read" : undefined,
9923
10008
  });
9924
10009
  await withRetry(() => s3Client.send(command), {
9925
10010
  maxRetries: 3,
@@ -9935,7 +10020,7 @@ async function zipDirectory(sourceDir, outPath) {
9935
10020
  const zip = new AdmZip();
9936
10021
  let fileCount = 0;
9937
10022
  try {
9938
- async function addFilesToZip(currentPath, relativePath = '') {
10023
+ async function addFilesToZip(currentPath, relativePath = "") {
9939
10024
  const files = await fs$1.readdir(currentPath, { withFileTypes: true });
9940
10025
  for (const file of files) {
9941
10026
  const filePath = path$1.join(currentPath, file.name);
@@ -9978,27 +10063,33 @@ async function downloadFromS3Helper(s3Client, bucketName, s3Path, localPath) {
9978
10063
  Prefix: s3Path,
9979
10064
  ContinuationToken: continuationToken,
9980
10065
  });
9981
- const listResponse = await withRetry(() => s3Client.send(listCommand), {
10066
+ const listResponse = (await withRetry(() => s3Client.send(listCommand), {
9982
10067
  maxRetries: 3,
9983
10068
  baseDelayMs: 1000,
9984
10069
  maxDelayMs: 15000,
9985
10070
  retryableErrors: isRetryableS3Error,
9986
- }, `S3:ListObjects:${bucketName}`);
10071
+ }, `S3:ListObjects:${bucketName}`));
9987
10072
  const objects = listResponse.Contents || [];
9988
10073
  if (objects.length === 0) {
9989
10074
  return { fileCount: 0, folderCount: 0, totalSize: 0, fileList: [] };
9990
10075
  }
9991
- if (objects.length === 1 && objects[0].Key?.endsWith('.zip')) {
10076
+ if (objects.length === 1 && objects[0].Key?.endsWith(".zip")) {
9992
10077
  // It's a zip file, download and extract it
9993
10078
  const zipPath = path$1.join(localPath, path$1.basename(objects[0].Key));
9994
10079
  await downloadFile(s3Client, bucketName, objects[0].Key, zipPath);
9995
- const { totalFiles, totalFolders, totalSize: extractedSize, fileList: extractedFileList } = await unzipFile(zipPath, localPath);
10080
+ const { totalFiles, totalFolders, totalSize: extractedSize, fileList: extractedFileList, } = await unzipFile(zipPath, localPath);
9996
10081
  await fs$1.unlink(zipPath);
9997
- return { fileCount: totalFiles, folderCount: totalFolders, totalSize: extractedSize, fileList: extractedFileList };
10082
+ return {
10083
+ fileCount: totalFiles,
10084
+ folderCount: totalFolders,
10085
+ totalSize: extractedSize,
10086
+ fileList: extractedFileList,
10087
+ };
9998
10088
  }
9999
10089
  else {
10000
10090
  // Non-zip files. Download files in batches.
10001
- for (let i = 0; i < objects.length; i += 1000) { // AWS allows up to 1000 per request
10091
+ for (let i = 0; i < objects.length; i += 1000) {
10092
+ // AWS allows up to 1000 per request
10002
10093
  const batch = objects.slice(i, i + 1000);
10003
10094
  await Promise.all(batch.map(async (obj) => {
10004
10095
  if (!obj.Key)
@@ -10014,7 +10105,9 @@ async function downloadFromS3Helper(s3Client, bucketName, s3Path, localPath) {
10014
10105
  }
10015
10106
  // Count folders
10016
10107
  const relativePath = path$1.relative(localPath, path$1.dirname(localFilePath));
10017
- if (relativePath && !relativePath.startsWith('..') && relativePath !== '.') {
10108
+ if (relativePath &&
10109
+ !relativePath.startsWith("..") &&
10110
+ relativePath !== ".") {
10018
10111
  folderCount++;
10019
10112
  }
10020
10113
  }));
@@ -10035,7 +10128,7 @@ async function downloadFile(s3Client, bucketName, s3Key, localFilePath) {
10035
10128
  await withRetry(async () => {
10036
10129
  const { Body } = await s3Client.send(getCommand);
10037
10130
  if (!Body)
10038
- throw new Error('No body returned from S3');
10131
+ throw new Error("No body returned from S3");
10039
10132
  const writeStream = fs.createWriteStream(localFilePath);
10040
10133
  await promises.pipeline(Body, writeStream);
10041
10134
  }, {
@@ -10091,17 +10184,19 @@ async function emptyBucket(s3Client, bucketName) {
10091
10184
  Bucket: bucketName,
10092
10185
  ContinuationToken: continuationToken,
10093
10186
  });
10094
- const response = await withRetry(() => s3Client.send(listCommand), {
10187
+ const response = (await withRetry(() => s3Client.send(listCommand), {
10095
10188
  maxRetries: 3,
10096
10189
  baseDelayMs: 1000,
10097
10190
  maxDelayMs: 15000,
10098
10191
  retryableErrors: isRetryableS3Error,
10099
- }, `S3:ListObjects:${bucketName}`);
10192
+ }, `S3:ListObjects:${bucketName}`));
10100
10193
  const { Contents, IsTruncated, NextContinuationToken } = response;
10101
10194
  if (Contents && Contents.length > 0) {
10102
10195
  const deleteCommand = new clientS3.DeleteObjectsCommand({
10103
10196
  Bucket: bucketName,
10104
- Delete: { Objects: Contents.map(({ Key }) => ({ Key: Key })) },
10197
+ Delete: {
10198
+ Objects: Contents.filter((c) => c.Key).map((c) => ({ Key: c.Key })),
10199
+ },
10105
10200
  });
10106
10201
  await withRetry(() => s3Client.send(deleteCommand), {
10107
10202
  maxRetries: 3,
@@ -23009,11 +23104,11 @@ let poolConfig = DEFAULT_POOL_CONFIG;
23009
23104
  async function loadApolloModules() {
23010
23105
  if (typeof window === "undefined" || process.env.AWS_EXECUTION_ENV) {
23011
23106
  // Server-side (or Lambda): load the CommonJS‑based implementation.
23012
- return (await Promise.resolve().then(function () { return require('./apollo-client.server-BTHAQqYl.js'); }));
23107
+ return (await Promise.resolve().then(function () { return require('./apollo-client.server-DB3jLbBx.js'); }));
23013
23108
  }
23014
23109
  else {
23015
23110
  // Client-side: load the ESM‑based implementation.
23016
- return (await Promise.resolve().then(function () { return require('./apollo-client.client-YzlpL7kf.js'); }));
23111
+ return (await Promise.resolve().then(function () { return require('./apollo-client.client-CyxU1hTu.js'); }));
23017
23112
  }
23018
23113
  }
23019
23114
  /**
@@ -79040,7 +79135,7 @@ const RETRY_CONFIG = {
79040
79135
  BASE_DELAY: 2000, // Increased base delay to 2 seconds
79041
79136
  MAX_DELAY: 64000,
79042
79137
  MAX_RETRIES: 5,
79043
- MAX_RANDOM_DELAY: 1000
79138
+ MAX_RANDOM_DELAY: 1000,
79044
79139
  };
79045
79140
  /**
79046
79141
  * Determines if an error is related to Google Sheets API quotas or rate limits.
@@ -79066,10 +79161,10 @@ const RETRY_CONFIG = {
79066
79161
  */
79067
79162
  function isQuotaError(error) {
79068
79163
  const message = error.message.toLowerCase();
79069
- return message.includes('quota exceeded') ||
79070
- message.includes('rate limit') ||
79071
- message.includes('429') ||
79072
- message.includes('too many requests');
79164
+ return (message.includes("quota exceeded") ||
79165
+ message.includes("rate limit") ||
79166
+ message.includes("429") ||
79167
+ message.includes("too many requests"));
79073
79168
  }
79074
79169
  /**
79075
79170
  * Implements exponential backoff retry mechanism for Google Sheets API calls.
@@ -79128,14 +79223,14 @@ async function withExponentialBackoff(operation) {
79128
79223
  const exponentialDelay = Math.min(Math.pow(2, retries) * RETRY_CONFIG.BASE_DELAY + randomDelay, RETRY_CONFIG.MAX_DELAY);
79129
79224
  logIfDebug(`Quota/Rate limit exceeded. Error: ${error.message}`);
79130
79225
  logIfDebug(`Retrying in ${exponentialDelay}ms (attempt ${retries}/${RETRY_CONFIG.MAX_RETRIES})`);
79131
- await new Promise(resolve => setTimeout(resolve, exponentialDelay));
79226
+ await new Promise((resolve) => setTimeout(resolve, exponentialDelay));
79132
79227
  }
79133
79228
  }
79134
79229
  }
79135
79230
  function checkEnvVars() {
79136
79231
  const secrets = getSecrets();
79137
79232
  if (!secrets.googleSheets.clientEmail || !secrets.googleSheets.privateKey) {
79138
- throw new Error('GOOGLE_SHEETS_CLIENT_EMAIL or GOOGLE_SHEETS_PRIVATE_KEY is not defined in environment variables.');
79233
+ throw new Error("GOOGLE_SHEETS_CLIENT_EMAIL or GOOGLE_SHEETS_PRIVATE_KEY is not defined in environment variables.");
79139
79234
  }
79140
79235
  }
79141
79236
  /**
@@ -79150,16 +79245,16 @@ async function getAuthClient() {
79150
79245
  const secrets = getSecrets();
79151
79246
  const credentials = {
79152
79247
  client_email: secrets.googleSheets.clientEmail,
79153
- private_key: secrets.googleSheets.privateKey?.replace(/\\n/g, '\n'),
79248
+ private_key: secrets.googleSheets.privateKey?.replace(/\\n/g, "\n"),
79154
79249
  };
79155
79250
  const auth = new require$$0$6.GoogleAuth({
79156
79251
  credentials,
79157
- scopes: ['https://www.googleapis.com/auth/spreadsheets'],
79252
+ scopes: ["https://www.googleapis.com/auth/spreadsheets"],
79158
79253
  });
79159
79254
  return auth.getClient();
79160
79255
  }
79161
79256
  catch (error) {
79162
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
79257
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
79163
79258
  logIfDebug(`Error initializing Google Sheets auth: ${errorMessage}`);
79164
79259
  throw new Error(`Failed to initialize Google Sheets auth: ${errorMessage}`);
79165
79260
  }
@@ -79171,7 +79266,7 @@ async function getSheetsClient() {
79171
79266
  const auth = await getAuthClient();
79172
79267
  return new buildExports.sheets_v4.Sheets({
79173
79268
  auth,
79174
- timeout: GOOGLE_SHEETS_TIMEOUT_MS
79269
+ timeout: GOOGLE_SHEETS_TIMEOUT_MS,
79175
79270
  });
79176
79271
  }
79177
79272
  /**
@@ -79204,7 +79299,7 @@ function escapeSheetName(sheetName) {
79204
79299
  * @param startColumn Optional starting column (defaults to 'A')
79205
79300
  * @returns Promise resolving to response with success status and row details
79206
79301
  */
79207
- async function addRow(config, values, startColumn = 'A') {
79302
+ async function addRow(config, values, startColumn = "A") {
79208
79303
  try {
79209
79304
  const sheets = await getSheetsClient();
79210
79305
  const escapedSheetName = escapeSheetName(config.sheetName);
@@ -79212,7 +79307,7 @@ async function addRow(config, values, startColumn = 'A') {
79212
79307
  const response = await withExponentialBackoff(() => sheets.spreadsheets.values.append({
79213
79308
  spreadsheetId: config.spreadsheetId,
79214
79309
  range,
79215
- valueInputOption: 'USER_ENTERED',
79310
+ valueInputOption: "USER_ENTERED",
79216
79311
  requestBody: {
79217
79312
  values: [values],
79218
79313
  },
@@ -79220,9 +79315,9 @@ async function addRow(config, values, startColumn = 'A') {
79220
79315
  //logIfDebug(`Added row to sheet ${config.sheetName}: ${values.join(', ')}`);
79221
79316
  const rowNumber = response.data.updates?.updatedRange
79222
79317
  ? parseInt(response.data.updates.updatedRange
79223
- .split('!')[1]
79224
- .split(':')[0]
79225
- .replace(/[^0-9]/g, ''))
79318
+ .split("!")[1]
79319
+ .split(":")[0]
79320
+ .replace(/[^0-9]/g, ""))
79226
79321
  : 0;
79227
79322
  return {
79228
79323
  success: true,
@@ -79233,7 +79328,7 @@ async function addRow(config, values, startColumn = 'A') {
79233
79328
  };
79234
79329
  }
79235
79330
  catch (error) {
79236
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
79331
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
79237
79332
  logIfDebug(`Error adding row to sheet: ${errorMessage}`);
79238
79333
  return {
79239
79334
  success: false,
@@ -79275,7 +79370,7 @@ async function addSheet(spreadsheetId, sheetTitle) {
79275
79370
  };
79276
79371
  }
79277
79372
  catch (error) {
79278
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
79373
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
79279
79374
  logIfDebug(`Error adding sheet: ${errorMessage}`);
79280
79375
  return {
79281
79376
  success: false,
@@ -79299,7 +79394,7 @@ async function writeCell(config, cell, value) {
79299
79394
  await withExponentialBackoff(() => sheets.spreadsheets.values.update({
79300
79395
  spreadsheetId: config.spreadsheetId,
79301
79396
  range,
79302
- valueInputOption: 'USER_ENTERED',
79397
+ valueInputOption: "USER_ENTERED",
79303
79398
  requestBody: {
79304
79399
  values: [[value]],
79305
79400
  },
@@ -79313,7 +79408,7 @@ async function writeCell(config, cell, value) {
79313
79408
  };
79314
79409
  }
79315
79410
  catch (error) {
79316
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
79411
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
79317
79412
  logIfDebug(`Error writing to cell: ${errorMessage}`);
79318
79413
  return {
79319
79414
  success: false,
@@ -79337,8 +79432,11 @@ async function getCell(config, cell) {
79337
79432
  spreadsheetId: config.spreadsheetId,
79338
79433
  range,
79339
79434
  }));
79340
- const value = response.data.values?.[0]?.[0];
79341
- logIfDebug(`Read value from cell ${range}: ${value}`);
79435
+ const rawValue = response.data.values?.[0]?.[0];
79436
+ const value = rawValue === undefined || rawValue === null
79437
+ ? null
79438
+ : rawValue;
79439
+ logIfDebug(`Read value from cell ${range}: ${String(value)}`);
79342
79440
  return {
79343
79441
  success: true,
79344
79442
  data: {
@@ -79347,7 +79445,7 @@ async function getCell(config, cell) {
79347
79445
  };
79348
79446
  }
79349
79447
  catch (error) {
79350
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
79448
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
79351
79449
  logIfDebug(`Error reading from cell: ${errorMessage}`);
79352
79450
  return {
79353
79451
  success: false,
@@ -79380,10 +79478,11 @@ function convertA1ToRowCol(a1Notation) {
79380
79478
  * @returns Padded array of arrays
79381
79479
  */
79382
79480
  function padArrays(arrays) {
79383
- const maxLength = Math.max(...arrays.map(arr => arr.length));
79384
- return arrays.map(arr => {
79481
+ const maxLength = Math.max(...arrays.map((arr) => arr.length));
79482
+ return arrays.map((arr) => {
79385
79483
  if (arr.length < maxLength) {
79386
- return [...arr, ...Array(maxLength - arr.length).fill('')];
79484
+ const padding = Array(maxLength - arr.length).fill("");
79485
+ return [...arr, ...padding];
79387
79486
  }
79388
79487
  return arr;
79389
79488
  });
@@ -79395,10 +79494,10 @@ function padArrays(arrays) {
79395
79494
  * @param startCell Optional starting cell in A1 notation (defaults to 'A1')
79396
79495
  * @returns Promise resolving to response with success status and update details
79397
79496
  */
79398
- async function writeArray(config, data, startCell = 'A1') {
79497
+ async function writeArray(config, data, startCell = "A1") {
79399
79498
  try {
79400
79499
  if (!data.length) {
79401
- throw new Error('Data array is empty');
79500
+ throw new Error("Data array is empty");
79402
79501
  }
79403
79502
  const sheets = await getSheetsClient();
79404
79503
  const { row: startRow, column: startCol } = convertA1ToRowCol(startCell);
@@ -79414,7 +79513,7 @@ async function writeArray(config, data, startCell = 'A1') {
79414
79513
  const response = await withExponentialBackoff(() => sheets.spreadsheets.values.update({
79415
79514
  spreadsheetId: config.spreadsheetId,
79416
79515
  range,
79417
- valueInputOption: 'USER_ENTERED',
79516
+ valueInputOption: "USER_ENTERED",
79418
79517
  requestBody: {
79419
79518
  values: paddedData,
79420
79519
  },
@@ -79430,7 +79529,7 @@ async function writeArray(config, data, startCell = 'A1') {
79430
79529
  };
79431
79530
  }
79432
79531
  catch (error) {
79433
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
79532
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
79434
79533
  logIfDebug(`Error writing array to sheet: ${errorMessage}`);
79435
79534
  return {
79436
79535
  success: false,
@@ -81724,4 +81823,4 @@ exports.withCorrelationId = withCorrelationId;
81724
81823
  exports.withMetrics = withMetrics;
81725
81824
  exports.withRateLimit = withRateLimit;
81726
81825
  exports.withRetry = withRetry;
81727
- //# sourceMappingURL=index-DfuMX-MS.js.map
81826
+ //# sourceMappingURL=index-KzQOh2uu.js.map