@theokit/sdk 2.11.3 → 2.12.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/a2a/index.js CHANGED
@@ -10094,6 +10094,40 @@ var init_ollama_native = __esm({
10094
10094
  }
10095
10095
  });
10096
10096
 
10097
+ // src/internal/llm/hermes-tool-extract.ts
10098
+ function extractHermesToolCalls(content, makeId) {
10099
+ const toolCalls = [];
10100
+ for (const block of content.matchAll(HERMES_BLOCK)) {
10101
+ const name = (block[1] ?? "").trim();
10102
+ if (name.length === 0) continue;
10103
+ toolCalls.push({
10104
+ type: "tool_use",
10105
+ id: makeId(),
10106
+ name,
10107
+ input: parseHermesParams(block[2] ?? "")
10108
+ });
10109
+ }
10110
+ const residualText = toolCalls.length === 0 ? content : content.replace(HERMES_BLOCK, "").trim();
10111
+ return { toolCalls, residualText };
10112
+ }
10113
+ function parseHermesParams(inner) {
10114
+ const input = {};
10115
+ for (const param of inner.matchAll(HERMES_PARAM)) {
10116
+ const key = param[1];
10117
+ const value = param[2];
10118
+ if (key === void 0 || value === void 0) continue;
10119
+ input[key.trim()] = value;
10120
+ }
10121
+ return input;
10122
+ }
10123
+ var HERMES_BLOCK, HERMES_PARAM;
10124
+ var init_hermes_tool_extract = __esm({
10125
+ "src/internal/llm/hermes-tool-extract.ts"() {
10126
+ HERMES_BLOCK = /<function=\s*([^>\s]+)\s*>([\s\S]*?)<\/tool_call>/g;
10127
+ HERMES_PARAM = /<parameter=\s*([^>\s]+)\s*>([\s\S]*?)<\/parameter>/g;
10128
+ }
10129
+ });
10130
+
10097
10131
  // src/internal/llm/openai.ts
10098
10132
  function mapOpenAIFinish(reason) {
10099
10133
  switch (reason) {
@@ -10206,6 +10240,7 @@ var init_openai2 = __esm({
10206
10240
  init_ollama2();
10207
10241
  init_openai_compatible();
10208
10242
  init_finish();
10243
+ init_hermes_tool_extract();
10209
10244
  init_sse();
10210
10245
  OpenAIClient = class {
10211
10246
  constructor(options) {
@@ -10267,7 +10302,10 @@ var init_openai2 = __esm({
10267
10302
  endpoint: "/v1/chat/completions"
10268
10303
  });
10269
10304
  }
10270
- const accumulator = new OpenAIStreamAccumulator();
10305
+ const accumulator = new OpenAIStreamAccumulator(
10306
+ this.options.extractToolCallsFromContent ?? false,
10307
+ providerId
10308
+ );
10271
10309
  for await (const record of parseSseStream(response.body, signal)) {
10272
10310
  if (record.data === "[DONE]") break;
10273
10311
  let chunk;
@@ -10293,6 +10331,16 @@ var init_openai2 = __esm({
10293
10331
  }
10294
10332
  };
10295
10333
  OpenAIStreamAccumulator = class {
10334
+ /**
10335
+ * @param extractFromContent opt-in leaked-dialect safe-parse (theokit#58). Default false.
10336
+ * @param providerName provider id, used only to label the recovery log line.
10337
+ */
10338
+ constructor(extractFromContent = false, providerName = "openai") {
10339
+ this.extractFromContent = extractFromContent;
10340
+ this.providerName = providerName;
10341
+ }
10342
+ extractFromContent;
10343
+ providerName;
10296
10344
  text = "";
10297
10345
  stopReason = "end_turn";
10298
10346
  inputTokens;
@@ -10358,9 +10406,26 @@ var init_openai2 = __esm({
10358
10406
  const input = parseToolArguments(call.args);
10359
10407
  toolCalls.push({ type: "tool_use", id: call.id, name: call.name, input });
10360
10408
  }
10409
+ let text = this.text;
10410
+ let stopReason = this.stopReason;
10411
+ if (this.extractFromContent && toolCalls.length === 0) {
10412
+ const recovered = extractHermesToolCalls(
10413
+ this.text,
10414
+ () => `hermes-${globalThis.crypto.randomUUID()}`
10415
+ );
10416
+ if (recovered.toolCalls.length > 0) {
10417
+ toolCalls.push(...recovered.toolCalls);
10418
+ text = recovered.residualText;
10419
+ stopReason = "tool_use";
10420
+ process.stderr.write(
10421
+ `[theokit-sdk] recovered ${recovered.toolCalls.length} leaked tool call(s) from assistant content (provider="${this.providerName}", names=${recovered.toolCalls.map((c) => c.name).join(",")})
10422
+ `
10423
+ );
10424
+ }
10425
+ }
10361
10426
  return makeLlmFinish({
10362
- stopReason: this.stopReason,
10363
- text: this.text,
10427
+ stopReason,
10428
+ text,
10364
10429
  toolCalls,
10365
10430
  inputTokens: this.inputTokens,
10366
10431
  outputTokens: this.outputTokens,
@@ -10873,6 +10938,9 @@ function selectTransport(profile, apiKey) {
10873
10938
  const opts = { apiKey };
10874
10939
  opts.baseUrl = profile.baseUrl;
10875
10940
  opts.providerName = profile.name;
10941
+ if (profile.extractToolCallsFromContent === true) {
10942
+ opts.extractToolCallsFromContent = true;
10943
+ }
10876
10944
  if (profile.name === "openai" && process.env.OPENAI_ORGANIZATION !== void 0) {
10877
10945
  opts.organization = process.env.OPENAI_ORGANIZATION;
10878
10946
  }