llm-relay 0.32.2 → 0.33.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/backend.d.ts +24 -2
- package/dist/backend.js +81 -6
- package/dist/backend.js.map +1 -1
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +79 -0
- package/dist/cli.js.map +1 -1
- package/dist/dispatch.d.ts +16 -1
- package/dist/dispatch.js +101 -1
- package/dist/dispatch.js.map +1 -1
- package/dist/lane-manifest.d.ts +78 -0
- package/dist/lane-manifest.js +100 -0
- package/dist/lane-manifest.js.map +1 -0
- package/dist/lane-probe.d.ts +28 -0
- package/dist/lane-probe.js +113 -0
- package/dist/lane-probe.js.map +1 -0
- package/dist/routes/admin.js +3 -0
- package/dist/routes/admin.js.map +1 -1
- package/dist/tool-dialects.d.ts +58 -0
- package/dist/tool-dialects.js +205 -0
- package/dist/tool-dialects.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recovering tool calls a HOST failed to parse.
|
|
3
|
+
*
|
|
4
|
+
* A model emits tool calls in its own dialect; the serving host is supposed to parse that into the
|
|
5
|
+
* OpenAI `message.tool_calls` field. NIM and OpenRouter do. Some free hosts do not, and hand back
|
|
6
|
+
* the raw envelope as ordinary assistant TEXT. Before this module the consequence was silent and
|
|
7
|
+
* total: no `tool_calls` ⇒ `stop_reason: end_turn` ⇒ zero `tool_use` blocks ⇒ the validator finds
|
|
8
|
+
* nothing malformed and PASSES ⇒ repair never engages ⇒ the client receives markup it treats as a
|
|
9
|
+
* final answer. Measured 2026-08-08: a task wrote its output correctly and then emitted
|
|
10
|
+
* `</|DSML|parameter></|DSML|invoke></|DSML|tool_calls>` as its entire visible response.
|
|
11
|
+
* See docs/tool-call-dialect-leak.md.
|
|
12
|
+
*
|
|
13
|
+
* ⚠ This is PARSING, not inference — the same side of the repair boundary as fixing args that
|
|
14
|
+
* violate a schema. The envelope set is CLOSED (same reasoning as the effort vocabulary in
|
|
15
|
+
* sync-tiers.mjs and the alias list in authEnv.ts): prose that merely mentions a tool name is not a
|
|
16
|
+
* tool call, and promoting it to one would be fabricating intent, which is the one thing the repair
|
|
17
|
+
* path must never do. A dialect we do not recognize yields `detected` at most, never a guess.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Marker substrings that mean "a tool-call envelope is present". Detection is deliberately broader
|
|
21
|
+
* than parsing: a truncated envelope must still be recognized as one, because returning its
|
|
22
|
+
* fragment as an answer is what made this failure read as "the job died".
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* ⚠ Markers deliberately omit the `<` / `</` prefix so a CLOSING tag matches too. The truncated
|
|
26
|
+
* tail of a stream is mostly closing tags — one of the two measured failure bodies was exactly
|
|
27
|
+
* `</|DSML|parameter></|DSML|invoke></|DSML|tool_calls>`, which an open-tag-only marker set
|
|
28
|
+
* reports as ordinary prose. That is the single case where detection matters most, because there
|
|
29
|
+
* is no call left to recover and the alternative is handing the fragment back as an answer.
|
|
30
|
+
*/
|
|
31
|
+
const DIALECT_MARKERS = [
|
|
32
|
+
{ dialect: "deepseek", markers: ["|tool▁calls▁begin|", "|tool▁call▁begin|", "|tool▁sep|", "|tool▁call▁end|", "|tool▁calls▁end|"] },
|
|
33
|
+
{ dialect: "dsml", markers: ["|DSML|tool_calls", "|DSML|invoke", "|DSML|parameter"] },
|
|
34
|
+
{ dialect: "hermes", markers: ["<tool_call>", "</tool_call>"] },
|
|
35
|
+
{ dialect: "xml-invoke", markers: ["<function_calls>", "</function_calls>", "<invoke name=", "</invoke>"] },
|
|
36
|
+
{ dialect: "functionary", markers: ["<function="] },
|
|
37
|
+
];
|
|
38
|
+
export function detectDialect(text) {
|
|
39
|
+
for (const { dialect, markers } of DIALECT_MARKERS) {
|
|
40
|
+
if (markers.some((m) => text.includes(m)))
|
|
41
|
+
return dialect;
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
/** Coerce a stringly-typed dialect parameter using the tool's declared schema. */
|
|
46
|
+
function coerce(raw, schema) {
|
|
47
|
+
const t = Array.isArray(schema?.type) ? schema?.type[0] : schema?.type;
|
|
48
|
+
const s = raw.trim();
|
|
49
|
+
switch (t) {
|
|
50
|
+
case "number":
|
|
51
|
+
case "integer": {
|
|
52
|
+
const n = Number(s);
|
|
53
|
+
return Number.isFinite(n) ? n : raw;
|
|
54
|
+
}
|
|
55
|
+
case "boolean":
|
|
56
|
+
return s === "true" ? true : s === "false" ? false : raw;
|
|
57
|
+
case "object":
|
|
58
|
+
case "array":
|
|
59
|
+
try {
|
|
60
|
+
return JSON.parse(s);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return raw;
|
|
64
|
+
}
|
|
65
|
+
case "string":
|
|
66
|
+
return raw;
|
|
67
|
+
default:
|
|
68
|
+
// No declared type: keep the literal. Guessing a shape here would silently rewrite an
|
|
69
|
+
// argument the model meant as text.
|
|
70
|
+
return raw;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** `{"name": "x", "arguments": {...}}` — the JSON payload shape shared by several dialects. */
|
|
74
|
+
function fromJsonPayload(raw) {
|
|
75
|
+
let j;
|
|
76
|
+
try {
|
|
77
|
+
j = JSON.parse(raw.trim());
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
if (typeof j !== "object" || j === null)
|
|
83
|
+
return null;
|
|
84
|
+
const o = j;
|
|
85
|
+
const name = typeof o.name === "string" ? o.name : null;
|
|
86
|
+
if (!name)
|
|
87
|
+
return null;
|
|
88
|
+
const args = o.arguments ?? o.parameters ?? o.input ?? {};
|
|
89
|
+
if (typeof args === "string") {
|
|
90
|
+
try {
|
|
91
|
+
return { name, input: JSON.parse(args) };
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (typeof args !== "object" || args === null)
|
|
98
|
+
return null;
|
|
99
|
+
return { name, input: args };
|
|
100
|
+
}
|
|
101
|
+
/** `<invoke name="x"><parameter name="p">v</parameter></invoke>`, with or without DSML markers. */
|
|
102
|
+
function fromInvokeForm(text, schemas) {
|
|
103
|
+
const calls = [];
|
|
104
|
+
const invoke = /<(?:|DSML|)?invoke\s+name="([^"]+)"\s*>([\s\S]*?)<\/(?:|DSML|)?invoke>/g;
|
|
105
|
+
for (const m of text.matchAll(invoke)) {
|
|
106
|
+
const name = m[1];
|
|
107
|
+
const bodyText = m[2];
|
|
108
|
+
if (!name || bodyText === undefined)
|
|
109
|
+
continue;
|
|
110
|
+
const input = {};
|
|
111
|
+
const param = /<(?:|DSML|)?parameter\s+name="([^"]+)"\s*>([\s\S]*?)<\/(?:|DSML|)?parameter>/g;
|
|
112
|
+
for (const p of bodyText.matchAll(param)) {
|
|
113
|
+
const key = p[1];
|
|
114
|
+
const value = p[2];
|
|
115
|
+
if (!key || value === undefined)
|
|
116
|
+
continue;
|
|
117
|
+
input[key] = coerce(value, schemas.get(name)?.properties?.[key]);
|
|
118
|
+
}
|
|
119
|
+
calls.push({ name, input });
|
|
120
|
+
}
|
|
121
|
+
return calls;
|
|
122
|
+
}
|
|
123
|
+
/** DeepSeek native: `…begin|>function<|tool▁sep|>NAME\n```json\n{…}\n``` `. */
|
|
124
|
+
function fromDeepSeekForm(text) {
|
|
125
|
+
const calls = [];
|
|
126
|
+
const re = /<|tool▁sep|>([^\n<]+)\n+(?:```(?:json)?\n)?([\s\S]*?)(?:\n?```)?\s*<|tool▁call▁end|>/g;
|
|
127
|
+
for (const m of text.matchAll(re)) {
|
|
128
|
+
const name = m[1];
|
|
129
|
+
const payload = m[2];
|
|
130
|
+
if (!name || payload === undefined)
|
|
131
|
+
continue;
|
|
132
|
+
let input = {};
|
|
133
|
+
try {
|
|
134
|
+
const parsed = JSON.parse(payload.trim());
|
|
135
|
+
if (typeof parsed === "object" && parsed !== null)
|
|
136
|
+
input = parsed;
|
|
137
|
+
}
|
|
138
|
+
catch { /* an unparseable body leaves `detected` to the caller */
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
calls.push({ name: name.trim(), input });
|
|
142
|
+
}
|
|
143
|
+
return calls;
|
|
144
|
+
}
|
|
145
|
+
/** `<tool_call>{json}</tool_call>` (Hermes/Qwen) and `<function=NAME>{json}</function>`. */
|
|
146
|
+
function fromTaggedJsonForms(text) {
|
|
147
|
+
const calls = [];
|
|
148
|
+
for (const m of text.matchAll(/<tool_call>([\s\S]*?)<\/tool_call>/g)) {
|
|
149
|
+
if (m[1] === undefined)
|
|
150
|
+
continue;
|
|
151
|
+
const c = fromJsonPayload(m[1]);
|
|
152
|
+
if (c)
|
|
153
|
+
calls.push(c);
|
|
154
|
+
}
|
|
155
|
+
for (const m of text.matchAll(/<function=([^>]+)>([\s\S]*?)<\/function>/g)) {
|
|
156
|
+
const name = m[1];
|
|
157
|
+
const payload = m[2];
|
|
158
|
+
if (!name || payload === undefined)
|
|
159
|
+
continue;
|
|
160
|
+
let input = {};
|
|
161
|
+
try {
|
|
162
|
+
const parsed = JSON.parse(payload.trim());
|
|
163
|
+
if (typeof parsed === "object" && parsed !== null)
|
|
164
|
+
input = parsed;
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
calls.push({ name: name.trim(), input });
|
|
170
|
+
}
|
|
171
|
+
return calls;
|
|
172
|
+
}
|
|
173
|
+
/** Everything the envelope occupied, so the surviving prose can stay a text block. */
|
|
174
|
+
function stripEnvelopes(text) {
|
|
175
|
+
return text
|
|
176
|
+
.replace(/<(?:|DSML|)?function_calls>[\s\S]*?<\/(?:|DSML|)?function_calls>/g, "")
|
|
177
|
+
.replace(/<|DSML|tool_calls>[\s\S]*?(?:<\/|DSML|tool_calls>|$)/g, "")
|
|
178
|
+
.replace(/<(?:|DSML|)?invoke\s+name="[^"]*"\s*>[\s\S]*?<\/(?:|DSML|)?invoke>/g, "")
|
|
179
|
+
.replace(/<|tool▁calls▁begin|>[\s\S]*?(?:<|tool▁calls▁end|>|$)/g, "")
|
|
180
|
+
.replace(/<tool_call>[\s\S]*?<\/tool_call>/g, "")
|
|
181
|
+
.replace(/<function=[^>]+>[\s\S]*?<\/function>/g, "")
|
|
182
|
+
.replace(/<\/?think>/g, "")
|
|
183
|
+
.trim();
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Recover tool calls from a text block a host failed to parse.
|
|
187
|
+
*
|
|
188
|
+
* `schemas` supplies declared parameter types for the dialects that carry parameters as strings;
|
|
189
|
+
* without it those values stay strings and the validator reports the type error, which is the
|
|
190
|
+
* correct visible failure rather than a silent coercion.
|
|
191
|
+
*/
|
|
192
|
+
export function recoverToolCalls(text, schemas = new Map()) {
|
|
193
|
+
const dialect = detectDialect(text);
|
|
194
|
+
if (!dialect)
|
|
195
|
+
return { status: "none" };
|
|
196
|
+
const calls = [
|
|
197
|
+
...fromInvokeForm(text, schemas),
|
|
198
|
+
...fromDeepSeekForm(text),
|
|
199
|
+
...fromTaggedJsonForms(text),
|
|
200
|
+
].filter((c) => c.name.length > 0);
|
|
201
|
+
if (calls.length === 0)
|
|
202
|
+
return { status: "detected", dialect };
|
|
203
|
+
return { status: "parsed", calls, text: stripEnvelopes(text), dialect };
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=tool-dialects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-dialects.js","sourceRoot":"","sources":["../src/tool-dialects.ts"],"names":[],"mappings":"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"}
|