@jsonstudio/llms 0.6.473 → 0.6.567
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/compat/actions/claude-thinking-tools.d.ts +15 -0
- package/dist/conversion/compat/actions/claude-thinking-tools.js +72 -0
- package/dist/conversion/compat/profiles/chat-gemini.json +15 -14
- package/dist/conversion/compat/profiles/chat-glm.json +194 -194
- package/dist/conversion/compat/profiles/chat-iflow.json +199 -199
- package/dist/conversion/compat/profiles/chat-lmstudio.json +43 -43
- package/dist/conversion/compat/profiles/chat-qwen.json +20 -20
- package/dist/conversion/compat/profiles/responses-c4m.json +42 -42
- package/dist/conversion/compat/profiles/responses-output2choices-test.json +12 -0
- package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +6 -0
- package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +2 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +15 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +15 -0
- package/dist/conversion/hub/process/chat-process.js +44 -17
- package/dist/conversion/hub/semantic-mappers/anthropic-mapper.js +8 -0
- package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +13 -8
- package/dist/conversion/hub/tool-session-compat.d.ts +26 -0
- package/dist/conversion/hub/tool-session-compat.js +299 -0
- package/dist/conversion/responses/responses-openai-bridge.d.ts +0 -1
- package/dist/conversion/responses/responses-openai-bridge.js +0 -71
- package/dist/conversion/shared/gemini-tool-utils.js +8 -0
- package/dist/conversion/shared/responses-output-builder.js +6 -68
- package/dist/conversion/shared/tool-governor.js +75 -4
- package/dist/conversion/shared/tool-mapping.js +14 -8
- package/dist/filters/special/request-toolcalls-stringify.js +5 -55
- package/dist/filters/special/request-tools-normalize.js +0 -19
- package/dist/guidance/index.js +25 -9
- package/dist/router/virtual-router/engine-health.d.ts +11 -0
- package/dist/router/virtual-router/engine-health.js +210 -0
- package/dist/router/virtual-router/engine-logging.d.ts +19 -0
- package/dist/router/virtual-router/engine-logging.js +165 -0
- package/dist/router/virtual-router/engine-selection.d.ts +32 -0
- package/dist/router/virtual-router/engine-selection.js +649 -0
- package/dist/router/virtual-router/engine.d.ts +4 -13
- package/dist/router/virtual-router/engine.js +64 -535
- package/dist/router/virtual-router/message-utils.js +22 -0
- package/dist/router/virtual-router/routing-instructions.d.ts +6 -1
- package/dist/router/virtual-router/routing-instructions.js +119 -3
- package/dist/servertool/handlers/gemini-empty-reply-continue.d.ts +1 -0
- package/dist/servertool/handlers/gemini-empty-reply-continue.js +120 -0
- package/dist/servertool/handlers/stop-message-auto.d.ts +1 -0
- package/dist/servertool/handlers/stop-message-auto.js +147 -0
- package/dist/servertool/handlers/vision.js +105 -7
- package/dist/servertool/server-side-tools.d.ts +2 -0
- package/dist/servertool/server-side-tools.js +2 -0
- package/dist/tools/tool-registry.js +195 -4
- package/package.json +1 -1
|
@@ -43,6 +43,164 @@ const toJson = (value) => {
|
|
|
43
43
|
return '{}';
|
|
44
44
|
}
|
|
45
45
|
};
|
|
46
|
+
const APPLY_PATCH_SECTION_RE = /^\*\*\*\s+(Add|Update|Delete|Copy|Move)\s+File:\s*(.+)$/;
|
|
47
|
+
const sanitizeRelativePath = (value) => {
|
|
48
|
+
if (!value)
|
|
49
|
+
return null;
|
|
50
|
+
const trimmed = value.trim().replace(/\\/g, '/');
|
|
51
|
+
if (!trimmed)
|
|
52
|
+
return null;
|
|
53
|
+
if (trimmed.startsWith('/'))
|
|
54
|
+
return null;
|
|
55
|
+
if (/^[a-zA-Z]:/.test(trimmed))
|
|
56
|
+
return null;
|
|
57
|
+
if (trimmed.includes('\0'))
|
|
58
|
+
return null;
|
|
59
|
+
if (trimmed.includes('..')) {
|
|
60
|
+
const segments = trimmed.split('/');
|
|
61
|
+
if (segments.some((seg) => seg === '..')) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return trimmed.replace(/\/{2,}/g, '/');
|
|
66
|
+
};
|
|
67
|
+
const collectExplicitPaths = (record) => {
|
|
68
|
+
const bucket = [];
|
|
69
|
+
const invalid = [];
|
|
70
|
+
const pushPath = (candidate) => {
|
|
71
|
+
const str = asString(candidate);
|
|
72
|
+
const normalized = sanitizeRelativePath(str);
|
|
73
|
+
if (normalized)
|
|
74
|
+
bucket.push(normalized);
|
|
75
|
+
else if (typeof candidate === 'string')
|
|
76
|
+
invalid.push(candidate);
|
|
77
|
+
};
|
|
78
|
+
const entries = [
|
|
79
|
+
record.paths,
|
|
80
|
+
record.path,
|
|
81
|
+
record.files,
|
|
82
|
+
record.file,
|
|
83
|
+
record.targets,
|
|
84
|
+
record.target_path
|
|
85
|
+
];
|
|
86
|
+
for (const entry of entries) {
|
|
87
|
+
if (!entry)
|
|
88
|
+
continue;
|
|
89
|
+
if (typeof entry === 'string') {
|
|
90
|
+
pushPath(entry);
|
|
91
|
+
}
|
|
92
|
+
else if (Array.isArray(entry)) {
|
|
93
|
+
entry.forEach((item) => {
|
|
94
|
+
if (typeof item === 'string')
|
|
95
|
+
pushPath(item);
|
|
96
|
+
else if (isRecord(item))
|
|
97
|
+
pushPath(item.path);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
else if (isRecord(entry)) {
|
|
101
|
+
pushPath(entry.path ?? entry.value);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return { paths: bucket, invalid };
|
|
105
|
+
};
|
|
106
|
+
const looksLikePatchBody = (text) => {
|
|
107
|
+
const trimmed = text.trim();
|
|
108
|
+
if (!trimmed)
|
|
109
|
+
return false;
|
|
110
|
+
const hunkRe = /^@@/m;
|
|
111
|
+
const diffLineRe = /^[ +-]/m;
|
|
112
|
+
return hunkRe.test(trimmed) || diffLineRe.test(trimmed);
|
|
113
|
+
};
|
|
114
|
+
const applyPathOverrides = (lines, overridePaths) => {
|
|
115
|
+
if (!overridePaths.length)
|
|
116
|
+
return;
|
|
117
|
+
const sections = [];
|
|
118
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
119
|
+
const match = lines[i].match(APPLY_PATCH_SECTION_RE);
|
|
120
|
+
if (match) {
|
|
121
|
+
sections.push({ index: i, action: match[1] });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (!sections.length) {
|
|
125
|
+
const beginIdx = lines.findIndex((line) => line.trim() === '*** Begin Patch');
|
|
126
|
+
if (beginIdx >= 0) {
|
|
127
|
+
lines.splice(beginIdx + 1, 0, `*** Update File: ${overridePaths[0]}`);
|
|
128
|
+
}
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const limit = Math.min(sections.length, overridePaths.length);
|
|
132
|
+
for (let i = 0; i < limit; i += 1) {
|
|
133
|
+
lines[sections[i].index] = `*** ${sections[i].action} File: ${overridePaths[i]}`;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
const normalizeApplyPatchInput = (rawPatch, options) => {
|
|
137
|
+
if (typeof rawPatch !== 'string') {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
const text = rawPatch.replace(/\r\n/g, '\n');
|
|
141
|
+
const beginIdx = text.toLowerCase().indexOf('*** begin patch');
|
|
142
|
+
const endIdx = text.toLowerCase().lastIndexOf('*** end patch');
|
|
143
|
+
let candidate = '';
|
|
144
|
+
if (beginIdx >= 0 && endIdx >= 0 && endIdx > beginIdx) {
|
|
145
|
+
candidate = text.slice(beginIdx, endIdx + '*** End Patch'.length);
|
|
146
|
+
}
|
|
147
|
+
else if (options?.overridePaths && options.overridePaths.length) {
|
|
148
|
+
if (!looksLikePatchBody(text)) {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
const headerPath = options.overridePaths[0];
|
|
152
|
+
candidate = ['*** Begin Patch', `*** Update File: ${headerPath}`, text.trim(), '*** End Patch'].join('\n');
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
const lines = candidate.split(/\r?\n/);
|
|
158
|
+
if (!lines.length) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
let firstIdx = 0;
|
|
162
|
+
while (firstIdx < lines.length && lines[firstIdx].trim().length === 0) {
|
|
163
|
+
firstIdx += 1;
|
|
164
|
+
}
|
|
165
|
+
if (firstIdx >= lines.length) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
const firstLineRaw = lines[firstIdx];
|
|
169
|
+
const firstLineTrimmed = firstLineRaw.trim();
|
|
170
|
+
if (!firstLineTrimmed.toLowerCase().startsWith('*** begin patch')) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
if (firstLineTrimmed !== '*** Begin Patch') {
|
|
174
|
+
lines[firstIdx] = '*** Begin Patch';
|
|
175
|
+
}
|
|
176
|
+
let lastIdx = lines.length - 1;
|
|
177
|
+
while (lastIdx > firstIdx && lines[lastIdx].trim().length === 0) {
|
|
178
|
+
lastIdx -= 1;
|
|
179
|
+
}
|
|
180
|
+
if (lastIdx > firstIdx) {
|
|
181
|
+
const lastLineTrimmed = lines[lastIdx].trim();
|
|
182
|
+
if (lastLineTrimmed.toLowerCase().startsWith('*** end patch') && lastLineTrimmed !== '*** End Patch') {
|
|
183
|
+
lines[lastIdx] = '*** End Patch';
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (options?.overridePaths && options.overridePaths.length) {
|
|
187
|
+
applyPathOverrides(lines, options.overridePaths);
|
|
188
|
+
}
|
|
189
|
+
const normalized = lines.join('\n');
|
|
190
|
+
if (!normalized.includes('*** Begin Patch') || !normalized.includes('*** End Patch')) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
return normalized;
|
|
194
|
+
};
|
|
195
|
+
const logApplyPatchValidatorError = (message) => {
|
|
196
|
+
try {
|
|
197
|
+
// eslint-disable-next-line no-console
|
|
198
|
+
console.error(`\x1b[31m[apply_patch][validator] ${message}\x1b[0m`);
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
/* ignore */
|
|
202
|
+
}
|
|
203
|
+
};
|
|
46
204
|
const detectForbiddenWrite = (script) => {
|
|
47
205
|
const normalized = script.toLowerCase();
|
|
48
206
|
if (!normalized) {
|
|
@@ -95,12 +253,45 @@ export function validateToolCall(name, argsString) {
|
|
|
95
253
|
const rawArgs = tryParseJson(typeof argsString === 'string' ? argsString : '{}');
|
|
96
254
|
switch (normalizedName) {
|
|
97
255
|
case 'apply_patch': {
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
|
|
256
|
+
const record = rawArgs;
|
|
257
|
+
const inputField = asString(record.input);
|
|
258
|
+
const patchField = asString(record.patch);
|
|
259
|
+
const rawStr = typeof argsString === 'string' ? argsString : '';
|
|
260
|
+
let patchRaw = null;
|
|
261
|
+
if (patchField) {
|
|
262
|
+
patchRaw = patchField;
|
|
263
|
+
}
|
|
264
|
+
else if (inputField) {
|
|
265
|
+
patchRaw = inputField;
|
|
266
|
+
}
|
|
267
|
+
else if (rawStr && /\*\*\*\s+Begin Patch/i.test(rawStr)) {
|
|
268
|
+
patchRaw = rawStr;
|
|
269
|
+
}
|
|
270
|
+
if (!patchRaw) {
|
|
271
|
+
logApplyPatchValidatorError('missing apply_patch patch/input payload');
|
|
101
272
|
return { ok: false, reason: 'missing_input' };
|
|
102
273
|
}
|
|
103
|
-
|
|
274
|
+
const { paths: explicitPaths, invalid } = collectExplicitPaths(record);
|
|
275
|
+
if (invalid.length) {
|
|
276
|
+
invalid.forEach((value) => logApplyPatchValidatorError(`invalid path argument: ${value}`));
|
|
277
|
+
}
|
|
278
|
+
const normalizedPatch = normalizeApplyPatchInput(patchRaw, { overridePaths: explicitPaths });
|
|
279
|
+
if (!normalizedPatch) {
|
|
280
|
+
logApplyPatchValidatorError('patch text missing *** Begin Patch/*** End Patch or failed to auto-wrap with provided paths');
|
|
281
|
+
return { ok: false, reason: 'invalid_patch_header' };
|
|
282
|
+
}
|
|
283
|
+
// Canonical, parameterized shape; keep input for backwards compatibility.
|
|
284
|
+
const payload = {
|
|
285
|
+
patch: normalizedPatch,
|
|
286
|
+
input: normalizedPatch
|
|
287
|
+
};
|
|
288
|
+
if (explicitPaths.length) {
|
|
289
|
+
payload.paths = explicitPaths;
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
ok: true,
|
|
293
|
+
normalizedArgs: toJson(payload)
|
|
294
|
+
};
|
|
104
295
|
}
|
|
105
296
|
case 'shell': {
|
|
106
297
|
const rawCommand = rawArgs.command;
|