@jsonstudio/llms 0.6.1462 → 0.6.1733

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 (148) hide show
  1. package/dist/conversion/codecs/gemini-openai-codec.js +6 -1
  2. package/dist/conversion/compat/actions/anthropic-claude-code-system-prompt.d.ts +4 -7
  3. package/dist/conversion/compat/actions/anthropic-claude-code-system-prompt.js +140 -21
  4. package/dist/conversion/compat/actions/antigravity-thought-signature-cache.js +68 -10
  5. package/dist/conversion/compat/actions/antigravity-thought-signature-prepare.js +151 -23
  6. package/dist/conversion/compat/actions/gemini-cli-request.js +72 -13
  7. package/dist/conversion/compat/actions/harvest-tool-calls-from-text.d.ts +10 -0
  8. package/dist/conversion/compat/actions/harvest-tool-calls-from-text.js +121 -0
  9. package/dist/conversion/compat/actions/iflow-kimi-cli-defaults.d.ts +10 -0
  10. package/dist/conversion/compat/actions/iflow-kimi-cli-defaults.js +80 -0
  11. package/dist/conversion/compat/actions/iflow-kimi-history-media-placeholder.d.ts +7 -0
  12. package/dist/conversion/compat/actions/iflow-kimi-history-media-placeholder.js +161 -0
  13. package/dist/conversion/compat/actions/iflow-kimi-thinking-reasoning-fill.d.ts +12 -0
  14. package/dist/conversion/compat/actions/iflow-kimi-thinking-reasoning-fill.js +67 -0
  15. package/dist/conversion/compat/actions/iflow-response-body-unwrap.d.ts +9 -0
  16. package/dist/conversion/compat/actions/iflow-response-body-unwrap.js +140 -0
  17. package/dist/conversion/compat/actions/lmstudio-responses-fc-ids.d.ts +10 -0
  18. package/dist/conversion/compat/actions/lmstudio-responses-fc-ids.js +59 -0
  19. package/dist/conversion/compat/actions/lmstudio-responses-input-stringify.d.ts +14 -0
  20. package/dist/conversion/compat/actions/lmstudio-responses-input-stringify.js +125 -0
  21. package/dist/conversion/compat/actions/normalize-tool-call-ids.d.ts +11 -0
  22. package/dist/conversion/compat/actions/normalize-tool-call-ids.js +140 -0
  23. package/dist/conversion/compat/actions/strip-orphan-function-calls-tag.d.ts +2 -0
  24. package/dist/conversion/compat/actions/strip-orphan-function-calls-tag.js +152 -0
  25. package/dist/conversion/compat/antigravity-session-signature.d.ts +57 -3
  26. package/dist/conversion/compat/antigravity-session-signature.js +821 -27
  27. package/dist/conversion/compat/profiles/anthropic-claude-code.json +0 -9
  28. package/dist/conversion/compat/profiles/chat-gemini-cli.json +1 -0
  29. package/dist/conversion/compat/profiles/chat-iflow.json +6 -0
  30. package/dist/conversion/compat/profiles/chat-lmstudio.json +7 -1
  31. package/dist/conversion/hub/operation-table/operation-table-runner.js +1 -1
  32. package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +52 -10
  33. package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +102 -6
  34. package/dist/conversion/hub/pipeline/compat/compat-profile-resolver.d.ts +2 -0
  35. package/dist/conversion/hub/pipeline/compat/compat-profile-resolver.js +63 -0
  36. package/dist/conversion/hub/pipeline/compat/compat-profile-store.js +12 -3
  37. package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +18 -0
  38. package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +1 -0
  39. package/dist/conversion/hub/pipeline/hub-pipeline.js +25 -1
  40. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +20 -0
  41. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.js +8 -5
  42. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage3_compat/index.js +5 -1
  43. package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js +113 -0
  44. package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +26 -1
  45. package/dist/conversion/hub/pipeline/target-utils.js +3 -0
  46. package/dist/conversion/hub/process/chat-process.js +300 -67
  47. package/dist/conversion/hub/response/provider-response.js +31 -4
  48. package/dist/conversion/responses/responses-openai-bridge.js +32 -6
  49. package/dist/conversion/shared/anthropic-message-utils.js +20 -5
  50. package/dist/conversion/shared/bridge-id-utils.d.ts +2 -0
  51. package/dist/conversion/shared/bridge-id-utils.js +52 -15
  52. package/dist/conversion/shared/gemini-tool-utils.js +134 -9
  53. package/dist/conversion/shared/responses-conversation-store.js +40 -5
  54. package/dist/conversion/shared/responses-output-builder.js +23 -7
  55. package/dist/conversion/shared/responses-tool-utils.d.ts +1 -0
  56. package/dist/conversion/shared/responses-tool-utils.js +30 -13
  57. package/dist/conversion/shared/text-markup-normalizer.d.ts +1 -0
  58. package/dist/conversion/shared/text-markup-normalizer.js +359 -2
  59. package/dist/conversion/shared/thought-signature-validator.d.ts +1 -1
  60. package/dist/conversion/shared/thought-signature-validator.js +2 -1
  61. package/dist/quota/apikey-reset.d.ts +17 -0
  62. package/dist/quota/apikey-reset.js +43 -0
  63. package/dist/quota/index.d.ts +2 -0
  64. package/dist/quota/index.js +1 -0
  65. package/dist/quota/quota-manager.d.ts +44 -0
  66. package/dist/quota/quota-manager.js +491 -0
  67. package/dist/quota/quota-state.d.ts +6 -0
  68. package/dist/quota/quota-state.js +167 -0
  69. package/dist/quota/types.d.ts +61 -0
  70. package/dist/quota/types.js +1 -0
  71. package/dist/router/virtual-router/bootstrap.js +134 -13
  72. package/dist/router/virtual-router/classifier.js +1 -1
  73. package/dist/router/virtual-router/engine/antigravity/alias-lease.d.ts +33 -0
  74. package/dist/router/virtual-router/engine/antigravity/alias-lease.js +247 -0
  75. package/dist/router/virtual-router/engine/health/index.d.ts +23 -0
  76. package/dist/router/virtual-router/engine/health/index.js +720 -0
  77. package/dist/router/virtual-router/engine/provider-key/parse.d.ts +6 -0
  78. package/dist/router/virtual-router/engine/provider-key/parse.js +43 -0
  79. package/dist/router/virtual-router/engine/routing-pools/index.d.ts +13 -0
  80. package/dist/router/virtual-router/engine/routing-pools/index.js +225 -0
  81. package/dist/router/virtual-router/engine/routing-state/keys.d.ts +3 -0
  82. package/dist/router/virtual-router/engine/routing-state/keys.js +30 -0
  83. package/dist/router/virtual-router/engine/routing-state/metadata.d.ts +6 -0
  84. package/dist/router/virtual-router/engine/routing-state/metadata.js +132 -0
  85. package/dist/router/virtual-router/engine/routing-state/store.d.ts +11 -0
  86. package/dist/router/virtual-router/engine/routing-state/store.js +107 -0
  87. package/dist/router/virtual-router/engine-health.d.ts +1 -23
  88. package/dist/router/virtual-router/engine-health.js +1 -616
  89. package/dist/router/virtual-router/engine-selection/route-utils.js +57 -0
  90. package/dist/router/virtual-router/engine-selection/selection-deps.d.ts +18 -0
  91. package/dist/router/virtual-router/engine-selection/tier-priority.d.ts +1 -2
  92. package/dist/router/virtual-router/engine-selection/tier-priority.js +2 -2
  93. package/dist/router/virtual-router/engine-selection/tier-selection-select.js +39 -55
  94. package/dist/router/virtual-router/engine-selection/tier-selection.js +284 -23
  95. package/dist/router/virtual-router/engine-selection.d.ts +1 -13
  96. package/dist/router/virtual-router/engine-selection.js +1 -225
  97. package/dist/router/virtual-router/engine.d.ts +8 -14
  98. package/dist/router/virtual-router/engine.js +187 -382
  99. package/dist/router/virtual-router/features.js +20 -2
  100. package/dist/router/virtual-router/message-utils.js +15 -5
  101. package/dist/router/virtual-router/success-center.d.ts +10 -0
  102. package/dist/router/virtual-router/success-center.js +32 -0
  103. package/dist/router/virtual-router/types.d.ts +48 -0
  104. package/dist/servertool/clock/config.d.ts +2 -0
  105. package/dist/servertool/clock/config.js +10 -2
  106. package/dist/servertool/clock/daemon.js +3 -0
  107. package/dist/servertool/clock/ntp.d.ts +18 -0
  108. package/dist/servertool/clock/ntp.js +318 -0
  109. package/dist/servertool/clock/paths.d.ts +1 -0
  110. package/dist/servertool/clock/paths.js +3 -0
  111. package/dist/servertool/clock/state.d.ts +2 -0
  112. package/dist/servertool/clock/state.js +15 -2
  113. package/dist/servertool/clock/tasks.d.ts +1 -0
  114. package/dist/servertool/clock/tasks.js +24 -1
  115. package/dist/servertool/clock/types.d.ts +21 -0
  116. package/dist/servertool/engine.js +109 -5
  117. package/dist/servertool/handlers/antigravity-thought-signature-bootstrap.d.ts +1 -0
  118. package/dist/servertool/handlers/antigravity-thought-signature-bootstrap.js +201 -0
  119. package/dist/servertool/handlers/clock-auto.js +39 -4
  120. package/dist/servertool/handlers/clock.js +145 -16
  121. package/dist/servertool/handlers/followup-request-builder.js +84 -0
  122. package/dist/servertool/handlers/gemini-empty-reply-continue.js +48 -47
  123. package/dist/servertool/handlers/stop-message-auto.js +3 -3
  124. package/dist/servertool/handlers/vision.js +10 -0
  125. package/dist/servertool/server-side-tools.d.ts +1 -0
  126. package/dist/servertool/server-side-tools.js +1 -0
  127. package/dist/servertool/types.d.ts +2 -0
  128. package/dist/sse/sse-to-json/builders/response-builder.js +6 -0
  129. package/dist/sse/sse-to-json/chat-sse-to-json-converter.js +32 -2
  130. package/dist/sse/sse-to-json/parsers/sse-parser.js +34 -0
  131. package/dist/sse/sse-to-json/responses-sse-to-json-converter.d.ts +1 -0
  132. package/dist/sse/sse-to-json/responses-sse-to-json-converter.js +33 -1
  133. package/dist/tools/apply-patch/args-normalizer/default-actions.d.ts +2 -0
  134. package/dist/tools/apply-patch/args-normalizer/default-actions.js +12 -0
  135. package/dist/tools/apply-patch/args-normalizer/extract-patch.d.ts +2 -0
  136. package/dist/tools/apply-patch/args-normalizer/extract-patch.js +15 -0
  137. package/dist/tools/apply-patch/args-normalizer/index.d.ts +2 -0
  138. package/dist/tools/apply-patch/args-normalizer/index.js +164 -0
  139. package/dist/tools/apply-patch/args-normalizer/structured-builders.d.ts +7 -0
  140. package/dist/tools/apply-patch/args-normalizer/structured-builders.js +85 -0
  141. package/dist/tools/apply-patch/args-normalizer/types.d.ts +54 -0
  142. package/dist/tools/apply-patch/args-normalizer/types.js +1 -0
  143. package/dist/tools/apply-patch/execution-capturer.js +24 -3
  144. package/dist/tools/apply-patch/patch-text/looks-like-patch.js +1 -0
  145. package/dist/tools/apply-patch/patch-text/normalize.js +104 -5
  146. package/dist/tools/apply-patch/structured/coercion.js +28 -4
  147. package/dist/tools/apply-patch/validator.js +7 -146
  148. package/package.json +3 -2
