@theokit/sdk 4.13.0 → 4.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/{cron-C7catiH8.d.ts → cron-DY0uC1ng.d.ts} +7 -0
  3. package/dist/{cron-DK1WVZnI.d.cts → cron-ElTj1cSH.d.cts} +7 -0
  4. package/dist/cron.cjs +183 -20
  5. package/dist/cron.cjs.map +1 -1
  6. package/dist/cron.d.cts +1 -1
  7. package/dist/cron.d.ts +1 -1
  8. package/dist/cron.js +183 -20
  9. package/dist/cron.js.map +1 -1
  10. package/dist/eval.cjs +183 -20
  11. package/dist/eval.cjs.map +1 -1
  12. package/dist/eval.js +183 -20
  13. package/dist/eval.js.map +1 -1
  14. package/dist/index.cjs +183 -20
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +2 -2
  17. package/dist/index.d.ts +2 -2
  18. package/dist/index.js +183 -20
  19. package/dist/index.js.map +1 -1
  20. package/dist/internal/llm/openai.d.ts +1 -0
  21. package/dist/internal/providers/builtin/cerebras.d.ts +5 -0
  22. package/dist/internal/providers/builtin/cohere.d.ts +6 -0
  23. package/dist/internal/providers/builtin/deepinfra.d.ts +2 -0
  24. package/dist/internal/providers/builtin/google.d.ts +6 -0
  25. package/dist/internal/providers/builtin/groq.d.ts +2 -0
  26. package/dist/internal/providers/builtin/mistral.d.ts +2 -0
  27. package/dist/internal/providers/builtin/openai-compatible.d.ts +1 -0
  28. package/dist/internal/providers/builtin/perplexity.d.ts +5 -0
  29. package/dist/internal/providers/builtin/together.d.ts +2 -0
  30. package/dist/internal/providers/builtin/xai.d.ts +2 -0
  31. package/dist/models.cjs +753 -17
  32. package/dist/models.cjs.map +1 -1
  33. package/dist/models.js +754 -18
  34. package/dist/models.js.map +1 -1
  35. package/dist/provider-catalog.json +473 -146
  36. package/dist/types/provider-profile.d.ts +7 -0
  37. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.14.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Data-provider fleet (agent-builder M45): 9 new first-party builtins on a data-only `openAiCompatibleProfile` base — `google` (DIRECT Gemini via the OpenAI-compat endpoint, `GOOGLE_API_KEY`/`GEMINI_API_KEY`; distinct from the `gemini` OpenRouter passthrough), `mistral`, `groq`, `cohere` (via `api.cohere.ai/compatibility/v1`), `deepinfra`, `together` (alias `togetherai`), `xai` (alias `grok`), `perplexity`, `cerebras` — each ~10 lines with source-cited values. Two defects fixed: the chat_completions URL-join no longer doubles version segments (`…/v1/v1/chat/completions` — every version-suffixed catalog baseUrl was broken for streaming) via version-segment detection + a data-only `ProviderProfile.chatCompletionsPath` escape (existing builtins byte-identical, contract-asserted), and Google is finally reachable (the `google-gemini` catalog entry was silently skipped by an alias collision). The `anthropic_messages` transport now consumes `extraHeaders` + the provider `transform` (mirror of the M41 chat_completions wiring) and the anthropic builtin ships `anthropic-beta: interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14` (the sanctioned behavior delta); openrouter gains theokit's own attribution headers (`HTTP-Referer: https://usetheo.dev`, `X-Title: theokit`); cerebras sends `X-Cerebras-3rd-Party-Integration: theokit`. A table-driven contract suite asserts identity + the EXACT wire URL and headers per provider. Values adapted from OpenCode (MIT); see NOTICE.
