@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/CHANGELOG.md +12 -0
- package/dist/a2a/index.cjs +85 -6
- package/dist/a2a/index.cjs.map +1 -1
- package/dist/a2a/index.js +85 -6
- package/dist/a2a/index.js.map +1 -1
- package/dist/{cron-BRfFPEKY.d.ts → cron-CL_9nfhQ.d.ts} +18 -0
- package/dist/{cron-DOw-Hqol.d.cts → cron-CpxLdAXc.d.cts} +18 -0
- package/dist/cron.cjs +79 -6
- 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 +79 -6
- package/dist/cron.js.map +1 -1
- package/dist/eval.cjs +79 -6
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +79 -6
- package/dist/eval.js.map +1 -1
- package/dist/index.cjs +79 -6
- 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 +79 -6
- 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/llm/router.d.ts +8 -0
- package/dist/internal/providers/types.d.ts +7 -0
- package/dist/types/providers.d.ts +11 -0
- package/package.json +14 -14
|
@@ -760,6 +760,17 @@ interface ProviderRoute {
|
|
|
760
760
|
capability: ProviderCapability;
|
|
761
761
|
provider: string;
|
|
762
762
|
model?: string;
|
|
763
|
+
/**
|
|
764
|
+
* Opt-in leaked-dialect safe-parse for this route's provider (theokit#58
|
|
765
|
+
* follow-up). When `true`, a `chat_completions` finish that carries ZERO
|
|
766
|
+
* native `tool_calls` has its assistant text scanned for the Hermes
|
|
767
|
+
* `<function=…></tool_call>` dialect, and any recovered calls are surfaced as
|
|
768
|
+
* real `tool_calls` so the loop executes them — for models (qwen3-coder via
|
|
769
|
+
* OpenRouter) that intermittently leak tool calls as text. Default `false`;
|
|
770
|
+
* fail-open (a partial/unclosed block never fabricates a call). Scoped to the
|
|
771
|
+
* resolved chat chain, so a non-leaking route is unaffected.
|
|
772
|
+
*/
|
|
773
|
+
extractToolCallsFromContent?: boolean;
|
|
763
774
|
}
|
|
764
775
|
/**
|
|
765
776
|
* Provider routing configuration accepted by `Agent.create()` via
|
|
@@ -873,6 +884,13 @@ interface ProviderProfile {
|
|
|
873
884
|
fallbackModels: ReadonlyArray<string>;
|
|
874
885
|
extraHeaders?: Record<string, string>;
|
|
875
886
|
bodyOverrides?: Record<string, unknown>;
|
|
887
|
+
/**
|
|
888
|
+
* Opt-in leaked-dialect safe-parse (theokit#58 follow-up). When `true`, a chat_completions finish
|
|
889
|
+
* with ZERO native `tool_calls` has its assistant content scanned for the Hermes
|
|
890
|
+
* `<function=…></tool_call>` dialect and any recovered calls are surfaced as real `tool_calls`.
|
|
891
|
+
* Default off — only enable for routes/models known to leak (e.g. a qwen3-coder profile variant).
|
|
892
|
+
*/
|
|
893
|
+
extractToolCallsFromContent?: boolean;
|
|
876
894
|
}
|
|
877
895
|
|
|
878
896
|
type HookName = "pre_tool_call" | "post_tool_call" | "pre_llm_call" | "post_llm_call" | "on_session_start" | "on_session_end" | "transform_tool_result" | "transform_llm_output" | "pre_user_send" | "post_assistant_reply";
|
|
@@ -760,6 +760,17 @@ interface ProviderRoute {
|
|
|
760
760
|
capability: ProviderCapability;
|
|
761
761
|
provider: string;
|
|
762
762
|
model?: string;
|
|
763
|
+
/**
|
|
764
|
+
* Opt-in leaked-dialect safe-parse for this route's provider (theokit#58
|
|
765
|
+
* follow-up). When `true`, a `chat_completions` finish that carries ZERO
|
|
766
|
+
* native `tool_calls` has its assistant text scanned for the Hermes
|
|
767
|
+
* `<function=…></tool_call>` dialect, and any recovered calls are surfaced as
|
|
768
|
+
* real `tool_calls` so the loop executes them — for models (qwen3-coder via
|
|
769
|
+
* OpenRouter) that intermittently leak tool calls as text. Default `false`;
|
|
770
|
+
* fail-open (a partial/unclosed block never fabricates a call). Scoped to the
|
|
771
|
+
* resolved chat chain, so a non-leaking route is unaffected.
|
|
772
|
+
*/
|
|
773
|
+
extractToolCallsFromContent?: boolean;
|
|
763
774
|
}
|
|
764
775
|
/**
|
|
765
776
|
* Provider routing configuration accepted by `Agent.create()` via
|
|
@@ -873,6 +884,13 @@ interface ProviderProfile {
|
|
|
873
884
|
fallbackModels: ReadonlyArray<string>;
|
|
874
885
|
extraHeaders?: Record<string, string>;
|
|
875
886
|
bodyOverrides?: Record<string, unknown>;
|
|
887
|
+
/**
|
|
888
|
+
* Opt-in leaked-dialect safe-parse (theokit#58 follow-up). When `true`, a chat_completions finish
|
|
889
|
+
* with ZERO native `tool_calls` has its assistant content scanned for the Hermes
|
|
890
|
+
* `<function=…></tool_call>` dialect and any recovered calls are surfaced as real `tool_calls`.
|
|
891
|
+
* Default off — only enable for routes/models known to leak (e.g. a qwen3-coder profile variant).
|
|
892
|
+
*/
|
|
893
|
+
extractToolCallsFromContent?: boolean;
|
|
876
894
|
}
|
|
877
895
|
|
|
878
896
|
type HookName = "pre_tool_call" | "post_tool_call" | "pre_llm_call" | "post_llm_call" | "on_session_start" | "on_session_end" | "transform_tool_result" | "transform_llm_output" | "pre_user_send" | "post_assistant_reply";
|
package/dist/cron.cjs
CHANGED
|
@@ -10956,6 +10956,35 @@ function toOllamaTools(tools) {
|
|
|
10956
10956
|
}));
|
|
10957
10957
|
}
|
|
10958
10958
|
|
|
10959
|
+
// src/internal/llm/hermes-tool-extract.ts
|
|
10960
|
+
var HERMES_BLOCK = /<function=\s*([^>\s]+)\s*>([\s\S]*?)<\/tool_call>/g;
|
|
10961
|
+
var HERMES_PARAM = /<parameter=\s*([^>\s]+)\s*>([\s\S]*?)<\/parameter>/g;
|
|
10962
|
+
function extractHermesToolCalls(content, makeId) {
|
|
10963
|
+
const toolCalls = [];
|
|
10964
|
+
for (const block of content.matchAll(HERMES_BLOCK)) {
|
|
10965
|
+
const name = (block[1] ?? "").trim();
|
|
10966
|
+
if (name.length === 0) continue;
|
|
10967
|
+
toolCalls.push({
|
|
10968
|
+
type: "tool_use",
|
|
10969
|
+
id: makeId(),
|
|
10970
|
+
name,
|
|
10971
|
+
input: parseHermesParams(block[2] ?? "")
|
|
10972
|
+
});
|
|
10973
|
+
}
|
|
10974
|
+
const residualText = toolCalls.length === 0 ? content : content.replace(HERMES_BLOCK, "").trim();
|
|
10975
|
+
return { toolCalls, residualText };
|
|
10976
|
+
}
|
|
10977
|
+
function parseHermesParams(inner) {
|
|
10978
|
+
const input = {};
|
|
10979
|
+
for (const param of inner.matchAll(HERMES_PARAM)) {
|
|
10980
|
+
const key = param[1];
|
|
10981
|
+
const value = param[2];
|
|
10982
|
+
if (key === void 0 || value === void 0) continue;
|
|
10983
|
+
input[key.trim()] = value;
|
|
10984
|
+
}
|
|
10985
|
+
return input;
|
|
10986
|
+
}
|
|
10987
|
+
|
|
10959
10988
|
// src/internal/llm/openai.ts
|
|
10960
10989
|
var OpenAIClient = class {
|
|
10961
10990
|
constructor(options) {
|
|
@@ -10967,6 +10996,14 @@ var OpenAIClient = class {
|
|
|
10967
10996
|
name = "openai";
|
|
10968
10997
|
baseUrl;
|
|
10969
10998
|
fetchImpl;
|
|
10999
|
+
/**
|
|
11000
|
+
* Whether this client recovers leaked Hermes tool-call dialect from assistant
|
|
11001
|
+
* text (theokit#58 follow-up). Observability for the route→client wiring of
|
|
11002
|
+
* `extractToolCallsFromContent`. @internal
|
|
11003
|
+
*/
|
|
11004
|
+
get recoversLeakedToolCalls() {
|
|
11005
|
+
return this.options.extractToolCallsFromContent ?? false;
|
|
11006
|
+
}
|
|
10970
11007
|
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: HTTP+SSE handshake + accumulator is intentionally one block
|
|
10971
11008
|
async *stream(request, signal) {
|
|
10972
11009
|
const headers = {
|
|
@@ -11017,7 +11054,10 @@ var OpenAIClient = class {
|
|
|
11017
11054
|
endpoint: "/v1/chat/completions"
|
|
11018
11055
|
});
|
|
11019
11056
|
}
|
|
11020
|
-
const accumulator = new OpenAIStreamAccumulator(
|
|
11057
|
+
const accumulator = new OpenAIStreamAccumulator(
|
|
11058
|
+
this.options.extractToolCallsFromContent ?? false,
|
|
11059
|
+
providerId
|
|
11060
|
+
);
|
|
11021
11061
|
for await (const record of parseSseStream(response.body, signal)) {
|
|
11022
11062
|
if (record.data === "[DONE]") break;
|
|
11023
11063
|
let chunk;
|
|
@@ -11043,6 +11083,16 @@ var OpenAIClient = class {
|
|
|
11043
11083
|
}
|
|
11044
11084
|
};
|
|
11045
11085
|
var OpenAIStreamAccumulator = class {
|
|
11086
|
+
/**
|
|
11087
|
+
* @param extractFromContent opt-in leaked-dialect safe-parse (theokit#58). Default false.
|
|
11088
|
+
* @param providerName provider id, used only to label the recovery log line.
|
|
11089
|
+
*/
|
|
11090
|
+
constructor(extractFromContent = false, providerName = "openai") {
|
|
11091
|
+
this.extractFromContent = extractFromContent;
|
|
11092
|
+
this.providerName = providerName;
|
|
11093
|
+
}
|
|
11094
|
+
extractFromContent;
|
|
11095
|
+
providerName;
|
|
11046
11096
|
text = "";
|
|
11047
11097
|
stopReason = "end_turn";
|
|
11048
11098
|
inputTokens;
|
|
@@ -11108,9 +11158,26 @@ var OpenAIStreamAccumulator = class {
|
|
|
11108
11158
|
const input = parseToolArguments(call.args);
|
|
11109
11159
|
toolCalls.push({ type: "tool_use", id: call.id, name: call.name, input });
|
|
11110
11160
|
}
|
|
11161
|
+
let text = this.text;
|
|
11162
|
+
let stopReason = this.stopReason;
|
|
11163
|
+
if (this.extractFromContent && toolCalls.length === 0) {
|
|
11164
|
+
const recovered = extractHermesToolCalls(
|
|
11165
|
+
this.text,
|
|
11166
|
+
() => `hermes-${globalThis.crypto.randomUUID()}`
|
|
11167
|
+
);
|
|
11168
|
+
if (recovered.toolCalls.length > 0) {
|
|
11169
|
+
toolCalls.push(...recovered.toolCalls);
|
|
11170
|
+
text = recovered.residualText;
|
|
11171
|
+
stopReason = "tool_use";
|
|
11172
|
+
process.stderr.write(
|
|
11173
|
+
`[theokit-sdk] recovered ${recovered.toolCalls.length} leaked tool call(s) from assistant content (provider="${this.providerName}", names=${recovered.toolCalls.map((c) => c.name).join(",")})
|
|
11174
|
+
`
|
|
11175
|
+
);
|
|
11176
|
+
}
|
|
11177
|
+
}
|
|
11111
11178
|
return makeLlmFinish({
|
|
11112
|
-
stopReason
|
|
11113
|
-
text
|
|
11179
|
+
stopReason,
|
|
11180
|
+
text,
|
|
11114
11181
|
toolCalls,
|
|
11115
11182
|
inputTokens: this.inputTokens,
|
|
11116
11183
|
outputTokens: this.outputTokens,
|
|
@@ -11587,8 +11654,9 @@ function buildChain(options) {
|
|
|
11587
11654
|
return clients;
|
|
11588
11655
|
}
|
|
11589
11656
|
function buildClient(name, routerOptions) {
|
|
11590
|
-
const
|
|
11591
|
-
if (
|
|
11657
|
+
const baseProfile = getProviderProfile(name);
|
|
11658
|
+
if (baseProfile === void 0) return void 0;
|
|
11659
|
+
const profile = routerOptions.extractToolCallsFromContent === true && baseProfile.extractToolCallsFromContent !== true ? { ...baseProfile, extractToolCallsFromContent: true } : baseProfile;
|
|
11592
11660
|
const ambient = currentCredentialPool(name);
|
|
11593
11661
|
if (ambient !== void 0) {
|
|
11594
11662
|
return new PoolAwareLlmClient(ambient, (apiKey) => selectTransport(profile, apiKey));
|
|
@@ -11690,6 +11758,9 @@ function selectTransport(profile, apiKey) {
|
|
|
11690
11758
|
const opts = { apiKey };
|
|
11691
11759
|
opts.baseUrl = profile.baseUrl;
|
|
11692
11760
|
opts.providerName = profile.name;
|
|
11761
|
+
if (profile.extractToolCallsFromContent === true) {
|
|
11762
|
+
opts.extractToolCallsFromContent = true;
|
|
11763
|
+
}
|
|
11693
11764
|
if (profile.name === "openai" && process.env.OPENAI_ORGANIZATION !== void 0) {
|
|
11694
11765
|
opts.organization = process.env.OPENAI_ORGANIZATION;
|
|
11695
11766
|
}
|
|
@@ -11986,11 +12057,13 @@ function buildLoopInputs(options, runId, userText) {
|
|
|
11986
12057
|
const fallback = options.agentOptions.providers?.fallback;
|
|
11987
12058
|
const apiKeys = options.agentOptions.providers?.apiKeys;
|
|
11988
12059
|
const credentialPoolStrategy = options.agentOptions.providers?.credentialPoolStrategy;
|
|
12060
|
+
const extractToolCallsFromContent = options.agentOptions.providers?.routes?.[0]?.extractToolCallsFromContent;
|
|
11989
12061
|
const chain = resolveProviderChain({
|
|
11990
12062
|
primary,
|
|
11991
12063
|
...fallback !== void 0 ? { fallback } : {},
|
|
11992
12064
|
...apiKeys !== void 0 ? { apiKeys } : {},
|
|
11993
|
-
...credentialPoolStrategy !== void 0 ? { credentialPoolStrategy } : {}
|
|
12065
|
+
...credentialPoolStrategy !== void 0 ? { credentialPoolStrategy } : {},
|
|
12066
|
+
...extractToolCallsFromContent === true ? { extractToolCallsFromContent: true } : {}
|
|
11994
12067
|
});
|
|
11995
12068
|
const llm = chain.length === 1 ? chain[0] : new FallbackLlmClient(chain);
|
|
11996
12069
|
return {
|