@theokit/sdk 4.13.1 → 4.14.1

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 (36) 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 +159 -21
  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 +159 -21
  9. package/dist/cron.js.map +1 -1
  10. package/dist/eval.cjs +159 -21
  11. package/dist/eval.cjs.map +1 -1
  12. package/dist/eval.js +159 -21
  13. package/dist/eval.js.map +1 -1
  14. package/dist/index.cjs +162 -21
  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 +162 -21
  19. package/dist/index.js.map +1 -1
  20. package/dist/internal/llm/openai.d.ts +29 -0
  21. package/dist/internal/providers/builtin/cerebras.d.ts +5 -0
  22. package/dist/internal/providers/builtin/cohere.d.ts +8 -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 +124 -5
  32. package/dist/models.cjs.map +1 -1
  33. package/dist/models.js +124 -5
  34. package/dist/models.js.map +1 -1
  35. package/dist/types/provider-profile.d.ts +7 -0
  36. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.14.1
4
+
5
+ ### Patch Changes
6
+
7
+ - M45 adversarial-review fixes: (H1) a malformed `baseUrl` (scheme-less host, empty env var) no longer throws an untyped `TypeError` from the OpenAIClient CONSTRUCTOR — poisoning the whole provider chain at `resolveProviderChain` time even when only a fallback was misconfigured; the URL parse now degrades to the legacy `/v1/chat/completions` path (byte-identical to pre-M45) and fails typed at fetch time. (M2) re-running `registerBuiltins()` across bundle copies (`@theokit/sdk` + `@theokit/sdk/models`) no longer emits 19 bogus `overridden by user plugin` WARNs — the guard lives on `globalThis` like the registry itself. (M3) a trailing-slash versioned baseUrl (`…/v1/`) now joins cleanly (no `/v1//chat/completions`). (L1) the `google` builtin also honors `GOOGLE_GENERATIVE_AI_API_KEY` (the ai-sdk convention). (L4) `getCatalogCapabilities` resolves entry aliases (e.g. `google`). NOTICE extended for the M45 adaptations. **Migration note (M1):** the chat-completions URL-join now detects version segments ANYWHERE in the baseUrl path — a gateway mounting an OpenAI-compat surface under a versioned prefix (e.g. `https://gw.corp/v2/tenants/x`) that previously got `/v1/chat/completions` appended now gets `/chat/completions`; declare `chatCompletionsPath` on the profile to pin an exact path.
8
+
9
+ ## 4.14.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 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.
14
+
3
15
  ## 4.13.1
4
16
 
5
17
  ### Patch 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
@@ -752,13 +752,13 @@ function setAgentFacade(facade) {
752
752
  globalThis[FACADE_KEY] = facade;
753
753
  }
