@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,602 @@
1
+ import { isImagePath } from '../media.js';
2
+ import { KNOWN_TOOLS, coerceCommandValueToString, filterArgsForTool, genToolCallId, normalizeKey, readDefaultWorkdirFromEnv, tryParseJsonValue, tryParsePrimitiveValue } from './extractors-shared.js';
3
+ function applyToolInnerField(lname, argsObj, rawKey, rawValInput) {
4
+ const key = normalizeKey(rawKey).toLowerCase();
5
+ if (!key || key === 'requires_approval') {
6
+ return;
7
+ }
8
+ const rawVal = String(rawValInput ?? '');
9
+ const value = tryParsePrimitiveValue(rawVal);
10
+ if (lname === 'exec_command' && (key === 'command' || key === 'cmd')) {
11
+ const cmd = coerceCommandValueToString(value);
12
+ if (cmd.trim().length) {
13
+ argsObj.cmd = cmd;
14
+ argsObj.command = cmd;
15
+ }
16
+ return;
17
+ }
18
+ if (lname === 'exec_command' && (key === 'cwd' || key === 'workdir')) {
19
+ const wd = String(value ?? rawVal).trim();
20
+ if (wd)
21
+ argsObj.workdir = wd;
22
+ return;
23
+ }
24
+ if (lname === 'write_stdin') {
25
+ if (key === 'input' || key === 'data' || key === 'chars' || key === 'text') {
26
+ argsObj.chars = rawVal;
27
+ return;
28
+ }
29
+ if (key === 'session_id') {
30
+ const n = Number.parseInt(String(value), 10);
31
+ argsObj.session_id = Number.isFinite(n) ? n : value;
32
+ return;
33
+ }
34
+ }
35
+ if (lname === 'apply_patch' && (key === 'patch' || key === 'input' || key === 'text' || key === 'instructions')) {
36
+ const patchText = typeof value === 'string' ? value : rawVal;
37
+ if (typeof patchText === 'string' && patchText.trim().length) {
38
+ argsObj.patch = patchText;
39
+ }
40
+ return;
41
+ }
42
+ argsObj[key] = value;
43
+ }
44
+ // Extract <tool:NAME>...</tool:NAME> blocks used by some tool-mode outputs.
45
+ export function extractToolNamespaceXmlBlocksFromText(text) {
46
+ try {
47
+ if (typeof text !== 'string' || !text)
48
+ return null;
49
+ const hasOpenTag = text.includes('<tool:');
50
+ const hasCloseTag = /<\/\s*tool:\s*[A-Za-z0-9_]+\s*>/i.test(text);
51
+ const hasToolPrefix = /(?:^|\n)\s*(?:[•*+-]\s*)?tool:[A-Za-z0-9_]+/i.test(text);
52
+ if (!hasOpenTag && !(hasCloseTag && hasToolPrefix)) {
53
+ return null;
54
+ }
55
+ const out = [];
56
+ const blockRe = /<\s*tool:([A-Za-z0-9_]+)\s*>([\s\S]*?)<\/\s*tool:\s*\1\s*>/gi;
57
+ let bm;
58
+ while ((bm = blockRe.exec(text)) !== null) {
59
+ const rawName = String(bm[1] || '').trim();
60
+ const lname = rawName.toLowerCase();
61
+ if (!lname || !KNOWN_TOOLS.has(lname))
62
+ continue;
63
+ const inner = String(bm[2] || '');
64
+ const argsObj = {};
65
+ const kvRe = /<\s*([A-Za-z_][A-Za-z0-9_]*)\s*>([\s\S]*?)<\/\s*\1\s*>/g;
66
+ let km;
67
+ while ((km = kvRe.exec(inner)) !== null) {
68
+ const rawKey = String(km[1] || '').trim();
69
+ const rawVal = String(km[2] ?? '');
70
+ applyToolInnerField(lname, argsObj, rawKey, rawVal);
71
+ }
72
+ // Tolerate malformed parameter blocks like:
73
+ // <parameter name="command">...</command>
74
+ // and the normal form:
75
+ // <parameter name="command">...</parameter>
76
+ const paramRe = /<\s*parameter\s+name\s*=\s*"([^">]+)"\s*>([\s\S]*?)<\/\s*(?:parameter|\1)\s*>/gi;
77
+ let pm;
78
+ while ((pm = paramRe.exec(inner)) !== null) {
79
+ const rawKey = String(pm[1] || '').trim();
80
+ const rawVal = String(pm[2] ?? '');
81
+ applyToolInnerField(lname, argsObj, rawKey, rawVal);
82
+ }
83
+ const filtered = filterArgsForTool(lname, argsObj);
84
+ if (lname === 'exec_command') {
85
+ const cmd = typeof filtered?.cmd === 'string' ? String(filtered.cmd).trim() : '';
86
+ if (!cmd)
87
+ continue;
88
+ }
89
+ if (lname === 'write_stdin') {
90
+ const sid = filtered?.session_id;
91
+ if (sid === undefined || sid === null || String(sid).trim().length === 0)
92
+ continue;
93
+ }
94
+ if (lname === 'apply_patch') {
95
+ const patchText = typeof filtered?.patch === 'string' ? String(filtered.patch).trim() : '';
96
+ if (!patchText)
97
+ continue;
98
+ }
99
+ let argsStr = '{}';
100
+ try {
101
+ argsStr = JSON.stringify(filtered);
102
+ }
103
+ catch {
104
+ argsStr = '{}';
105
+ }
106
+ out.push({ id: genToolCallId(), name: lname, args: argsStr });
107
+ }
108
+ // Broken variant (seen in the wild):
109
+ // tool:exec_command (tool:exec_command)
110
+ // <command>...</command>
111
+ // </tool:exec_command>
112
+ const prefixBlockRe = /(?:^|\n)\s*(?:[•*+-]\s*)?tool:([A-Za-z0-9_]+)[^\n]*\n([\s\S]*?)<\/\s*tool:\s*\1\s*>/gi;
113
+ let pm;
114
+ while ((pm = prefixBlockRe.exec(text)) !== null) {
115
+ const rawName = String(pm[1] || '').trim();
116
+ const lname = rawName.toLowerCase();
117
+ if (!lname || !KNOWN_TOOLS.has(lname))
118
+ continue;
119
+ const inner = String(pm[2] || '');
120
+ const argsObj = {};
121
+ const kvRe = /<\s*([A-Za-z_][A-Za-z0-9_]*)\s*>([\s\S]*?)<\/\s*\1\s*>/g;
122
+ let km;
123
+ while ((km = kvRe.exec(inner)) !== null) {
124
+ const rawKey = String(km[1] || '').trim();
125
+ const rawVal = String(km[2] ?? '');
126
+ applyToolInnerField(lname, argsObj, rawKey, rawVal);
127
+ }
128
+ const paramRe = /<\s*parameter\s+name\s*=\s*"([^">]+)"\s*>([\s\S]*?)<\/\s*(?:parameter|\1)\s*>/gi;
129
+ let pm2;
130
+ while ((pm2 = paramRe.exec(inner)) !== null) {
131
+ const rawKey = String(pm2[1] || '').trim();
132
+ const rawVal = String(pm2[2] ?? '');
133
+ applyToolInnerField(lname, argsObj, rawKey, rawVal);
134
+ }
135
+ const filtered = filterArgsForTool(lname, argsObj);
136
+ if (lname === 'exec_command') {
137
+ const cmd = typeof filtered?.cmd === 'string' ? String(filtered.cmd).trim() : '';
138
+ if (!cmd)
139
+ continue;
140
+ }
141
+ if (lname === 'write_stdin') {
142
+ const sid = filtered?.session_id;
143
+ if (sid === undefined || sid === null || String(sid).trim().length === 0)
144
+ continue;
145
+ }
146
+ if (lname === 'apply_patch') {
147
+ const patchText = typeof filtered?.patch === 'string' ? String(filtered.patch).trim() : '';
148
+ if (!patchText)
149
+ continue;
150
+ }
151
+ let argsStr = '{}';
152
+ try {
153
+ argsStr = JSON.stringify(filtered);
154
+ }
155
+ catch {
156
+ argsStr = '{}';
157
+ }
158
+ out.push({ id: genToolCallId(), name: lname, args: argsStr });
159
+ }
160
+ return out.length ? out : null;
161
+ }
162
+ catch {
163
+ return null;
164
+ }
165
+ }
166
+ // Extract Anthropic/GLM-style XML tool tags that use <parameter name="...">...</parameter>.
167
+ export function extractParameterXmlToolsFromText(text) {
168
+ try {
169
+ if (typeof text !== 'string' || !text)
170
+ return null;
171
+ const out = [];
172
+ // Some providers/models emit mismatched closing tags like </func_call>; accept a small set of known variants.
173
+ const toolRe = /<\s*(exec_command)\s*>([\s\S]*?)<\/\s*(?:\1|func_call|tool_call)\s*>/gi;
174
+ let tm;
175
+ while ((tm = toolRe.exec(text)) !== null) {
176
+ const rawName = (tm[1] || '').trim();
177
+ const inner = (tm[2] || '').trim();
178
+ if (!rawName || !inner)
179
+ continue;
180
+ const lname = rawName.toLowerCase();
181
+ const argsObj = {};
182
+ const paramRe = /<\s*parameter\s+name\s*=\s*"([^"]+)"\s*>([\s\S]*?)<\/\s*parameter\s*>/gi;
183
+ let pm;
184
+ while ((pm = paramRe.exec(inner)) !== null) {
185
+ const rawKey = (pm[1] || '').trim();
186
+ const key = normalizeKey(rawKey);
187
+ if (!key)
188
+ continue;
189
+ const rawVal = (pm[2] || '').trim();
190
+ if (!rawVal)
191
+ continue;
192
+ const parsed = tryParseJsonValue(rawVal);
193
+ if (key.toLowerCase() === 'command' || key.toLowerCase() === 'cmd') {
194
+ const cmd = coerceCommandValueToString(parsed ?? rawVal);
195
+ if (cmd.trim().length) {
196
+ argsObj.cmd = cmd;
197
+ argsObj.command = cmd;
198
+ }
199
+ continue;
200
+ }
201
+ if (key.toLowerCase() === 'workdir') {
202
+ argsObj.workdir = rawVal;
203
+ continue;
204
+ }
205
+ argsObj[key] = parsed ?? rawVal;
206
+ }
207
+ const filtered = filterArgsForTool(lname, argsObj);
208
+ if (!filtered || typeof filtered !== 'object' || Array.isArray(filtered))
209
+ continue;
210
+ const cmd = typeof filtered.cmd === 'string' ? String(filtered.cmd).trim() : '';
211
+ if (!cmd)
212
+ continue;
213
+ // If caller didn't provide workdir, fallback to a conservative env-derived workdir.
214
+ try {
215
+ if (!filtered.workdir) {
216
+ const envWorkdir = readDefaultWorkdirFromEnv();
217
+ if (envWorkdir)
218
+ filtered.workdir = envWorkdir;
219
+ }
220
+ }
221
+ catch {
222
+ /* ignore */
223
+ }
224
+ let argsStr = '{}';
225
+ try {
226
+ argsStr = JSON.stringify(filtered);
227
+ }
228
+ catch {
229
+ argsStr = '{}';
230
+ }
231
+ out.push({
232
+ id: genToolCallId(),
233
+ name: lname,
234
+ args: argsStr
235
+ });
236
+ }
237
+ return out.length ? out : null;
238
+ }
239
+ catch {
240
+ return null;
241
+ }
242
+ }
243
+ function applyInvokeParameterAliases(toolName, argsObj) {
244
+ try {
245
+ const lname = String(toolName || '').toLowerCase();
246
+ if (lname === 'write_stdin') {
247
+ // Some models emit `data` / `wait` instead of our canonical `chars` / `yield_time_ms`.
248
+ if (Object.prototype.hasOwnProperty.call(argsObj, 'data')) {
249
+ const data = argsObj.data;
250
+ if (!Object.prototype.hasOwnProperty.call(argsObj, 'chars') && !Object.prototype.hasOwnProperty.call(argsObj, 'text')) {
251
+ argsObj.chars = data == null ? '' : String(data);
252
+ }
253
+ delete argsObj.data;
254
+ }
255
+ if (Object.prototype.hasOwnProperty.call(argsObj, 'wait') && !Object.prototype.hasOwnProperty.call(argsObj, 'yield_time_ms')) {
256
+ const wait = argsObj.wait;
257
+ let ms;
258
+ if (typeof wait === 'number' && Number.isFinite(wait)) {
259
+ // Heuristic: small values are usually seconds; large values are likely already ms.
260
+ ms = wait <= 1000 ? Math.round(wait * 1000) : Math.round(wait);
261
+ }
262
+ else if (typeof wait === 'string' && wait.trim().length) {
263
+ const num = Number(wait.trim());
264
+ if (Number.isFinite(num)) {
265
+ ms = num <= 1000 ? Math.round(num * 1000) : Math.round(num);
266
+ }
267
+ }
268
+ if (typeof ms === 'number' && Number.isFinite(ms) && ms >= 0) {
269
+ argsObj.yield_time_ms = ms;
270
+ }
271
+ delete argsObj.wait;
272
+ }
273
+ }
274
+ }
275
+ catch {
276
+ // ignore
277
+ }
278
+ }
279
+ // Extract <function_calls><invoke name="...">...</invoke> blocks.
280
+ export function extractInvokeToolsFromText(text) {
281
+ try {
282
+ if (typeof text !== 'string' || !text)
283
+ return null;
284
+ const out = [];
285
+ const invokeRe = /<\s*invoke\s+name\s*=\s*"([^">]+)"\s*>([\s\S]*?)<\/\s*invoke\s*>/gi;
286
+ let im;
287
+ while ((im = invokeRe.exec(text)) !== null) {
288
+ const rawName = (im[1] || '').trim();
289
+ const inner = (im[2] || '').trim();
290
+ if (!rawName || !inner)
291
+ continue;
292
+ const lname = rawName.toLowerCase();
293
+ const argsObj = {};
294
+ const paramRe = /<\s*parameter\s+name\s*=\s*"([^">]+)"\s*>([\s\S]*?)<\/\s*parameter\s*>/gi;
295
+ let pm;
296
+ while ((pm = paramRe.exec(inner)) !== null) {
297
+ const rawKey = (pm[1] || '').trim();
298
+ const key = normalizeKey(rawKey);
299
+ if (!key)
300
+ continue;
301
+ const rawVal = (pm[2] ?? '').toString();
302
+ const value = tryParsePrimitiveValue(rawVal);
303
+ if (lname === 'exec_command' && (key.toLowerCase() === 'command' || key.toLowerCase() === 'cmd')) {
304
+ const cmd = coerceCommandValueToString(value);
305
+ if (cmd.trim().length) {
306
+ argsObj.cmd = cmd;
307
+ argsObj.command = cmd;
308
+ }
309
+ continue;
310
+ }
311
+ argsObj[key] = value;
312
+ }
313
+ applyInvokeParameterAliases(lname, argsObj);
314
+ const filtered = filterArgsForTool(lname, argsObj);
315
+ let argsStr = '{}';
316
+ try {
317
+ argsStr = JSON.stringify(filtered);
318
+ }
319
+ catch {
320
+ argsStr = '{}';
321
+ }
322
+ out.push({ id: genToolCallId(), name: lname, args: argsStr });
323
+ }
324
+ // Some Gemini CLI / antigravity variants emit a looser XML shape.
325
+ if (out.length === 0) {
326
+ const invokeBareRe = /<\s*invoke\s*>([\s\S]*?)<\/\s*invoke\s*>/gi;
327
+ let bm;
328
+ while ((bm = invokeBareRe.exec(text)) !== null) {
329
+ const inner = (bm[1] || '').trim();
330
+ if (!inner)
331
+ continue;
332
+ const toolNameMatch = /<\s*(?:tool_name|toolname|tool)\s*>\s*([\s\S]*?)\s*<\/\s*(?:tool_name|toolname|tool)\s*>/i.exec(inner);
333
+ const rawName = (toolNameMatch?.[1] || '').trim();
334
+ if (!rawName)
335
+ continue;
336
+ const lname = rawName.toLowerCase();
337
+ if (!KNOWN_TOOLS.has(lname))
338
+ continue;
339
+ const argsObj = {};
340
+ const paramsMatch = /<\s*parameters\s*>([\s\S]*?)<\/\s*parameters\s*>/i.exec(inner);
341
+ if (paramsMatch && paramsMatch[1]) {
342
+ const paramsInner = String(paramsMatch[1] || '');
343
+ const kvRe = /<\s*([A-Za-z_][A-Za-z0-9_]*)\s*>([\s\S]*?)<\/\s*\1\s*>/g;
344
+ let km;
345
+ while ((km = kvRe.exec(paramsInner)) !== null) {
346
+ const rawKey = (km[1] || '').trim();
347
+ const key = normalizeKey(rawKey);
348
+ if (!key)
349
+ continue;
350
+ const rawVal = (km[2] ?? '').toString();
351
+ const value = tryParsePrimitiveValue(rawVal);
352
+ if (lname === 'exec_command' && (key.toLowerCase() === 'command' || key.toLowerCase() === 'cmd')) {
353
+ const cmd = coerceCommandValueToString(value);
354
+ if (cmd.trim().length) {
355
+ argsObj.cmd = cmd;
356
+ argsObj.command = cmd;
357
+ }
358
+ continue;
359
+ }
360
+ argsObj[key] = value;
361
+ }
362
+ }
363
+ applyInvokeParameterAliases(lname, argsObj);
364
+ const filtered = filterArgsForTool(lname, argsObj);
365
+ let argsStr = '{}';
366
+ try {
367
+ argsStr = JSON.stringify(filtered);
368
+ }
369
+ catch {
370
+ argsStr = '{}';
371
+ }
372
+ out.push({ id: genToolCallId(), name: lname, args: argsStr });
373
+ }
374
+ }
375
+ return out.length ? out : null;
376
+ }
377
+ catch {
378
+ return null;
379
+ }
380
+ }
381
+ // Extract XML-like <tool_call> blocks used by some agents.
382
+ export function extractXMLToolCallsFromText(text) {
383
+ try {
384
+ if (typeof text !== 'string' || !text)
385
+ return null;
386
+ const out = [];
387
+ const blockRe = /<tool_call[\s\S]*?>([\s\S]*?)<\/tool_call>/gi;
388
+ let bm;
389
+ while ((bm = blockRe.exec(text)) !== null) {
390
+ const inner = (bm[1] || '').trim();
391
+ if (!inner)
392
+ continue;
393
+ // 1) try function/name tags
394
+ let name = '';
395
+ const fnTag = inner.match(/<\s*(?:function|name)\s*>\s*([a-zA-Z0-9_.-]+)\s*<\/(?:function|name)\s*>/i);
396
+ if (fnTag && fnTag[1]) {
397
+ name = String(fnTag[1]).trim();
398
+ }
399
+ else {
400
+ // 2) else pick the first non-empty line without tags as the name
401
+ const lines = inner.split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
402
+ const candidate = lines.find((l) => !l.startsWith('<') && /^[a-zA-Z0-9_.-]+$/.test(l));
403
+ if (candidate)
404
+ name = candidate;
405
+ }
406
+ if (!name)
407
+ continue;
408
+ const lname = String(name).toLowerCase();
409
+ // Collect arg_key/arg_value pairs
410
+ const argRe = /<\s*arg_key\s*>\s*([^<]+?)\s*<\/(?:arg_key)\s*>\s*<\s*arg_value\s*>\s*([\s\S]*?)\s*<\/(?:arg_value)\s*>/gi;
411
+ let am;
412
+ const argsObj = {};
413
+ while ((am = argRe.exec(inner)) !== null) {
414
+ const k = normalizeKey((am[1] || '').trim());
415
+ const vRaw = (am[2] || '').trim();
416
+ if (!k)
417
+ continue;
418
+ // If value looks like JSON array/object, parse; else keep as string
419
+ let v = vRaw;
420
+ if ((vRaw.startsWith('[') && vRaw.endsWith(']')) || (vRaw.startsWith('{') && vRaw.endsWith('}'))) {
421
+ try {
422
+ v = JSON.parse(vRaw);
423
+ }
424
+ catch {
425
+ v = vRaw;
426
+ }
427
+ }
428
+ argsObj[k] = v;
429
+ }
430
+ // If no args collected but inner contains JSON object, try as whole arguments
431
+ const hasAnyArg = Object.keys(argsObj).length > 0;
432
+ if (!hasAnyArg) {
433
+ const jsonMatch = inner.match(/\{[\s\S]*\}|\[[\s\S]*\]/);
434
+ if (jsonMatch) {
435
+ try {
436
+ const val = JSON.parse(jsonMatch[0]);
437
+ argsObj.arguments = val;
438
+ }
439
+ catch {
440
+ /* ignore */
441
+ }
442
+ }
443
+ }
444
+ const filtered = filterArgsForTool(lname, argsObj);
445
+ // Guard: view_image must have a valid image path
446
+ try {
447
+ if (lname === 'view_image') {
448
+ const p = filtered && typeof filtered === 'object' ? filtered.path : undefined;
449
+ if (!isImagePath(p)) {
450
+ continue;
451
+ }
452
+ }
453
+ }
454
+ catch {
455
+ /* ignore guard errors */
456
+ }
457
+ let argsStr = '{}';
458
+ try {
459
+ argsStr = JSON.stringify(filtered);
460
+ }
461
+ catch {
462
+ argsStr = '{}';
463
+ }
464
+ out.push({ id: genToolCallId(), name, args: argsStr });
465
+ }
466
+ // Fallback: loose XML variant (missing <tool_call> start).
467
+ try {
468
+ const pairRe = /<\s*arg_key\s*>\s*([^<]+?)\s*<\/\s*arg_key\s*>\s*<\s*arg_value\s*>\s*([\s\S]*?)\s*<\/\s*arg_value\s*>/gi;
469
+ let pm;
470
+ while ((pm = pairRe.exec(text)) !== null) {
471
+ const start = pm.index;
472
+ // find a likely function name on the immediately preceding non-empty line
473
+ let name = '';
474
+ try {
475
+ const before = text.slice(0, start);
476
+ const lines = before.split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
477
+ const cand = lines.length ? lines[lines.length - 1] : '';
478
+ if (/^[a-zA-Z0-9_.-]{2,}$/.test(cand))
479
+ name = cand;
480
+ }
481
+ catch {
482
+ /* ignore */
483
+ }
484
+ // 如果前一行抽不到合法函数名,但 arg_key 明显是 toon/command,
485
+ // 视为 CLI 通路下的 exec_command 工具。
486
+ const rawKey = (pm[1] || '').trim();
487
+ const normalizedKey = normalizeKey(rawKey).toLowerCase();
488
+ if (!name && (normalizedKey === 'toon' || normalizedKey === 'command')) {
489
+ name = 'exec_command';
490
+ }
491
+ if (!name)
492
+ continue;
493
+ const k = normalizeKey(rawKey);
494
+ const vRaw = (pm[2] || '').trim();
495
+ const argsObj = {};
496
+ if (k) {
497
+ let v = vRaw;
498
+ if ((vRaw.startsWith('[') && vRaw.endsWith(']')) || (vRaw.startsWith('{') && vRaw.endsWith('}'))) {
499
+ try {
500
+ v = JSON.parse(vRaw);
501
+ }
502
+ catch {
503
+ v = vRaw;
504
+ }
505
+ }
506
+ argsObj[k] = v;
507
+ }
508
+ const lname2 = String(name || '').toLowerCase();
509
+ const filtered2 = filterArgsForTool(lname2, argsObj);
510
+ // Guard: view_image must have a valid image path
511
+ try {
512
+ if (lname2 === 'view_image') {
513
+ const p = filtered2 && typeof filtered2 === 'object' ? filtered2.path : undefined;
514
+ if (!isImagePath(p)) {
515
+ continue;
516
+ }
517
+ }
518
+ }
519
+ catch {
520
+ /* ignore guard errors */
521
+ }
522
+ let argsStr = '{}';
523
+ try {
524
+ argsStr = JSON.stringify(filtered2);
525
+ }
526
+ catch {
527
+ argsStr = '{}';
528
+ }
529
+ out.push({ id: genToolCallId(), name, args: argsStr });
530
+ }
531
+ }
532
+ catch {
533
+ /* ignore */
534
+ }
535
+ return out.length ? out : null;
536
+ }
537
+ catch {
538
+ return null;
539
+ }
540
+ }
541
+ /**
542
+ * 提取简单 XML 形式的工具调用块,例如:
543
+ * <list_directory><path>/path</path><recursive>false</recursive></list_directory>
544
+ */
545
+ export function extractSimpleXmlToolsFromText(text) {
546
+ try {
547
+ if (typeof text !== 'string' || !text)
548
+ return null;
549
+ const out = [];
550
+ const blockRe = /<\s*([A-Za-z0-9_.-]+)\s*>([\s\S]*?)<\/\s*\1\s*>/gi;
551
+ let bm;
552
+ while ((bm = blockRe.exec(text)) !== null) {
553
+ const rawName = (bm[1] || '').trim();
554
+ const lname = rawName.toLowerCase();
555
+ if (!lname || lname === 'tool_call')
556
+ continue;
557
+ // 目前仅支持 list_directory,后续按需扩展
558
+ if (lname !== 'list_directory')
559
+ continue;
560
+ const inner = bm[2] || '';
561
+ const args = {};
562
+ const argRe = /<\s*([A-Za-z0-9_]+)\s*>([\s\S]*?)<\/\s*\1\s*>/gi;
563
+ let am;
564
+ while ((am = argRe.exec(inner)) !== null) {
565
+ const key = normalizeKey((am[1] || '').trim());
566
+ if (!key)
567
+ continue;
568
+ const rawVal = (am[2] || '').trim();
569
+ let v = rawVal;
570
+ if ((rawVal.startsWith('[') && rawVal.endsWith(']')) || (rawVal.startsWith('{') && rawVal.endsWith('}'))) {
571
+ try {
572
+ v = JSON.parse(rawVal);
573
+ }
574
+ catch {
575
+ v = rawVal;
576
+ }
577
+ }
578
+ else if (rawVal === 'true' || rawVal === 'false') {
579
+ v = rawVal === 'true';
580
+ }
581
+ args[key] = v;
582
+ }
583
+ const filtered = filterArgsForTool(lname, args);
584
+ let argsStr = '{}';
585
+ try {
586
+ argsStr = JSON.stringify(filtered);
587
+ }
588
+ catch {
589
+ argsStr = '{}';
590
+ }
591
+ out.push({
592
+ id: genToolCallId(),
593
+ name: lname,
594
+ args: argsStr
595
+ });
596
+ }
597
+ return out.length ? out : null;
598
+ }
599
+ catch {
600
+ return null;
601
+ }
602
+ }
@@ -0,0 +1,5 @@
1
+ export type { JsonToolRepairConfig, TextMarkupNormalizeOptions, ToolCallLite } from './extractors-shared.js';
2
+ export { extractJsonToolCallsFromText } from './extractors-json.js';
3
+ export { extractInvokeToolsFromText, extractParameterXmlToolsFromText, extractSimpleXmlToolsFromText, extractToolNamespaceXmlBlocksFromText, extractXMLToolCallsFromText } from './extractors-xml.js';
4
+ export { extractApplyPatchCallsFromText } from './extractors-apply-patch.js';
5
+ export { extractBareExecCommandFromText, extractExecuteBlocksFromText, extractExploredListDirectoryCallsFromText, extractQwenToolCallTokensFromText } from './extractors-transcript.js';
@@ -0,0 +1,4 @@
1
+ export { extractJsonToolCallsFromText } from './extractors-json.js';
2
+ export { extractInvokeToolsFromText, extractParameterXmlToolsFromText, extractSimpleXmlToolsFromText, extractToolNamespaceXmlBlocksFromText, extractXMLToolCallsFromText } from './extractors-xml.js';
3
+ export { extractApplyPatchCallsFromText } from './extractors-apply-patch.js';
4
+ export { extractBareExecCommandFromText, extractExecuteBlocksFromText, extractExploredListDirectoryCallsFromText, extractQwenToolCallTokensFromText } from './extractors-transcript.js';
@@ -0,0 +1,2 @@
1
+ import type { TextMarkupNormalizeOptions } from './extractors.js';
2
+ export declare function normalizeAssistantTextToToolCalls(message: Record<string, any>, options?: TextMarkupNormalizeOptions): Record<string, any>;