@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
@@ -0,0 +1,637 @@
1
+ import { KNOWN_TOOLS, coerceCommandValueToString, filterArgsForTool, genToolCallId } from './extractors-shared.js';
2
+ const DEFAULT_JSON_TOOL_NAME_ALIASES = {
3
+ shell_command: 'exec_command',
4
+ shell: 'exec_command',
5
+ bash: 'exec_command',
6
+ terminal: 'exec_command'
7
+ };
8
+ const DEFAULT_JSON_TOOL_ARGUMENT_ALIASES = {
9
+ exec_command: {
10
+ cmd: ['cmd', 'command', 'script', 'toon', 'input.command', 'input.cmd', 'input.script', 'input.toon'],
11
+ command: ['cmd', 'command', 'script', 'toon', 'input.command', 'input.cmd', 'input.script', 'input.toon'],
12
+ workdir: ['workdir', 'cwd', 'input.workdir', 'input.cwd']
13
+ },
14
+ write_stdin: {
15
+ chars: ['chars', 'text', 'input', 'data', 'input.chars', 'input.text', 'input.input', 'input.data'],
16
+ session_id: ['session_id', 'sessionId', 'input.session_id', 'input.sessionId']
17
+ },
18
+ apply_patch: {
19
+ patch: ['patch', 'text', 'input', 'instructions', 'input.patch', 'input.text', 'input.input', 'input.instructions']
20
+ }
21
+ };
22
+ function escapeControlCharsInsideJsonStrings(raw) {
23
+ try {
24
+ if (typeof raw !== 'string' || !raw)
25
+ return null;
26
+ let out = '';
27
+ let changed = false;
28
+ let inString = false;
29
+ let escaped = false;
30
+ for (let i = 0; i < raw.length; i++) {
31
+ const ch = raw[i];
32
+ if (inString) {
33
+ if (!escaped && ch === '"') {
34
+ inString = false;
35
+ out += ch;
36
+ continue;
37
+ }
38
+ if (!escaped && ch === '\\') {
39
+ escaped = true;
40
+ out += ch;
41
+ continue;
42
+ }
43
+ // JSON disallows unescaped control chars inside strings; models sometimes emit raw newlines/tabs.
44
+ if (!escaped) {
45
+ if (ch === '\n') {
46
+ out += '\\n';
47
+ changed = true;
48
+ continue;
49
+ }
50
+ if (ch === '\r') {
51
+ if (raw[i + 1] === '\n') {
52
+ i++;
53
+ }
54
+ out += '\\n';
55
+ changed = true;
56
+ continue;
57
+ }
58
+ if (ch === '\t') {
59
+ out += '\\t';
60
+ changed = true;
61
+ continue;
62
+ }
63
+ const code = ch.charCodeAt(0);
64
+ if (code >= 0 && code < 0x20) {
65
+ out += `\\u${code.toString(16).padStart(4, '0')}`;
66
+ changed = true;
67
+ continue;
68
+ }
69
+ }
70
+ out += ch;
71
+ escaped = false;
72
+ continue;
73
+ }
74
+ if (ch === '"') {
75
+ inString = true;
76
+ out += ch;
77
+ continue;
78
+ }
79
+ out += ch;
80
+ }
81
+ return changed ? out : null;
82
+ }
83
+ catch {
84
+ return null;
85
+ }
86
+ }
87
+ export function tryParseJsonWithModelRepairs(raw) {
88
+ try {
89
+ if (typeof raw !== 'string')
90
+ return null;
91
+ const text = raw.trim();
92
+ if (!text)
93
+ return null;
94
+ try {
95
+ return JSON.parse(text);
96
+ }
97
+ catch {
98
+ const repaired = escapeControlCharsInsideJsonStrings(text);
99
+ if (!repaired)
100
+ return null;
101
+ try {
102
+ return JSON.parse(repaired);
103
+ }
104
+ catch {
105
+ return null;
106
+ }
107
+ }
108
+ }
109
+ catch {
110
+ return null;
111
+ }
112
+ }
113
+ export function salvageToolArgsFromRawText(toolName, rawArgs) {
114
+ try {
115
+ const lname = String(toolName || '').toLowerCase();
116
+ const text = String(rawArgs || '');
117
+ const out = {};
118
+ const pickString = (re) => {
119
+ const m = text.match(re);
120
+ if (!m)
121
+ return undefined;
122
+ return String(m[1] ?? '');
123
+ };
124
+ const pickNumber = (re) => {
125
+ const m = text.match(re);
126
+ if (!m)
127
+ return undefined;
128
+ const n = Number.parseInt(String(m[1] ?? ''), 10);
129
+ return Number.isFinite(n) ? n : undefined;
130
+ };
131
+ if (lname === 'exec_command') {
132
+ const cmd = pickString(/"(?:cmd|command)"\s*:\s*"([\s\S]*?)"\s*(?:,|})/i);
133
+ const workdir = pickString(/"(?:workdir|cwd)"\s*:\s*"([\s\S]*?)"\s*(?:,|})/i);
134
+ const timeout = pickNumber(/"(?:timeout_ms|timeout)"\s*:\s*(\d+)\s*(?:,|})/i);
135
+ if (cmd !== undefined)
136
+ out.cmd = cmd;
137
+ if (cmd !== undefined)
138
+ out.command = cmd;
139
+ if (workdir !== undefined)
140
+ out.workdir = workdir;
141
+ if (timeout !== undefined)
142
+ out.timeout_ms = timeout;
143
+ return Object.keys(out).length ? out : null;
144
+ }
145
+ if (lname === 'write_stdin') {
146
+ const sessionId = pickNumber(/"(?:session_id|sessionId)"\s*:\s*(\d+)\s*(?:,|})/i);
147
+ const chars = pickString(/"(?:chars|text|input|data)"\s*:\s*"([\s\S]*?)"\s*(?:,|})/i);
148
+ if (sessionId !== undefined)
149
+ out.session_id = sessionId;
150
+ if (chars !== undefined)
151
+ out.chars = chars;
152
+ return Object.keys(out).length ? out : null;
153
+ }
154
+ if (lname === 'apply_patch') {
155
+ const patch = pickString(/"(?:patch|text|input|instructions)"\s*:\s*"([\s\S]*?)"\s*(?:,|})/i);
156
+ if (patch !== undefined)
157
+ out.patch = patch;
158
+ return Object.keys(out).length ? out : null;
159
+ }
160
+ return null;
161
+ }
162
+ catch {
163
+ return null;
164
+ }
165
+ }
166
+ function extractToolCallEntriesFromUnknown(value) {
167
+ if (Array.isArray(value)) {
168
+ return value;
169
+ }
170
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
171
+ return [];
172
+ }
173
+ const rec = value;
174
+ if (Array.isArray(rec.tool_calls)) {
175
+ return rec.tool_calls;
176
+ }
177
+ if (typeof rec.tool_calls === 'string') {
178
+ const nested = tryParseJsonWithModelRepairs(rec.tool_calls);
179
+ return extractToolCallEntriesFromUnknown(nested);
180
+ }
181
+ return [];
182
+ }
183
+ function resolveJsonToolNameAliases(options) {
184
+ const merged = { ...DEFAULT_JSON_TOOL_NAME_ALIASES };
185
+ const raw = options?.jsonToolRepair?.toolNameAliases;
186
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {
187
+ return merged;
188
+ }
189
+ for (const [key, value] of Object.entries(raw)) {
190
+ const src = String(key || '').trim().toLowerCase();
191
+ const dst = String(value || '').trim().toLowerCase();
192
+ if (!src || !dst)
193
+ continue;
194
+ merged[src] = dst;
195
+ }
196
+ return merged;
197
+ }
198
+ function resolveJsonToolArgAliases(toolName, options) {
199
+ const lname = String(toolName || '').trim().toLowerCase();
200
+ const merged = {};
201
+ const base = DEFAULT_JSON_TOOL_ARGUMENT_ALIASES[lname];
202
+ if (base && typeof base === 'object' && !Array.isArray(base)) {
203
+ for (const [target, paths] of Object.entries(base)) {
204
+ merged[target] = Array.isArray(paths) ? [...paths] : [];
205
+ }
206
+ }
207
+ const customRoot = options?.jsonToolRepair?.argumentAliases;
208
+ if (!customRoot || typeof customRoot !== 'object' || Array.isArray(customRoot)) {
209
+ return merged;
210
+ }
211
+ const custom = customRoot[lname];
212
+ if (!custom || typeof custom !== 'object' || Array.isArray(custom)) {
213
+ return merged;
214
+ }
215
+ for (const [target, paths] of Object.entries(custom)) {
216
+ if (!Array.isArray(paths))
217
+ continue;
218
+ merged[target] = paths.map((item) => String(item || '').trim()).filter((item) => item.length > 0);
219
+ }
220
+ return merged;
221
+ }
222
+ function hasNonEmptyAliasValue(value) {
223
+ if (value === undefined || value === null) {
224
+ return false;
225
+ }
226
+ if (typeof value === 'string') {
227
+ return value.trim().length > 0;
228
+ }
229
+ return true;
230
+ }
231
+ function readAliasPathValue(source, path) {
232
+ const trimmed = String(path || '').trim();
233
+ if (!trimmed) {
234
+ return undefined;
235
+ }
236
+ if (!trimmed.includes('.')) {
237
+ return source[trimmed];
238
+ }
239
+ const parts = trimmed.split('.').map((part) => part.trim()).filter((part) => part.length > 0);
240
+ if (!parts.length) {
241
+ return undefined;
242
+ }
243
+ let cursor = source;
244
+ for (const part of parts) {
245
+ if (!cursor || typeof cursor !== 'object' || Array.isArray(cursor)) {
246
+ return undefined;
247
+ }
248
+ cursor = cursor[part];
249
+ }
250
+ return cursor;
251
+ }
252
+ function applyJsonToolArgumentAliases(toolName, argsObj, options) {
253
+ const mapping = resolveJsonToolArgAliases(toolName, options);
254
+ for (const [target, candidates] of Object.entries(mapping)) {
255
+ if (!Array.isArray(candidates) || candidates.length === 0) {
256
+ continue;
257
+ }
258
+ const current = argsObj[target];
259
+ if (hasNonEmptyAliasValue(current)) {
260
+ continue;
261
+ }
262
+ for (const candidate of candidates) {
263
+ const picked = readAliasPathValue(argsObj, candidate);
264
+ if (!hasNonEmptyAliasValue(picked)) {
265
+ continue;
266
+ }
267
+ argsObj[target] = picked;
268
+ break;
269
+ }
270
+ }
271
+ }
272
+ function canonicalizeJsonToolName(value, options) {
273
+ if (typeof value !== 'string') {
274
+ return null;
275
+ }
276
+ let name = value.trim();
277
+ if (!name) {
278
+ return null;
279
+ }
280
+ if (name.startsWith('functions.')) {
281
+ name = name.slice('functions.'.length);
282
+ }
283
+ const lowered = name.toLowerCase();
284
+ const aliasMap = resolveJsonToolNameAliases(options);
285
+ const canonical = aliasMap[lowered] ?? lowered;
286
+ return KNOWN_TOOLS.has(canonical) ? canonical : null;
287
+ }
288
+ function coerceToolCallArgsObject(raw) {
289
+ if (raw && typeof raw === 'object' && !Array.isArray(raw)) {
290
+ return { ...raw };
291
+ }
292
+ if (typeof raw === 'string') {
293
+ const parsed = tryParseJsonWithModelRepairs(raw);
294
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
295
+ return { ...parsed };
296
+ }
297
+ return {};
298
+ }
299
+ if (Array.isArray(raw)) {
300
+ const command = raw.map((entry) => String(entry ?? '')).join(' ').trim();
301
+ return command ? { command } : {};
302
+ }
303
+ return {};
304
+ }
305
+ function normalizeJsonToolArgs(toolName, rawArgs, options) {
306
+ const lname = String(toolName || '').toLowerCase();
307
+ const argsObj = coerceToolCallArgsObject(rawArgs);
308
+ applyJsonToolArgumentAliases(lname, argsObj, options);
309
+ if (lname === 'exec_command') {
310
+ const cmd = coerceCommandValueToString(argsObj.cmd);
311
+ if (!cmd) {
312
+ return null;
313
+ }
314
+ argsObj.cmd = cmd;
315
+ argsObj.command = cmd;
316
+ if (typeof argsObj.workdir === 'string') {
317
+ argsObj.workdir = String(argsObj.workdir).trim();
318
+ }
319
+ }
320
+ if (lname === 'write_stdin') {
321
+ if (argsObj.chars !== undefined && argsObj.chars !== null) {
322
+ argsObj.chars = String(argsObj.chars);
323
+ }
324
+ if (argsObj.session_id !== undefined && argsObj.session_id !== null) {
325
+ const sid = Number.parseInt(String(argsObj.session_id), 10);
326
+ if (Number.isFinite(sid)) {
327
+ argsObj.session_id = sid;
328
+ }
329
+ }
330
+ }
331
+ if (lname === 'apply_patch') {
332
+ if (typeof argsObj.patch === 'string') {
333
+ argsObj.patch = String(argsObj.patch);
334
+ }
335
+ }
336
+ const filtered = filterArgsForTool(lname, argsObj);
337
+ if (lname === 'exec_command') {
338
+ const cmd = typeof filtered?.cmd === 'string' ? String(filtered.cmd).trim() : '';
339
+ if (!cmd) {
340
+ return null;
341
+ }
342
+ }
343
+ if (lname === 'write_stdin') {
344
+ const sid = filtered?.session_id;
345
+ if (sid === undefined || sid === null || String(sid).trim().length === 0) {
346
+ return null;
347
+ }
348
+ }
349
+ if (lname === 'apply_patch') {
350
+ const patch = typeof filtered?.patch === 'string' ? String(filtered.patch).trim() : '';
351
+ if (!patch) {
352
+ return null;
353
+ }
354
+ }
355
+ return filtered;
356
+ }
357
+ function normalizeJsonToolCallEntry(entry, options) {
358
+ if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
359
+ return null;
360
+ }
361
+ const rec = entry;
362
+ const fn = rec.function && typeof rec.function === 'object' && !Array.isArray(rec.function)
363
+ ? rec.function
364
+ : undefined;
365
+ const name = canonicalizeJsonToolName(rec.name ?? fn?.name, options);
366
+ if (!name) {
367
+ return null;
368
+ }
369
+ const argsSource = rec.input !== undefined
370
+ ? rec.input
371
+ : rec.arguments !== undefined
372
+ ? rec.arguments
373
+ : fn?.arguments !== undefined
374
+ ? fn.arguments
375
+ : fn?.input;
376
+ const argsObj = normalizeJsonToolArgs(name, argsSource, options);
377
+ if (!argsObj) {
378
+ return null;
379
+ }
380
+ let args = '{}';
381
+ try {
382
+ args = JSON.stringify(argsObj);
383
+ }
384
+ catch {
385
+ args = '{}';
386
+ }
387
+ const id = typeof rec.call_id === 'string' && rec.call_id.trim().length
388
+ ? rec.call_id.trim()
389
+ : typeof rec.id === 'string' && rec.id.trim().length
390
+ ? rec.id.trim()
391
+ : genToolCallId();
392
+ return { id, name, args };
393
+ }
394
+ function extractBalancedJsonObjectAt(text, startIndex) {
395
+ if (startIndex < 0 || startIndex >= text.length || text[startIndex] !== '{') {
396
+ return null;
397
+ }
398
+ let depth = 0;
399
+ let inString = false;
400
+ let escaped = false;
401
+ for (let i = startIndex; i < text.length; i += 1) {
402
+ const ch = text[i] ?? '';
403
+ if (inString) {
404
+ if (escaped) {
405
+ escaped = false;
406
+ continue;
407
+ }
408
+ if (ch === '\\') {
409
+ escaped = true;
410
+ continue;
411
+ }
412
+ if (ch === '"') {
413
+ inString = false;
414
+ }
415
+ continue;
416
+ }
417
+ if (ch === '"') {
418
+ inString = true;
419
+ continue;
420
+ }
421
+ if (ch === '{') {
422
+ depth += 1;
423
+ continue;
424
+ }
425
+ if (ch === '}') {
426
+ depth -= 1;
427
+ if (depth === 0) {
428
+ return text.slice(startIndex, i + 1);
429
+ }
430
+ }
431
+ }
432
+ return null;
433
+ }
434
+ function collectEmbeddedToolCallObjects(text) {
435
+ const out = [];
436
+ const seen = new Set();
437
+ const quoteRanges = [];
438
+ {
439
+ const lower = text.toLowerCase();
440
+ let cursor = 0;
441
+ while (cursor < lower.length) {
442
+ const open = lower.indexOf('<quote>', cursor);
443
+ if (open < 0)
444
+ break;
445
+ const close = lower.indexOf('</quote>', open + '<quote>'.length);
446
+ if (close < 0)
447
+ break;
448
+ quoteRanges.push({ start: open, end: close + '</quote>'.length });
449
+ cursor = close + '</quote>'.length;
450
+ }
451
+ }
452
+ const isInsideQuoteRange = (index) => quoteRanges.some((range) => index >= range.start && index < range.end);
453
+ for (let i = 0; i < text.length; i += 1) {
454
+ if (text[i] !== '{') {
455
+ continue;
456
+ }
457
+ if (isInsideQuoteRange(i)) {
458
+ continue;
459
+ }
460
+ const objectText = extractBalancedJsonObjectAt(text, i);
461
+ if (!objectText) {
462
+ continue;
463
+ }
464
+ const trimmed = objectText.trim();
465
+ if (trimmed.length > 0 &&
466
+ /["']tool_calls["']\s*:/.test(trimmed) &&
467
+ !seen.has(trimmed)) {
468
+ seen.add(trimmed);
469
+ out.push(trimmed);
470
+ }
471
+ }
472
+ return out;
473
+ }
474
+ function decodeJsonEscapes(raw) {
475
+ return String(raw || '')
476
+ .replace(/\\r\\n/g, '\n')
477
+ .replace(/\\n/g, '\n')
478
+ .replace(/\\r/g, '\n')
479
+ .replace(/\\t/g, '\t')
480
+ .replace(/\\"/g, '"');
481
+ }
482
+ function extractPossiblyBrokenQuotedValue(text, keys) {
483
+ for (const key of keys) {
484
+ const re = new RegExp(`"${key}"\\s*:\\s*"`, 'ig');
485
+ let match;
486
+ while ((match = re.exec(text)) !== null) {
487
+ const start = match.index + match[0].length;
488
+ let escaped = false;
489
+ for (let i = start; i < text.length; i += 1) {
490
+ const ch = text[i] ?? '';
491
+ if (escaped) {
492
+ escaped = false;
493
+ continue;
494
+ }
495
+ if (ch === '\\') {
496
+ escaped = true;
497
+ continue;
498
+ }
499
+ if (ch === '"') {
500
+ return decodeJsonEscapes(text.slice(start, i));
501
+ }
502
+ }
503
+ return decodeJsonEscapes(text.slice(start));
504
+ }
505
+ }
506
+ return null;
507
+ }
508
+ function salvageToolCallFromBrokenJsonText(candidate, options) {
509
+ const rawName = candidate.match(/"name"\s*:\s*"([^"]+)"/i)?.[1];
510
+ const canonicalName = canonicalizeJsonToolName(rawName, options);
511
+ if (!canonicalName) {
512
+ return null;
513
+ }
514
+ let args = null;
515
+ if (canonicalName === 'exec_command') {
516
+ const cmd = extractPossiblyBrokenQuotedValue(candidate, ['cmd', 'command', 'script', 'toon']);
517
+ if (cmd && cmd.trim().length) {
518
+ args = { cmd, command: cmd };
519
+ }
520
+ }
521
+ if (!args) {
522
+ args = salvageToolArgsFromRawText(canonicalName, candidate);
523
+ }
524
+ if (!args) {
525
+ return null;
526
+ }
527
+ const normalizedArgs = normalizeJsonToolArgs(canonicalName, args, options);
528
+ if (!normalizedArgs) {
529
+ return null;
530
+ }
531
+ return {
532
+ id: genToolCallId(),
533
+ name: canonicalName,
534
+ args: JSON.stringify(normalizedArgs)
535
+ };
536
+ }
537
+ export function extractJsonToolCallsFromText(text, options) {
538
+ try {
539
+ if (typeof text !== 'string' || !text.trim()) {
540
+ return null;
541
+ }
542
+ const candidates = [];
543
+ const seenCandidates = new Set();
544
+ const addCandidate = (raw) => {
545
+ const trimmed = String(raw || '').trim();
546
+ if (!trimmed || seenCandidates.has(trimmed)) {
547
+ return;
548
+ }
549
+ seenCandidates.add(trimmed);
550
+ candidates.push(trimmed);
551
+ const decoded = decodeJsonEscapes(trimmed).trim();
552
+ if (!decoded || decoded === trimmed || seenCandidates.has(decoded)) {
553
+ return;
554
+ }
555
+ seenCandidates.add(decoded);
556
+ candidates.push(decoded);
557
+ };
558
+ addCandidate(text);
559
+ const fenceRe = /```(?:json|tool_call|tool_calls|function_call)?\s*([\s\S]*?)\s*```/gi;
560
+ let fm;
561
+ while ((fm = fenceRe.exec(text)) !== null) {
562
+ const body = String(fm[1] || '').trim();
563
+ if (body) {
564
+ addCandidate(body);
565
+ }
566
+ }
567
+ for (const embedded of collectEmbeddedToolCallObjects(text)) {
568
+ addCandidate(embedded);
569
+ }
570
+ const decodedText = decodeJsonEscapes(text);
571
+ if (decodedText && decodedText !== text) {
572
+ for (const embedded of collectEmbeddedToolCallObjects(decodedText)) {
573
+ addCandidate(embedded);
574
+ }
575
+ }
576
+ const out = [];
577
+ const seen = new Set();
578
+ const pushEntry = (rawEntry) => {
579
+ const normalized = normalizeJsonToolCallEntry(rawEntry, options);
580
+ if (!normalized) {
581
+ return;
582
+ }
583
+ const key = `${normalized.name}:${normalized.args}`;
584
+ if (seen.has(key)) {
585
+ return;
586
+ }
587
+ seen.add(key);
588
+ out.push(normalized);
589
+ };
590
+ for (const candidate of candidates) {
591
+ const parsed = tryParseJsonWithModelRepairs(candidate);
592
+ if (parsed !== null) {
593
+ for (const entry of extractToolCallEntriesFromUnknown(parsed)) {
594
+ pushEntry(entry);
595
+ }
596
+ }
597
+ if (out.length > 0) {
598
+ continue;
599
+ }
600
+ const standaloneWrapper = candidate.match(/^\s*\{\s*["']tool_calls["']\s*:\s*(\[[\s\S]*\])\s*\}\s*$/);
601
+ if (standaloneWrapper?.[1]) {
602
+ const wrapped = `{"tool_calls":${standaloneWrapper[1]}}`;
603
+ const parsedWrapped = tryParseJsonWithModelRepairs(wrapped);
604
+ if (parsedWrapped !== null) {
605
+ for (const entry of extractToolCallEntriesFromUnknown(parsedWrapped)) {
606
+ pushEntry(entry);
607
+ }
608
+ }
609
+ }
610
+ }
611
+ // Last-resort salvage should run only when normal JSON extraction found nothing.
612
+ if (out.length === 0) {
613
+ for (const candidate of candidates) {
614
+ const lower = candidate.toLowerCase();
615
+ if (lower.includes('<quote>') && lower.includes('</quote>')) {
616
+ continue;
617
+ }
618
+ const salvaged = salvageToolCallFromBrokenJsonText(candidate, options);
619
+ if (!salvaged) {
620
+ continue;
621
+ }
622
+ pushEntry({
623
+ id: salvaged.id,
624
+ name: salvaged.name,
625
+ function: {
626
+ name: salvaged.name,
627
+ arguments: salvaged.args
628
+ }
629
+ });
630
+ }
631
+ }
632
+ return out.length ? out : null;
633
+ }
634
+ catch {
635
+ return null;
636
+ }
637
+ }
@@ -0,0 +1,21 @@
1
+ export declare const KNOWN_TOOLS: Set<string>;
2
+ export type JsonToolArgumentAliasMap = Record<string, string[]>;
3
+ export type JsonToolRepairConfig = {
4
+ toolNameAliases?: Record<string, string>;
5
+ argumentAliases?: Record<string, JsonToolArgumentAliasMap>;
6
+ };
7
+ export type TextMarkupNormalizeOptions = {
8
+ jsonToolRepair?: JsonToolRepairConfig;
9
+ };
10
+ export type ToolCallLite = {
11
+ id?: string;
12
+ name: string;
13
+ args: string;
14
+ };
15
+ export declare function genToolCallId(): string;
16
+ export declare function normalizeKey(raw: string): string;
17
+ export declare function readDefaultWorkdirFromEnv(): string | undefined;
18
+ export declare function filterArgsForTool(name: string, args: Record<string, unknown>): Record<string, unknown>;
19
+ export declare function tryParseJsonValue(text: string): unknown | null;
20
+ export declare function tryParsePrimitiveValue(text: string): unknown;
21
+ export declare function coerceCommandValueToString(value: unknown): string;