@theokit/sdk 2.11.3 → 2.13.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.
package/dist/cron.d.cts CHANGED
@@ -1,2 +1,2 @@
1
1
  import './run-TMdc7gmo.cjs';
2
- export { K as Cron } from './cron-DOw-Hqol.cjs';
2
+ export { K as Cron } from './cron-CpxLdAXc.cjs';
package/dist/cron.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  import './run-TMdc7gmo.js';
2
- export { K as Cron } from './cron-BRfFPEKY.js';
2
+ export { K as Cron } from './cron-CL_9nfhQ.js';
package/dist/cron.js CHANGED
@@ -10953,6 +10953,35 @@ function toOllamaTools(tools) {
10953
10953
  }));
10954
10954
  }
10955
10955
 
10956
+ // src/internal/llm/hermes-tool-extract.ts
10957
+ var HERMES_BLOCK = /<function=\s*([^>\s]+)\s*>([\s\S]*?)<\/tool_call>/g;
10958
+ var HERMES_PARAM = /<parameter=\s*([^>\s]+)\s*>([\s\S]*?)<\/parameter>/g;
10959
+ function extractHermesToolCalls(content, makeId) {
10960
+ const toolCalls = [];
10961
+ for (const block of content.matchAll(HERMES_BLOCK)) {
10962
+ const name = (block[1] ?? "").trim();
10963
+ if (name.length === 0) continue;
10964
+ toolCalls.push({
10965
+ type: "tool_use",
10966
+ id: makeId(),
10967
+ name,
10968
+ input: parseHermesParams(block[2] ?? "")
10969
+ });
10970
+ }
10971
+ const residualText = toolCalls.length === 0 ? content : content.replace(HERMES_BLOCK, "").trim();
10972
+ return { toolCalls, residualText };
10973
+ }
10974
+ function parseHermesParams(inner) {
10975
+ const input = {};
10976
+ for (const param of inner.matchAll(HERMES_PARAM)) {
10977
+ const key = param[1];
10978
+ const value = param[2];
10979
+ if (key === void 0 || value === void 0) continue;
10980
+ input[key.trim()] = value;
10981
+ }
10982
+ return input;
10983
+ }
10984
+
10956
10985
  // src/internal/llm/openai.ts