@@ -53,6 +53,77 @@ const convertUnifiedDiffToApplyPatchIfPossible = (text) => {
53
53
  return null;
54
54
  }
55
55
  };
56
+ const convertStarHeaderDiffToApplyPatchIfPossible = (text) => {
57
+ try {
58
+ if (!text || text.includes('*** Begin Patch') || text.includes('diff --git'))
59
+ return null;
60
+ const lines = text.replace(/\r\n/g, '\n').split('\n');
61
+ if (lines.length < 3)
62
+ return null;
63
+ const first = String(lines[0] ?? '').trim();
64
+ const second = String(lines[1] ?? '').trim();
65
+ if (!first.startsWith('*** ') || !second.startsWith('--- '))
66
+ return null;
67
+ if (first.startsWith('*** Add File:') || first.startsWith('*** Update File:') || first.startsWith('*** Delete File:')) {
68
+ return null;
69
+ }
70
+ if (!lines.some((line) => line.startsWith('@@')))
71
+ return null;
72
+ const normalizeHeaderPath = (value) => {
73
+ const v = String(value || '').trim().replace(/\s+\*\*\*$/g, '').trim();
74
+ if (!v)
75
+ return '';
76
+ const m = v.match(/^(?:a\/|b\/)?(.+)$/);
77
+ return (m && m[1] ? m[1] : v).trim();
78
+ };
79
+ const oldPath = normalizeHeaderPath(first.slice(4));
80
+ const newPath = normalizeHeaderPath(second.slice(4));
81
+ const body = lines.slice(2);
82
+ const out = ['*** Begin Patch'];
83
+ if (oldPath === '/dev/null' && newPath && newPath !== '/dev/null') {
84
+ out.push(`*** Add File: ${newPath}`);
85
+ for (const line of body) {
86
+ if (line.startsWith('+')) {
87
+ out.push(line);
88
+ }
89
+ }
90
+ out.push('*** End Patch');
91
+ return out.join('\n');
92
+ }
93
+ if (newPath === '/dev/null' && oldPath && oldPath !== '/dev/null') {
94
+ out.push(`*** Delete File: ${oldPath}`);
95
+ out.push('*** End Patch');
96
+ return out.join('\n');
97
+ }
98
+ const filePath = newPath || oldPath;
99
+ if (!filePath)
100
+ return null;
101
+ out.push(`*** Update File: ${filePath}`);
102
+ for (const line of body) {
103
+ out.push(line);
104
+ }
105
+ out.push('*** End Patch');
106
+ return out.join('\n');
107
+ }
108
+ catch {
109
+ return null;
110
+ }
111
+ };
112
+ const normalizeApplyPatchFileHeader = (line) => {
113
+ const addMatch = line.match(/^\*\*\* Add File:\s*(.+?)(?:\s+\*\*\*)?\s*$/);
114
+ if (addMatch && addMatch[1]) {
115
+ return `*** Add File: ${addMatch[1].trim()}`;
116
+ }
117
+ const updateMatch = line.match(/^\*\*\* Update File:\s*(.+?)(?:\s+\*\*\*)?\s*$/);
118
+ if (updateMatch && updateMatch[1]) {
119
+ return `*** Update File: ${updateMatch[1].trim()}`;
120
+ }
121
+ const deleteMatch = line.match(/^\*\*\* Delete File:\s*(.+?)(?:\s+\*\*\*)?\s*$/);
122
+ if (deleteMatch && deleteMatch[1]) {
123
+ return `*** Delete File: ${deleteMatch[1].trim()}`;
124
+ }
125
+ return line;
126
+ };
56
127
  const stripCodeFences = (text) => {
57
128
  const trimmed = text.trim();
58
129
  // Only treat the entire payload as fenced when it *starts* with a code fence.
@@ -152,7 +223,12 @@ export const normalizeApplyPatchText = (raw) => {
152
223
  if (converted)
153
224
  text = converted;
154
225
  }
155
- else if (!text.includes('*** Begin Patch') &&
226
+ else if (!text.includes('*** Begin Patch') && !text.includes('diff --git')) {
227
+ const converted = convertStarHeaderDiffToApplyPatchIfPossible(text);
228
+ if (converted)
229
+ text = converted;
230
+ }
231
+ if (!text.includes('*** Begin Patch') &&
156
232
  !text.includes('diff --git') &&
157
233
  text.includes('***************') &&
158
234
  /^\*\*\*\s+\S+/m.test(text) &&
@@ -172,9 +248,11 @@ export const normalizeApplyPatchText = (raw) => {
172
248
  if (converted)
173
249
  text = converted;
174
250
  }
175
- if (text.includes('*** Add File:')) {
176
- text = text.replace(/\*\*\* Create File:/g, '*** Add File:');
177
- }
251
+ text = text.replace(/\*\*\* Create File:/g, '*** Add File:');
252
+ text = text
253
+ .split('\n')
254
+ .map((line) => normalizeApplyPatchFileHeader(line))
255
+ .join('\n');
178
256
  let hasBegin = text.includes('*** Begin Patch');
179
257
  const hasEnd = text.includes('*** End Patch');
180
258
  if (hasBegin && !hasEnd) {
@@ -216,29 +294,41 @@ export const normalizeApplyPatchText = (raw) => {
216
294
  const lines = text.split('\n');
217
295
  const output = [];
218
296
  let inUpdateSection = false;
297
+ let inAddSection = false;
219
298
  let afterUpdateHeader = false;
220
299
  for (const line of lines) {
221
300
  if (line.startsWith('*** Begin Patch')) {
222
301
  output.push(line);
223
302
  inUpdateSection = false;
303
+ inAddSection = false;
224
304
  afterUpdateHeader = false;
225
305
  continue;
226
306
  }
227
307
  if (line.startsWith('*** End Patch')) {
228
308
  output.push(line);
229
309
  inUpdateSection = false;
310
+ inAddSection = false;
230
311
  afterUpdateHeader = false;
231
312
  continue;
232
313
  }
233
314
  if (line.startsWith('*** Update File:')) {
234
315
  output.push(line);
235
316
  inUpdateSection = true;
317
+ inAddSection = false;
236
318
  afterUpdateHeader = true;
237
319
  continue;
238
320
  }
239
- if (line.startsWith('*** Add File:') || line.startsWith('*** Delete File:')) {
321
+ if (line.startsWith('*** Add File:')) {
240
322
  output.push(line);
241
323
  inUpdateSection = false;
324
+ inAddSection = true;
325
+ afterUpdateHeader = false;
326
+ continue;
327
+ }
328
+ if (line.startsWith('*** Delete File:')) {
329
+ output.push(line);
330
+ inUpdateSection = false;
331
+ inAddSection = false;
242
332
  afterUpdateHeader = false;
243
333
  continue;
244
334
  }
@@ -255,6 +345,15 @@ export const normalizeApplyPatchText = (raw) => {
255
345
  }
256
346
  continue;
257
347
  }
348
+ if (inAddSection) {
349
+ if (line.startsWith('+')) {
350
+ output.push(line);
351
+ }
352
+ else {
353
+ output.push(`+${line}`);
354
+ }
355
+ continue;
356
+ }
258
357
  output.push(line);
259
358
  }
260
359
  return output.join('\n');
@@ -1,6 +1,22 @@
1
1
  import { isStructuredApplyPatchPayload } from '../structured.js';
2
2
  import { tryParseJson } from '../json/parse-loose.js';
3
3
  import { asString } from '../validation/shared.js';
4
+ const resolveTopLevelFile = (record) => {
5
+ const direct = asString(record.file) ??
6
+ asString(record.path) ??
7
+ asString(record.filepath) ??
8
+ asString(record.filename);
9
+ if (direct)
10
+ return direct;
11
+ const targetAlias = asString(record.target);
12
+ if (!targetAlias)
13
+ return undefined;
14
+ if (targetAlias.includes('\n') || targetAlias.includes('\r'))
15
+ return undefined;
16
+ if (!/[./\\]/.test(targetAlias))
17
+ return undefined;
18
+ return targetAlias;
19
+ };
4
20
  const buildSingleChangePayload = (record) => {
5
21
  const kindRaw = asString(record.kind);
6
22
  if (!kindRaw)
@@ -14,7 +30,11 @@ const buildSingleChangePayload = (record) => {
14
30
  if (typeof record.use_anchor_indent === 'boolean') {
15
31
  change.use_anchor_indent = record.use_anchor_indent;
16
32
  }
17
- const changeFile = asString(record.file);
33
+ const changeFile = asString(record.file) ??
34
+ asString(record.path) ??
35
+ asString(record.filepath) ??
36
+ asString(record.filename) ??
37
+ resolveTopLevelFile(record);
18
38
  if (changeFile) {
19
39
  change.file = changeFile;
20
40
  }
@@ -44,7 +64,11 @@ const coerceChangesArray = (value) => {
44
64
  return undefined;
45
65
  };
46
66
  export const coerceStructuredPayload = (record) => {
67
+ const topLevelFile = resolveTopLevelFile(record);
47
68
  if (isStructuredApplyPatchPayload(record)) {
69
+ if (topLevelFile && !asString(record.file)) {
70
+ return { ...record, file: topLevelFile };
71
+ }
48
72
  return record;
49
73
  }
50
74
  if (Array.isArray(record.changes) && record.changes.length === 0) {
@@ -55,7 +79,7 @@ export const coerceStructuredPayload = (record) => {
55
79
  const changesFromInstructions = coerceChangesArray(record.instructions);
56
80
  if (changesFromInstructions) {
57
81
  return {
58
- ...(typeof record.file === 'string' ? { file: record.file } : {}),
82
+ ...(topLevelFile ? { file: topLevelFile } : {}),
59
83
  changes: changesFromInstructions
60
84
  };
61
85
  }
@@ -63,14 +87,14 @@ export const coerceStructuredPayload = (record) => {
63
87
  const changesFromString = coerceChangesArray(record.changes);
64
88
  if (changesFromString) {
65
89
  return {
66
- ...(typeof record.file === 'string' ? { file: record.file } : {}),
90
+ ...(topLevelFile ? { file: topLevelFile } : {}),
67
91
  changes: changesFromString
68
92
  };
69
93
  }
70
94
  const editsFromString = coerceChangesArray(record.edits ?? record.operations ?? record.ops);
71
95
  if (editsFromString) {
72
96
  return {
73
- ...(typeof record.file === 'string' ? { file: record.file } : {}),
97
+ ...(topLevelFile ? { file: topLevelFile } : {}),
74
98
  changes: editsFromString
75
99
  };
76
100
  }
@@ -1,8 +1,5 @@
1
- import { buildStructuredPatch, StructuredApplyPatchError } from './structured.js';
2
- import { coerceStructuredPayload } from './structured/coercion.js';
3
- import { tryParseJsonLoose } from './json/parse-loose.js';
1
+ import { normalizeApplyPatchArgs } from './args-normalizer/index.js';
4
2
  import { normalizeApplyPatchText, looksLikePatch } from './patch-text/normalize.js';
5
- import { asString, isRecord } from './validation/shared.js';
6
3
  export { looksLikePatch, normalizeApplyPatchText };
7
4
  const toJson = (value) => {
8
5
  try {
@@ -13,148 +10,12 @@ const toJson = (value) => {
13
10
  }
14
11
  };
15
12
  export function validateApplyPatchArgs(argsString, rawArgs) {
16
- const rawTrimmed = typeof argsString === 'string' ? argsString.trim() : '';
17
- const looksJsonContainer = rawTrimmed.startsWith('{') || rawTrimmed.startsWith('[');
18
- // Raw patch text without JSON wrapper
19
- if (!looksJsonContainer && looksLikePatch(rawTrimmed)) {
20
- const patchText = normalizeApplyPatchText(rawTrimmed);
21
- if (!patchText.includes('*** Begin Patch')) {
22
- return { ok: false, reason: 'unsupported_patch_format' };
23
- }
24
- return { ok: true, normalizedArgs: toJson({ patch: patchText, input: patchText }) };
13
+ const normalized = normalizeApplyPatchArgs(argsString, rawArgs);
14
+ if (normalized.ok === false) {
15
+ return { ok: false, reason: normalized.reason };
25
16
  }
26
- const extractFromRecord = (rec) => {
27
- // Special case: argsString claims to be JSON but isn't parseable and raw text looks like a patch.
28
- if (looksJsonContainer && Object.keys(rec).length === 0 && looksLikePatch(rawTrimmed)) {
29
- const patchText = normalizeApplyPatchText(rawTrimmed);
30
- if (!patchText.includes('*** Begin Patch'))
31
- return { failureReason: 'unsupported_patch_format' };
32
- return { patchText };
33
- }
34
- const patchField = asString(rec.patch);
35
- if (patchField && looksLikePatch(patchField)) {
36
- const patchText = normalizeApplyPatchText(patchField);
37
- if (!patchText.includes('*** Begin Patch'))
38
- return { failureReason: 'unsupported_patch_format' };
39
- return { patchText };
40
- }
41
- const diffField = asString(rec.diff) ?? asString(rec.patchText) ?? asString(rec.body);
42
- if (diffField && looksLikePatch(diffField)) {
43
- const patchText = normalizeApplyPatchText(diffField);
44
- if (!patchText.includes('*** Begin Patch'))
45
- return { failureReason: 'unsupported_patch_format' };
46
- return { patchText };
47
- }
48
- const inputField = asString(rec.input);
49
- if (inputField && looksLikePatch(inputField)) {
50
- const patchText = normalizeApplyPatchText(inputField);
51
- if (!patchText.includes('*** Begin Patch'))
52
- return { failureReason: 'unsupported_patch_format' };
53
- return { patchText };
54
- }
55
- // Common shape: patch text stored under `instructions` (e.g. "*** Update File: ...").
56
- const instructionsField = asString(rec.instructions);
57
- if (instructionsField && looksLikePatch(instructionsField)) {
58
- const patchText = normalizeApplyPatchText(instructionsField);
59
- if (!patchText.includes('*** Begin Patch'))
60
- return { failureReason: 'unsupported_patch_format' };
61
- return { patchText };
62
- }
63
- // Common wrapper shape (seen in codex samples): { _raw: "{...json...}" }.
64
- // `_raw` may contain either patch text or a JSON-encoded structured payload.
65
- const rawEnvelope = asString(rec._raw);
66
- if (rawEnvelope) {
67
- const trimmed = rawEnvelope.trim();
68
- if (looksLikePatch(trimmed)) {
69
- const patchText = normalizeApplyPatchText(trimmed);
70
- if (!patchText.includes('*** Begin Patch'))
71
- return { failureReason: 'unsupported_patch_format' };
72
- return { patchText };
73
- }
74
- const parsed = tryParseJsonLoose(trimmed);
75
- if (parsed && isRecord(parsed)) {
76
- return extractFromRecord(parsed);
77
- }
78
- if (Array.isArray(parsed) && parsed.length > 0) {
79
- const changesArray = parsed.filter((entry) => isRecord(entry));
80
- if (changesArray.length && changesArray.some((c) => typeof c.kind === 'string')) {
81
- const payload = { changes: changesArray };
82
- try {
83
- return { patchText: buildStructuredPatch(payload) };
84
- }
85
- catch (error) {
86
- if (!(error instanceof StructuredApplyPatchError))
87
- throw error;
88
- return { failureReason: error.reason || 'structured_apply_patch_error' };
89
- }
90
- }
91
- }
92
- }
93
- const payload = coerceStructuredPayload(rec);
94
- if (payload) {
95
- try {
96
- return { patchText: buildStructuredPatch(payload) };
97
- }
98
- catch (error) {
99
- if (!(error instanceof StructuredApplyPatchError))
100
- throw error;
101
- return { failureReason: error.reason || 'structured_apply_patch_error' };
102
- }
103
- }
104
- return {};
17
+ return {
18
+ ok: true,
19
+ normalizedArgs: toJson({ patch: normalized.patchText, input: normalized.patchText })
105
20
  };
106
- let patchText;
107
- let failureReason;
108
- if (isRecord(rawArgs)) {
109
- const res = extractFromRecord(rawArgs);
110
- patchText = res.patchText;
111
- failureReason = res.failureReason;
112
- }
113
- else if (Array.isArray(rawArgs) && rawArgs.length > 0) {
114
- // compatibility: arguments may be either:
115
- // - a single-element array [{ file, changes: [...] }]
116
- // - a raw changes array [{ kind, ... }, ...]
117
- const first = rawArgs.find((entry) => isRecord(entry));
118
- if (first && Array.isArray(first.changes)) {
119
- const res = extractFromRecord(first);
120
- patchText = res.patchText;
121
- failureReason = res.failureReason;
122
- }
123
- else {
124
- const changesArray = rawArgs.filter((entry) => isRecord(entry));
125
- if (changesArray.length && changesArray.some((c) => typeof c.kind === 'string')) {
126
- const payload = { changes: changesArray };
127
- try {
128
- patchText = buildStructuredPatch(payload);
129
- }
130
- catch (error) {
131
- if (!(error instanceof StructuredApplyPatchError))
132
- throw error;
133
- failureReason = error.reason || 'structured_apply_patch_error';
134
- }
135
- }
136
- }
137
- }
138
- else if (typeof rawArgs === 'string' && looksLikePatch(rawArgs)) {
139
- const normalized = normalizeApplyPatchText(rawArgs);
140
- if (normalized.includes('*** Begin Patch')) {
141
- patchText = normalized;
142
- }
143
- else {
144
- failureReason = 'unsupported_patch_format';
145
- }
146
- }
147
- if (!patchText) {
148
- if (failureReason)
149
- return { ok: false, reason: failureReason };
150
- if (looksJsonContainer &&
151
- isRecord(rawArgs) &&
152
- Object.keys(rawArgs).length === 0 &&
153
- rawTrimmed.length > 0 &&
154
- !looksLikePatch(rawTrimmed)) {
155
- return { ok: false, reason: 'invalid_json' };
156
- }
157
- return { ok: false, reason: 'missing_changes' };
158
- }
159
- return { ok: true, normalizedArgs: toJson({ patch: patchText, input: patchText }) };
160
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsonstudio/llms",
3
- "version": "0.6.1462",
3
+ "version": "0.6.1733",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -27,7 +27,8 @@
27
27
  "test:looprt:gemini": "npm run build && node scripts/tests/loop-rt-gemini.mjs",
28
28
  "replay:responses:chat-sse": "node scripts/exp3-responses-sse-to-chat-sse.mjs",
29
29
  "replay:responses:loop": "node scripts/exp4-responses-sse-loop.mjs",
30
- "test:virtual-router": "npm run build:dev && node scripts/tests/virtual-router-prefer-autoclear.mjs && node scripts/tests/virtual-router-dry-run.mjs && node scripts/tests/virtual-router-context.mjs && node scripts/tests/virtual-router-antigravity-alias-pin.mjs && node scripts/tests/virtual-router-antigravity-auth-verify.mjs",
30
+ "test:quota-manager": "npm run build:dev && node scripts/tests/quota-manager-402-reset.mjs",
31
+ "test:virtual-router": "npm run build:dev && node scripts/tests/virtual-router-prefer-autoclear.mjs && node scripts/tests/virtual-router-dry-run.mjs && node scripts/tests/virtual-router-context.mjs && node scripts/tests/virtual-router-antigravity-alias-pin.mjs && node scripts/tests/virtual-router-antigravity-session-binding.mjs && node scripts/tests/virtual-router-antigravity-auth-verify.mjs",
31
32
  "test:virtual-router-health": "npm run build:dev && node scripts/tests/virtual-router-health.mjs",
32
33
  "test:golden": "npm run build:ci && node scripts/tests/chat-golden-roundtrip.mjs && node scripts/tests/anthropic-golden-roundtrip.mjs",
33
34
  "test:coverage": "node scripts/run-ci-coverage.mjs"