@jsonstudio/llms 0.6.1892 → 0.6.2172

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 (159) hide show
  1. package/dist/conversion/compat/actions/deepseek-web-request.js +16 -2
  2. package/dist/conversion/compat/actions/deepseek-web-response.d.ts +7 -1
  3. package/dist/conversion/compat/actions/deepseek-web-response.js +302 -40
  4. package/dist/conversion/compat/actions/harvest-tool-calls-from-text.d.ts +5 -0
  5. package/dist/conversion/compat/actions/harvest-tool-calls-from-text.js +7 -4
  6. package/dist/conversion/compat/actions/iflow-tool-text-fallback.d.ts +1 -0
  7. package/dist/conversion/compat/actions/iflow-tool-text-fallback.js +12 -0
  8. package/dist/conversion/compat/actions/strip-orphan-function-calls-tag.js +1 -1
  9. package/dist/conversion/compat/actions/tool-text-request-guidance.d.ts +9 -0
  10. package/dist/conversion/compat/actions/tool-text-request-guidance.js +177 -0
  11. package/dist/conversion/compat/antigravity-session-signature.d.ts +6 -0
  12. package/dist/conversion/compat/antigravity-session-signature.js +15 -0
  13. package/dist/conversion/compat/profiles/chat-deepseek-web.json +52 -1
  14. package/dist/conversion/compat/profiles/chat-glm.json +22 -0
  15. package/dist/conversion/compat/profiles/chat-iflow.json +4 -0
  16. package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +13 -27
  17. package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +10 -1
  18. package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +13 -4
  19. package/dist/conversion/hub/pipeline/compat/compat-profile-resolver.js +1 -53
  20. package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +8 -0
  21. package/dist/conversion/hub/pipeline/hub-pipeline.js +8 -4
  22. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +191 -9
  23. package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js +118 -15
  24. package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +65 -2
  25. package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage3_servertool_orchestration/index.d.ts +34 -0
  26. package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage3_servertool_orchestration/index.js +75 -0
  27. package/dist/conversion/hub/process/chat-process.js +85 -18
  28. package/dist/conversion/hub/response/provider-response.js +21 -50
  29. package/dist/conversion/hub/response/response-runtime.js +71 -10
  30. package/dist/conversion/responses/responses-openai-bridge/response-payload.d.ts +3 -0
  31. package/dist/conversion/responses/responses-openai-bridge/response-payload.js +576 -0
  32. package/dist/conversion/responses/responses-openai-bridge/types.d.ts +42 -0
  33. package/dist/conversion/responses/responses-openai-bridge/types.js +1 -0
  34. package/dist/conversion/responses/responses-openai-bridge.d.ts +3 -44
  35. package/dist/conversion/responses/responses-openai-bridge.js +193 -504
  36. package/dist/conversion/shared/anthropic-message-utils.js +82 -2
  37. package/dist/conversion/shared/bridge-message-utils.js +92 -39
  38. package/dist/conversion/shared/snapshot-hooks.js +8 -13
  39. package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.d.ts +2 -0
  40. package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.js +129 -0
  41. package/dist/conversion/shared/text-markup-normalizer/extractors-json.d.ts +4 -0
  42. package/dist/conversion/shared/text-markup-normalizer/extractors-json.js +637 -0
  43. package/dist/conversion/shared/text-markup-normalizer/extractors-shared.d.ts +21 -0
  44. package/dist/conversion/shared/text-markup-normalizer/extractors-shared.js +177 -0
  45. package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.d.ts +5 -0
  46. package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.js +385 -0
  47. package/dist/conversion/shared/text-markup-normalizer/extractors-xml.d.ts +10 -0
  48. package/dist/conversion/shared/text-markup-normalizer/extractors-xml.js +602 -0
  49. package/dist/conversion/shared/text-markup-normalizer/extractors.d.ts +5 -0
  50. package/dist/conversion/shared/text-markup-normalizer/extractors.js +4 -0
  51. package/dist/conversion/shared/text-markup-normalizer/normalize.d.ts +2 -0
  52. package/dist/conversion/shared/text-markup-normalizer/normalize.js +76 -0
  53. package/dist/conversion/shared/text-markup-normalizer.d.ts +3 -25
  54. package/dist/conversion/shared/text-markup-normalizer.js +2 -1386
  55. package/dist/conversion/shared/tool-governor.js +136 -10
  56. package/dist/filters/utils/snapshot-writer.js +3 -3
  57. package/dist/router/virtual-router/bootstrap/auth-utils.d.ts +6 -0
  58. package/dist/router/virtual-router/bootstrap/auth-utils.js +288 -0
  59. package/dist/router/virtual-router/bootstrap/claude-code-helpers.d.ts +11 -0
  60. package/dist/router/virtual-router/bootstrap/claude-code-helpers.js +18 -0
  61. package/dist/router/virtual-router/bootstrap/config-defaults.d.ts +5 -0
  62. package/dist/router/virtual-router/bootstrap/config-defaults.js +13 -0
  63. package/dist/router/virtual-router/bootstrap/config-normalizers.d.ts +4 -0
  64. package/dist/router/virtual-router/bootstrap/config-normalizers.js +106 -0
  65. package/dist/router/virtual-router/bootstrap/profile-builder.d.ts +7 -0
  66. package/dist/router/virtual-router/bootstrap/profile-builder.js +68 -0
  67. package/dist/router/virtual-router/bootstrap/provider-normalization.d.ts +40 -0
  68. package/dist/router/virtual-router/bootstrap/provider-normalization.js +212 -0
  69. package/dist/router/virtual-router/bootstrap/responses-helpers.d.ts +15 -0
  70. package/dist/router/virtual-router/bootstrap/responses-helpers.js +65 -0
  71. package/dist/router/virtual-router/bootstrap/routing-config.d.ts +23 -0
  72. package/dist/router/virtual-router/bootstrap/routing-config.js +293 -0
  73. package/dist/router/virtual-router/bootstrap/streaming-helpers.d.ts +12 -0
  74. package/dist/router/virtual-router/bootstrap/streaming-helpers.js +128 -0
  75. package/dist/router/virtual-router/bootstrap/utils.d.ts +5 -0
  76. package/dist/router/virtual-router/bootstrap/utils.js +41 -0
  77. package/dist/router/virtual-router/bootstrap/web-search-config.d.ts +4 -0
  78. package/dist/router/virtual-router/bootstrap/web-search-config.js +131 -0
  79. package/dist/router/virtual-router/bootstrap.d.ts +0 -4
  80. package/dist/router/virtual-router/bootstrap.js +31 -1275
  81. package/dist/router/virtual-router/classifier.js +32 -14
  82. package/dist/router/virtual-router/engine/antigravity/alias-lease.js +2 -2
  83. package/dist/router/virtual-router/engine/cooldown-manager.d.ts +34 -0
  84. package/dist/router/virtual-router/engine/cooldown-manager.js +118 -0
  85. package/dist/router/virtual-router/engine/route-analytics.d.ts +28 -0
  86. package/dist/router/virtual-router/engine/route-analytics.js +44 -0
  87. package/dist/router/virtual-router/engine/routing-pools/index.js +165 -4
  88. package/dist/router/virtual-router/engine/sticky-session-manager.d.ts +29 -0
  89. package/dist/router/virtual-router/engine/sticky-session-manager.js +55 -0
  90. package/dist/router/virtual-router/engine-logging.d.ts +42 -1
  91. package/dist/router/virtual-router/engine-logging.js +82 -15
  92. package/dist/router/virtual-router/engine-selection/multimodal-capability.d.ts +3 -0
  93. package/dist/router/virtual-router/engine-selection/multimodal-capability.js +26 -0
  94. package/dist/router/virtual-router/engine-selection/route-utils.js +6 -2
  95. package/dist/router/virtual-router/engine-selection/selection-deps.d.ts +1 -0
  96. package/dist/router/virtual-router/engine-selection/tier-selection.js +31 -1
  97. package/dist/router/virtual-router/engine.d.ts +21 -7
  98. package/dist/router/virtual-router/engine.js +198 -194
  99. package/dist/router/virtual-router/features.js +12 -4
  100. package/dist/router/virtual-router/message-utils.d.ts +8 -0
  101. package/dist/router/virtual-router/message-utils.js +170 -45
  102. package/dist/router/virtual-router/pre-command-file-resolver.js +40 -2
  103. package/dist/router/virtual-router/routing-instructions.d.ts +8 -0
  104. package/dist/router/virtual-router/routing-instructions.js +18 -2
  105. package/dist/router/virtual-router/routing-stop-message-actions.js +34 -10
  106. package/dist/router/virtual-router/routing-stop-message-state-codec.d.ts +2 -0
  107. package/dist/router/virtual-router/routing-stop-message-state-codec.js +50 -1
  108. package/dist/router/virtual-router/stop-message-state-sync.d.ts +1 -1
  109. package/dist/router/virtual-router/stop-message-state-sync.js +3 -0
  110. package/dist/router/virtual-router/token-counter.js +51 -10
  111. package/dist/router/virtual-router/tool-signals.js +4 -0
  112. package/dist/router/virtual-router/types.d.ts +15 -0
  113. package/dist/servertool/clock/session-scope.d.ts +3 -0
  114. package/dist/servertool/clock/session-scope.js +52 -0
  115. package/dist/servertool/clock/state.js +9 -0
  116. package/dist/servertool/clock/tasks.js +12 -1
  117. package/dist/servertool/clock/types.d.ts +3 -0
  118. package/dist/servertool/engine.js +177 -31
  119. package/dist/servertool/handlers/clock-auto.js +2 -8
  120. package/dist/servertool/handlers/clock.js +6 -9
  121. package/dist/servertool/handlers/recursive-detection-guard.js +53 -14
  122. package/dist/servertool/handlers/stop-message-auto/blocked-report.d.ts +16 -0
  123. package/dist/servertool/handlers/stop-message-auto/blocked-report.js +349 -0
  124. package/dist/servertool/handlers/stop-message-auto/iflow-followup.d.ts +23 -0
  125. package/dist/servertool/handlers/stop-message-auto/iflow-followup.js +503 -0
  126. package/dist/servertool/handlers/stop-message-auto/routing-state.d.ts +38 -0
  127. package/dist/servertool/handlers/stop-message-auto/routing-state.js +149 -0
  128. package/dist/servertool/handlers/stop-message-auto/runtime-utils.d.ts +67 -0
  129. package/dist/servertool/handlers/stop-message-auto/runtime-utils.js +387 -0
  130. package/dist/servertool/handlers/stop-message-auto.d.ts +1 -1
  131. package/dist/servertool/handlers/stop-message-auto.js +80 -556
  132. package/dist/servertool/handlers/stop-message-stage-policy/bd-runtime.d.ts +18 -0
  133. package/dist/servertool/handlers/stop-message-stage-policy/bd-runtime.js +398 -0
  134. package/dist/servertool/handlers/stop-message-stage-policy/decision.d.ts +9 -0
  135. package/dist/servertool/handlers/stop-message-stage-policy/decision.js +127 -0
  136. package/dist/servertool/handlers/stop-message-stage-policy/observation.d.ts +2 -0
  137. package/dist/servertool/handlers/stop-message-stage-policy/observation.js +179 -0
  138. package/dist/servertool/handlers/stop-message-stage-policy/templates.d.ts +4 -0
  139. package/dist/servertool/handlers/stop-message-stage-policy/templates.js +96 -0
  140. package/dist/servertool/handlers/stop-message-stage-policy/text-utils.d.ts +9 -0
  141. package/dist/servertool/handlers/stop-message-stage-policy/text-utils.js +89 -0
  142. package/dist/servertool/handlers/stop-message-stage-policy/types.d.ts +59 -0
  143. package/dist/servertool/handlers/stop-message-stage-policy/types.js +1 -0
  144. package/dist/servertool/handlers/stop-message-stage-policy.d.ts +3 -43
  145. package/dist/servertool/handlers/stop-message-stage-policy.js +2 -684
  146. package/dist/servertool/handlers/web-search.js +117 -0
  147. package/dist/servertool/server-side-tools.d.ts +0 -1
  148. package/dist/servertool/server-side-tools.js +4 -3
  149. package/dist/sse/sse-to-json/builders/response-builder.js +16 -0
  150. package/dist/sse/sse-to-json/chat-sse-to-json-converter.d.ts +1 -0
  151. package/dist/sse/sse-to-json/chat-sse-to-json-converter.js +110 -37
  152. package/dist/telemetry/stats-center.d.ts +9 -0
  153. package/dist/telemetry/stats-center.js +29 -1
  154. package/dist/tools/apply-patch/structured/coercion.js +3 -11
  155. package/dist/tools/exec-command/validator.d.ts +1 -0
  156. package/dist/tools/exec-command/validator.js +132 -0
  157. package/dist/tools/tool-registry.d.ts +1 -0
  158. package/dist/tools/tool-registry.js +1 -1
  159. package/package.json +1 -1