754
754
  function getAgentFacade() {
755
- const registered3 = globalThis[FACADE_KEY];
756
- if (registered3 === void 0) {
755
+ const registered2 = globalThis[FACADE_KEY];
756
+ if (registered2 === void 0) {
757
757
  throw new Error(
758
758
  "internal: Agent facade not registered. The `agent.ts` module must be loaded before internal subsystems (LocalAgent.runUntil/fork, eval, scorers, cron) invoke it."
759
759
  );
760
760
  }
761
- return registered3;
761
+ return registered2;
762
762
  }
763
763
  var FACADE_KEY;
764
764
  var init_agent_factory_registry = __esm({
@@ -11407,7 +11407,13 @@ var ANTHROPIC = {
11407
11407
  baseUrl: "https://api.anthropic.com",
11408
11408
  modelsUrl: "https://api.anthropic.com/v1/models",
11409
11409
  hostname: "api.anthropic.com",
11410
- 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
+ }
11411
11417
  };
11412
11418
 
11413
11419
  // src/internal/providers/builtin/bedrock.ts
@@ -11442,6 +11448,44 @@ function resolveBedrockBaseUrl(modelId) {
11442
11448
  return `https://bedrock-runtime.${region}.amazonaws.com`;
11443
11449
  }
11444
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
+
11445
11489
  // src/internal/providers/builtin/gemini.ts
11446
11490
  var GEMINI = {
11447
11491
  name: "gemini",
@@ -11453,6 +11497,24 @@ var GEMINI = {
11453
11497
  fallbackModels: ["google/gemini-2.0-flash-001"]
11454
11498
  };
11455
11499
 
11500
+ // src/internal/providers/builtin/google.ts
11501
+ var GOOGLE = openAiCompatibleProfile({
11502
+ name: "google",
11503
+ baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai",
11504
+ envVars: ["GOOGLE_API_KEY", "GEMINI_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY"],
11505
+ fallbackModels: ["gemini-2.5-pro", "gemini-2.5-flash"],
11506
+ hostname: "generativelanguage.googleapis.com"
11507
+ });
11508
+
11509
+ // src/internal/providers/builtin/groq.ts
11510
+ var GROQ = openAiCompatibleProfile({
11511
+ name: "groq",
11512
+ baseUrl: "https://api.groq.com/openai/v1",
11513
+ envVars: ["GROQ_API_KEY"],
11514
+ fallbackModels: ["llama-3.3-70b-versatile", "llama-3.1-8b-instant"],
11515
+ hostname: "api.groq.com"
11516
+ });
11517
+
11456
11518
  // src/internal/providers/builtin/llamacpp.ts
11457
11519
  var LLAMACPP = {
11458
11520
  name: "llamacpp",
@@ -11479,6 +11541,15 @@ var LMSTUDIO = {
11479
11541
  fallbackModels: ["loaded-model"]
11480
11542
  };
11481
11543
 
11544
+ // src/internal/providers/builtin/mistral.ts
11545
+ var MISTRAL = openAiCompatibleProfile({
11546
+ name: "mistral",
11547
+ baseUrl: "https://api.mistral.ai/v1",
11548
+ envVars: ["MISTRAL_API_KEY"],
11549
+ fallbackModels: ["mistral-large-latest", "codestral-latest"],
11550
+ hostname: "api.mistral.ai"
11551
+ });
11552
+
11482
11553
  // src/internal/providers/builtin/ollama.ts
11483
11554
  var OLLAMA = {
11484
11555
  name: "ollama",
@@ -11866,9 +11937,33 @@ var OPENROUTER = {
11866
11937
  baseUrl: "https://openrouter.ai/api",
11867
11938
  modelsUrl: "https://openrouter.ai/api/v1/models",
11868
11939
  hostname: "openrouter.ai",
11869
- fallbackModels: ["openai/gpt-4o-mini", "anthropic/claude-3-haiku"]
11940
+ // M45 — models refreshed (claude-3-haiku retired upstream).
11941
+ fallbackModels: ["openai/gpt-4o-mini", "anthropic/claude-haiku-4-5"],
11942
+ // M45 — OpenRouter app-attribution headers (mechanism from OpenCode's openrouter plugin, MIT; VALUES are
11943
+ // theokit's own — copying another app's referer would misattribute traffic).
11944
+ extraHeaders: { "HTTP-Referer": "https://usetheo.dev", "X-Title": "theokit" }
11870
11945
  };
11871
11946
 
11947
+ // src/internal/providers/builtin/perplexity.ts
11948
+ var PERPLEXITY = openAiCompatibleProfile({
11949
+ name: "perplexity",
11950
+ baseUrl: "https://api.perplexity.ai",
11951
+ chatCompletionsPath: "/chat/completions",
11952
+ envVars: ["PERPLEXITY_API_KEY"],
11953
+ fallbackModels: ["sonar-pro", "sonar"],
11954
+ hostname: "api.perplexity.ai"
11955
+ });
11956
+
11957
+ // src/internal/providers/builtin/together.ts
11958
+ var TOGETHER = openAiCompatibleProfile({
11959
+ name: "together",
11960
+ aliases: ["togetherai"],
11961
+ baseUrl: "https://api.together.xyz/v1",
11962
+ envVars: ["TOGETHER_API_KEY"],
11963
+ fallbackModels: ["Qwen/Qwen2.5-7B-Instruct-Turbo"],
11964
+ hostname: "api.together.xyz"
11965
+ });
11966
+
11872
11967
  // src/internal/providers/builtin/vertex.ts
11873
11968
  var VERTEX = {
11874
11969
  name: "vertex",
@@ -11900,11 +11995,26 @@ function stripVertexPrefix(modelId) {
11900
11995
  return modelId.replace(/^vertex\/(anthropic|google)\//, "");
11901
11996
  }
11902
11997
 
11998
+ // src/internal/providers/builtin/xai.ts
11999
+ var XAI = openAiCompatibleProfile({
12000
+ name: "xai",
12001
+ aliases: ["grok"],
12002
+ baseUrl: "https://api.x.ai/v1",
12003
+ envVars: ["XAI_API_KEY"],
12004
+ fallbackModels: ["grok-4.5", "grok-4.3"],
12005
+ hostname: "api.x.ai"
12006
+ });
12007
+
11903
12008
  // src/internal/providers/builtin/index.ts
11904
- var registered2 = false;
12009
+ var _registeredState = (() => {
12010
+ const g = globalThis;
12011
+ const sym = /* @__PURE__ */ Symbol.for("theokit-sdk.providers.builtins-registered");
12012
+ if (g[sym] === void 0) g[sym] = { done: false };
12013
+ return g[sym];
12014
+ })();
11905
12015
  function registerBuiltins() {
11906
- if (registered2) return;
11907
- registered2 = true;
12016
+ if (_registeredState.done) return;
12017
+ _registeredState.done = true;
11908
12018
  registerProvider(ANTHROPIC);
11909
12019
  registerProvider(OPENAI);
11910
12020
  registerProvider(OPENAI_CHATGPT);
@@ -11915,6 +12025,15 @@ function registerBuiltins() {
11915
12025
  registerProvider(LLAMACPP);
11916
12026
  registerProvider(BEDROCK);
11917
12027
  registerProvider(VERTEX);
12028
+ registerProvider(GOOGLE);
12029
+ registerProvider(MISTRAL);
12030
+ registerProvider(GROQ);
12031
+ registerProvider(COHERE);
12032
+ registerProvider(DEEPINFRA);
12033
+ registerProvider(TOGETHER);
12034
+ registerProvider(XAI);
12035
+ registerProvider(PERPLEXITY);
12036
+ registerProvider(CEREBRAS);
11918
12037
  registerCatalogProviders();
11919
12038
  }
11920
12039
 
@@ -12182,14 +12301,16 @@ var AnthropicClient = class {
12182
12301
  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: HTTP+SSE handshake + accumulator is intentionally one block
12183
12302
  async *stream(request, signal) {
12184
12303
  const body = buildAnthropicBody(request);
12304
+ const headers = {
12305
+ "content-type": "application/json",
12306
+ "x-api-key": this.options.apiKey,
12307
+ "anthropic-version": this.options.version ?? "2023-06-01"
12308
+ };
12309
+ if (this.options.extraHeaders !== void 0) Object.assign(headers, this.options.extraHeaders);
12185
12310
  const response = await this.fetchImpl(`${this.baseUrl}/v1/messages`, {
12186
12311
  method: "POST",
12187
12312
  signal,
12188
- headers: {
12189
- "content-type": "application/json",
12190
- "x-api-key": this.options.apiKey,
12191
- "anthropic-version": this.options.version ?? "2023-06-01"
12192
- },
12313
+ headers,
12193
12314
  body: JSON.stringify(body)
12194
12315
  });
12195
12316
  if (!response.ok) {
@@ -13062,15 +13183,24 @@ var StreamSuppressionBuffer = class {
13062
13183
  };
13063
13184
 
13064
13185
  // src/internal/llm/openai.ts
13186
+ function deriveChatPath(baseUrl) {
13187
+ try {
13188
+ return /\/v\d+[a-z]*(\/|$)/.test(new URL(baseUrl).pathname) ? "/chat/completions" : "/v1/chat/completions";
13189
+ } catch {
13190
+ return "/v1/chat/completions";
13191
+ }
13192
+ }
13065
13193
  var OpenAIClient = class {
13066
13194
  constructor(options) {
13067
13195
  this.options = options;
13068
- this.baseUrl = options.baseUrl ?? "https://api.openai.com";
13196
+ this.baseUrl = (options.baseUrl ?? "https://api.openai.com").replace(/\/+$/, "");
13197
+ this.chatPath = options.chatCompletionsPath ?? deriveChatPath(this.baseUrl);
13069
13198
  this.fetchImpl = options.fetch ?? fetch;
13070
13199
  }
13071
13200
  options;
13072
13201
  name = "openai";
13073
13202
  baseUrl;
13203
+ chatPath;
13074
13204
  fetchImpl;
13075
13205
  /**
13076
13206
  * Whether this client recovers leaked Hermes tool-call dialect from assistant
@@ -13093,7 +13223,7 @@ var OpenAIClient = class {
13093
13223
  const providerId = this.options.providerName ?? this.name;
13094
13224
  let response;
13095
13225
  try {
13096
- response = await this.fetchImpl(`${this.baseUrl}/v1/chat/completions`, {
13226
+ response = await this.fetchImpl(`${this.baseUrl}${this.chatPath}`, {
13097
13227
  method: "POST",
13098
13228
  signal,
13099
13229
  headers,
@@ -14190,6 +14320,9 @@ function selectTransport(profile, apiKey) {
14190
14320
  if (profile.extractToolCallsFromContent === true) {
14191
14321
  opts.extractToolCallsFromContent = true;
14192
14322
  }
14323
+ if (profile.chatCompletionsPath !== void 0) {
14324
+ opts.chatCompletionsPath = profile.chatCompletionsPath;
14325
+ }
14193
14326
  if (profile.name === "openai" && process.env.OPENAI_ORGANIZATION !== void 0) {
14194
14327
  opts.organization = process.env.OPENAI_ORGANIZATION;
14195
14328
  }
@@ -14209,6 +14342,11 @@ function selectTransport(profile, apiKey) {
14209
14342
  }
14210
14343
  const opts = { apiKey };
14211
14344
  opts.baseUrl = process.env.ANTHROPIC_API_BASE_URL ?? profile.baseUrl;
14345
+ const t = applyTransform();
14346
+ assertOAuthResolved(t);
14347
+ if (t.fetch !== void 0) opts.fetch = t.fetch;
14348
+ const merged = profile.extraHeaders !== void 0 || t.headers !== void 0 ? { ...profile.extraHeaders, ...t.headers } : void 0;
14349
+ if (merged !== void 0) opts.extraHeaders = merged;
14212
14350
  return new AnthropicClient(opts);
14213
14351
  }
14214
14352
  if (profile.apiMode === "bedrock_anthropic") {
@@ -14526,12 +14664,12 @@ function resolveMcpCwd(configCwd) {
14526
14664
 
14527
14665
  // src/internal/providers/register-plugin-providers.ts
14528
14666
  function registerPluginProviderProfiles(entries) {
14529
- let registered3 = 0;
14667
+ let registered2 = 0;
14530
14668
  for (const entry of entries) {
14531
14669
  registerProvider(entry.profile);
14532
- registered3 += 1;
14670
+ registered2 += 1;
14533
14671
  }
14534
- return registered3;
14672
+ return registered2;
14535
14673
  }
14536
14674
 
14537
14675
  // src/internal/local-agent/real-local-run.ts
@@ -14856,12 +14994,12 @@ var pluginProvidersAnnounced = false;
14856
14994
  function resolveRunProvider(options) {
14857
14995
  registerBuiltins();
14858
14996
  const profiles = options.pluginManager?.aggregated.providerProfiles ?? [];
14859
- const registered3 = registerPluginProviderProfiles(profiles);
14860
- if (registered3 > 0 && !pluginProvidersAnnounced) {
14997
+ const registered2 = registerPluginProviderProfiles(profiles);
14998
+ if (registered2 > 0 && !pluginProvidersAnnounced) {
14861
14999
  pluginProvidersAnnounced = true;
14862
15000
  const names = profiles.map((e) => e.profile.name).join(", ");
14863
15001
  process.stderr.write(
14864
- `[theokit-sdk] registered ${registered3} plugin provider profile(s): ${names}
15002
+ `[theokit-sdk] registered ${registered2} plugin provider profile(s): ${names}
14865
15003
  `
14866
15004
  );
14867
15005
  }