8
+
9
+ ## 4.13.1
10
+
11
+ ### Patch Changes
12
+
13
+ - M44 adversarial-review fixes for the model catalog: (B1) the provider registry + model-info index now live on `globalThis` via `Symbol.for` so every bundle copy (`dist/index.js`, `dist/models.js` — tsup bundles entries separately) shares the SAME state — previously `refreshModelCatalog` from `@theokit/sdk/models` patched a bundle-local index invisible to capability/pricing lookups and saw an empty registry (a published-artifact-only defect the src-level tests could not catch); (H2) a live models-dev patch is now a per-field MERGE that preserves theokit extension fields (`cache_control`, overlay `structured_output`) instead of a wholesale replace that wiped them; (H3) the runtime refresh gained the models.dev↔theokit id mapping (google↔google-gemini, zai↔zhipu, togetherai↔together, fireworks-ai↔fireworks, amazon-bedrock↔bedrock, google-vertex↔vertex) resolving against catalog entries (id + aliases) with a WARN for skipped unknowns — Google/Z.AI/Together/Fireworks now actually refresh; (M4) `refreshModelCatalog` self-initializes provider registration so the `/models` subpath works standalone; (M5) pricing provenance is honest post-refresh (`catalog-models-dev` vs `catalog-vendored`); (M6) the anthropic builtin defaults (opus-4-7 / sonnet-4-6 / haiku-4-5) now carry `cache_control: true` in the vendored catalog; (L8) the models-dev cache honors `THEOKIT_HOME`; (L9) a missing/corrupt vendored catalog degrades with WARN instead of throwing from `resolveModelCapabilities`, cache patch errors never delete a valid cache, and refresh never rejects; (L10) the pricing step-5 fallback also tries the date-stripped id; (L11) falsy `THEOKIT_DISABLE_MODELS_FETCH` values (`0`/`false`/empty) no longer disable the fetch.
14
+
3
15
  ## 4.13.0
4
16
 
5
17
  ### Minor Changes
