@jsonstudio/llms 0.6.1172 → 0.6.1397
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/conversion/codecs/gemini-openai-codec.d.ts +3 -1
- package/dist/conversion/codecs/gemini-openai-codec.js +10 -4
- package/dist/conversion/compat/actions/gemini-web-search.d.ts +1 -1
- package/dist/conversion/compat/actions/gemini-web-search.js +5 -2
- package/dist/conversion/compat/actions/iflow-tool-text-fallback.d.ts +12 -0
- package/dist/conversion/compat/actions/iflow-tool-text-fallback.js +199 -0
- package/dist/conversion/compat/actions/iflow-web-search.d.ts +1 -1
- package/dist/conversion/compat/actions/iflow-web-search.js +5 -2
- package/dist/conversion/compat/profiles/chat-gemini.json +5 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.js +47 -56
- package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.js +1 -13
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +748 -52
- package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +18 -38
- package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +6 -0
- package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +3 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/adapter-context.d.ts +10 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/adapter-context.js +142 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/anthropic-alias-map.d.ts +6 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/anthropic-alias-map.js +79 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/apply-patch-tool-mode.d.ts +3 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/apply-patch-tool-mode.js +46 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/execute-chat-process-entry.d.ts +8 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/execute-chat-process-entry.js +366 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/execute-request-stage.d.ts +9 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/execute-request-stage.js +390 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/node-results.d.ts +3 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/node-results.js +14 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/payload-normalize.d.ts +2 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/payload-normalize.js +144 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/policy.d.ts +4 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/policy.js +32 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/protocol.d.ts +8 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/protocol.js +63 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/resolve-protocol-hooks.d.ts +2 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/resolve-protocol-hooks.js +43 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/semantic-gate.d.ts +1 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/semantic-gate.js +29 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/servertool-runtime-config.d.ts +2 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/servertool-runtime-config.js +16 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/types.d.ts +116 -0
- package/dist/conversion/hub/pipeline/hub-pipeline/types.js +1 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +3 -95
- package/dist/conversion/hub/pipeline/hub-pipeline.js +19 -1281
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage1_format_parse/index.js +1 -1
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.d.ts +7 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +65 -1
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +25 -22
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.js +1 -1
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage2_format_build/index.d.ts +1 -1
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage2_format_build/index.js +2 -2
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage2_thought_signature_inject/index.d.ts +10 -0
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage2_thought_signature_inject/index.js +172 -0
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage3_compat/index.js +2 -2
- package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage1_tool_governance/index.js +1 -1
- package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage2_route_select/index.js +1 -1
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js +11 -11
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage2_format_parse/index.js +1 -1
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage3_semantic_map/index.d.ts +1 -0
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage3_semantic_map/index.js +4 -2
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage3_thought_signature_capture/index.d.ts +10 -0
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage3_thought_signature_capture/index.js +71 -0
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.d.ts +1 -0
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +17 -9
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage2_sse_stream/index.js +2 -2
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +40 -2
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage2_finalize/index.js +1 -1
- package/dist/conversion/hub/pipeline/target-utils.js +9 -5
- package/dist/conversion/hub/pipeline/thought-signature/thought-signature-center.d.ts +14 -0
- package/dist/conversion/hub/pipeline/thought-signature/thought-signature-center.js +289 -0
- package/dist/conversion/hub/process/chat-process.js +256 -16
- package/dist/conversion/hub/response/provider-response.d.ts +8 -0
- package/dist/conversion/hub/response/provider-response.js +91 -27
- package/dist/conversion/hub/response/response-mappers.d.ts +10 -3
- package/dist/conversion/hub/response/response-mappers.js +30 -6
- package/dist/conversion/hub/response/response-runtime.js +4 -38
- package/dist/conversion/hub/snapshot-recorder.js +5 -1
- package/dist/conversion/hub/standardized-bridge.js +23 -15
- package/dist/conversion/pipeline/codecs/v2/anthropic-openai-pipeline.js +36 -5
- package/dist/conversion/responses/responses-openai-bridge.js +20 -4
- package/dist/conversion/shared/gemini-tool-utils.d.ts +8 -1
- package/dist/conversion/shared/gemini-tool-utils.js +580 -108
- package/dist/conversion/shared/jsonish.js +1 -1
- package/dist/conversion/shared/mcp-injection.js +67 -33
- package/dist/conversion/shared/openai-finalizer.js +2 -1
- package/dist/conversion/shared/openai-message-normalize.js +76 -21
- package/dist/conversion/shared/responses-output-builder.js +6 -0
- package/dist/conversion/shared/runtime-metadata.d.ts +7 -0
- package/dist/conversion/shared/runtime-metadata.js +23 -0
- package/dist/conversion/shared/text-markup-normalizer.d.ts +2 -0
- package/dist/conversion/shared/text-markup-normalizer.js +284 -4
- package/dist/conversion/shared/tool-canonicalizer.js +2 -1
- package/dist/conversion/shared/tool-governor.js +3 -3
- package/dist/filters/engine.js +5 -5
- package/dist/filters/special/request-tool-list-filter.js +194 -60
- package/dist/filters/special/request-tools-normalize.js +1 -1
- package/dist/filters/special/response-tool-text-canonicalize.d.ts +4 -7
- package/dist/filters/special/response-tool-text-canonicalize.js +7 -35
- package/dist/filters/special/tool-filter-hooks.js +58 -62
- package/dist/guidance/index.js +5 -1
- package/dist/http/sse-response.js +6 -6
- package/dist/router/virtual-router/bootstrap.js +54 -4
- package/dist/router/virtual-router/engine-health.d.ts +1 -1
- package/dist/router/virtual-router/engine-health.js +11 -110
- package/dist/router/virtual-router/engine-selection/alias-selection.d.ts +30 -0
- package/dist/router/virtual-router/engine-selection/alias-selection.js +237 -0
- package/dist/router/virtual-router/engine-selection/context-weight-multipliers.d.ts +11 -0
- package/dist/router/virtual-router/engine-selection/context-weight-multipliers.js +23 -0
- package/dist/router/virtual-router/engine-selection/direct-provider-model.d.ts +9 -0
- package/dist/router/virtual-router/engine-selection/direct-provider-model.js +49 -0
- package/dist/router/virtual-router/engine-selection/instruction-target.d.ts +6 -0
- package/dist/router/virtual-router/engine-selection/instruction-target.js +54 -0
- package/dist/router/virtual-router/engine-selection/key-parsing.d.ts +8 -0
- package/dist/router/virtual-router/engine-selection/key-parsing.js +64 -0
- package/dist/router/virtual-router/engine-selection/route-utils.d.ts +12 -0
- package/dist/router/virtual-router/engine-selection/route-utils.js +150 -0
- package/dist/router/virtual-router/engine-selection/routing-state-filter.d.ts +4 -0
- package/dist/router/virtual-router/engine-selection/routing-state-filter.js +50 -0
- package/dist/router/virtual-router/engine-selection/selection-deps.d.ts +39 -0
- package/dist/router/virtual-router/engine-selection/selection-deps.js +1 -0
- package/dist/router/virtual-router/engine-selection/sticky-pool.d.ts +11 -0
- package/dist/router/virtual-router/engine-selection/sticky-pool.js +109 -0
- package/dist/router/virtual-router/engine-selection/tier-priority.d.ts +12 -0
- package/dist/router/virtual-router/engine-selection/tier-priority.js +55 -0
- package/dist/router/virtual-router/engine-selection/tier-selection-select.d.ts +22 -0
- package/dist/router/virtual-router/engine-selection/tier-selection-select.js +423 -0
- package/dist/router/virtual-router/engine-selection/tier-selection.d.ts +3 -0
- package/dist/router/virtual-router/engine-selection/tier-selection.js +228 -0
- package/dist/router/virtual-router/engine-selection.d.ts +4 -30
- package/dist/router/virtual-router/engine-selection.js +10 -962
- package/dist/router/virtual-router/engine.d.ts +1 -0
- package/dist/router/virtual-router/engine.js +64 -11
- package/dist/router/virtual-router/routing-instructions.js +6 -1
- package/dist/router/virtual-router/stop-message-state-sync.d.ts +5 -0
- package/dist/router/virtual-router/stop-message-state-sync.js +6 -14
- package/dist/router/virtual-router/types.d.ts +38 -1
- package/dist/servertool/clock/config.d.ts +8 -0
- package/dist/servertool/clock/config.js +22 -0
- package/dist/servertool/clock/log.d.ts +3 -0
- package/dist/servertool/clock/log.js +13 -0
- package/dist/servertool/clock/task-store.d.ts +1 -1
- package/dist/servertool/clock/task-store.js +1 -1
- package/dist/servertool/clock/tasks.js +1 -1
- package/dist/servertool/engine.js +146 -21
- package/dist/servertool/handlers/clock-auto.js +11 -6
- package/dist/servertool/handlers/clock.js +36 -10
- package/dist/servertool/handlers/followup-request-builder.js +8 -2
- package/dist/servertool/handlers/gemini-empty-reply-continue.js +15 -9
- package/dist/servertool/handlers/iflow-model-error-retry.js +6 -4
- package/dist/servertool/handlers/recursive-detection-guard.js +4 -2
- package/dist/servertool/handlers/stop-message-auto.js +100 -10
- package/dist/servertool/handlers/vision.js +4 -1
- package/dist/servertool/handlers/web-search.js +3 -1
- package/dist/servertool/pending-session.d.ts +19 -0
- package/dist/servertool/pending-session.js +97 -0
- package/dist/servertool/reenter-backend.js +5 -3
- package/dist/servertool/server-side-tools.js +235 -6
- package/dist/servertool/types.d.ts +13 -0
- package/dist/sse/json-to-sse/event-generators/responses.js +1 -1
- package/dist/sse/shared/chat-serializer.js +2 -2
- package/dist/sse/shared/constants.js +1 -1
- package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +7 -1
- package/dist/sse/sse-to-json/builders/response-builder.js +16 -0
- package/dist/sse/sse-to-json/responses-sse-to-json-converter.d.ts +1 -1
- package/dist/tools/apply-patch/execution-capturer.js +1 -1
- package/dist/tools/exec-command/normalize.js +4 -0
- package/dist/tools/exec-command/regression-capturer.js +1 -1
- package/package.json +10 -5
|
@@ -118,6 +118,105 @@ function enabled() {
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
// 已移除所有 rcc.tool.v1 相关处理:不再识别或剥离 rcc 封装
|
|
121
|
+
// Extract <tool:NAME>...</tool:NAME> blocks used by some tool-mode outputs.
|
|
122
|
+
// Example:
|
|
123
|
+
// <tool:exec_command>
|
|
124
|
+
// <command>cd /repo && npm test</command>
|
|
125
|
+
// <timeout_ms>120000</timeout_ms>
|
|
126
|
+
// <requires_approval>false</requires_approval>
|
|
127
|
+
// </tool:exec_command>
|
|
128
|
+
export function extractToolNamespaceXmlBlocksFromText(text) {
|
|
129
|
+
try {
|
|
130
|
+
if (typeof text !== 'string' || !text)
|
|
131
|
+
return null;
|
|
132
|
+
if (!text.includes('<tool:'))
|
|
133
|
+
return null;
|
|
134
|
+
const out = [];
|
|
135
|
+
const blockRe = /<\s*tool:([A-Za-z0-9_]+)\s*>([\s\S]*?)<\/\s*tool:\s*\1\s*>/gi;
|
|
136
|
+
let bm;
|
|
137
|
+
while ((bm = blockRe.exec(text)) !== null) {
|
|
138
|
+
const rawName = String(bm[1] || '').trim();
|
|
139
|
+
const lname = rawName.toLowerCase();
|
|
140
|
+
if (!lname || !KNOWN_TOOLS.has(lname))
|
|
141
|
+
continue;
|
|
142
|
+
const inner = String(bm[2] || '');
|
|
143
|
+
const argsObj = {};
|
|
144
|
+
const kvRe = /<\s*([A-Za-z_][A-Za-z0-9_]*)\s*>([\s\S]*?)<\/\s*\1\s*>/g;
|
|
145
|
+
let km;
|
|
146
|
+
while ((km = kvRe.exec(inner)) !== null) {
|
|
147
|
+
const rawKey = String(km[1] || '').trim();
|
|
148
|
+
const key = normalizeKey(rawKey).toLowerCase();
|
|
149
|
+
if (!key)
|
|
150
|
+
continue;
|
|
151
|
+
if (key === 'requires_approval')
|
|
152
|
+
continue;
|
|
153
|
+
const rawVal = String(km[2] ?? '');
|
|
154
|
+
const value = tryParsePrimitiveValue(rawVal);
|
|
155
|
+
if (lname === 'exec_command' && (key === 'command' || key === 'cmd')) {
|
|
156
|
+
const cmd = coerceCommandValueToString(value);
|
|
157
|
+
if (cmd.trim().length) {
|
|
158
|
+
argsObj.cmd = cmd;
|
|
159
|
+
argsObj.command = cmd;
|
|
160
|
+
}
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (lname === 'exec_command' && (key === 'cwd' || key === 'workdir')) {
|
|
164
|
+
const wd = String(value ?? rawVal).trim();
|
|
165
|
+
if (wd)
|
|
166
|
+
argsObj.workdir = wd;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (lname === 'write_stdin') {
|
|
170
|
+
if (key === 'input' || key === 'data' || key === 'chars' || key === 'text') {
|
|
171
|
+
argsObj.chars = rawVal;
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (key === 'session_id') {
|
|
175
|
+
const n = Number.parseInt(String(value), 10);
|
|
176
|
+
argsObj.session_id = Number.isFinite(n) ? n : value;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (lname === 'apply_patch' && (key === 'patch' || key === 'input' || key === 'text' || key === 'instructions')) {
|
|
181
|
+
const patchText = typeof value === 'string' ? value : rawVal;
|
|
182
|
+
if (typeof patchText === 'string' && patchText.trim().length) {
|
|
183
|
+
argsObj.patch = patchText;
|
|
184
|
+
}
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
argsObj[key] = value;
|
|
188
|
+
}
|
|
189
|
+
const filtered = filterArgsForTool(lname, argsObj);
|
|
190
|
+
if (lname === 'exec_command') {
|
|
191
|
+
const cmd = typeof filtered?.cmd === 'string' ? String(filtered.cmd).trim() : '';
|
|
192
|
+
if (!cmd)
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (lname === 'write_stdin') {
|
|
196
|
+
const sid = filtered?.session_id;
|
|
197
|
+
if (sid === undefined || sid === null || String(sid).trim().length === 0)
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (lname === 'apply_patch') {
|
|
201
|
+
const patchText = typeof filtered?.patch === 'string' ? String(filtered.patch).trim() : '';
|
|
202
|
+
if (!patchText)
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
let argsStr = '{}';
|
|
206
|
+
try {
|
|
207
|
+
argsStr = JSON.stringify(filtered);
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
argsStr = '{}';
|
|
211
|
+
}
|
|
212
|
+
out.push({ id: `call_${Math.random().toString(36).slice(2, 10)}`, name: lname, args: argsStr });
|
|
213
|
+
}
|
|
214
|
+
return out.length ? out : null;
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
121
220
|
function extractStructuredApplyPatchPayloads(text) {
|
|
122
221
|
const payloads = [];
|
|
123
222
|
try {
|
|
@@ -160,6 +259,27 @@ function tryParseJsonValue(text) {
|
|
|
160
259
|
return null;
|
|
161
260
|
}
|
|
162
261
|
}
|
|
262
|
+
function tryParsePrimitiveValue(text) {
|
|
263
|
+
try {
|
|
264
|
+
const trimmed = String(text ?? '').trim();
|
|
265
|
+
if (trimmed.length === 0)
|
|
266
|
+
return '';
|
|
267
|
+
const parsed = tryParseJsonValue(trimmed);
|
|
268
|
+
if (parsed !== null)
|
|
269
|
+
return parsed;
|
|
270
|
+
if (trimmed === 'true' || trimmed === 'false')
|
|
271
|
+
return trimmed === 'true';
|
|
272
|
+
if (/^-?\d+(?:\.\d+)?$/.test(trimmed)) {
|
|
273
|
+
const n = Number(trimmed);
|
|
274
|
+
if (Number.isFinite(n))
|
|
275
|
+
return n;
|
|
276
|
+
}
|
|
277
|
+
return trimmed;
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
return String(text ?? '');
|
|
281
|
+
}
|
|
282
|
+
}
|
|
163
283
|
function coerceCommandValueToString(value) {
|
|
164
284
|
try {
|
|
165
285
|
if (value === null || value === undefined)
|
|
@@ -197,6 +317,8 @@ function looksLikeBrokenToolMarkup(text) {
|
|
|
197
317
|
if (!t)
|
|
198
318
|
return false;
|
|
199
319
|
return (t.includes('<exec_command') ||
|
|
320
|
+
t.includes('<invoke') ||
|
|
321
|
+
t.includes('<function_calls') ||
|
|
200
322
|
t.includes('<parameter') ||
|
|
201
323
|
t.includes('<tool_call') ||
|
|
202
324
|
t.includes('</tool_call') ||
|
|
@@ -329,6 +451,162 @@ export function extractParameterXmlToolsFromText(text) {
|
|
|
329
451
|
return null;
|
|
330
452
|
}
|
|
331
453
|
}
|
|
454
|
+
function applyInvokeParameterAliases(toolName, argsObj) {
|
|
455
|
+
try {
|
|
456
|
+
const lname = String(toolName || '').toLowerCase();
|
|
457
|
+
if (lname === 'write_stdin') {
|
|
458
|
+
// Some models emit `data` / `wait` instead of our canonical `chars` / `yield_time_ms`.
|
|
459
|
+
if (Object.prototype.hasOwnProperty.call(argsObj, 'data')) {
|
|
460
|
+
const data = argsObj.data;
|
|
461
|
+
if (!Object.prototype.hasOwnProperty.call(argsObj, 'chars') && !Object.prototype.hasOwnProperty.call(argsObj, 'text')) {
|
|
462
|
+
argsObj.chars = data == null ? '' : String(data);
|
|
463
|
+
}
|
|
464
|
+
delete argsObj.data;
|
|
465
|
+
}
|
|
466
|
+
if (Object.prototype.hasOwnProperty.call(argsObj, 'wait') && !Object.prototype.hasOwnProperty.call(argsObj, 'yield_time_ms')) {
|
|
467
|
+
const wait = argsObj.wait;
|
|
468
|
+
let ms;
|
|
469
|
+
if (typeof wait === 'number' && Number.isFinite(wait)) {
|
|
470
|
+
// Heuristic: small values are usually seconds; large values are likely already ms.
|
|
471
|
+
ms = wait <= 1000 ? Math.round(wait * 1000) : Math.round(wait);
|
|
472
|
+
}
|
|
473
|
+
else if (typeof wait === 'string' && wait.trim().length) {
|
|
474
|
+
const num = Number(wait.trim());
|
|
475
|
+
if (Number.isFinite(num)) {
|
|
476
|
+
ms = num <= 1000 ? Math.round(num * 1000) : Math.round(num);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
if (typeof ms === 'number' && Number.isFinite(ms) && ms >= 0) {
|
|
480
|
+
argsObj.yield_time_ms = ms;
|
|
481
|
+
}
|
|
482
|
+
delete argsObj.wait;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
catch {
|
|
487
|
+
// ignore
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
// Extract <function_calls><invoke name="..."><parameter name="...">...</parameter>...</invoke> blocks.
|
|
491
|
+
// Example seen in Gemini CLI / antigravity compact output:
|
|
492
|
+
// <function_calls>
|
|
493
|
+
// <invoke name="write_stdin">
|
|
494
|
+
// <parameter name="session_id">91806</parameter>
|
|
495
|
+
// <parameter name="data"></parameter>
|
|
496
|
+
// <parameter name="wait">10</parameter>
|
|
497
|
+
// </invoke>
|
|
498
|
+
// </function_calls>
|
|
499
|
+
export function extractInvokeToolsFromText(text) {
|
|
500
|
+
try {
|
|
501
|
+
if (typeof text !== 'string' || !text)
|
|
502
|
+
return null;
|
|
503
|
+
const out = [];
|
|
504
|
+
const invokeRe = /<\s*invoke\s+name\s*=\s*"([^">]+)"\s*>([\s\S]*?)<\/\s*invoke\s*>/gi;
|
|
505
|
+
let im;
|
|
506
|
+
while ((im = invokeRe.exec(text)) !== null) {
|
|
507
|
+
const rawName = (im[1] || '').trim();
|
|
508
|
+
const inner = (im[2] || '').trim();
|
|
509
|
+
if (!rawName || !inner)
|
|
510
|
+
continue;
|
|
511
|
+
const lname = rawName.toLowerCase();
|
|
512
|
+
const argsObj = {};
|
|
513
|
+
const paramRe = /<\s*parameter\s+name\s*=\s*"([^">]+)"\s*>([\s\S]*?)<\/\s*parameter\s*>/gi;
|
|
514
|
+
let pm;
|
|
515
|
+
while ((pm = paramRe.exec(inner)) !== null) {
|
|
516
|
+
const rawKey = (pm[1] || '').trim();
|
|
517
|
+
const key = normalizeKey(rawKey);
|
|
518
|
+
if (!key)
|
|
519
|
+
continue;
|
|
520
|
+
const rawVal = (pm[2] ?? '').toString();
|
|
521
|
+
const value = tryParsePrimitiveValue(rawVal);
|
|
522
|
+
if (lname === 'exec_command' && (key.toLowerCase() === 'command' || key.toLowerCase() === 'cmd')) {
|
|
523
|
+
const cmd = coerceCommandValueToString(value);
|
|
524
|
+
if (cmd.trim().length) {
|
|
525
|
+
argsObj.cmd = cmd;
|
|
526
|
+
argsObj.command = cmd;
|
|
527
|
+
}
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
argsObj[key] = value;
|
|
531
|
+
}
|
|
532
|
+
applyInvokeParameterAliases(lname, argsObj);
|
|
533
|
+
const filtered = filterArgsForTool(lname, argsObj);
|
|
534
|
+
let argsStr = '{}';
|
|
535
|
+
try {
|
|
536
|
+
argsStr = JSON.stringify(filtered);
|
|
537
|
+
}
|
|
538
|
+
catch {
|
|
539
|
+
argsStr = '{}';
|
|
540
|
+
}
|
|
541
|
+
out.push({ id: `call_${Math.random().toString(36).slice(2, 10)}`, name: lname, args: argsStr });
|
|
542
|
+
}
|
|
543
|
+
// Some Gemini CLI / antigravity variants emit a looser XML shape:
|
|
544
|
+
// <function_calls>
|
|
545
|
+
// <invoke>
|
|
546
|
+
// <tool_name>exec_command</tool_name>
|
|
547
|
+
// <parameters>
|
|
548
|
+
// <command>echo hi</command>
|
|
549
|
+
// </parameters>
|
|
550
|
+
// </invoke>
|
|
551
|
+
// </function_calls>
|
|
552
|
+
//
|
|
553
|
+
// Best-effort: only accept known tools, and only read simple <parameters><k>v</k></parameters>.
|
|
554
|
+
if (out.length === 0) {
|
|
555
|
+
const invokeBareRe = /<\s*invoke\s*>([\s\S]*?)<\/\s*invoke\s*>/gi;
|
|
556
|
+
let bm;
|
|
557
|
+
while ((bm = invokeBareRe.exec(text)) !== null) {
|
|
558
|
+
const inner = (bm[1] || '').trim();
|
|
559
|
+
if (!inner)
|
|
560
|
+
continue;
|
|
561
|
+
const toolNameMatch = /<\s*(?:tool_name|toolname|tool)\s*>\s*([\s\S]*?)\s*<\/\s*(?:tool_name|toolname|tool)\s*>/i.exec(inner);
|
|
562
|
+
const rawName = (toolNameMatch?.[1] || '').trim();
|
|
563
|
+
if (!rawName)
|
|
564
|
+
continue;
|
|
565
|
+
const lname = rawName.toLowerCase();
|
|
566
|
+
if (!KNOWN_TOOLS.has(lname))
|
|
567
|
+
continue;
|
|
568
|
+
const argsObj = {};
|
|
569
|
+
const paramsMatch = /<\s*parameters\s*>([\s\S]*?)<\/\s*parameters\s*>/i.exec(inner);
|
|
570
|
+
if (paramsMatch && paramsMatch[1]) {
|
|
571
|
+
const paramsInner = String(paramsMatch[1] || '');
|
|
572
|
+
const kvRe = /<\s*([A-Za-z_][A-Za-z0-9_]*)\s*>([\s\S]*?)<\/\s*\1\s*>/g;
|
|
573
|
+
let km;
|
|
574
|
+
while ((km = kvRe.exec(paramsInner)) !== null) {
|
|
575
|
+
const rawKey = (km[1] || '').trim();
|
|
576
|
+
const key = normalizeKey(rawKey);
|
|
577
|
+
if (!key)
|
|
578
|
+
continue;
|
|
579
|
+
const rawVal = (km[2] ?? '').toString();
|
|
580
|
+
const value = tryParsePrimitiveValue(rawVal);
|
|
581
|
+
if (lname === 'exec_command' && (key.toLowerCase() === 'command' || key.toLowerCase() === 'cmd')) {
|
|
582
|
+
const cmd = coerceCommandValueToString(value);
|
|
583
|
+
if (cmd.trim().length) {
|
|
584
|
+
argsObj.cmd = cmd;
|
|
585
|
+
argsObj.command = cmd;
|
|
586
|
+
}
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
589
|
+
argsObj[key] = value;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
applyInvokeParameterAliases(lname, argsObj);
|
|
593
|
+
const filtered = filterArgsForTool(lname, argsObj);
|
|
594
|
+
let argsStr = '{}';
|
|
595
|
+
try {
|
|
596
|
+
argsStr = JSON.stringify(filtered);
|
|
597
|
+
}
|
|
598
|
+
catch {
|
|
599
|
+
argsStr = '{}';
|
|
600
|
+
}
|
|
601
|
+
out.push({ id: `call_${Math.random().toString(36).slice(2, 10)}`, name: lname, args: argsStr });
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return out.length ? out : null;
|
|
605
|
+
}
|
|
606
|
+
catch {
|
|
607
|
+
return null;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
332
610
|
function tryParseJsonArrayOnLine(line) {
|
|
333
611
|
try {
|
|
334
612
|
const trimmed = String(line || '').trim();
|
|
@@ -477,14 +755,14 @@ export function extractXMLToolCallsFromText(text) {
|
|
|
477
755
|
continue;
|
|
478
756
|
// 1) try function/name tags
|
|
479
757
|
let name = '';
|
|
480
|
-
const fnTag = inner.match(/<\s*(?:function|name)\s*>\s*([a-zA-Z0-9_
|
|
758
|
+
const fnTag = inner.match(/<\s*(?:function|name)\s*>\s*([a-zA-Z0-9_.-]+)\s*<\/(?:function|name)\s*>/i);
|
|
481
759
|
if (fnTag && fnTag[1]) {
|
|
482
760
|
name = String(fnTag[1]).trim();
|
|
483
761
|
}
|
|
484
762
|
else {
|
|
485
763
|
// 2) else pick the first non-empty line without tags as the name
|
|
486
764
|
const lines = inner.split(/\r?\n/).map(s => s.trim()).filter(Boolean);
|
|
487
|
-
const candidate = lines.find(l => !l.startsWith('<') && /^[a-zA-Z0-9_
|
|
765
|
+
const candidate = lines.find(l => !l.startsWith('<') && /^[a-zA-Z0-9_.-]+$/.test(l));
|
|
488
766
|
if (candidate)
|
|
489
767
|
name = candidate;
|
|
490
768
|
}
|
|
@@ -562,7 +840,7 @@ export function extractXMLToolCallsFromText(text) {
|
|
|
562
840
|
const before = text.slice(0, start);
|
|
563
841
|
const lines = before.split(/\r?\n/).map(s => s.trim()).filter(Boolean);
|
|
564
842
|
const cand = lines.length ? lines[lines.length - 1] : '';
|
|
565
|
-
if (/^[a-zA-Z0-9_
|
|
843
|
+
if (/^[a-zA-Z0-9_.-]{2,}$/.test(cand))
|
|
566
844
|
name = cand;
|
|
567
845
|
}
|
|
568
846
|
catch { /* ignore */ }
|
|
@@ -727,7 +1005,9 @@ export function normalizeAssistantTextToToolCalls(message) {
|
|
|
727
1005
|
for (const text of candidates) {
|
|
728
1006
|
// Order: xml-like <tool_call> → apply_patch → execute blocks → 简单 XML 工具(list_directory 等) → bare command salvage
|
|
729
1007
|
calls =
|
|
730
|
-
|
|
1008
|
+
extractToolNamespaceXmlBlocksFromText(text) ||
|
|
1009
|
+
extractParameterXmlToolsFromText(text) ||
|
|
1010
|
+
extractInvokeToolsFromText(text) ||
|
|
731
1011
|
extractXMLToolCallsFromText(text) ||
|
|
732
1012
|
extractApplyPatchCallsFromText(text) ||
|
|
733
1013
|
extractExecuteBlocksFromText(text) ||
|
|
@@ -14,8 +14,9 @@ export function canonicalizeChatResponseTools(payload) {
|
|
|
14
14
|
continue;
|
|
15
15
|
// ensure arguments is string and content is null when tool_calls present
|
|
16
16
|
try {
|
|
17
|
-
if (
|
|
17
|
+
if (String(ch.finish_reason || '').toLowerCase() !== 'tool_calls') {
|
|
18
18
|
ch.finish_reason = 'tool_calls';
|
|
19
|
+
}
|
|
19
20
|
}
|
|
20
21
|
catch { /* ignore */ }
|
|
21
22
|
try {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Unified tool governance API (标准)
|
|
2
|
-
// Centralizes tool augmentation, guidance injection/refinement, and
|
|
2
|
+
// Centralizes tool augmentation, guidance injection/refinement, and structured tool_calls canonicalization
|
|
3
3
|
// canonicalizer 按需加载(避免在请求侧仅注入时引入不必要的模块)
|
|
4
4
|
// enforceChatBudget: 为避免在请求侧引入多余依赖,这里提供最小实现(保留形状,不裁剪)。
|
|
5
5
|
import { augmentOpenAITools } from '../../guidance/index.js';
|
|
@@ -45,7 +45,7 @@ function tryWriteSnapshot(options, stage, data) {
|
|
|
45
45
|
* Process OpenAI Chat request (messages/tools) with unified 标准 governance.
|
|
46
46
|
* - Augment tools (strict schemas)
|
|
47
47
|
* - Inject/Refine system tool guidance (idempotent)
|
|
48
|
-
* - Canonicalize
|
|
48
|
+
* - Canonicalize structured tool_calls; set content=null when applicable
|
|
49
49
|
*/
|
|
50
50
|
const IMAGE_EXT_RE = /\.(png|jpe?g|gif|webp|bmp|svg)(?:[?#].*)?$/i;
|
|
51
51
|
function hasImageReference(messages) {
|
|
@@ -223,7 +223,7 @@ export function processChatRequestTools(request, opts) {
|
|
|
223
223
|
}
|
|
224
224
|
/**
|
|
225
225
|
* Process OpenAI Chat response (choices[0].message) with unified 标准 governance.
|
|
226
|
-
* - Canonicalize
|
|
226
|
+
* - Canonicalize structured tool_calls; ensure finish_reason and content=null policy
|
|
227
227
|
*/
|
|
228
228
|
import { repairArgumentsToString, parseLenient } from './jsonish.js';
|
|
229
229
|
export function normalizeApplyPatchToolCallsOnResponse(chat) {
|
package/dist/filters/engine.js
CHANGED
|
@@ -13,7 +13,7 @@ export class FilterEngine {
|
|
|
13
13
|
try {
|
|
14
14
|
await writeFilterSnapshot({ requestId: ctx.requestId, endpoint: ctx.endpoint, profile: ctx.profile, stage, tag: 'begin', data: out });
|
|
15
15
|
}
|
|
16
|
-
catch { }
|
|
16
|
+
catch { /* ignore */ }
|
|
17
17
|
// stage pre filters
|
|
18
18
|
for (const f of this.filters) {
|
|
19
19
|
if (f.stage !== stage)
|
|
@@ -25,7 +25,7 @@ export class FilterEngine {
|
|
|
25
25
|
try {
|
|
26
26
|
await writeFilterSnapshot({ requestId: ctx.requestId, endpoint: ctx.endpoint, profile: ctx.profile, stage, name: f.name, tag: 'after', data: out });
|
|
27
27
|
}
|
|
28
|
-
catch { }
|
|
28
|
+
catch { /* ignore */ }
|
|
29
29
|
}
|
|
30
30
|
// field map in map stages
|
|
31
31
|
if (stage === 'request_map' || stage === 'response_map') {
|
|
@@ -33,17 +33,17 @@ export class FilterEngine {
|
|
|
33
33
|
try {
|
|
34
34
|
await writeFilterSnapshot({ requestId: ctx.requestId, endpoint: ctx.endpoint, profile: ctx.profile, stage, tag: 'map_before', data: out });
|
|
35
35
|
}
|
|
36
|
-
catch { }
|
|
36
|
+
catch { /* ignore */ }
|
|
37
37
|
out = this.applyFieldMap(out, rules);
|
|
38
38
|
try {
|
|
39
39
|
await writeFilterSnapshot({ requestId: ctx.requestId, endpoint: ctx.endpoint, profile: ctx.profile, stage, tag: 'map_after', data: out });
|
|
40
40
|
}
|
|
41
|
-
catch { }
|
|
41
|
+
catch { /* ignore */ }
|
|
42
42
|
}
|
|
43
43
|
try {
|
|
44
44
|
await writeFilterSnapshot({ requestId: ctx.requestId, endpoint: ctx.endpoint, profile: ctx.profile, stage, tag: 'end', data: out });
|
|
45
45
|
}
|
|
46
|
-
catch { }
|
|
46
|
+
catch { /* ignore */ }
|
|
47
47
|
return out;
|
|
48
48
|
}
|
|
49
49
|
applyFieldMap(input, rules) {
|