@jsonstudio/llms 0.6.567 → 0.6.586

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.
Files changed (62) hide show
  1. package/dist/conversion/codecs/gemini-openai-codec.js +33 -4
  2. package/dist/conversion/codecs/openai-openai-codec.js +2 -1
  3. package/dist/conversion/codecs/responses-openai-codec.js +3 -2
  4. package/dist/conversion/compat/actions/glm-history-image-trim.d.ts +2 -0
  5. package/dist/conversion/compat/actions/glm-history-image-trim.js +88 -0
  6. package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +6 -2
  7. package/dist/conversion/hub/pipeline/hub-pipeline.js +72 -81
  8. package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +0 -34
  9. package/dist/conversion/hub/process/chat-process.js +68 -24
  10. package/dist/conversion/hub/response/provider-response.js +0 -8
  11. package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +22 -3
  12. package/dist/conversion/hub/semantic-mappers/responses-mapper.js +267 -14
  13. package/dist/conversion/hub/types/chat-envelope.d.ts +1 -0
  14. package/dist/conversion/responses/responses-openai-bridge.d.ts +3 -2
  15. package/dist/conversion/responses/responses-openai-bridge.js +1 -13
  16. package/dist/conversion/shared/anthropic-message-utils.js +54 -0
  17. package/dist/conversion/shared/args-mapping.js +11 -3
  18. package/dist/conversion/shared/responses-output-builder.js +42 -21
  19. package/dist/conversion/shared/streaming-text-extractor.d.ts +25 -0
  20. package/dist/conversion/shared/streaming-text-extractor.js +31 -38
  21. package/dist/conversion/shared/text-markup-normalizer.d.ts +20 -0
  22. package/dist/conversion/shared/text-markup-normalizer.js +118 -31
  23. package/dist/conversion/shared/tool-filter-pipeline.js +56 -30
  24. package/dist/conversion/shared/tool-harvester.js +43 -12
  25. package/dist/conversion/shared/tool-mapping.d.ts +1 -0
  26. package/dist/conversion/shared/tool-mapping.js +33 -19
  27. package/dist/filters/index.d.ts +1 -0
  28. package/dist/filters/index.js +1 -0
  29. package/dist/filters/special/request-tools-normalize.js +14 -4
  30. package/dist/filters/special/response-apply-patch-toon-decode.d.ts +23 -0
  31. package/dist/filters/special/response-apply-patch-toon-decode.js +117 -0
  32. package/dist/filters/special/response-tool-arguments-toon-decode.d.ts +10 -0
  33. package/dist/filters/special/response-tool-arguments-toon-decode.js +154 -26
  34. package/dist/guidance/index.js +71 -42
  35. package/dist/router/virtual-router/bootstrap.js +10 -5
  36. package/dist/router/virtual-router/classifier.js +16 -7
  37. package/dist/router/virtual-router/engine-health.d.ts +11 -0
  38. package/dist/router/virtual-router/engine-health.js +217 -4
  39. package/dist/router/virtual-router/engine-logging.d.ts +2 -1
  40. package/dist/router/virtual-router/engine-logging.js +35 -3
  41. package/dist/router/virtual-router/engine.d.ts +17 -1
  42. package/dist/router/virtual-router/engine.js +184 -6
  43. package/dist/router/virtual-router/routing-instructions.d.ts +2 -0
  44. package/dist/router/virtual-router/routing-instructions.js +19 -1
  45. package/dist/router/virtual-router/tool-signals.d.ts +2 -1
  46. package/dist/router/virtual-router/tool-signals.js +324 -119
  47. package/dist/router/virtual-router/types.d.ts +31 -1
  48. package/dist/router/virtual-router/types.js +2 -2
  49. package/dist/servertool/engine.js +3 -0
  50. package/dist/servertool/handlers/iflow-model-error-retry.d.ts +1 -0
  51. package/dist/servertool/handlers/iflow-model-error-retry.js +93 -0
  52. package/dist/servertool/handlers/stop-message-auto.js +61 -4
  53. package/dist/servertool/server-side-tools.d.ts +1 -0
  54. package/dist/servertool/server-side-tools.js +27 -0
  55. package/dist/sse/json-to-sse/event-generators/responses.js +9 -2
  56. package/dist/sse/sse-to-json/builders/anthropic-response-builder.js +23 -3
  57. package/dist/tools/apply-patch-structured.d.ts +20 -0
  58. package/dist/tools/apply-patch-structured.js +240 -0
  59. package/dist/tools/tool-description-utils.d.ts +5 -0
  60. package/dist/tools/tool-description-utils.js +50 -0
  61. package/dist/tools/tool-registry.js +11 -193
  62. package/package.json +1 -1
@@ -1,4 +1,5 @@
1
1
  // Tool registry and validator (single source of truth)
2
+ import { buildStructuredPatch, isStructuredApplyPatchPayload, StructuredApplyPatchError } from './apply-patch-structured.js';
2
3
  const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
3
4
  const asString = (value) => {
4
5
  if (typeof value === 'string' && value.trim().length > 0) {
@@ -43,164 +44,6 @@ const toJson = (value) => {
43
44
  return '{}';
44
45
  }
45
46
  };
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
- };
204
47
  const detectForbiddenWrite = (script) => {
205
48
  const normalized = script.toLowerCase();
206
49
  if (!normalized) {
@@ -254,44 +97,19 @@ export function validateToolCall(name, argsString) {
254
97
  switch (normalizedName) {
255
98
  case 'apply_patch': {
256
99
  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;
100
+ if (!isStructuredApplyPatchPayload(record)) {
101
+ return { ok: false, reason: 'missing_changes' };
269
102
  }
270
- if (!patchRaw) {
271
- logApplyPatchValidatorError('missing apply_patch patch/input payload');
272
- return { ok: false, reason: 'missing_input' };
103
+ try {
104
+ const patchText = buildStructuredPatch(record);
105
+ return { ok: true, normalizedArgs: toJson({ patch: patchText, input: patchText }) };
273
106
  }
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;
107
+ catch (error) {
108
+ if (error instanceof StructuredApplyPatchError) {
109
+ return { ok: false, reason: error.reason || 'invalid_patch_payload' };
110
+ }
111
+ return { ok: false, reason: 'invalid_patch_payload' };
290
112
  }
291
- return {
292
- ok: true,
293
- normalizedArgs: toJson(payload)
294
- };
295
113
  }
296
114
  case 'shell': {
297
115
  const rawCommand = rawArgs.command;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsonstudio/llms",
3
- "version": "0.6.567",
3
+ "version": "0.6.586",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",