@@ -1230,6 +1230,13 @@ interface ProviderProfile {
1230
1230
  hostname?: string;
1231
1231
  fallbackModels: ReadonlyArray<string>;
1232
1232
  extraHeaders?: Record<string, string>;
1233
+ /**
1234
+ * M45 — explicit chat-completions path override (data-only). Absent, the transport derives it: a baseUrl
1235
+ * whose path already carries a version segment (`/v1`, `/v2beta`, …) gets `/chat/completions` appended;
1236
+ * a host-only baseUrl keeps the legacy `/v1/chat/completions`. Set this for shapes neither rule expresses
1237
+ * (e.g. Perplexity's unversioned `/chat/completions`).
1238
+ */
1239
+ chatCompletionsPath?: string;
1233
1240
  bodyOverrides?: Record<string, unknown>;
1234
1241
  /**
1235
1242
  * M41 — the optional per-request behavior seam (dynamic headers + refresh-aware fetch). Absent ⇒ the profile
@@ -1230,6 +1230,13 @@ interface ProviderProfile {
1230
1230
  hostname?: string;
1231
1231
  fallbackModels: ReadonlyArray<string>;
1232
1232
  extraHeaders?: Record<string, string>;
1233
+ /**
1234
+ * M45 — explicit chat-completions path override (data-only). Absent, the transport derives it: a baseUrl
1235
+ * whose path already carries a version segment (`/v1`, `/v2beta`, …) gets `/chat/completions` appended;
1236
+ * a host-only baseUrl keeps the legacy `/v1/chat/completions`. Set this for shapes neither rule expresses
1237
+ * (e.g. Perplexity's unversioned `/chat/completions`).
1238
+ */
1239
+ chatCompletionsPath?: string;
1233
1240
  bodyOverrides?: Record<string, unknown>;
1234
1241
  /**
1235
1242
  * M41 — the optional per-request behavior seam (dynamic headers + refresh-aware fetch). Absent ⇒ the profile
package/dist/cron.cjs CHANGED
@@ -10539,8 +10539,17 @@ var catalogModelSchema = zod.z.object({
10539
10539
  }).loose();
10540
10540
 
10541
10541
  // src/internal/providers/registry.ts
10542
- var REGISTRY = /* @__PURE__ */ new Map();
10543
- var ALIASES = /* @__PURE__ */ new Map();
10542
+ function globalSingleton(key, create) {
10543
+ const g = globalThis;
10544
+ const sym = Symbol.for(key);
10545
+ if (g[sym] === void 0) g[sym] = create();
10546
+ return g[sym];
10547
+ }
10548
+ var REGISTRY = globalSingleton(
10549
+ "theokit-sdk.providers.registry",
10550
+ () => /* @__PURE__ */ new Map()
10551
+ );
10552
+ var ALIASES = globalSingleton("theokit-sdk.providers.aliases", () => /* @__PURE__ */ new Map());
10544
10553
  function registerProvider(profile) {
10545
10554
  if (REGISTRY.has(profile.name)) {
10546
10555
  process.stderr.write(`[theokit-sdk] Provider "${profile.name}" overridden by user plugin.
@@ -10565,18 +10574,43 @@ function getProviderProfile(name) {
10565
10574
 
10566
10575
  // src/internal/providers/catalog-loader.ts
10567
10576
  var __dirname_resolved = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('cron.cjs', document.baseURI).href))));
10568
- var modelInfoIndex = /* @__PURE__ */ new Map();
10577
+ function globalSingleton2(key, create) {
10578
+ const g = globalThis;
10579
+ const sym = Symbol.for(key);
10580
+ if (g[sym] === void 0) g[sym] = create();
10581
+ return g[sym];
10582
+ }
10583
+ var modelInfoIndex = globalSingleton2(
10584
+ "theokit-sdk.providers.model-info-index",
10585
+ () => /* @__PURE__ */ new Map()
10586
+ );
10587
+ var patchedModelKeys = globalSingleton2(
10588
+ "theokit-sdk.providers.model-info-patched",
10589
+ () => /* @__PURE__ */ new Set()
10590
+ );
10591
+ var indexState = globalSingleton2("theokit-sdk.providers.model-info-loaded", () => ({
10592
+ loaded: false
10593
+ }));
10569
10594
  function getCatalogModelInfo(key) {
10570
10595
  ensureModelIndexLoaded();
10571
10596
  return modelInfoIndex.get(key);
10572
10597
  }
10573
- var _modelIndexLoaded = false;
10598
+ function isPatchedModelKey(key) {
10599
+ return patchedModelKeys.has(key);
10600
+ }
10574
10601
  function ensureModelIndexLoaded() {
10575
- if (_modelIndexLoaded) return;
10576
- _modelIndexLoaded = true;
10577
- const catalog = loadProviderCatalog();
10578
- for (const entry of Object.values(catalog)) {
10579
- indexEntryModels(entry);
10602
+ if (indexState.loaded) return;
10603
+ indexState.loaded = true;
10604
+ try {
10605
+ const catalog = loadProviderCatalog();
10606
+ for (const entry of Object.values(catalog)) {
10607
+ indexEntryModels(entry);
10608
+ }
10609
+ } catch (err) {
10610
+ process.stderr.write(
10611
+ `[theokit-sdk] WARN: provider catalog unavailable (${err.message}) \u2014 per-model data disabled
10612
+ `
10613
+ );
10580
10614
  }
10581
10615
  }
10582
10616
  function indexEntryModels(entry) {
@@ -10829,8 +10863,10 @@ function getPricingEntry(opts) {
10829
10863
  return void 0;
10830
10864
  }
10831
10865
  function catalogCostFallback(provider, cleanedModel) {
10832
- const keys = [`${provider}/${cleanedModel}`, cleanedModel];
10833
- for (const key of keys) {
10866
+ const stripped = stripDateSuffix(cleanedModel);
10867
+ const candidates = [`${provider}/${cleanedModel}`, cleanedModel];
10868
+ if (stripped !== cleanedModel) candidates.push(`${provider}/${stripped}`, stripped);
10869
+ for (const key of candidates) {
10834
10870
  const info = getCatalogModelInfo(key);
10835
10871
  const cost = info?.cost;
10836
10872
  if (cost === void 0) continue;
@@ -10842,7 +10878,8 @@ function catalogCostFallback(provider, cleanedModel) {
10842
10878
  outputCostPerMillion: cost.output,
10843
10879
  ...cost.cache_read !== void 0 ? { cacheReadCostPerMillion: cost.cache_read } : {},
10844
10880
  ...cost.cache_write !== void 0 ? { cacheWriteCostPerMillion: cost.cache_write } : {},
10845
- pricingVersion: "catalog-vendored"
10881
+ // M44 M5 fix — honest provenance: a key patched by the LIVE models-dev source is not "vendored".
10882
+ pricingVersion: isPatchedModelKey(key) ? "catalog-models-dev" : "catalog-vendored"
10846
10883
  };
10847
10884
  }
10848
10885
  return void 0;
@@ -11370,7 +11407,13 @@ var ANTHROPIC = {
11370
11407
  baseUrl: "https://api.anthropic.com",
11371
11408
  modelsUrl: "https://api.anthropic.com/v1/models",
11372
11409
  hostname: "api.anthropic.com",
11373
- fallbackModels: ["claude-opus-4-7", "claude-sonnet-4-6", "claude-haiku-4-5-20251001"]
11410
+ fallbackModels: ["claude-opus-4-7", "claude-sonnet-4-6", "claude-haiku-4-5-20251001"],
11411
+ // M45 — the Anthropic beta-features header (interleaved thinking + fine-grained tool streaming). An
11412
+ // Anthropic API constant, adapted verbatim from OpenCode's anthropic plugin (MIT © 2025 opencode). The
11413
+ // SANCTIONED behavior delta of M45 (ADR D4) — consumed by the anthropic transport's extraHeaders wiring.
11414
+ extraHeaders: {
11415
+ "anthropic-beta": "interleaved-thinking-2025-05-14,fine-grained-tool-streaming-2025-05-14"
11416
+ }
11374
11417
  };
11375
11418
 
11376
11419
  // src/internal/providers/builtin/bedrock.ts
@@ -11405,6 +11448,101 @@ function resolveBedrockBaseUrl(modelId) {
11405
11448
  return `https://bedrock-runtime.${region}.amazonaws.com`;
11406
11449
  }
11407
11450
 
11451
+ // src/internal/providers/builtin/openai-compatible.ts
11452
+ function openAiCompatibleProfile(p) {
11453
+ return {
11454
+ apiMode: "chat_completions",
11455
+ authType: "api_key",
11456
+ fallbackModels: [],
11457
+ ...p
11458
+ };
11459
+ }
11460
+
11461
+ // src/internal/providers/builtin/cerebras.ts
11462
+ var CEREBRAS = openAiCompatibleProfile({
11463
+ name: "cerebras",
11464
+ baseUrl: "https://api.cerebras.ai/v1",
11465
+ envVars: ["CEREBRAS_API_KEY"],
11466
+ fallbackModels: ["gpt-oss-120b", "zai-glm-4.7"],
11467
+ extraHeaders: { "X-Cerebras-3rd-Party-Integration": "theokit" },
11468
+ hostname: "api.cerebras.ai"
11469
+ });
11470
+
11471
+ // src/internal/providers/builtin/cohere.ts
11472
+ var COHERE = openAiCompatibleProfile({
11473
+ name: "cohere",
11474
+ baseUrl: "https://api.cohere.ai/compatibility/v1",
11475
+ envVars: ["COHERE_API_KEY", "CO_API_KEY"],
11476
+ fallbackModels: ["command-a-03-2025"],
11477
+ hostname: "api.cohere.ai"
11478
+ });
11479
+
11480
+ // src/internal/providers/builtin/deepinfra.ts
11481
+ var DEEPINFRA = openAiCompatibleProfile({
11482
+ name: "deepinfra",
11483
+ baseUrl: "https://api.deepinfra.com/v1/openai",
11484
+ envVars: ["DEEPINFRA_API_KEY"],
11485
+ fallbackModels: ["Qwen/Qwen3-32B"],
11486
+ hostname: "api.deepinfra.com"
11487
+ });
11488
+
11489
+ // src/internal/providers/builtin/google.ts
11490
+ var GOOGLE = openAiCompatibleProfile({
11491
+ name: "google",
11492
+ baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai",
11493
+ envVars: ["GOOGLE_API_KEY", "GEMINI_API_KEY"],
11494
+ fallbackModels: ["gemini-2.5-pro", "gemini-2.5-flash"],
11495
+ hostname: "generativelanguage.googleapis.com"
11496
+ });
11497
+
11498
+ // src/internal/providers/builtin/groq.ts
11499
+ var GROQ = openAiCompatibleProfile({
11500
+ name: "groq",
11501
+ baseUrl: "https://api.groq.com/openai/v1",
11502
+ envVars: ["GROQ_API_KEY"],
11503
+ fallbackModels: ["llama-3.3-70b-versatile", "llama-3.1-8b-instant"],
11504
+ hostname: "api.groq.com"
11505
+ });
11506
+
11507
+ // src/internal/providers/builtin/mistral.ts
11508
+ var MISTRAL = openAiCompatibleProfile({
11509
+ name: "mistral",
11510
+ baseUrl: "https://api.mistral.ai/v1",
11511
+ envVars: ["MISTRAL_API_KEY"],
11512
+ fallbackModels: ["mistral-large-latest", "codestral-latest"],
11513
+ hostname: "api.mistral.ai"
11514
+ });
11515
+
11516
+ // src/internal/providers/builtin/perplexity.ts
11517
+ var PERPLEXITY = openAiCompatibleProfile({
11518
+ name: "perplexity",
11519
+ baseUrl: "https://api.perplexity.ai",
11520
+ chatCompletionsPath: "/chat/completions",
11521
+ envVars: ["PERPLEXITY_API_KEY"],
11522
+ fallbackModels: ["sonar-pro", "sonar"],
11523
+ hostname: "api.perplexity.ai"
11524
+ });
11525
+
11526
+ // src/internal/providers/builtin/together.ts
11527
+ var TOGETHER = openAiCompatibleProfile({
11528
+ name: "together",
11529
+ aliases: ["togetherai"],
11530
+ baseUrl: "https://api.together.xyz/v1",
11531
+ envVars: ["TOGETHER_API_KEY"],
11532
+ fallbackModels: ["Qwen/Qwen2.5-7B-Instruct-Turbo"],
11533
+ hostname: "api.together.xyz"
11534
+ });
11535
+
11536
+ // src/internal/providers/builtin/xai.ts
11537
+ var XAI = openAiCompatibleProfile({
11538
+ name: "xai",
11539
+ aliases: ["grok"],
11540
+ baseUrl: "https://api.x.ai/v1",
11541
+ envVars: ["XAI_API_KEY"],
11542
+ fallbackModels: ["grok-4.5", "grok-4.3"],
11543
+ hostname: "api.x.ai"
11544
+ });
11545
+
11408
11546
  // src/internal/providers/builtin/gemini.ts
11409
11547
  var GEMINI = {
11410
11548
  name: "gemini",
@@ -11829,7 +11967,11 @@ var OPENROUTER = {
11829
11967
  baseUrl: "https://openrouter.ai/api",
11830
11968
  modelsUrl: "https://openrouter.ai/api/v1/models",
11831
11969
  hostname: "openrouter.ai",
11832
- fallbackModels: ["openai/gpt-4o-mini", "anthropic/claude-3-haiku"]
11970
+ // M45 — models refreshed (claude-3-haiku retired upstream).
11971
+ fallbackModels: ["openai/gpt-4o-mini", "anthropic/claude-haiku-4-5"],
11972
+ // M45 — OpenRouter app-attribution headers (mechanism from OpenCode's openrouter plugin, MIT; VALUES are
11973
+ // theokit's own — copying another app's referer would misattribute traffic).
11974
+ extraHeaders: { "HTTP-Referer": "https://usetheo.dev", "X-Title": "theokit" }
11833
11975
  };
11834
11976
 
11835
11977
  // src/internal/providers/builtin/vertex.ts
@@ -11878,6 +12020,15 @@ function registerBuiltins() {
11878
12020
  registerProvider(LLAMACPP);
11879
12021
  registerProvider(BEDROCK);
11880
12022
  registerProvider(VERTEX);
12023
+ registerProvider(GOOGLE);
12024
+ registerProvider(MISTRAL);
12025
+ registerProvider(GROQ);
12026
+ registerProvider(COHERE);
12027
+ registerProvider(DEEPINFRA);
12028
+ registerProvider(TOGETHER);
12029
+ registerProvider(XAI);
12030
+ registerProvider(PERPLEXITY);
12031
+ registerProvider(CEREBRAS);
11881
12032
  registerCatalogProviders();
11882
12033
  }
11883
12034
 
@@ -12145,14 +12296,16 @@ var AnthropicClient = class {
12145
12296
  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: HTTP+SSE handshake + accumulator is intentionally one block
12146
12297
  async *stream(request, signal) {
12147
12298
  const body = buildAnthropicBody(request);
12299
+ const headers = {
12300
+ "content-type": "application/json",
12301
+ "x-api-key": this.options.apiKey,
12302
+ "anthropic-version": this.options.version ?? "2023-06-01"
12303
+ };
12304
+ if (this.options.extraHeaders !== void 0) Object.assign(headers, this.options.extraHeaders);
12148
12305
  const response = await this.fetchImpl(`${this.baseUrl}/v1/messages`, {
12149
12306
  method: "POST",
12150
12307
  signal,
12151
- headers: {
12152
- "content-type": "application/json",
12153
- "x-api-key": this.options.apiKey,
12154
- "anthropic-version": this.options.version ?? "2023-06-01"
12155
- },
12308
+ headers,
12156
12309
  body: JSON.stringify(body)
12157
12310
  });
12158
12311
  if (!response.ok) {
@@ -13029,11 +13182,13 @@ var OpenAIClient = class {
13029
13182
  constructor(options) {
13030
13183
  this.options = options;
13031
13184
  this.baseUrl = options.baseUrl ?? "https://api.openai.com";
13185
+ this.chatPath = options.chatCompletionsPath ?? (/\/v\d+[a-z]*(\/|$)/.test(new URL(this.baseUrl).pathname) ? "/chat/completions" : "/v1/chat/completions");
13032
13186
  this.fetchImpl = options.fetch ?? fetch;
13033
13187
  }
13034
13188
  options;
13035
13189
  name = "openai";
13036
13190
  baseUrl;
13191
+ chatPath;
13037
13192
  fetchImpl;
13038
13193
  /**
13039
13194
  * Whether this client recovers leaked Hermes tool-call dialect from assistant
@@ -13056,7 +13211,7 @@ var OpenAIClient = class {
13056
13211
  const providerId = this.options.providerName ?? this.name;
13057
13212
  let response;
13058
13213
  try {
13059
- response = await this.fetchImpl(`${this.baseUrl}/v1/chat/completions`, {
13214
+ response = await this.fetchImpl(`${this.baseUrl}${this.chatPath}`, {
13060
13215
  method: "POST",
13061
13216
  signal,
13062
13217
  headers,
@@ -14153,6 +14308,9 @@ function selectTransport(profile, apiKey) {
14153
14308
  if (profile.extractToolCallsFromContent === true) {
14154
14309
  opts.extractToolCallsFromContent = true;
14155
14310
  }
14311
+ if (profile.chatCompletionsPath !== void 0) {
14312
+ opts.chatCompletionsPath = profile.chatCompletionsPath;
14313
+ }
14156
14314
  if (profile.name === "openai" && process.env.OPENAI_ORGANIZATION !== void 0) {
14157
14315
  opts.organization = process.env.OPENAI_ORGANIZATION;
14158
14316
  }
@@ -14172,6 +14330,11 @@ function selectTransport(profile, apiKey) {
14172
14330
  }
14173
14331
  const opts = { apiKey };
14174
14332
  opts.baseUrl = process.env.ANTHROPIC_API_BASE_URL ?? profile.baseUrl;
14333
+ const t = applyTransform();
14334
+ assertOAuthResolved(t);
14335
+ if (t.fetch !== void 0) opts.fetch = t.fetch;
14336
+ const merged = profile.extraHeaders !== void 0 || t.headers !== void 0 ? { ...profile.extraHeaders, ...t.headers } : void 0;
14337
+ if (merged !== void 0) opts.extraHeaders = merged;
14175
14338
  return new AnthropicClient(opts);
14176
14339
  }
14177
14340
  if (profile.apiMode === "bedrock_anthropic") {