@ljoukov/llm 4.0.7 → 4.0.8

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.
package/dist/index.cjs CHANGED
@@ -441,6 +441,34 @@ function estimateCallCostUsd({
441
441
  var import_node_os2 = __toESM(require("os"), 1);
442
442
  var import_node_util = require("util");
443
443
 
444
+ // src/utils/runtimeSingleton.ts
445
+ var runtimeSingletonStoreKey = /* @__PURE__ */ Symbol.for("@ljoukov/llm.runtimeSingletonStore");
446
+ function getRuntimeSingletonStore() {
447
+ const globalObject = globalThis;
448
+ const existingStore = globalObject[runtimeSingletonStoreKey];
449
+ if (existingStore) {
450
+ return existingStore;
451
+ }
452
+ const store = /* @__PURE__ */ new Map();
453
+ Object.defineProperty(globalObject, runtimeSingletonStoreKey, {
454
+ value: store,
455
+ enumerable: false,
456
+ configurable: false,
457
+ writable: false
458
+ });
459
+ return store;
460
+ }
461
+ function getRuntimeSingleton(key, create) {
462
+ const store = getRuntimeSingletonStore();
463
+ const existingValue = store.get(key);
464
+ if (existingValue !== void 0) {
465
+ return existingValue;
466
+ }
467
+ const createdValue = create();
468
+ store.set(key, createdValue);
469
+ return createdValue;
470
+ }
471
+
444
472
  // src/openai/chatgpt-auth.ts
445
473
  var import_node_buffer = require("buffer");
446
474
  var import_node_fs2 = __toESM(require("fs"), 1);
@@ -451,14 +479,16 @@ var import_zod = require("zod");
451
479
  // src/utils/env.ts
452
480
  var import_node_fs = __toESM(require("fs"), 1);
453
481
  var import_node_path = __toESM(require("path"), 1);
454
- var envLoaded = false;
482
+ var envState = getRuntimeSingleton(/* @__PURE__ */ Symbol.for("@ljoukov/llm.envState"), () => ({
483
+ envLoaded: false
484
+ }));
455
485
  function loadLocalEnv() {
456
- if (envLoaded) {
486
+ if (envState.envLoaded) {
457
487
  return;
458
488
  }
459
489
  const envPath = import_node_path.default.join(process.cwd(), ".env.local");
460
490
  loadEnvFromFile(envPath, { override: false });
461
- envLoaded = true;
491
+ envState.envLoaded = true;
462
492
  }
463
493
  function loadEnvFromFile(filePath, { override = false } = {}) {
464
494
  let content;
@@ -544,8 +574,10 @@ var ExchangeResponseSchema = import_zod.z.object({
544
574
  expires_in: import_zod.z.union([import_zod.z.number(), import_zod.z.string()]),
545
575
  id_token: import_zod.z.string().optional()
546
576
  });
547
- var cachedProfile = null;
548
- var refreshPromise = null;
577
+ var chatGptAuthState = getRuntimeSingleton(/* @__PURE__ */ Symbol.for("@ljoukov/llm.chatGptAuthState"), () => ({
578
+ cachedProfile: null,
579
+ refreshPromise: null
580
+ }));
549
581
  async function fetchChatGptAuthProfileFromTokenProvider(options) {
550
582
  const base = options.baseUrl.replace(/\/+$/u, "");
551
583
  const store = options.store?.trim() ? options.store.trim() : "kv";
@@ -646,13 +678,13 @@ async function getChatGptAuthProfile() {
646
678
  const tokenProviderUrl = process.env[CHATGPT_AUTH_TOKEN_PROVIDER_URL_ENV];
647
679
  const tokenProviderKey = process.env[CHATGPT_AUTH_TOKEN_PROVIDER_API_KEY_ENV] ?? process.env[CHATGPT_AUTH_API_KEY_ENV];
648
680
  if (tokenProviderUrl && tokenProviderUrl.trim().length > 0 && tokenProviderKey && tokenProviderKey.trim().length > 0) {
649
- if (cachedProfile && !isExpired(cachedProfile)) {
650
- return cachedProfile;
681
+ if (chatGptAuthState.cachedProfile && !isExpired(chatGptAuthState.cachedProfile)) {
682
+ return chatGptAuthState.cachedProfile;
651
683
  }
652
- if (refreshPromise) {
653
- return refreshPromise;
684
+ if (chatGptAuthState.refreshPromise) {
685
+ return chatGptAuthState.refreshPromise;
654
686
  }
655
- refreshPromise = (async () => {
687
+ chatGptAuthState.refreshPromise = (async () => {
656
688
  try {
657
689
  const store = process.env[CHATGPT_AUTH_TOKEN_PROVIDER_STORE_ENV];
658
690
  const profile = await fetchChatGptAuthProfileFromTokenProvider({
@@ -660,31 +692,31 @@ async function getChatGptAuthProfile() {
660
692
  apiKey: tokenProviderKey,
661
693
  store: store ?? void 0
662
694
  });
663
- cachedProfile = profile;
695
+ chatGptAuthState.cachedProfile = profile;
664
696
  return profile;
665
697
  } finally {
666
- refreshPromise = null;
698
+ chatGptAuthState.refreshPromise = null;
667
699
  }
668
700
  })();
669
- return refreshPromise;
701
+ return chatGptAuthState.refreshPromise;
670
702
  }
671
- if (cachedProfile && !isExpired(cachedProfile)) {
672
- return cachedProfile;
703
+ if (chatGptAuthState.cachedProfile && !isExpired(chatGptAuthState.cachedProfile)) {
704
+ return chatGptAuthState.cachedProfile;
673
705
  }
674
- if (refreshPromise) {
675
- return refreshPromise;
706
+ if (chatGptAuthState.refreshPromise) {
707
+ return chatGptAuthState.refreshPromise;
676
708
  }
677
- refreshPromise = (async () => {
709
+ chatGptAuthState.refreshPromise = (async () => {
678
710
  try {
679
- const baseProfile = cachedProfile ?? loadAuthProfileFromCodexStore();
711
+ const baseProfile = chatGptAuthState.cachedProfile ?? loadAuthProfileFromCodexStore();
680
712
  const profile = isExpired(baseProfile) ? await refreshAndPersistCodexProfile(baseProfile) : baseProfile;
681
- cachedProfile = profile;
713
+ chatGptAuthState.cachedProfile = profile;
682
714
  return profile;
683
715
  } finally {
684
- refreshPromise = null;
716
+ chatGptAuthState.refreshPromise = null;
685
717
  }
686
718
  })();
687
- return refreshPromise;
719
+ return chatGptAuthState.refreshPromise;
688
720
  }
689
721
  function resolveCodexHome() {
690
722
  const codexHome = process.env.CODEX_HOME;
@@ -1416,8 +1448,10 @@ function createAbortError(reason) {
1416
1448
  // src/openai/chatgpt-codex.ts
1417
1449
  var CHATGPT_CODEX_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses";
1418
1450
  var CHATGPT_RESPONSES_EXPERIMENTAL_HEADER = "responses=experimental";
1419
- var cachedResponsesWebSocketMode = null;
1420
- var chatGptResponsesWebSocketDisabled = false;
1451
+ var chatGptCodexState = getRuntimeSingleton(/* @__PURE__ */ Symbol.for("@ljoukov/llm.chatGptCodexState"), () => ({
1452
+ cachedResponsesWebSocketMode: null,
1453
+ chatGptResponsesWebSocketDisabled: false
1454
+ }));
1421
1455
  async function streamChatGptCodexResponse(options) {
1422
1456
  const { access, accountId } = await getChatGptAuthProfile();
1423
1457
  const mode = resolveChatGptResponsesWebSocketMode();
@@ -1443,7 +1477,7 @@ async function streamChatGptCodexResponse(options) {
1443
1477
  }
1444
1478
  };
1445
1479
  };
1446
- if (mode === "off" || chatGptResponsesWebSocketDisabled) {
1480
+ if (mode === "off" || chatGptCodexState.chatGptResponsesWebSocketDisabled) {
1447
1481
  return fallbackStreamFactory();
1448
1482
  }
1449
1483
  const websocketHeaders = buildChatGptCodexHeaders({
@@ -1462,7 +1496,7 @@ async function streamChatGptCodexResponse(options) {
1462
1496
  }),
1463
1497
  createFallbackStream: fallbackStreamFactory,
1464
1498
  onWebSocketFallback: () => {
1465
- chatGptResponsesWebSocketDisabled = true;
1499
+ chatGptCodexState.chatGptResponsesWebSocketDisabled = true;
1466
1500
  }
1467
1501
  });
1468
1502
  }
@@ -1492,14 +1526,14 @@ async function streamChatGptCodexResponseSse(options) {
1492
1526
  return parseEventStream(body);
1493
1527
  }
1494
1528
  function resolveChatGptResponsesWebSocketMode() {
1495
- if (cachedResponsesWebSocketMode) {
1496
- return cachedResponsesWebSocketMode;
1529
+ if (chatGptCodexState.cachedResponsesWebSocketMode) {
1530
+ return chatGptCodexState.cachedResponsesWebSocketMode;
1497
1531
  }
1498
- cachedResponsesWebSocketMode = resolveResponsesWebSocketMode(
1532
+ chatGptCodexState.cachedResponsesWebSocketMode = resolveResponsesWebSocketMode(
1499
1533
  process.env.CHATGPT_RESPONSES_WEBSOCKET_MODE ?? process.env.OPENAI_RESPONSES_WEBSOCKET_MODE,
1500
1534
  "auto"
1501
1535
  );
1502
- return cachedResponsesWebSocketMode;
1536
+ return chatGptCodexState.cachedResponsesWebSocketMode;
1503
1537
  }
1504
1538
  function buildChatGptCodexHeaders(options) {
1505
1539
  const openAiBeta = options.useWebSocket ? mergeOpenAiBetaHeader(
@@ -1537,8 +1571,8 @@ async function collectChatGptCodexResponse(options) {
1537
1571
  }
1538
1572
  });
1539
1573
  } catch (error) {
1540
- if (!sawAnyDelta && !retriedViaSseFallback && shouldRetryViaSseFallback(error) && !chatGptResponsesWebSocketDisabled) {
1541
- chatGptResponsesWebSocketDisabled = true;
1574
+ if (!sawAnyDelta && !retriedViaSseFallback && shouldRetryViaSseFallback(error) && !chatGptCodexState.chatGptResponsesWebSocketDisabled) {
1575
+ chatGptCodexState.chatGptResponsesWebSocketDisabled = true;
1542
1576
  retriedViaSseFallback = true;
1543
1577
  continue;
1544
1578
  }
@@ -1774,7 +1808,12 @@ var MODEL_CONCURRENCY_PROVIDERS = [
1774
1808
  "google",
1775
1809
  "fireworks"
1776
1810
  ];
1777
- var configuredModelConcurrency = normalizeModelConcurrencyConfig({});
1811
+ var modelConcurrencyState = getRuntimeSingleton(
1812
+ /* @__PURE__ */ Symbol.for("@ljoukov/llm.modelConcurrencyState"),
1813
+ () => ({
1814
+ configuredModelConcurrency: normalizeModelConcurrencyConfig({})
1815
+ })
1816
+ );
1778
1817
  function clampModelConcurrencyCap(value) {
1779
1818
  if (!Number.isFinite(value)) {
1780
1819
  return DEFAULT_MODEL_CONCURRENCY_CAP;
@@ -1848,14 +1887,14 @@ function resolveDefaultProviderCap(provider, modelId) {
1848
1887
  return DEFAULT_FIREWORKS_MODEL_CONCURRENCY_CAP;
1849
1888
  }
1850
1889
  function configureModelConcurrency(config = {}) {
1851
- configuredModelConcurrency = normalizeModelConcurrencyConfig(config);
1890
+ modelConcurrencyState.configuredModelConcurrency = normalizeModelConcurrencyConfig(config);
1852
1891
  }
1853
1892
  function resetModelConcurrencyConfig() {
1854
- configuredModelConcurrency = normalizeModelConcurrencyConfig({});
1893
+ modelConcurrencyState.configuredModelConcurrency = normalizeModelConcurrencyConfig({});
1855
1894
  }
1856
1895
  function resolveModelConcurrencyCap(options) {
1857
1896
  const modelId = options.modelId ? normalizeModelIdForConfig(options.modelId) : void 0;
1858
- const config = options.config ? normalizeModelConcurrencyConfig(options.config) : configuredModelConcurrency;
1897
+ const config = options.config ? normalizeModelConcurrencyConfig(options.config) : modelConcurrencyState.configuredModelConcurrency;
1859
1898
  const providerModelCap = modelId ? config.providerModelCaps[options.provider].get(modelId) : void 0;
1860
1899
  if (providerModelCap !== void 0) {
1861
1900
  return providerModelCap;
@@ -2089,32 +2128,37 @@ var import_openai = __toESM(require("openai"), 1);
2089
2128
  var import_undici = require("undici");
2090
2129
  var DEFAULT_FIREWORKS_BASE_URL = "https://api.fireworks.ai/inference/v1";
2091
2130
  var DEFAULT_FIREWORKS_TIMEOUT_MS = 15 * 6e4;
2092
- var cachedClient = null;
2093
- var cachedFetch = null;
2094
- var cachedBaseUrl = null;
2095
- var cachedApiKey = null;
2096
- var cachedTimeoutMs = null;
2131
+ var fireworksClientState = getRuntimeSingleton(
2132
+ /* @__PURE__ */ Symbol.for("@ljoukov/llm.fireworksClientState"),
2133
+ () => ({
2134
+ cachedClient: null,
2135
+ cachedFetch: null,
2136
+ cachedBaseUrl: null,
2137
+ cachedApiKey: null,
2138
+ cachedTimeoutMs: null
2139
+ })
2140
+ );
2097
2141
  function resolveTimeoutMs() {
2098
- if (cachedTimeoutMs !== null) {
2099
- return cachedTimeoutMs;
2142
+ if (fireworksClientState.cachedTimeoutMs !== null) {
2143
+ return fireworksClientState.cachedTimeoutMs;
2100
2144
  }
2101
2145
  const raw = process.env.FIREWORKS_TIMEOUT_MS;
2102
2146
  const parsed = raw ? Number(raw) : Number.NaN;
2103
- cachedTimeoutMs = Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_FIREWORKS_TIMEOUT_MS;
2104
- return cachedTimeoutMs;
2147
+ fireworksClientState.cachedTimeoutMs = Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_FIREWORKS_TIMEOUT_MS;
2148
+ return fireworksClientState.cachedTimeoutMs;
2105
2149
  }
2106
2150
  function resolveBaseUrl() {
2107
- if (cachedBaseUrl !== null) {
2108
- return cachedBaseUrl;
2151
+ if (fireworksClientState.cachedBaseUrl !== null) {
2152
+ return fireworksClientState.cachedBaseUrl;
2109
2153
  }
2110
2154
  loadLocalEnv();
2111
2155
  const raw = process.env.FIREWORKS_BASE_URL?.trim();
2112
- cachedBaseUrl = raw && raw.length > 0 ? raw : DEFAULT_FIREWORKS_BASE_URL;
2113
- return cachedBaseUrl;
2156
+ fireworksClientState.cachedBaseUrl = raw && raw.length > 0 ? raw : DEFAULT_FIREWORKS_BASE_URL;
2157
+ return fireworksClientState.cachedBaseUrl;
2114
2158
  }
2115
2159
  function resolveApiKey() {
2116
- if (cachedApiKey !== null) {
2117
- return cachedApiKey;
2160
+ if (fireworksClientState.cachedApiKey !== null) {
2161
+ return fireworksClientState.cachedApiKey;
2118
2162
  }
2119
2163
  loadLocalEnv();
2120
2164
  const raw = process.env.FIREWORKS_TOKEN ?? process.env.FIREWORKS_API_KEY;
@@ -2124,46 +2168,51 @@ function resolveApiKey() {
2124
2168
  "FIREWORKS_TOKEN (or FIREWORKS_API_KEY) must be provided to access Fireworks APIs."
2125
2169
  );
2126
2170
  }
2127
- cachedApiKey = token;
2128
- return cachedApiKey;
2171
+ fireworksClientState.cachedApiKey = token;
2172
+ return fireworksClientState.cachedApiKey;
2129
2173
  }
2130
2174
  function getFireworksFetch() {
2131
- if (cachedFetch) {
2132
- return cachedFetch;
2175
+ if (fireworksClientState.cachedFetch) {
2176
+ return fireworksClientState.cachedFetch;
2133
2177
  }
2134
2178
  const timeoutMs = resolveTimeoutMs();
2135
2179
  const dispatcher = new import_undici.Agent({
2136
2180
  bodyTimeout: timeoutMs,
2137
2181
  headersTimeout: timeoutMs
2138
2182
  });
2139
- cachedFetch = ((input, init) => {
2183
+ fireworksClientState.cachedFetch = ((input, init) => {
2140
2184
  return (0, import_undici.fetch)(input, {
2141
2185
  ...init ?? {},
2142
2186
  dispatcher
2143
2187
  });
2144
2188
  });
2145
- return cachedFetch;
2189
+ return fireworksClientState.cachedFetch;
2146
2190
  }
2147
2191
  function getFireworksClient() {
2148
- if (cachedClient) {
2149
- return cachedClient;
2192
+ if (fireworksClientState.cachedClient) {
2193
+ return fireworksClientState.cachedClient;
2150
2194
  }
2151
- cachedClient = new import_openai.default({
2195
+ fireworksClientState.cachedClient = new import_openai.default({
2152
2196
  apiKey: resolveApiKey(),
2153
2197
  baseURL: resolveBaseUrl(),
2154
2198
  timeout: resolveTimeoutMs(),
2155
2199
  fetch: getFireworksFetch()
2156
2200
  });
2157
- return cachedClient;
2201
+ return fireworksClientState.cachedClient;
2158
2202
  }
2159
2203
 
2160
2204
  // src/fireworks/calls.ts
2161
2205
  var DEFAULT_SCHEDULER_KEY = "__default__";
2162
- var schedulerByModel = /* @__PURE__ */ new Map();
2206
+ var fireworksCallState = getRuntimeSingleton(
2207
+ /* @__PURE__ */ Symbol.for("@ljoukov/llm.fireworksCallState"),
2208
+ () => ({
2209
+ schedulerByModel: /* @__PURE__ */ new Map()
2210
+ })
2211
+ );
2163
2212
  function getSchedulerForModel(modelId) {
2164
2213
  const normalizedModelId = modelId?.trim();
2165
2214
  const schedulerKey = normalizedModelId && normalizedModelId.length > 0 ? normalizedModelId : DEFAULT_SCHEDULER_KEY;
2166
- const existing = schedulerByModel.get(schedulerKey);
2215
+ const existing = fireworksCallState.schedulerByModel.get(schedulerKey);
2167
2216
  if (existing) {
2168
2217
  return existing;
2169
2218
  }
@@ -2175,7 +2224,7 @@ function getSchedulerForModel(modelId) {
2175
2224
  minIntervalBetweenStartMs: 200,
2176
2225
  startJitterMs: 200
2177
2226
  });
2178
- schedulerByModel.set(schedulerKey, created);
2227
+ fireworksCallState.schedulerByModel.set(schedulerKey, created);
2179
2228
  return created;
2180
2229
  }
2181
2230
  async function runFireworksCall(fn, modelId, runOptions) {
@@ -2222,7 +2271,10 @@ var ServiceAccountSchema = import_zod2.z.object({
2222
2271
  privateKey: private_key.replace(/\\n/g, "\n"),
2223
2272
  tokenUri: token_uri
2224
2273
  }));
2225
- var cachedServiceAccount = null;
2274
+ var googleAuthState = getRuntimeSingleton(/* @__PURE__ */ Symbol.for("@ljoukov/llm.googleAuthState"), () => ({
2275
+ cachedServiceAccount: null,
2276
+ authClientCache: /* @__PURE__ */ new Map()
2277
+ }));
2226
2278
  function parseGoogleServiceAccount(input) {
2227
2279
  let parsed;
2228
2280
  try {
@@ -2233,16 +2285,16 @@ function parseGoogleServiceAccount(input) {
2233
2285
  return ServiceAccountSchema.parse(parsed);
2234
2286
  }
2235
2287
  function getGoogleServiceAccount() {
2236
- if (cachedServiceAccount) {
2237
- return cachedServiceAccount;
2288
+ if (googleAuthState.cachedServiceAccount) {
2289
+ return googleAuthState.cachedServiceAccount;
2238
2290
  }
2239
2291
  loadLocalEnv();
2240
2292
  const raw = process.env.GOOGLE_SERVICE_ACCOUNT_JSON;
2241
2293
  if (!raw || raw.trim().length === 0) {
2242
2294
  throw new Error("GOOGLE_SERVICE_ACCOUNT_JSON must be provided for Google APIs access.");
2243
2295
  }
2244
- cachedServiceAccount = parseGoogleServiceAccount(raw);
2245
- return cachedServiceAccount;
2296
+ googleAuthState.cachedServiceAccount = parseGoogleServiceAccount(raw);
2297
+ return googleAuthState.cachedServiceAccount;
2246
2298
  }
2247
2299
  function normaliseScopes(scopes) {
2248
2300
  if (!scopes) {
@@ -2294,8 +2346,10 @@ function isGeminiImageModelId(value) {
2294
2346
  }
2295
2347
  var CLOUD_PLATFORM_SCOPE = "https://www.googleapis.com/auth/cloud-platform";
2296
2348
  var DEFAULT_VERTEX_LOCATION = "global";
2297
- var geminiConfiguration = {};
2298
- var clientPromise;
2349
+ var geminiClientState = getRuntimeSingleton(/* @__PURE__ */ Symbol.for("@ljoukov/llm.geminiClientState"), () => ({
2350
+ geminiConfiguration: {},
2351
+ clientPromise: void 0
2352
+ }));
2299
2353
  function normaliseConfigValue(value) {
2300
2354
  if (value === void 0 || value === null) {
2301
2355
  return void 0;
@@ -2306,14 +2360,14 @@ function normaliseConfigValue(value) {
2306
2360
  function configureGemini(options = {}) {
2307
2361
  const nextProjectId = normaliseConfigValue(options.projectId);
2308
2362
  const nextLocation = normaliseConfigValue(options.location);
2309
- geminiConfiguration = {
2310
- projectId: nextProjectId !== void 0 ? nextProjectId : geminiConfiguration.projectId,
2311
- location: nextLocation !== void 0 ? nextLocation : geminiConfiguration.location
2363
+ geminiClientState.geminiConfiguration = {
2364
+ projectId: nextProjectId !== void 0 ? nextProjectId : geminiClientState.geminiConfiguration.projectId,
2365
+ location: nextLocation !== void 0 ? nextLocation : geminiClientState.geminiConfiguration.location
2312
2366
  };
2313
- clientPromise = void 0;
2367
+ geminiClientState.clientPromise = void 0;
2314
2368
  }
2315
2369
  function resolveProjectId() {
2316
- const override = geminiConfiguration.projectId;
2370
+ const override = geminiClientState.geminiConfiguration.projectId;
2317
2371
  if (override) {
2318
2372
  return override;
2319
2373
  }
@@ -2321,15 +2375,15 @@ function resolveProjectId() {
2321
2375
  return serviceAccount.projectId;
2322
2376
  }
2323
2377
  function resolveLocation() {
2324
- const override = geminiConfiguration.location;
2378
+ const override = geminiClientState.geminiConfiguration.location;
2325
2379
  if (override) {
2326
2380
  return override;
2327
2381
  }
2328
2382
  return DEFAULT_VERTEX_LOCATION;
2329
2383
  }
2330
2384
  async function getGeminiClient() {
2331
- if (!clientPromise) {
2332
- clientPromise = Promise.resolve().then(() => {
2385
+ if (!geminiClientState.clientPromise) {
2386
+ geminiClientState.clientPromise = Promise.resolve().then(() => {
2333
2387
  const projectId = resolveProjectId();
2334
2388
  const location = resolveLocation();
2335
2389
  const googleAuthOptions = getGoogleAuthOptions(CLOUD_PLATFORM_SCOPE);
@@ -2341,7 +2395,7 @@ async function getGeminiClient() {
2341
2395
  });
2342
2396
  });
2343
2397
  }
2344
- return clientPromise;
2398
+ return geminiClientState.clientPromise;
2345
2399
  }
2346
2400
 
2347
2401
  // src/google/calls.ts
@@ -2537,11 +2591,13 @@ function retryDelayMs(attempt) {
2537
2591
  return base + jitter;
2538
2592
  }
2539
2593
  var DEFAULT_SCHEDULER_KEY2 = "__default__";
2540
- var schedulerByModel2 = /* @__PURE__ */ new Map();
2594
+ var googleCallState = getRuntimeSingleton(/* @__PURE__ */ Symbol.for("@ljoukov/llm.googleCallState"), () => ({
2595
+ schedulerByModel: /* @__PURE__ */ new Map()
2596
+ }));
2541
2597
  function getSchedulerForModel2(modelId) {
2542
2598
  const normalizedModelId = modelId?.trim();
2543
2599
  const schedulerKey = normalizedModelId && normalizedModelId.length > 0 ? normalizedModelId : DEFAULT_SCHEDULER_KEY2;
2544
- const existing = schedulerByModel2.get(schedulerKey);
2600
+ const existing = googleCallState.schedulerByModel.get(schedulerKey);
2545
2601
  if (existing) {
2546
2602
  return existing;
2547
2603
  }
@@ -2564,7 +2620,7 @@ function getSchedulerForModel2(modelId) {
2564
2620
  }
2565
2621
  }
2566
2622
  });
2567
- schedulerByModel2.set(schedulerKey, created);
2623
+ googleCallState.schedulerByModel.set(schedulerKey, created);
2568
2624
  return created;
2569
2625
  }
2570
2626
  async function runGeminiCall(fn, modelId, runOptions) {
@@ -2574,53 +2630,55 @@ async function runGeminiCall(fn, modelId, runOptions) {
2574
2630
  // src/openai/client.ts
2575
2631
  var import_openai2 = __toESM(require("openai"), 1);
2576
2632
  var import_undici2 = require("undici");
2577
- var cachedApiKey2 = null;
2578
- var cachedClient2 = null;
2579
- var cachedFetch2 = null;
2580
- var cachedTimeoutMs2 = null;
2581
- var openAiResponsesWebSocketMode = null;
2582
- var openAiResponsesWebSocketDisabled = false;
2633
+ var openAiClientState = getRuntimeSingleton(/* @__PURE__ */ Symbol.for("@ljoukov/llm.openAiClientState"), () => ({
2634
+ cachedApiKey: null,
2635
+ cachedClient: null,
2636
+ cachedFetch: null,
2637
+ cachedTimeoutMs: null,
2638
+ openAiResponsesWebSocketMode: null,
2639
+ openAiResponsesWebSocketDisabled: false
2640
+ }));
2583
2641
  var DEFAULT_OPENAI_TIMEOUT_MS = 15 * 6e4;
2584
2642
  function resolveOpenAiTimeoutMs() {
2585
- if (cachedTimeoutMs2 !== null) {
2586
- return cachedTimeoutMs2;
2643
+ if (openAiClientState.cachedTimeoutMs !== null) {
2644
+ return openAiClientState.cachedTimeoutMs;
2587
2645
  }
2588
2646
  const raw = process.env.OPENAI_STREAM_TIMEOUT_MS ?? process.env.OPENAI_TIMEOUT_MS;
2589
2647
  const parsed = raw ? Number(raw) : Number.NaN;
2590
- cachedTimeoutMs2 = Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_OPENAI_TIMEOUT_MS;
2591
- return cachedTimeoutMs2;
2648
+ openAiClientState.cachedTimeoutMs = Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_OPENAI_TIMEOUT_MS;
2649
+ return openAiClientState.cachedTimeoutMs;
2592
2650
  }
2593
2651
  function getOpenAiFetch() {
2594
- if (cachedFetch2) {
2595
- return cachedFetch2;
2652
+ if (openAiClientState.cachedFetch) {
2653
+ return openAiClientState.cachedFetch;
2596
2654
  }
2597
2655
  const timeoutMs = resolveOpenAiTimeoutMs();
2598
2656
  const dispatcher = new import_undici2.Agent({
2599
2657
  bodyTimeout: timeoutMs,
2600
2658
  headersTimeout: timeoutMs
2601
2659
  });
2602
- cachedFetch2 = ((input, init) => {
2660
+ openAiClientState.cachedFetch = ((input, init) => {
2603
2661
  return (0, import_undici2.fetch)(input, {
2604
2662
  ...init ?? {},
2605
2663
  dispatcher
2606
2664
  });
2607
2665
  });
2608
- return cachedFetch2;
2666
+ return openAiClientState.cachedFetch;
2609
2667
  }
2610
2668
  function resolveOpenAiBaseUrl() {
2611
2669
  loadLocalEnv();
2612
2670
  return process.env.OPENAI_BASE_URL?.trim() || "https://api.openai.com/v1";
2613
2671
  }
2614
2672
  function resolveOpenAiResponsesWebSocketMode() {
2615
- if (openAiResponsesWebSocketMode) {
2616
- return openAiResponsesWebSocketMode;
2673
+ if (openAiClientState.openAiResponsesWebSocketMode) {
2674
+ return openAiClientState.openAiResponsesWebSocketMode;
2617
2675
  }
2618
2676
  loadLocalEnv();
2619
- openAiResponsesWebSocketMode = resolveResponsesWebSocketMode(
2677
+ openAiClientState.openAiResponsesWebSocketMode = resolveResponsesWebSocketMode(
2620
2678
  process.env.OPENAI_RESPONSES_WEBSOCKET_MODE,
2621
2679
  "auto"
2622
2680
  );
2623
- return openAiResponsesWebSocketMode;
2681
+ return openAiClientState.openAiResponsesWebSocketMode;
2624
2682
  }
2625
2683
  function wrapFallbackStream(stream) {
2626
2684
  return {
@@ -2673,7 +2731,7 @@ function installResponsesWebSocketTransport(client, apiKey) {
2673
2731
  responsesApi.stream = (request, options) => {
2674
2732
  const mode = resolveOpenAiResponsesWebSocketMode();
2675
2733
  const fallbackStreamFactory = () => wrapFallbackStream(originalStream(request, options));
2676
- if (mode === "off" || openAiResponsesWebSocketDisabled) {
2734
+ if (mode === "off" || openAiClientState.openAiResponsesWebSocketDisabled) {
2677
2735
  return fallbackStreamFactory();
2678
2736
  }
2679
2737
  const signal = options && typeof options === "object" ? options.signal ?? void 0 : void 0;
@@ -2692,15 +2750,15 @@ function installResponsesWebSocketTransport(client, apiKey) {
2692
2750
  createFallbackStream: fallbackStreamFactory,
2693
2751
  onWebSocketFallback: (error) => {
2694
2752
  if (isResponsesWebSocketUnsupportedError(error)) {
2695
- openAiResponsesWebSocketDisabled = true;
2753
+ openAiClientState.openAiResponsesWebSocketDisabled = true;
2696
2754
  }
2697
2755
  }
2698
2756
  });
2699
2757
  };
2700
2758
  }
2701
2759
  function getOpenAiApiKey() {
2702
- if (cachedApiKey2 !== null) {
2703
- return cachedApiKey2;
2760
+ if (openAiClientState.cachedApiKey !== null) {
2761
+ return openAiClientState.cachedApiKey;
2704
2762
  }
2705
2763
  loadLocalEnv();
2706
2764
  const raw = process.env.OPENAI_API_KEY;
@@ -2708,33 +2766,35 @@ function getOpenAiApiKey() {
2708
2766
  if (!value) {
2709
2767
  throw new Error("OPENAI_API_KEY must be provided to access OpenAI APIs.");
2710
2768
  }
2711
- cachedApiKey2 = value;
2712
- return cachedApiKey2;
2769
+ openAiClientState.cachedApiKey = value;
2770
+ return openAiClientState.cachedApiKey;
2713
2771
  }
2714
2772
  function getOpenAiClient() {
2715
- if (cachedClient2) {
2716
- return cachedClient2;
2773
+ if (openAiClientState.cachedClient) {
2774
+ return openAiClientState.cachedClient;
2717
2775
  }
2718
2776
  loadLocalEnv();
2719
2777
  const apiKey = getOpenAiApiKey();
2720
2778
  const timeoutMs = resolveOpenAiTimeoutMs();
2721
- cachedClient2 = new import_openai2.default({
2779
+ openAiClientState.cachedClient = new import_openai2.default({
2722
2780
  apiKey,
2723
2781
  fetch: getOpenAiFetch(),
2724
2782
  timeout: timeoutMs
2725
2783
  });
2726
- installResponsesWebSocketTransport(cachedClient2, apiKey);
2727
- return cachedClient2;
2784
+ installResponsesWebSocketTransport(openAiClientState.cachedClient, apiKey);
2785
+ return openAiClientState.cachedClient;
2728
2786
  }
2729
2787
 
2730
2788
  // src/openai/calls.ts
2731
2789
  var DEFAULT_OPENAI_REASONING_EFFORT = "medium";
2732
2790
  var DEFAULT_SCHEDULER_KEY3 = "__default__";
2733
- var schedulerByModel3 = /* @__PURE__ */ new Map();
2791
+ var openAiCallState = getRuntimeSingleton(/* @__PURE__ */ Symbol.for("@ljoukov/llm.openAiCallState"), () => ({
2792
+ schedulerByModel: /* @__PURE__ */ new Map()
2793
+ }));
2734
2794
  function getSchedulerForModel3(modelId) {
2735
2795
  const normalizedModelId = modelId?.trim();
2736
2796
  const schedulerKey = normalizedModelId && normalizedModelId.length > 0 ? normalizedModelId : DEFAULT_SCHEDULER_KEY3;
2737
- const existing = schedulerByModel3.get(schedulerKey);
2797
+ const existing = openAiCallState.schedulerByModel.get(schedulerKey);
2738
2798
  if (existing) {
2739
2799
  return existing;
2740
2800
  }
@@ -2746,7 +2806,7 @@ function getSchedulerForModel3(modelId) {
2746
2806
  minIntervalBetweenStartMs: 200,
2747
2807
  startJitterMs: 200
2748
2808
  });
2749
- schedulerByModel3.set(schedulerKey, created);
2809
+ openAiCallState.schedulerByModel.set(schedulerKey, created);
2750
2810
  return created;
2751
2811
  }
2752
2812
  async function runOpenAiCall(fn, modelId, runOptions) {
@@ -3232,7 +3292,10 @@ var AgentLoggingSessionImpl = class {
3232
3292
  }
3233
3293
  }
3234
3294
  };
3235
- var loggingSessionStorage = new import_node_async_hooks.AsyncLocalStorage();
3295
+ var loggingSessionStorage = getRuntimeSingleton(
3296
+ /* @__PURE__ */ Symbol.for("@ljoukov/llm.agentLogging.sessionStorage"),
3297
+ () => new import_node_async_hooks.AsyncLocalStorage()
3298
+ );
3236
3299
  function createAgentLoggingSession(config) {
3237
3300
  return new AgentLoggingSessionImpl(config);
3238
3301
  }
@@ -3247,7 +3310,10 @@ function getCurrentAgentLoggingSession() {
3247
3310
  }
3248
3311
 
3249
3312
  // src/llm.ts
3250
- var toolCallContextStorage = new import_node_async_hooks2.AsyncLocalStorage();
3313
+ var toolCallContextStorage = getRuntimeSingleton(
3314
+ /* @__PURE__ */ Symbol.for("@ljoukov/llm.toolCallContextStorage"),
3315
+ () => new import_node_async_hooks2.AsyncLocalStorage()
3316
+ );
3251
3317
  function getCurrentToolCallContext() {
3252
3318
  return toolCallContextStorage.getStore() ?? null;
3253
3319
  }
@@ -5915,7 +5981,10 @@ var DEFAULT_TOOL_LOOP_MAX_STEPS = 8;
5915
5981
  function resolveToolLoopContents(input) {
5916
5982
  return resolveTextContents(input);
5917
5983
  }
5918
- var toolLoopSteeringInternals = /* @__PURE__ */ new WeakMap();
5984
+ var toolLoopSteeringInternals = getRuntimeSingleton(
5985
+ /* @__PURE__ */ Symbol.for("@ljoukov/llm.toolLoopSteeringInternals"),
5986
+ () => /* @__PURE__ */ new WeakMap()
5987
+ );
5919
5988
  function createToolLoopSteeringChannel() {
5920
5989
  const pending = [];
5921
5990
  let closed = false;