@@ -166,7 +166,8 @@ function requireSystemText(block, context) {
166
166
  const ANTHROPIC_TOOL_NAME_ALIASES = new Map([
167
167
  ['bash', 'shell_command'],
168
168
  ['shell', 'shell_command'],
169
- ['terminal', 'shell_command']
169
+ ['terminal', 'shell_command'],
170
+ ['exec_command', 'shell_command']
170
171
  ]);
171
172
  const CANONICAL_TO_ANTHROPIC_TOOL_NAMES = new Map([['shell_command', 'Bash']]);
172
173
  const ANTHROPIC_TOP_LEVEL_FIELDS = new Set([
@@ -221,6 +222,69 @@ export function denormalizeAnthropicToolName(value) {
221
222
  }
222
223
  return trimmed;
223
224
  }
225
+ function coerceShellLikeCommand(value) {
226
+ if (typeof value === 'string') {
227
+ const trimmed = value.trim();
228
+ return trimmed.length ? trimmed : undefined;
229
+ }
230
+ if (Array.isArray(value)) {
231
+ const parts = value
232
+ .map((entry) => (typeof entry === 'string' ? entry.trim() : ''))
233
+ .filter((entry) => entry.length > 0);
234
+ if (!parts.length) {
235
+ return undefined;
236
+ }
237
+ return parts.join(' ');
238
+ }
239
+ return undefined;
240
+ }
241
+ function normalizeShellLikeToolInput(toolName, input) {
242
+ const canonical = normalizeAnthropicToolName(toolName);
243
+ if (canonical !== 'shell_command') {
244
+ return input;
245
+ }
246
+ const rawToolName = typeof toolName === 'string' ? toolName.trim().toLowerCase() : '';
247
+ const isExecCommand = rawToolName === 'exec_command';
248
+ if (!input || typeof input !== 'object' || Array.isArray(input)) {
249
+ const cmd = coerceShellLikeCommand(input);
250
+ if (!cmd) {
251
+ return {};
252
+ }
253
+ return isExecCommand ? { cmd } : { command: cmd };
254
+ }
255
+ const next = { ...input };
256
+ const commandValue = coerceShellLikeCommand(next.command);
257
+ const cmdValue = coerceShellLikeCommand(next.cmd);
258
+ const fallbackValue = coerceShellLikeCommand(next.script) ??
259
+ coerceShellLikeCommand(next.toon);
260
+ if (commandValue) {
261
+ next.command = commandValue;
262
+ }
263
+ if (cmdValue) {
264
+ next.cmd = cmdValue;
265
+ }
266
+ if (!commandValue && !cmdValue && fallbackValue) {
267
+ if (isExecCommand) {
268
+ next.cmd = fallbackValue;
269
+ }
270
+ else {
271
+ next.command = fallbackValue;
272
+ }
273
+ }
274
+ else if (!commandValue && cmdValue && !isExecCommand) {
275
+ next.command = cmdValue;
276
+ }
277
+ else if (!cmdValue && commandValue && isExecCommand) {
278
+ next.cmd = commandValue;
279
+ }
280
+ if (!isExecCommand && 'cmd' in next) {
281
+ delete next.cmd;
282
+ }
283
+ if (typeof next.workdir !== 'string' && typeof next.cwd === 'string' && next.cwd.trim().length > 0) {
284
+ next.workdir = next.cwd.trim();
285
+ }
286
+ return next;
287
+ }
224
288
  function invertAnthropicAliasMap(source) {
225
289
  if (!source) {
226
290
  return undefined;
@@ -510,6 +574,7 @@ export function buildAnthropicFromOpenAIChat(oa, options) {
510
574
  else {
511
575
  input = argsRaw ?? {};
512
576
  }
577
+ input = normalizeShellLikeToolInput(name, input);
513
578
  blocks.push({ type: 'tool_use', id, name, input });
514
579
  }
515
580
  catch {
@@ -660,7 +725,15 @@ function createAnthropicToolNameResolver(source) {
660
725
  if (!trimmed.length) {
661
726
  return name;
662
727
  }
663
- return lookup.get(trimmed) ?? lookup.get(trimmed.toLowerCase()) ?? trimmed;
728
+ const direct = lookup.get(trimmed) ?? lookup.get(trimmed.toLowerCase());
729
+ if (direct) {
730
+ return direct;
731
+ }
732
+ const normalized = normalizeAnthropicToolName(trimmed);
733
+ if (normalized) {
734
+ return lookup.get(normalized) ?? lookup.get(normalized.toLowerCase()) ?? trimmed;
735
+ }
736
+ return trimmed;
664
737
  };
665
738
  }
666
739
  function normalizeAnthropicToolChoice(value) {
@@ -928,6 +1001,7 @@ export function buildAnthropicRequestFromOpenAIChat(chatReq) {
928
1001
  else {
929
1002
  input = argsRaw ?? {};
930
1003
  }
1004
+ input = normalizeShellLikeToolInput(name, input);
931
1005
  blocks.push({ type: 'tool_use', id, name, input });
932
1006
  }
933
1007
  if (blocks.length > 0) {
@@ -1167,6 +1241,12 @@ export function buildAnthropicToolAliasMap(rawTools) {
1167
1241
  continue;
1168
1242
  }
1169
1243
  aliasMap.set(canonicalKey, rawName);
1244
+ // Anthropic shell-like tools (e.g. Bash) and exec_command are treated as one family.
1245
+ // Keep an explicit exec_command key so reverse mapping can preserve
1246
+ // canonical exec_command when upstream already uses that name.
1247
+ if (canonicalKey === 'shell_command' && !aliasMap.has('exec_command')) {
1248
+ aliasMap.set('exec_command', rawName);
1249
+ }
1170
1250
  const lowerKey = canonicalKey.toLowerCase();
1171
1251
  if (lowerKey !== canonicalKey && !aliasMap.has(lowerKey)) {
1172
1252
  aliasMap.set(lowerKey, rawName);
@@ -60,8 +60,8 @@ function collectText(value) {
60
60
  }
61
61
  return '';
62
62
  }
63
- function extractImageBlocksFromContent(content) {
64
- const images = [];
63
+ function extractMediaBlocksFromContent(content) {
64
+ const media = [];
65
65
  const visit = (value) => {
66
66
  if (!value)
67
67
  return;
@@ -75,14 +75,27 @@ function extractImageBlocksFromContent(content) {
75
75
  }
76
76
  const record = value;
77
77
  const typeValue = typeof record.type === 'string' ? record.type.toLowerCase() : '';
78
+ let kind = null;
78
79
  if (typeValue === 'image' || typeValue === 'image_url' || typeValue === 'input_image') {
80
+ kind = 'image';
81
+ }
82
+ else if (typeValue === 'video' || typeValue === 'video_url' || typeValue === 'input_video') {
83
+ kind = 'video';
84
+ }
85
+ else if (record.video_url !== undefined) {
86
+ kind = 'video';
87
+ }
88
+ else if (record.image_url !== undefined) {
89
+ kind = 'image';
90
+ }
91
+ if (kind) {
79
92
  let url = '';
80
- const imageUrl = record.image_url;
81
- if (typeof imageUrl === 'string') {
82
- url = imageUrl;
93
+ const mediaUrl = kind === 'video' ? record.video_url : record.image_url;
94
+ if (typeof mediaUrl === 'string') {
95
+ url = mediaUrl;
83
96
  }
84
- else if (imageUrl && typeof imageUrl === 'object' && typeof imageUrl.url === 'string') {
85
- url = imageUrl.url;
97
+ else if (mediaUrl && typeof mediaUrl === 'object' && typeof mediaUrl.url === 'string') {
98
+ url = mediaUrl.url;
86
99
  }
87
100
  else if (typeof record.url === 'string') {
88
101
  url = record.url;
@@ -96,13 +109,13 @@ function extractImageBlocksFromContent(content) {
96
109
  const trimmed = url.trim();
97
110
  if (trimmed.length) {
98
111
  let detail;
99
- if (imageUrl && typeof imageUrl === 'object' && typeof imageUrl.detail === 'string') {
100
- detail = imageUrl.detail.trim() || undefined;
112
+ if (mediaUrl && typeof mediaUrl === 'object' && typeof mediaUrl.detail === 'string') {
113
+ detail = mediaUrl.detail.trim() || undefined;
101
114
  }
102
115
  else if (typeof record.detail === 'string') {
103
116
  detail = record.detail.trim() || undefined;
104
117
  }
105
- images.push({ url: trimmed, detail });
118
+ media.push({ kind, url: trimmed, detail });
106
119
  }
107
120
  return;
108
121
  }
@@ -111,7 +124,7 @@ function extractImageBlocksFromContent(content) {
111
124
  }
112
125
  };
113
126
  visit(content);
114
- return images;
127
+ return media;
115
128
  }
116
129
  function extractUserTextFromEntry(entry) {
117
130
  if (!entry || typeof entry !== 'object')
@@ -141,7 +154,7 @@ export function convertMessagesToBridgeInput(options) {
141
154
  const role = coerceBridgeRole(m.role || 'user');
142
155
  const content = m.content;
143
156
  const collectedText = collectText(content);
144
- const imageBlocks = extractImageBlocksFromContent(content);
157
+ const mediaBlocks = extractMediaBlocksFromContent(content);
145
158
  const text = role === 'system' ? collectedText : collectedText.trim();
146
159
  if (role === 'system') {
147
160
  if (collectedText && collectedText.length) {
@@ -218,20 +231,26 @@ export function convertMessagesToBridgeInput(options) {
218
231
  }
219
232
  continue;
220
233
  }
221
- if (typeof text === 'string' || imageBlocks.length) {
234
+ if (typeof text === 'string' || mediaBlocks.length) {
222
235
  const tRole = role === 'assistant' ? 'output_text' : 'input_text';
223
236
  const blocks = [];
224
237
  if (typeof text === 'string' && text.length) {
225
238
  blocks.push({ type: tRole, text });
226
239
  }
227
- for (const img of imageBlocks) {
228
- const block = {
229
- type: 'input_image',
230
- image_url: img.url
231
- };
232
- if (img.detail) {
233
- block.detail = img.detail;
240
+ for (const media of mediaBlocks) {
241
+ const block = media.kind === 'video'
242
+ ? {
243
+ type: 'input_video',
244
+ video_url: media.url
245
+ }
246
+ : {
247
+ type: 'input_image',
248
+ image_url: media.url
249
+ };
250
+ if (media.detail) {
251
+ block.detail = media.detail;
234
252
  }
253
+ ;
235
254
  blocks.push(block);
236
255
  }
237
256
  if (blocks.length) {
@@ -324,7 +343,7 @@ function processMessageBlocks(blocks, normalizeFunctionName, tools, toolNameById
324
343
  const toolMessages = [];
325
344
  let currentLastCall = lastToolCallId;
326
345
  const reasoningSegments = [];
327
- const images = [];
346
+ const mediaBlocks = [];
328
347
  for (const block of blocks) {
329
348
  if (!block || typeof block !== 'object')
330
349
  continue;
@@ -347,17 +366,45 @@ function processMessageBlocks(blocks, normalizeFunctionName, tools, toolNameById
347
366
  toolMessages.push(tm);
348
367
  currentLastCall = nested.lastCallId;
349
368
  reasoningSegments.push(...nested.reasoningSegments);
350
- if (nested.images.length)
351
- images.push(...nested.images);
369
+ if (nested.mediaBlocks.length)
370
+ mediaBlocks.push(...nested.mediaBlocks);
371
+ continue;
372
+ }
373
+ if (type === 'input_image' || type === 'image' || type === 'image_url') {
374
+ let url = '';
375
+ if (typeof block.image_url === 'string') {
376
+ url = block.image_url.trim();
377
+ }
378
+ else if (block.image_url && typeof block.image_url.url === 'string') {
379
+ url = block.image_url.url.trim();
380
+ }
381
+ else if (typeof block.url === 'string') {
382
+ url = block.url.trim();
383
+ }
384
+ if (url) {
385
+ const detail = typeof block.detail === 'string' && block.detail.trim()
386
+ ? block.detail.trim()
387
+ : undefined;
388
+ mediaBlocks.push({ kind: 'image', url, detail });
389
+ }
352
390
  continue;
353
391
  }
354
- if (type === 'input_image') {
355
- const url = typeof block.image_url === 'string' ? block.image_url.trim() : '';
392
+ if (type === 'input_video' || type === 'video' || type === 'video_url') {
393
+ let url = '';
394
+ if (typeof block.video_url === 'string') {
395
+ url = block.video_url.trim();
396
+ }
397
+ else if (block.video_url && typeof block.video_url.url === 'string') {
398
+ url = block.video_url.url.trim();
399
+ }
400
+ else if (typeof block.url === 'string') {
401
+ url = block.url.trim();
402
+ }
356
403
  if (url) {
357
404
  const detail = typeof block.detail === 'string' && block.detail.trim()
358
405
  ? block.detail.trim()
359
406
  : undefined;
360
- images.push({ url, detail });
407
+ mediaBlocks.push({ kind: 'video', url, detail });
361
408
  }
362
409
  continue;
363
410
  }
@@ -421,7 +468,7 @@ function processMessageBlocks(blocks, normalizeFunctionName, tools, toolNameById
421
468
  }
422
469
  }
423
470
  const text = textParts.length ? textParts.join('\n').trim() : null;
424
- return { text, images, toolCalls, toolMessages, lastCallId: currentLastCall, reasoningSegments };
471
+ return { text, mediaBlocks, toolCalls, toolMessages, lastCallId: currentLastCall, reasoningSegments };
425
472
  }
426
473
  export function convertBridgeInputToChatMessages(options) {
427
474
  const { input, tools, normalizeFunctionName, toolResultFallbackText } = options;
@@ -547,17 +594,20 @@ export function convertBridgeInputToChatMessages(options) {
547
594
  for (const msg of nested.toolMessages)
548
595
  messages.push(msg);
549
596
  const normalizedRole = coerceBridgeRole((explicit.role ?? entry.role) || 'user');
550
- if (nested.images.length) {
597
+ if (nested.mediaBlocks.length) {
551
598
  const contentBlocks = [];
552
599
  if (typeof nested.text === 'string' && nested.text.trim().length) {
553
600
  contentBlocks.push({ type: 'text', text: nested.text });
554
601
  }
555
- for (const img of nested.images) {
556
- const imgBlock = { type: 'image_url', image_url: { url: img.url } };
557
- if (img.detail) {
558
- imgBlock.image_url.detail = img.detail;
602
+ for (const media of nested.mediaBlocks) {
603
+ const mediaBlock = media.kind === 'video'
604
+ ? { type: 'video_url', video_url: { url: media.url } }
605
+ : { type: 'image_url', image_url: { url: media.url } };
606
+ if (media.detail) {
607
+ const key = media.kind === 'video' ? 'video_url' : 'image_url';
608
+ mediaBlock[key].detail = media.detail;
559
609
  }
560
- contentBlocks.push(imgBlock);
610
+ contentBlocks.push(mediaBlock);
561
611
  }
562
612
  const msg = {
563
613
  role: normalizedRole,
@@ -590,17 +640,20 @@ export function convertBridgeInputToChatMessages(options) {
590
640
  for (const msg of nested.toolMessages)
591
641
  messages.push(msg);
592
642
  const normalizedRole = coerceBridgeRole(entry.role || 'user');
593
- if (nested.images.length) {
643
+ if (nested.mediaBlocks.length) {
594
644
  const contentBlocks = [];
595
645
  if (typeof nested.text === 'string' && nested.text.trim().length) {
596
646
  contentBlocks.push({ type: 'text', text: nested.text });
597
647
  }
598
- for (const img of nested.images) {
599
- const imgBlock = { type: 'image_url', image_url: { url: img.url } };
600
- if (img.detail) {
601
- imgBlock.image_url.detail = img.detail;
648
+ for (const media of nested.mediaBlocks) {
649
+ const mediaBlock = media.kind === 'video'
650
+ ? { type: 'video_url', video_url: { url: media.url } }
651
+ : { type: 'image_url', image_url: { url: media.url } };
652
+ if (media.detail) {
653
+ const key = media.kind === 'video' ? 'video_url' : 'image_url';
654
+ mediaBlock[key].detail = media.detail;
602
655
  }
603
- contentBlocks.push(imgBlock);
656
+ contentBlocks.push(mediaBlock);
604
657
  }
605
658
  const msg = {
606
659
  role: normalizedRole,
@@ -83,11 +83,11 @@ async function writeUniqueErrorsampleFile(dir, baseName, contents) {
83
83
  await fs.writeFile(path.join(dir, fallback), contents, { encoding: 'utf-8' });
84
84
  }
85
85
  function resolveSnapshotFolder(endpoint) {
86
- const lowered = (endpoint || '').toLowerCase();
87
- if (lowered.includes('/responses')) {
86
+ const lowered = (endpoint || '').trim().toLowerCase();
87
+ if (lowered.includes('/v1/responses') || lowered.includes('/responses.submit')) {
88
88
  return 'openai-responses';
89
89
  }
90
- if (lowered.includes('/messages')) {
90
+ if (lowered.includes('/v1/messages')) {
91
91
  return 'anthropic-messages';
92
92
  }
93
93
  return 'openai-chat';
@@ -187,8 +187,7 @@ function extractNestedEntryEndpoint(value) {
187
187
  }
188
188
  const obj = value;
189
189
  const direct = readStringField(obj.entryEndpoint) ||
190
- readStringField(obj.entry_endpoint) ||
191
- readStringField(obj.endpoint);
190
+ readStringField(obj.entry_endpoint);
192
191
  if (direct) {
193
192
  return direct;
194
193
  }
@@ -196,8 +195,7 @@ function extractNestedEntryEndpoint(value) {
196
195
  if (meta && typeof meta === 'object') {
197
196
  const m = meta;
198
197
  const fromMeta = readStringField(m.entryEndpoint) ||
199
- readStringField(m.entry_endpoint) ||
200
- readStringField(m.endpoint);
198
+ readStringField(m.entry_endpoint);
201
199
  if (fromMeta) {
202
200
  return fromMeta;
203
201
  }
@@ -205,8 +203,7 @@ function extractNestedEntryEndpoint(value) {
205
203
  if (ctx && typeof ctx === 'object') {
206
204
  const c = ctx;
207
205
  const fromCtx = readStringField(c.entryEndpoint) ||
208
- readStringField(c.entry_endpoint) ||
209
- readStringField(c.endpoint);
206
+ readStringField(c.entry_endpoint);
210
207
  if (fromCtx) {
211
208
  return fromCtx;
212
209
  }
@@ -216,8 +213,7 @@ function extractNestedEntryEndpoint(value) {
216
213
  if (metadata && typeof metadata === 'object') {
217
214
  const md = metadata;
218
215
  const fromMetadata = readStringField(md.entryEndpoint) ||
219
- readStringField(md.entry_endpoint) ||
220
- readStringField(md.endpoint);
216
+ readStringField(md.entry_endpoint);
221
217
  if (fromMetadata) {
222
218
  return fromMetadata;
223
219
  }
@@ -226,8 +222,7 @@ function extractNestedEntryEndpoint(value) {
226
222
  if (runtime && typeof runtime === 'object') {
227
223
  const r = runtime;
228
224
  const fromRuntime = readStringField(r.entryEndpoint) ||
229
- readStringField(r.entry_endpoint) ||
230
- readStringField(r.endpoint);
225
+ readStringField(r.entry_endpoint);
231
226
  if (fromRuntime) {
232
227
  return fromRuntime;
233
228
  }
@@ -0,0 +1,2 @@
1
+ import { type ToolCallLite } from './extractors-shared.js';
2
+ export declare function extractApplyPatchCallsFromText(text: string): ToolCallLite[] | null;
@@ -0,0 +1,129 @@
1
+ import { isStructuredApplyPatchPayload } from '../../../tools/apply-patch-structured.js';
2
+ import { genToolCallId } from './extractors-shared.js';
3
+ function extractStructuredApplyPatchPayloads(text) {
4
+ const payloads = [];
5
+ try {
6
+ const fenceRe = /```(?:json|apply_patch|toon)?\s*([\s\S]*?)\s*```/gi;
7
+ let fm;
8
+ while ((fm = fenceRe.exec(text)) !== null) {
9
+ const body = fm[1] || '';
10
+ try {
11
+ const parsed = JSON.parse(body);
12
+ if (isStructuredApplyPatchPayload(parsed)) {
13
+ payloads.push(parsed);
14
+ }
15
+ }
16
+ catch {
17
+ /* ignore invalid JSON */
18
+ }
19
+ }
20
+ if (!payloads.length && typeof text === 'string' && text.includes('"changes"')) {
21
+ try {
22
+ const parsed = JSON.parse(text);
23
+ if (isStructuredApplyPatchPayload(parsed)) {
24
+ payloads.push(parsed);
25
+ }
26
+ }
27
+ catch {
28
+ /* ignore */
29
+ }
30
+ }
31
+ }
32
+ catch {
33
+ /* ignore */
34
+ }
35
+ return payloads;
36
+ }
37
+ function normalizeRawApplyPatchBlock(raw) {
38
+ try {
39
+ const lines = String(raw || '')
40
+ .split(/\r?\n/)
41
+ .map((line) => line.replace(/\r/g, ''));
42
+ while (lines.length > 0 && !lines[0].trim()) {
43
+ lines.shift();
44
+ }
45
+ while (lines.length > 0 && !lines[lines.length - 1].trim()) {
46
+ lines.pop();
47
+ }
48
+ if (!lines.length)
49
+ return '';
50
+ const indents = lines
51
+ .filter((line) => line.trim().length > 0)
52
+ .map((line) => {
53
+ const m = line.match(/^[ \t]*/);
54
+ return m ? m[0].length : 0;
55
+ });
56
+ const minIndent = indents.length ? Math.min(...indents) : 0;
57
+ if (minIndent <= 0) {
58
+ return lines.join('\n').trim();
59
+ }
60
+ return lines
61
+ .map((line) => line.replace(new RegExp(`^[ \\t]{0,${minIndent}}`), ''))
62
+ .join('\n')
63
+ .trim();
64
+ }
65
+ catch {
66
+ return String(raw || '').trim();
67
+ }
68
+ }
69
+ function extractRawApplyPatchBlocks(text) {
70
+ const out = [];
71
+ try {
72
+ if (typeof text !== 'string' || !text)
73
+ return out;
74
+ const seen = new Set();
75
+ const blockRe = /\*\*\*\s*Begin Patch(?:\s*\*\*\*)?[\s\S]*?\*\*\*\s*End Patch(?:\s*\*\*\*)?/gi;
76
+ let m;
77
+ while ((m = blockRe.exec(text)) !== null) {
78
+ const normalized = normalizeRawApplyPatchBlock(String(m[0] || ''));
79
+ if (!normalized)
80
+ continue;
81
+ // Avoid turning incidental prose into apply_patch.
82
+ if (!/\*\*\*\s*(?:Add|Update|Delete)\s+File:/i.test(normalized))
83
+ continue;
84
+ if (seen.has(normalized))
85
+ continue;
86
+ seen.add(normalized);
87
+ out.push(normalized);
88
+ }
89
+ }
90
+ catch {
91
+ /* ignore */
92
+ }
93
+ return out;
94
+ }
95
+ export function extractApplyPatchCallsFromText(text) {
96
+ try {
97
+ if (typeof text !== 'string' || !text)
98
+ return null;
99
+ const payloads = extractStructuredApplyPatchPayloads(text);
100
+ const patchBlocks = extractRawApplyPatchBlocks(text);
101
+ if (!payloads.length && !patchBlocks.length)
102
+ return null;
103
+ const out = [];
104
+ for (const payload of payloads) {
105
+ let argsStr = '{}';
106
+ try {
107
+ argsStr = JSON.stringify(payload);
108
+ }
109
+ catch {
110
+ argsStr = '{"changes":[]}';
111
+ }
112
+ out.push({ id: genToolCallId(), name: 'apply_patch', args: argsStr });
113
+ }
114
+ for (const patch of patchBlocks) {
115
+ let argsStr = '{}';
116
+ try {
117
+ argsStr = JSON.stringify({ patch, input: patch });
118
+ }
119
+ catch {
120
+ argsStr = '{"patch":""}';
121
+ }
122
+ out.push({ id: genToolCallId(), name: 'apply_patch', args: argsStr });
123
+ }
124
+ return out;
125
+ }
126
+ catch {
127
+ return null;
128
+ }
129
+ }
@@ -0,0 +1,4 @@
1
+ import { type TextMarkupNormalizeOptions, type ToolCallLite } from './extractors-shared.js';
2
+ export declare function tryParseJsonWithModelRepairs(raw: string): unknown | null;
3
+ export declare function salvageToolArgsFromRawText(toolName: string, rawArgs: string): Record<string, unknown> | null;
4
+ export declare function extractJsonToolCallsFromText(text: string, options?: TextMarkupNormalizeOptions): ToolCallLite[] | null;