@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/CHANGELOG.md +6 -0
- package/dist/a2a/index.cjs +71 -3
- package/dist/a2a/index.cjs.map +1 -1
- package/dist/a2a/index.js +71 -3
- package/dist/a2a/index.js.map +1 -1
- package/dist/{cron-BRfFPEKY.d.ts → cron-BchPdvs2.d.ts} +7 -0
- package/dist/{cron-DOw-Hqol.d.cts → cron-Dv94Lgat.d.cts} +7 -0
- package/dist/cron.cjs +65 -3
- package/dist/cron.cjs.map +1 -1
- package/dist/cron.d.cts +1 -1
- package/dist/cron.d.ts +1 -1
- package/dist/cron.js +65 -3
- package/dist/cron.js.map +1 -1
- package/dist/eval.cjs +65 -3
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +65 -3
- package/dist/eval.js.map +1 -1
- package/dist/index.cjs +65 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +65 -3
- package/dist/index.js.map +1 -1
- package/dist/internal/llm/hermes-tool-extract.d.ts +6 -0
- package/dist/internal/llm/openai.d.ts +7 -0
- package/dist/internal/providers/types.d.ts +7 -0
- package/package.json +14 -14
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.12.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 95e9cba: Add opt-in leaked-dialect safe-parse for OpenAI-compatible providers (`ProviderProfile.extractToolCallsFromContent`, default off). Some models — notably qwen3-coder via OpenRouter — intermittently emit their Hermes tool-call dialect (`<function=NAME><parameter=KEY>VALUE</parameter></function></tool_call>`) as assistant TEXT instead of native `tool_calls`. When that happens the provider sends ZERO native `tool_calls`, so the agent loop sees a plain `end_turn` and the intended call is silently lost (theokit#58 follow-up). With the flag enabled, a `chat_completions` finish that has no native `tool_calls` has its assistant content scanned for the leaked dialect; any recovered calls are surfaced as real `tool_calls` and the stop reason flips to `tool_use` so the loop dispatches them. Fail-open like `stripThinkBlocks` — a partial/unclosed block is left as text and never fabricates a call. Default off, dedup-guarded (native `tool_calls` always win, no double-count), and scoped per-provider so a code assistant printing a literal `<function=` in a fenced block on a non-leaking route is unaffected.
|
|
8
|
+
|
|
3
9
|
## 2.11.3
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/dist/a2a/index.cjs
CHANGED
|
@@ -10097,6 +10097,40 @@ var init_ollama_native = __esm({
|
|
|
10097
10097
|
}
|
|
10098
10098
|
});
|
|
10099
10099
|
|
|
10100
|
+
// src/internal/llm/hermes-tool-extract.ts
|
|
10101
|
+
function extractHermesToolCalls(content, makeId) {
|
|
10102
|
+
const toolCalls = [];
|
|
10103
|
+
for (const block of content.matchAll(HERMES_BLOCK)) {
|
|
10104
|
+
const name = (block[1] ?? "").trim();
|
|
10105
|
+
if (name.length === 0) continue;
|
|
10106
|
+
toolCalls.push({
|
|
10107
|
+
type: "tool_use",
|
|
10108
|
+
id: makeId(),
|
|
10109
|
+
name,
|
|
10110
|
+
input: parseHermesParams(block[2] ?? "")
|
|
10111
|
+
});
|
|
10112
|
+
}
|
|
10113
|
+
const residualText = toolCalls.length === 0 ? content : content.replace(HERMES_BLOCK, "").trim();
|
|
10114
|
+
return { toolCalls, residualText };
|
|
10115
|
+
}
|
|
10116
|
+
function parseHermesParams(inner) {
|
|
10117
|
+
const input = {};
|
|
10118
|
+
for (const param of inner.matchAll(HERMES_PARAM)) {
|
|
10119
|
+
const key = param[1];
|
|
10120
|
+
const value = param[2];
|
|
10121
|
+
if (key === void 0 || value === void 0) continue;
|
|
10122
|
+
input[key.trim()] = value;
|
|
10123
|
+
}
|
|
10124
|
+
return input;
|
|
10125
|
+
}
|
|
10126
|
+
var HERMES_BLOCK, HERMES_PARAM;
|
|
10127
|
+
var init_hermes_tool_extract = __esm({
|
|
10128
|
+
"src/internal/llm/hermes-tool-extract.ts"() {
|
|
10129
|
+
HERMES_BLOCK = /<function=\s*([^>\s]+)\s*>([\s\S]*?)<\/tool_call>/g;
|
|
10130
|
+
HERMES_PARAM = /<parameter=\s*([^>\s]+)\s*>([\s\S]*?)<\/parameter>/g;
|
|
10131
|
+
}
|
|
10132
|
+
});
|
|
10133
|
+
|
|
10100
10134
|
// src/internal/llm/openai.ts
|
|
10101
10135
|
function mapOpenAIFinish(reason) {
|
|
10102
10136
|
switch (reason) {
|
|
@@ -10209,6 +10243,7 @@ var init_openai2 = __esm({
|
|
|
10209
10243
|
init_ollama2();
|
|
10210
10244
|
init_openai_compatible();
|
|
10211
10245
|
init_finish();
|
|
10246
|
+
init_hermes_tool_extract();
|
|
10212
10247
|
init_sse();
|
|
10213
10248
|
OpenAIClient = class {
|
|
10214
10249
|
constructor(options) {
|
|
@@ -10270,7 +10305,10 @@ var init_openai2 = __esm({
|
|
|
10270
10305
|
endpoint: "/v1/chat/completions"
|
|
10271
10306
|
});
|
|
10272
10307
|
}
|
|
10273
|
-
const accumulator = new OpenAIStreamAccumulator(
|
|
10308
|
+
const accumulator = new OpenAIStreamAccumulator(
|
|
10309
|
+
this.options.extractToolCallsFromContent ?? false,
|
|
10310
|
+
providerId
|
|
10311
|
+
);
|
|
10274
10312
|
for await (const record of parseSseStream(response.body, signal)) {
|
|
10275
10313
|
if (record.data === "[DONE]") break;
|
|
10276
10314
|
let chunk;
|
|
@@ -10296,6 +10334,16 @@ var init_openai2 = __esm({
|
|
|
10296
10334
|
}
|
|
10297
10335
|
};
|
|
10298
10336
|
OpenAIStreamAccumulator = class {
|
|
10337
|
+
/**
|
|
10338
|
+
* @param extractFromContent opt-in leaked-dialect safe-parse (theokit#58). Default false.
|
|
10339
|
+
* @param providerName provider id, used only to label the recovery log line.
|
|
10340
|
+
*/
|
|
10341
|
+
constructor(extractFromContent = false, providerName = "openai") {
|
|
10342
|
+
this.extractFromContent = extractFromContent;
|
|
10343
|
+
this.providerName = providerName;
|
|
10344
|
+
}
|
|
10345
|
+
extractFromContent;
|
|
10346
|
+
providerName;
|
|
10299
10347
|
text = "";
|
|
10300
10348
|
stopReason = "end_turn";
|
|
10301
10349
|
inputTokens;
|
|
@@ -10361,9 +10409,26 @@ var init_openai2 = __esm({
|
|
|
10361
10409
|
const input = parseToolArguments(call.args);
|
|
10362
10410
|
toolCalls.push({ type: "tool_use", id: call.id, name: call.name, input });
|
|
10363
10411
|
}
|
|
10412
|
+
let text = this.text;
|
|
10413
|
+
let stopReason = this.stopReason;
|
|
10414
|
+
if (this.extractFromContent && toolCalls.length === 0) {
|
|
10415
|
+
const recovered = extractHermesToolCalls(
|
|
10416
|
+
this.text,
|
|
10417
|
+
() => `hermes-${globalThis.crypto.randomUUID()}`
|
|
10418
|
+
);
|
|
10419
|
+
if (recovered.toolCalls.length > 0) {
|
|
10420
|
+
toolCalls.push(...recovered.toolCalls);
|
|
10421
|
+
text = recovered.residualText;
|
|
10422
|
+
stopReason = "tool_use";
|
|
10423
|
+
process.stderr.write(
|
|
10424
|
+
`[theokit-sdk] recovered ${recovered.toolCalls.length} leaked tool call(s) from assistant content (provider="${this.providerName}", names=${recovered.toolCalls.map((c) => c.name).join(",")})
|
|
10425
|
+
`
|
|
10426
|
+
);
|
|
10427
|
+
}
|
|
10428
|
+
}
|
|
10364
10429
|
return makeLlmFinish({
|
|
10365
|
-
stopReason
|
|
10366
|
-
text
|
|
10430
|
+
stopReason,
|
|
10431
|
+
text,
|
|
10367
10432
|
toolCalls,
|
|
10368
10433
|
inputTokens: this.inputTokens,
|
|
10369
10434
|
outputTokens: this.outputTokens,
|
|
@@ -10876,6 +10941,9 @@ function selectTransport(profile, apiKey) {
|
|
|
10876
10941
|
const opts = { apiKey };
|
|
10877
10942
|
opts.baseUrl = profile.baseUrl;
|
|
10878
10943
|
opts.providerName = profile.name;
|
|
10944
|
+
if (profile.extractToolCallsFromContent === true) {
|
|
10945
|
+
opts.extractToolCallsFromContent = true;
|
|
10946
|
+
}
|
|
10879
10947
|
if (profile.name === "openai" && process.env.OPENAI_ORGANIZATION !== void 0) {
|
|
10880
10948
|
opts.organization = process.env.OPENAI_ORGANIZATION;
|
|
10881
10949
|
}
|