10957
10986
  var OpenAIClient = class {
10958
10987
  constructor(options) {
@@ -10964,6 +10993,14 @@ var OpenAIClient = class {
10964
10993
  name = "openai";
10965
10994
  baseUrl;
10966
10995
  fetchImpl;
10996
+ /**
10997
+ * Whether this client recovers leaked Hermes tool-call dialect from assistant
10998
+ * text (theokit#58 follow-up). Observability for the route→client wiring of
10999
+ * `extractToolCallsFromContent`. @internal
11000
+ */
11001
+ get recoversLeakedToolCalls() {
11002
+ return this.options.extractToolCallsFromContent ?? false;
11003
+ }
10967
11004
  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: HTTP+SSE handshake + accumulator is intentionally one block
10968
11005
  async *stream(request, signal) {
10969
11006
  const headers = {
@@ -11014,7 +11051,10 @@ var OpenAIClient = class {
11014
11051
  endpoint: "/v1/chat/completions"
11015
11052
  });
11016
11053
  }
11017
- const accumulator = new OpenAIStreamAccumulator();
11054
+ const accumulator = new OpenAIStreamAccumulator(
11055
+ this.options.extractToolCallsFromContent ?? false,
11056
+ providerId
11057
+ );
11018
11058
  for await (const record of parseSseStream(response.body, signal)) {
11019
11059
  if (record.data === "[DONE]") break;
11020
11060
  let chunk;
@@ -11040,6 +11080,16 @@ var OpenAIClient = class {
11040
11080
  }
11041
11081
  };
11042
11082
  var OpenAIStreamAccumulator = class {
11083
+ /**
11084
+ * @param extractFromContent opt-in leaked-dialect safe-parse (theokit#58). Default false.
11085
+ * @param providerName provider id, used only to label the recovery log line.
11086
+ */
11087
+ constructor(extractFromContent = false, providerName = "openai") {
11088
+ this.extractFromContent = extractFromContent;
11089
+ this.providerName = providerName;
11090
+ }
11091
+ extractFromContent;
11092
+ providerName;
11043
11093
  text = "";
11044
11094
  stopReason = "end_turn";
11045
11095
  inputTokens;
@@ -11105,9 +11155,26 @@ var OpenAIStreamAccumulator = class {
11105
11155
  const input = parseToolArguments(call.args);
11106
11156
  toolCalls.push({ type: "tool_use", id: call.id, name: call.name, input });
11107
11157
  }
11158
+ let text = this.text;
11159
+ let stopReason = this.stopReason;
11160
+ if (this.extractFromContent && toolCalls.length === 0) {
11161
+ const recovered = extractHermesToolCalls(
11162
+ this.text,
11163
+ () => `hermes-${globalThis.crypto.randomUUID()}`
11164
+ );
11165
+ if (recovered.toolCalls.length > 0) {
11166
+ toolCalls.push(...recovered.toolCalls);
11167
+ text = recovered.residualText;
11168
+ stopReason = "tool_use";
11169
+ process.stderr.write(
11170
+ `[theokit-sdk] recovered ${recovered.toolCalls.length} leaked tool call(s) from assistant content (provider="${this.providerName}", names=${recovered.toolCalls.map((c) => c.name).join(",")})
11171
+ `
11172
+ );
11173
+ }
11174
+ }
11108
11175
  return makeLlmFinish({
11109
- stopReason: this.stopReason,
11110
- text: this.text,
11176
+ stopReason,
11177
+ text,
11111
11178
  toolCalls,
11112
11179
  inputTokens: this.inputTokens,
11113
11180
  outputTokens: this.outputTokens,
@@ -11584,8 +11651,9 @@ function buildChain(options) {
11584
11651
  return clients;
11585
11652
  }
11586
11653
  function buildClient(name, routerOptions) {
11587
- const profile = getProviderProfile(name);
11588
- if (profile === void 0) return void 0;
11654
+ const baseProfile = getProviderProfile(name);
11655
+ if (baseProfile === void 0) return void 0;
11656
+ const profile = routerOptions.extractToolCallsFromContent === true && baseProfile.extractToolCallsFromContent !== true ? { ...baseProfile, extractToolCallsFromContent: true } : baseProfile;
11589
11657
  const ambient = currentCredentialPool(name);
11590
11658
  if (ambient !== void 0) {
11591
11659
  return new PoolAwareLlmClient(ambient, (apiKey) => selectTransport(profile, apiKey));
@@ -11687,6 +11755,9 @@ function selectTransport(profile, apiKey) {
11687
11755
  const opts = { apiKey };
11688
11756
  opts.baseUrl = profile.baseUrl;
11689
11757
  opts.providerName = profile.name;
11758
+ if (profile.extractToolCallsFromContent === true) {
11759
+ opts.extractToolCallsFromContent = true;
11760
+ }
11690
11761
  if (profile.name === "openai" && process.env.OPENAI_ORGANIZATION !== void 0) {
11691
11762
  opts.organization = process.env.OPENAI_ORGANIZATION;
11692
11763
  }
@@ -11983,11 +12054,13 @@ function buildLoopInputs(options, runId, userText) {
11983
12054
  const fallback = options.agentOptions.providers?.fallback;
11984
12055
  const apiKeys = options.agentOptions.providers?.apiKeys;
11985
12056
  const credentialPoolStrategy = options.agentOptions.providers?.credentialPoolStrategy;
12057
+ const extractToolCallsFromContent = options.agentOptions.providers?.routes?.[0]?.extractToolCallsFromContent;
11986
12058
  const chain = resolveProviderChain({
11987
12059
  primary,
11988
12060
  ...fallback !== void 0 ? { fallback } : {},
11989
12061
  ...apiKeys !== void 0 ? { apiKeys } : {},
11990
- ...credentialPoolStrategy !== void 0 ? { credentialPoolStrategy } : {}
12062
+ ...credentialPoolStrategy !== void 0 ? { credentialPoolStrategy } : {},
12063
+ ...extractToolCallsFromContent === true ? { extractToolCallsFromContent: true } : {}
11991
12064
  });
11992
12065
  const llm = chain.length === 1 ? chain[0] : new FallbackLlmClient(chain);
11993
12066
  return {