@jsonstudio/llms 0.6.2979 → 0.6.3238

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 (246) hide show
  1. package/dist/conversion/args-mapping.js +8 -0
  2. package/dist/conversion/{shared/bridge-actions.js → bridge-actions.js} +2 -1
  3. package/dist/conversion/{shared/bridge-id-utils.js → bridge-id-utils.js} +1 -1
  4. package/dist/conversion/{shared/bridge-instructions.js → bridge-instructions.js} +1 -1
  5. package/dist/conversion/{shared/bridge-message-utils.d.ts → bridge-message-utils.d.ts} +1 -1
  6. package/dist/conversion/{shared/bridge-message-utils.js → bridge-message-utils.js} +5 -149
  7. package/dist/conversion/{shared/bridge-metadata.js → bridge-metadata.js} +1 -1
  8. package/dist/conversion/{shared/bridge-policies.js → bridge-policies.js} +1 -1
  9. package/dist/conversion/codecs/gemini-openai-codec.js +27 -8
  10. package/dist/conversion/codecs/responses-openai-codec.js +1 -1
  11. package/dist/conversion/{shared/compaction-detect.d.ts → compaction-detect.d.ts} +1 -1
  12. package/dist/conversion/compaction-detect.js +4 -0
  13. package/dist/conversion/compat/actions/apply-patch-fixer.js +2 -2
  14. package/dist/conversion/compat/actions/deepseek-web-response.d.ts +0 -1
  15. package/dist/conversion/compat/actions/deepseek-web-response.js +15 -405
  16. package/dist/conversion/compat/actions/harvest-tool-calls-from-text.js +1 -1
  17. package/dist/conversion/compat/actions/lmstudio-responses-fc-ids.js +1 -1
  18. package/dist/conversion/compat/actions/qwen-transform.js +74 -2
  19. package/dist/conversion/compat/actions/snapshot.js +1 -1
  20. package/dist/conversion/compat/antigravity-session-signature.js +36 -0
  21. package/dist/conversion/compat/profiles/chat-deepseek-web.json +0 -22
  22. package/dist/conversion/compat/profiles/chat-glm.json +251 -72
  23. package/dist/conversion/compat/profiles/chat-iflow.json +174 -39
  24. package/dist/conversion/compat/profiles/chat-lmstudio.json +43 -14
  25. package/dist/conversion/hub/operation-table/operation-table-runner.js +2 -2
  26. package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.js +1 -1
  27. package/dist/conversion/hub/operation-table/semantic-mappers/archive/chat-mapper.archive.d.ts +8 -0
  28. package/dist/conversion/hub/operation-table/semantic-mappers/archive/chat-mapper.archive.js +404 -0
  29. package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.js +5 -381
  30. package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +2 -2
  31. package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +2 -8
  32. package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +1 -0
  33. package/dist/conversion/hub/pipeline/hub-pipeline.js +50 -3
  34. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.d.ts +1 -1
  35. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +62 -0
  36. package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage2_route_select/index.js +3 -1
  37. package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js +1 -1
  38. package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/chat-process-semantics-bridge.d.ts +1 -1
  39. package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +42 -29
  40. package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage2_finalize/index.js +12 -0
  41. package/dist/conversion/hub/policy/protocol-spec.js +1 -1
  42. package/dist/conversion/hub/process/chat-process-clock-reminders.js +1 -1
  43. package/dist/conversion/hub/process/chat-process-clock-tools.js +1 -1
  44. package/dist/conversion/hub/process/chat-process-continue-execution.js +1 -1
  45. package/dist/conversion/hub/process/chat-process-servertool-orchestration.js +1 -1
  46. package/dist/conversion/hub/process/chat-process-web-search.js +1 -1
  47. package/dist/conversion/hub/response/provider-response.js +14 -5
  48. package/dist/conversion/hub/response/response-mappers.js +23 -1
  49. package/dist/conversion/hub/response/response-runtime.js +28 -5
  50. package/dist/conversion/hub/snapshot-recorder.js +3 -92
  51. package/dist/conversion/hub/tool-governance/engine.d.ts +8 -0
  52. package/dist/conversion/hub/tool-governance/engine.js +40 -193
  53. package/dist/conversion/hub/tool-governance/rules.js +73 -69
  54. package/dist/conversion/hub/tool-surface/tool-surface-engine.js +1 -1
  55. package/dist/conversion/index.d.ts +1 -2
  56. package/dist/conversion/index.js +1 -2
  57. package/dist/conversion/{shared/jsonish.js → jsonish.js} +1 -1
  58. package/dist/conversion/{shared/mcp-injection.js → mcp-injection.js} +1 -1
  59. package/dist/conversion/media.js +4 -0
  60. package/dist/conversion/{shared/metadata-passthrough.d.ts → metadata-passthrough.d.ts} +1 -1
  61. package/dist/conversion/{shared/metadata-passthrough.js → metadata-passthrough.js} +2 -2
  62. package/dist/conversion/payload-budget.js +47 -0
  63. package/dist/conversion/protocol-field-allowlists.d.ts +7 -0
  64. package/dist/conversion/protocol-field-allowlists.js +9 -0
  65. package/dist/conversion/{shared/protocol-state.d.ts → protocol-state.d.ts} +2 -2
  66. package/dist/conversion/{shared/protocol-state.js → protocol-state.js} +2 -2
  67. package/dist/conversion/{shared/errors.d.ts → provider-protocol-error.d.ts} +0 -3
  68. package/dist/conversion/provider-protocol-error.js +25 -0
  69. package/dist/conversion/responses/responses-openai-bridge/response-payload.js +8 -5
  70. package/dist/conversion/responses/responses-openai-bridge/types.d.ts +1 -1
  71. package/dist/conversion/responses/responses-openai-bridge.d.ts +1 -1
  72. package/dist/conversion/responses/responses-openai-bridge.js +43 -10
  73. package/dist/conversion/{shared/runtime-metadata.d.ts → runtime-metadata.d.ts} +1 -1
  74. package/dist/conversion/{shared/runtime-metadata.js → runtime-metadata.js} +2 -2
  75. package/dist/conversion/shared/anthropic-message-utils.js +19 -8
  76. package/dist/conversion/shared/chat-request-filters.d.ts +3 -4
  77. package/dist/conversion/shared/chat-request-filters.js +22 -78
  78. package/dist/conversion/shared/gemini-tool-utils.d.ts +1 -1
  79. package/dist/conversion/shared/openai-finalizer.js +1 -0
  80. package/dist/conversion/shared/openai-message-normalize.js +2 -2
  81. package/dist/conversion/shared/reasoning-normalizer.js +6 -0
  82. package/dist/conversion/shared/reasoning-utils.js +5 -2
  83. package/dist/conversion/shared/responses-conversation-store.js +1 -1
  84. package/dist/conversion/shared/responses-output-builder.js +55 -11
  85. package/dist/conversion/shared/responses-reasoning-registry.d.ts +14 -2
  86. package/dist/conversion/shared/responses-reasoning-registry.js +34 -6
  87. package/dist/conversion/shared/responses-response-utils.js +99 -9
  88. package/dist/conversion/shared/responses-tool-utils.js +1 -1
  89. package/dist/conversion/shared/text-markup-normalizer/normalize.d.ts +1 -1
  90. package/dist/conversion/shared/text-markup-normalizer.d.ts +2 -2
  91. package/dist/conversion/shared/text-markup-normalizer.js +1 -1
  92. package/dist/conversion/shared/tool-filter-pipeline.js +1 -1
  93. package/dist/conversion/shared/tool-governor.js +3 -3
  94. package/dist/conversion/shared/tool-mapping.d.ts +1 -1
  95. package/dist/conversion/{shared/snapshot-utils.d.ts → snapshot-utils.d.ts} +11 -0
  96. package/dist/conversion/{shared/snapshot-utils.js → snapshot-utils.js} +14 -23
  97. package/dist/conversion/types/text-markup-normalizer.d.ts +13 -0
  98. package/dist/conversion/types/text-markup-normalizer.js +1 -0
  99. package/dist/filters/special/request-tools-normalize.js +1 -1
  100. package/dist/filters/special/response-tool-text-canonicalize.js +2 -2
  101. package/dist/native/router_hotpath_napi.node +0 -0
  102. package/dist/quota/quota-manager.js +31 -59
  103. package/dist/quota/quota-state.js +14 -7
  104. package/dist/router/virtual-router/bootstrap/profile-builder.d.ts +1 -0
  105. package/dist/router/virtual-router/bootstrap/profile-builder.js +13 -0
  106. package/dist/router/virtual-router/bootstrap/provider-normalization.d.ts +2 -0
  107. package/dist/router/virtual-router/bootstrap/provider-normalization.js +4 -1
  108. package/dist/router/virtual-router/bootstrap/streaming-helpers.d.ts +7 -0
  109. package/dist/router/virtual-router/bootstrap/streaming-helpers.js +44 -0
  110. package/dist/router/virtual-router/bootstrap.js +2 -0
  111. package/dist/router/virtual-router/engine/routing-state/store.d.ts +1 -2
  112. package/dist/router/virtual-router/engine/routing-state/store.js +2 -2
  113. package/dist/router/virtual-router/engine-legacy/config.d.ts +11 -0
  114. package/dist/router/virtual-router/engine-legacy/config.js +108 -0
  115. package/dist/router/virtual-router/engine-legacy/direct-model.d.ts +10 -0
  116. package/dist/router/virtual-router/engine-legacy/direct-model.js +38 -0
  117. package/dist/router/virtual-router/engine-legacy/health.d.ts +13 -0
  118. package/dist/router/virtual-router/engine-legacy/health.js +104 -0
  119. package/dist/router/virtual-router/engine-legacy/helpers.d.ts +16 -0
  120. package/dist/router/virtual-router/engine-legacy/helpers.js +226 -0
  121. package/dist/router/virtual-router/engine-legacy/route-finalize.d.ts +9 -0
  122. package/dist/router/virtual-router/engine-legacy/route-finalize.js +84 -0
  123. package/dist/router/virtual-router/engine-legacy/route-selection.d.ts +17 -0
  124. package/dist/router/virtual-router/engine-legacy/route-selection.js +205 -0
  125. package/dist/router/virtual-router/engine-legacy/route-state-allowlist.d.ts +3 -0
  126. package/dist/router/virtual-router/engine-legacy/route-state-allowlist.js +36 -0
  127. package/dist/router/virtual-router/engine-legacy/route-state.d.ts +12 -0
  128. package/dist/router/virtual-router/engine-legacy/route-state.js +386 -0
  129. package/dist/router/virtual-router/engine-legacy/route-utils.d.ts +19 -0
  130. package/dist/router/virtual-router/engine-legacy/route-utils.js +212 -0
  131. package/dist/router/virtual-router/engine-legacy/routing.d.ts +8 -0
  132. package/dist/router/virtual-router/engine-legacy/routing.js +8 -0
  133. package/dist/router/virtual-router/engine-legacy/selection-core.d.ts +28 -0
  134. package/dist/router/virtual-router/engine-legacy/selection-core.js +112 -0
  135. package/dist/router/virtual-router/engine-legacy/selection-state.d.ts +16 -0
  136. package/dist/router/virtual-router/engine-legacy/selection-state.js +187 -0
  137. package/dist/router/virtual-router/engine-legacy/state-accessors.d.ts +21 -0
  138. package/dist/router/virtual-router/engine-legacy/state-accessors.js +118 -0
  139. package/dist/router/virtual-router/engine-legacy.d.ts +123 -0
  140. package/dist/router/virtual-router/engine-legacy.js +194 -0
  141. package/dist/router/virtual-router/engine-logging.d.ts +2 -0
  142. package/dist/router/virtual-router/engine-logging.js +7 -2
  143. package/dist/router/virtual-router/engine-selection/key-parsing.js +0 -3
  144. package/dist/router/virtual-router/engine-selection/native-chat-request-filter-semantics.d.ts +1 -0
  145. package/dist/router/virtual-router/engine-selection/native-chat-request-filter-semantics.js +54 -0
  146. package/dist/router/virtual-router/engine-selection/native-hub-bridge-policy-semantics.d.ts +10 -0
  147. package/dist/router/virtual-router/engine-selection/native-hub-bridge-policy-semantics.js +67 -0
  148. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-governance-semantics.d.ts +30 -0
  149. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-governance-semantics.js +202 -0
  150. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-semantic-mappers.d.ts +2 -0
  151. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-semantic-mappers.js +83 -0
  152. package/dist/router/virtual-router/engine-selection/native-router-hotpath-loader.js +43 -2
  153. package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.d.ts +75 -0
  154. package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.js +205 -0
  155. package/dist/router/virtual-router/engine-selection/native-snapshot-hooks.d.ts +3 -0
  156. package/dist/router/virtual-router/engine-selection/native-snapshot-hooks.js +109 -0
  157. package/dist/router/virtual-router/engine-selection/native-virtual-router-engine-proxy.d.ts +16 -0
  158. package/dist/router/virtual-router/engine-selection/native-virtual-router-engine-proxy.js +14 -0
  159. package/dist/router/virtual-router/engine-selection/native-virtual-router-routing-instructions-semantics.d.ts +2 -0
  160. package/dist/router/virtual-router/engine-selection/native-virtual-router-routing-instructions-semantics.js +86 -0
  161. package/dist/router/virtual-router/engine-selection/tier-selection-quota-integration.js +100 -0
  162. package/dist/router/virtual-router/engine-selection/tier-selection-select.js +99 -0
  163. package/dist/router/virtual-router/engine.d.ts +22 -105
  164. package/dist/router/virtual-router/engine.js +274 -1641
  165. package/dist/router/virtual-router/load-balancer.d.ts +8 -0
  166. package/dist/router/virtual-router/load-balancer.js +65 -2
  167. package/dist/router/virtual-router/provider-registry.js +2 -0
  168. package/dist/router/virtual-router/routing-instructions/clean.d.ts +3 -0
  169. package/dist/router/virtual-router/routing-instructions/clean.js +34 -0
  170. package/dist/router/virtual-router/routing-instructions/parse.d.ts +18 -0
  171. package/dist/router/virtual-router/routing-instructions/parse.js +377 -0
  172. package/dist/router/virtual-router/routing-instructions/state.d.ts +4 -0
  173. package/dist/router/virtual-router/routing-instructions/state.js +245 -0
  174. package/dist/router/virtual-router/routing-instructions/types.d.ts +70 -0
  175. package/dist/router/virtual-router/routing-instructions/types.js +2 -0
  176. package/dist/router/virtual-router/routing-instructions.d.ts +5 -89
  177. package/dist/router/virtual-router/routing-instructions.js +4 -655
  178. package/dist/router/virtual-router/sticky-session-store.d.ts +4 -0
  179. package/dist/router/virtual-router/sticky-session-store.js +19 -81
  180. package/dist/router/virtual-router/tool-signals.js +21 -3
  181. package/dist/router/virtual-router/types.d.ts +4 -0
  182. package/dist/servertool/clock/session-scope.js +32 -1
  183. package/dist/servertool/engine.js +79 -8
  184. package/dist/servertool/handlers/antigravity-thought-signature-bootstrap.js +1 -1
  185. package/dist/servertool/handlers/clock-auto.js +1 -1
  186. package/dist/servertool/handlers/clock.js +1 -1
  187. package/dist/servertool/handlers/compaction-detect.d.ts +1 -1
  188. package/dist/servertool/handlers/compaction-detect.js +1 -1
  189. package/dist/servertool/handlers/gemini-empty-reply-continue.js +1 -1
  190. package/dist/servertool/handlers/iflow-model-error-retry.js +1 -1
  191. package/dist/servertool/handlers/recursive-detection-guard.js +1 -1
  192. package/dist/servertool/handlers/review.js +1 -1
  193. package/dist/servertool/handlers/stop-message-auto/iflow-followup.js +1 -1
  194. package/dist/servertool/handlers/stop-message-auto/runtime-utils.js +1 -1
  195. package/dist/servertool/handlers/stop-message-auto.js +1 -1
  196. package/dist/servertool/handlers/vision.js +1 -1
  197. package/dist/servertool/handlers/web-search.js +1 -1
  198. package/dist/servertool/reenter-backend.js +1 -1
  199. package/dist/servertool/server-side-tools.js +2 -2
  200. package/dist/servertool/stop-gateway-context.js +1 -1
  201. package/dist/servertool/stop-message-compare-context.js +1 -1
  202. package/dist/sse/json-to-sse/event-generators/responses.d.ts +4 -0
  203. package/dist/sse/json-to-sse/event-generators/responses.js +95 -1
  204. package/dist/sse/json-to-sse/sequencers/responses-sequencer.js +6 -4
  205. package/dist/sse/sse-to-json/builders/response-builder.d.ts +8 -0
  206. package/dist/sse/sse-to-json/builders/response-builder.js +162 -4
  207. package/dist/sse/sse-to-json/responses-sse-to-json-converter.js +2 -0
  208. package/dist/sse/types/responses-types.d.ts +6 -2
  209. package/dist/tools/apply-patch/structured/coercion.js +5 -0
  210. package/dist/tools/args-json.js +29 -0
  211. package/package.json +8 -5
  212. package/dist/conversion/shared/args-mapping.js +0 -77
  213. package/dist/conversion/shared/compaction-detect.js +0 -4
  214. package/dist/conversion/shared/errors.js +0 -31
  215. package/dist/conversion/shared/media.js +0 -4
  216. package/dist/conversion/shared/payload-budget.js +0 -165
  217. package/dist/conversion/shared/protocol-field-allowlists.d.ts +0 -7
  218. package/dist/conversion/shared/protocol-field-allowlists.js +0 -149
  219. package/dist/conversion/shared/snapshot-hooks.d.ts +0 -11
  220. package/dist/conversion/shared/snapshot-hooks.js +0 -503
  221. package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.d.ts +0 -2
  222. package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.js +0 -129
  223. package/dist/conversion/shared/text-markup-normalizer/extractors-json.d.ts +0 -4
  224. package/dist/conversion/shared/text-markup-normalizer/extractors-json.js +0 -637
  225. package/dist/conversion/shared/text-markup-normalizer/extractors-shared.d.ts +0 -21
  226. package/dist/conversion/shared/text-markup-normalizer/extractors-shared.js +0 -177
  227. package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.d.ts +0 -5
  228. package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.js +0 -385
  229. package/dist/conversion/shared/text-markup-normalizer/extractors-xml.d.ts +0 -10
  230. package/dist/conversion/shared/text-markup-normalizer/extractors-xml.js +0 -602
  231. package/dist/conversion/shared/text-markup-normalizer/extractors.d.ts +0 -5
  232. package/dist/conversion/shared/text-markup-normalizer/extractors.js +0 -4
  233. package/dist/conversion/shared/tool-canonicalizer.d.ts +0 -2
  234. package/dist/conversion/shared/tool-canonicalizer.js +0 -38
  235. /package/dist/conversion/{shared/args-mapping.d.ts → args-mapping.d.ts} +0 -0
  236. /package/dist/conversion/{shared/bridge-actions.d.ts → bridge-actions.d.ts} +0 -0
  237. /package/dist/conversion/{shared/bridge-id-utils.d.ts → bridge-id-utils.d.ts} +0 -0
  238. /package/dist/conversion/{shared/bridge-instructions.d.ts → bridge-instructions.d.ts} +0 -0
  239. /package/dist/conversion/{shared/bridge-metadata.d.ts → bridge-metadata.d.ts} +0 -0
  240. /package/dist/conversion/{shared/bridge-policies.d.ts → bridge-policies.d.ts} +0 -0
  241. /package/dist/conversion/{shared/jsonish.d.ts → jsonish.d.ts} +0 -0
  242. /package/dist/conversion/{shared/mcp-injection.d.ts → mcp-injection.d.ts} +0 -0
  243. /package/dist/conversion/{shared/media.d.ts → media.d.ts} +0 -0
  244. /package/dist/conversion/{shared/payload-budget.d.ts → payload-budget.d.ts} +0 -0
  245. /package/dist/conversion/{shared → types}/bridge-message-types.d.ts +0 -0
  246. /package/dist/conversion/{shared → types}/bridge-message-types.js +0 -0
@@ -3,13 +3,28 @@ import { buildChatResponseFromResponses } from '../../../../../shared/responses-
3
3
  import { normalizeAssistantTextToToolCalls } from '../../../../../shared/text-markup-normalizer.js';
4
4
  import { recordStage } from '../../../stages/utils.js';
5
5
  import { applyRespProcessToolGovernanceWithNative, stripOrphanFunctionCallsTagWithNative } from '../../../../../../router/virtual-router/engine-selection/native-chat-process-governance-semantics.js';
6
- const TOOL_CALL_JSON_MARKER = /["']tool_calls["']\s*:/i;
7
6
  const SHELL_TOOL_NAME_ALIASES = {
8
7
  shell_command: 'exec_command',
9
8
  shell: 'exec_command',
10
9
  bash: 'exec_command',
11
10
  terminal: 'exec_command'
12
11
  };
12
+ /**
13
+ * Unified text-to-tool-calls harvest config.
14
+ * Shared across all providers via chat process tool governance.
15
+ */
16
+ const DEFAULT_TEXT_NORMALIZER_CONFIG = {
17
+ jsonToolRepair: {
18
+ toolNameAliases: SHELL_TOOL_NAME_ALIASES,
19
+ argumentAliases: {
20
+ exec_command: {
21
+ cmd: ['cmd', 'command', 'input.command', 'script'],
22
+ command: ['cmd', 'command', 'input.command', 'script'],
23
+ workdir: ['workdir', 'cwd', 'input.cwd']
24
+ }
25
+ }
26
+ }
27
+ };
13
28
  function isCanonicalChatCompletion(payload) {
14
29
  if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
15
30
  return false;
@@ -42,7 +57,11 @@ function coerceToCanonicalChatCompletion(payload) {
42
57
  }
43
58
  return payload;
44
59
  }
45
- function maybeHarvestEmptyToolCallsFromJsonContent(payload) {
60
+ /**
61
+ * Harvest tool calls from assistant text content when native tool_calls are missing or empty.
62
+ * This is the single entry point for text-based tool call extraction across all providers.
63
+ */
64
+ function harvestToolCallsFromText(payload) {
46
65
  if (!payload || typeof payload !== 'object') {
47
66
  return payload;
48
67
  }
@@ -50,6 +69,7 @@ function maybeHarvestEmptyToolCallsFromJsonContent(payload) {
50
69
  if (!choices.length) {
51
70
  return payload;
52
71
  }
72
+ let changed = false;
53
73
  for (const choice of choices) {
54
74
  if (!choice || typeof choice !== 'object' || Array.isArray(choice)) {
55
75
  continue;
@@ -58,37 +78,29 @@ function maybeHarvestEmptyToolCallsFromJsonContent(payload) {
58
78
  if (!message || typeof message !== 'object' || Array.isArray(message)) {
59
79
  continue;
60
80
  }
61
- const toolCalls = Array.isArray(message.tool_calls) ? message.tool_calls : undefined;
62
- if (!toolCalls || toolCalls.length !== 0) {
81
+ // Skip if already has native tool_calls
82
+ const existingToolCalls = Array.isArray(message.tool_calls) ? message.tool_calls : undefined;
83
+ if (existingToolCalls && existingToolCalls.length > 0) {
63
84
  continue;
64
85
  }
65
- const content = typeof message.content === 'string' ? String(message.content).trim() : '';
66
- if (!content || !TOOL_CALL_JSON_MARKER.test(content)) {
67
- continue;
68
- }
69
- const normalized = normalizeAssistantTextToToolCalls(message, {
70
- jsonToolRepair: {
71
- toolNameAliases: SHELL_TOOL_NAME_ALIASES,
72
- argumentAliases: {
73
- exec_command: {
74
- cmd: ['cmd', 'command', 'input.command', 'script'],
75
- command: ['cmd', 'command', 'input.command', 'script'],
76
- workdir: ['workdir', 'cwd', 'input.cwd']
77
- }
78
- }
86
+ // Try to harvest from text content
87
+ const normalized = normalizeAssistantTextToToolCalls(message, DEFAULT_TEXT_NORMALIZER_CONFIG);
88
+ const harvestedCalls = Array.isArray(normalized.tool_calls)
89
+ ? normalized.tool_calls
90
+ : [];
91
+ if (harvestedCalls.length > 0) {
92
+ choice.message = normalized;
93
+ changed = true;
94
+ // Update finish_reason if needed
95
+ const finish = typeof choice.finish_reason === 'string'
96
+ ? String(choice.finish_reason).trim().toLowerCase()
97
+ : '';
98
+ if (!finish || finish === 'stop') {
99
+ choice.finish_reason = 'tool_calls';
79
100
  }
80
- });
81
- const repairedCalls = Array.isArray(normalized.tool_calls) ? normalized.tool_calls : [];
82
- if (!repairedCalls.length) {
83
- continue;
84
- }
85
- choice.message = normalized;
86
- const finish = typeof choice.finish_reason === 'string' ? String(choice.finish_reason).trim().toLowerCase() : '';
87
- if (!finish || finish === 'stop') {
88
- choice.finish_reason = 'tool_calls';
89
101
  }
90
102
  }
91
- return payload;
103
+ return changed ? payload : payload;
92
104
  }
93
105
  function sanitizeResponseShapeBeforeGovernance(payload) {
94
106
  return stripOrphanFunctionCallsTagWithNative(payload);
@@ -96,7 +108,8 @@ function sanitizeResponseShapeBeforeGovernance(payload) {
96
108
  export async function runRespProcessStage1ToolGovernance(options) {
97
109
  const canonicalInput = coerceToCanonicalChatCompletion(options.payload);
98
110
  const shapeSanitizedInput = sanitizeResponseShapeBeforeGovernance(canonicalInput);
99
- maybeHarvestEmptyToolCallsFromJsonContent(shapeSanitizedInput);
111
+ // Single entry point for text-to-tool-calls harvest across all providers
112
+ harvestToolCallsFromText(shapeSanitizedInput);
100
113
  recordStage(options.stageRecorder, 'chat_process.resp.stage6.canonicalize_chat_completion', {
101
114
  converted: canonicalInput !== options.payload,
102
115
  shapeSanitized: shapeSanitizedInput !== canonicalInput,
@@ -1,7 +1,19 @@
1
1
  import { buildProcessedRequestFromChatResponse } from '../../../../response/chat-response-utils.js';
2
2
  import { recordStage } from '../../../stages/utils.js';
3
3
  import { finalizeRespProcessChatResponseWithNative } from '../../../../../../router/virtual-router/engine-selection/native-chat-process-governance-semantics.js';
4
+ import { normalizeReasoningInChatPayload } from '../../../../../shared/reasoning-normalizer.js';
4
5
  export async function runRespProcessStage2Finalize(options) {
6
+ const endpoint = (options.entryEndpoint || '').toLowerCase();
7
+ const wantsAnthropicReasoning = endpoint.includes('/v1/messages');
8
+ const shouldNormalize = (options.reasoningMode && options.reasoningMode !== 'keep') || wantsAnthropicReasoning;
9
+ if (shouldNormalize) {
10
+ try {
11
+ normalizeReasoningInChatPayload(options.payload);
12
+ }
13
+ catch {
14
+ // best-effort inline reasoning extraction
15
+ }
16
+ }
5
17
  const finalized = (await finalizeRespProcessChatResponseWithNative({
6
18
  payload: options.payload,
7
19
  stream: options.wantsStream,
@@ -1,4 +1,4 @@
1
- import { ANTHROPIC_ALLOWED_FIELDS, ANTHROPIC_PARAMETERS_WRAPPER_ALLOW_KEYS, GEMINI_ALLOWED_FIELDS, OPENAI_CHAT_ALLOWED_FIELDS, OPENAI_CHAT_PARAMETERS_WRAPPER_ALLOW_KEYS, OPENAI_RESPONSES_ALLOWED_FIELDS, OPENAI_RESPONSES_PARAMETERS_WRAPPER_ALLOW_KEYS } from '../../shared/protocol-field-allowlists.js';
1
+ import { ANTHROPIC_ALLOWED_FIELDS, ANTHROPIC_PARAMETERS_WRAPPER_ALLOW_KEYS, GEMINI_ALLOWED_FIELDS, OPENAI_CHAT_ALLOWED_FIELDS, OPENAI_CHAT_PARAMETERS_WRAPPER_ALLOW_KEYS, OPENAI_RESPONSES_ALLOWED_FIELDS, OPENAI_RESPONSES_PARAMETERS_WRAPPER_ALLOW_KEYS } from '../../protocol-field-allowlists.js';
2
2
  import { resolveHubProtocolSpecWithNative } from '../../../router/virtual-router/engine-selection/native-hub-bridge-policy-semantics.js';
3
3
  const ALLOWLISTS = {
4
4
  openaiChatAllowedFields: OPENAI_CHAT_ALLOWED_FIELDS,
@@ -1,4 +1,4 @@
1
- import { readRuntimeMetadata } from '../../shared/runtime-metadata.js';
1
+ import { readRuntimeMetadata } from '../../runtime-metadata.js';
2
2
  import { clearClockSession, resolveClockConfig, startClockDaemonIfNeeded } from '../../../servertool/clock/task-store.js';
3
3
  import { logClock } from '../../../servertool/clock/log.js';
4
4
  import { resolveClockSessionScope } from '../../../servertool/clock/session-scope.js';
@@ -1,4 +1,4 @@
1
- import { readRuntimeMetadata } from '../../shared/runtime-metadata.js';
1
+ import { readRuntimeMetadata } from '../../runtime-metadata.js';
2
2
  import { logClock } from '../../../servertool/clock/log.js';
3
3
  import { buildClockStandardToolAppendOperations, buildClockToolAppendOperations } from './chat-process-clock-tool-schemas.js';
4
4
  import { planChatClockOperationsWithNative } from '../../../router/virtual-router/engine-selection/native-chat-process-servertool-orchestration-semantics.js';
@@ -1,4 +1,4 @@
1
- import { readRuntimeMetadata } from '../../shared/runtime-metadata.js';
1
+ import { readRuntimeMetadata } from '../../runtime-metadata.js';
2
2
  import { loadRoutingInstructionStateSync } from '../../../router/virtual-router/sticky-session-store.js';
3
3
  import { logContinueExecution } from '../../../servertool/continue-execution/log.js';
4
4
  import { buildContinueExecutionOperationsWithNative, injectContinueExecutionDirectiveWithNative, planContinueExecutionOperationsWithNative, resolveHasActiveStopMessageForContinueExecutionWithNative, resolveStopMessageSessionScopeWithNative } from '../../../router/virtual-router/engine-selection/native-chat-process-servertool-orchestration-semantics.js';
@@ -4,7 +4,7 @@ import { buildWebSearchOperations } from './chat-process-web-search.js';
4
4
  import { buildClockOperationsWithPlan } from './chat-process-clock-tools.js';
5
5
  import { buildReviewOperations } from './chat-process-review.js';
6
6
  import { maybeInjectClockRemindersAndApplyDirectives } from './chat-process-clock-reminders.js';
7
- import { readRuntimeMetadata } from '../../shared/runtime-metadata.js';
7
+ import { readRuntimeMetadata } from '../../runtime-metadata.js';
8
8
  import { tryPlanChatServerToolBundleWithNative } from '../../../router/virtual-router/engine-selection/native-chat-process-servertool-orchestration-semantics.js';
9
9
  export async function applyServerToolOrchestration(options) {
10
10
  let request = options.request;
@@ -1,4 +1,4 @@
1
- import { readRuntimeMetadata } from '../../shared/runtime-metadata.js';
1
+ import { readRuntimeMetadata } from '../../runtime-metadata.js';
2
2
  import { buildWebSearchToolAppendOperations } from './chat-process-web-search-tool-schema.js';
3
3
  import { planChatWebSearchOperationsWithNative } from '../../../router/virtual-router/engine-selection/native-chat-process-servertool-orchestration-semantics.js';
4
4
  export function buildWebSearchOperations(request, metadata, precomputedPlan) {
@@ -15,8 +15,8 @@ import { runRespProcessStage3ServerToolOrchestration } from '../pipeline/stages/
15
15
  import { runRespOutboundStage1ClientRemap } from '../pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js';
16
16
  import { runRespOutboundStage2SseStream } from '../pipeline/stages/resp_outbound/resp_outbound_stage2_sse_stream/index.js';
17
17
  import { recordResponsesResponse } from '../../shared/responses-conversation-store.js';
18
- import { ProviderProtocolError } from '../../shared/errors.js';
19
- import { readRuntimeMetadata } from '../../shared/runtime-metadata.js';
18
+ import { ProviderProtocolError } from '../../provider-protocol-error.js';
19
+ import { readRuntimeMetadata } from '../../runtime-metadata.js';
20
20
  import { commitClockReservation, resolveClockConfig } from '../../../servertool/clock/task-store.js';
21
21
  import { detectProviderResponseShapeWithNative } from '../../../router/virtual-router/engine-selection/native-chat-process-servertool-orchestration-semantics.js';
22
22
  const PROVIDER_RESPONSE_REGISTRY = {
@@ -260,8 +260,11 @@ function applyModelOverride(payload, model) {
260
260
  /* ignore */
261
261
  }
262
262
  }
263
- function resolveChatReasoningMode(_entryEndpoint) {
264
- // 当前保持默认策略:保留 reasoning_content 字段,不做额外拼接或删除。
263
+ function resolveChatReasoningMode(entryEndpoint) {
264
+ const lowered = (entryEndpoint || '').toLowerCase();
265
+ if (lowered.includes('/v1/chat/completions')) {
266
+ return 'keep';
267
+ }
265
268
  return 'keep';
266
269
  }
267
270
  export async function convertProviderResponse(options) {
@@ -449,7 +452,13 @@ export async function convertProviderResponse(options) {
449
452
  // Commit scheduled-task delivery only after a successful client payload/stream is prepared.
450
453
  await maybeCommitClockReservationFromContext(options.context);
451
454
  if (outbound.stream) {
452
- return { __sse_responses: outbound.stream, format: clientProtocol };
455
+ const usage = clientPayload && typeof clientPayload === 'object' && !Array.isArray(clientPayload)
456
+ ? clientPayload.usage
457
+ : undefined;
458
+ const body = usage !== undefined
459
+ ? { usage }
460
+ : undefined;
461
+ return { __sse_responses: outbound.stream, body, format: clientProtocol };
453
462
  }
454
463
  return { body: clientPayload, format: clientProtocol };
455
464
  }
@@ -2,9 +2,31 @@ import { buildOpenAIChatFromGeminiResponse } from '../../codecs/gemini-openai-co
2
2
  import { buildChatResponseFromResponses } from '../../shared/responses-response-utils.js';
3
3
  import { buildOpenAIChatFromAnthropicMessage } from './response-runtime.js';
4
4
  import { resolveAliasMapFromRespSemanticsWithNative } from '../../../router/virtual-router/engine-selection/native-hub-pipeline-resp-semantics.js';
5
+ function injectResponsesReasoningExtension(payload) {
6
+ if (payload.__responses_reasoning) {
7
+ return;
8
+ }
9
+ const choices = Array.isArray(payload.choices) ? payload.choices : [];
10
+ const primary = choices[0] && typeof choices[0] === 'object' ? choices[0] : undefined;
11
+ const message = primary && typeof primary.message === 'object' ? primary.message : undefined;
12
+ if (!message)
13
+ return;
14
+ const reasoningText = typeof message.reasoning_content === 'string' && message.reasoning_content.trim().length
15
+ ? String(message.reasoning_content).trim()
16
+ : undefined;
17
+ if (!reasoningText)
18
+ return;
19
+ payload.__responses_reasoning = {
20
+ content: [{ type: 'reasoning_text', text: reasoningText }]
21
+ };
22
+ }
5
23
  export class OpenAIChatResponseMapper {
6
24
  toChatCompletion(format, _ctx) {
7
- return (format.payload ?? {});
25
+ const payload = (format.payload ?? {});
26
+ if (payload && typeof payload === 'object') {
27
+ injectResponsesReasoningExtension(payload);
28
+ }
29
+ return payload;
8
30
  }
9
31
  }
10
32
  export class ResponsesResponseMapper {
@@ -1,7 +1,7 @@
1
1
  import { extractToolCallsFromReasoningText } from '../../shared/reasoning-tool-parser.js';
2
2
  import { deriveToolCallKey } from '../../shared/tool-call-utils.js';
3
- import { createBridgeActionState, runBridgeActionPipeline } from '../../shared/bridge-actions.js';
4
- import { resolveBridgePolicy, resolvePolicyActions } from '../../shared/bridge-policies.js';
3
+ import { createBridgeActionState, runBridgeActionPipeline } from '../../bridge-actions.js';
4
+ import { resolveBridgePolicy, resolvePolicyActions } from '../../bridge-policies.js';
5
5
  import { normalizeAnthropicToolName } from '../../shared/anthropic-message-utils.js';
6
6
  import { buildAnthropicResponseFromChatWithNative } from '../../../router/virtual-router/engine-selection/native-hub-pipeline-resp-semantics.js';
7
7
  import { registerResponsesReasoning, consumeResponsesReasoning, registerResponsesOutputTextMeta, consumeResponsesOutputTextMeta, consumeResponsesPayloadSnapshot, registerResponsesPayloadSnapshot, consumeResponsesPassthrough, registerResponsesPassthrough } from '../../shared/responses-reasoning-registry.js';
@@ -153,7 +153,20 @@ export function buildOpenAIChatFromAnthropicMessage(payload, options) {
153
153
  continue;
154
154
  const kind = String(part.type || '').toLowerCase();
155
155
  if (kind === 'text' && typeof part.text === 'string') {
156
- textParts.push(part.text);
156
+ const rawText = part.text;
157
+ if (/<\s*(tool_call|function_call)\b|\[\s*(tool_call|function_call)\b/i.test(rawText)) {
158
+ const { cleanedText, toolCalls: inferred } = extractToolCallsFromReasoningText(rawText, { idPrefix: 'anthropic_text' });
159
+ const trimmed = cleanedText.trim();
160
+ if (trimmed.length) {
161
+ textParts.push(trimmed);
162
+ }
163
+ if (Array.isArray(inferred) && inferred.length) {
164
+ inferredToolCalls.push(...inferred);
165
+ }
166
+ }
167
+ else {
168
+ textParts.push(rawText);
169
+ }
157
170
  }
158
171
  else if (kind === 'tool_use') {
159
172
  const rawName = typeof part.name === 'string'
@@ -278,10 +291,18 @@ export function buildOpenAIChatFromAnthropicMessage(payload, options) {
278
291
  ? payload['usage']
279
292
  : undefined
280
293
  };
294
+ const localReasoning = reasoningParts.length
295
+ ? {
296
+ content: reasoningParts.map((text) => ({ type: 'reasoning_text', text }))
297
+ }
298
+ : undefined;
281
299
  const preserved = consumeResponsesReasoning(chatResponse.id);
282
- if (preserved && preserved.length) {
300
+ if (preserved) {
283
301
  chatResponse.__responses_reasoning = preserved;
284
302
  }
303
+ else if (localReasoning) {
304
+ chatResponse.__responses_reasoning = localReasoning;
305
+ }
285
306
  const preservedOutputMeta = consumeResponsesOutputTextMeta(chatResponse.id);
286
307
  if (preservedOutputMeta) {
287
308
  chatResponse.__responses_output_text_meta = preservedOutputMeta;
@@ -289,6 +310,7 @@ export function buildOpenAIChatFromAnthropicMessage(payload, options) {
289
310
  const payloadSnapshot = consumeResponsesPayloadSnapshot(chatResponse.id);
290
311
  if (payloadSnapshot) {
291
312
  registerResponsesPayloadSnapshot(chatResponse.id, payloadSnapshot);
313
+ chatResponse.__responses_payload_snapshot = payloadSnapshot;
292
314
  if (typeof chatResponse.request_id !== 'string') {
293
315
  chatResponse.request_id = chatResponse.id;
294
316
  }
@@ -296,6 +318,7 @@ export function buildOpenAIChatFromAnthropicMessage(payload, options) {
296
318
  const passthroughPayload = consumeResponsesPassthrough(chatResponse.id);
297
319
  if (passthroughPayload) {
298
320
  registerResponsesPassthrough(chatResponse.id, passthroughPayload);
321
+ chatResponse.__responses_passthrough = passthroughPayload;
299
322
  if (typeof chatResponse.request_id !== 'string') {
300
323
  chatResponse.request_id = chatResponse.id;
301
324
  }
@@ -372,7 +395,7 @@ export function buildAnthropicResponseFromChat(chatResponse, options) {
372
395
  }
373
396
  }
374
397
  const sanitized = buildAnthropicResponseFromChatWithNative(chatResponse, aliasMap);
375
- if (Array.isArray(chatResponse?.__responses_reasoning)) {
398
+ if (chatResponse?.__responses_reasoning) {
376
399
  registerResponsesReasoning(sanitized.id, chatResponse.__responses_reasoning);
377
400
  }
378
401
  if (chatResponse?.__responses_output_text_meta) {
@@ -1,6 +1,5 @@
1
- import { createSnapshotWriter } from '../shared/snapshot-utils.js';
2
- import { jsonClone } from './types/json.js';
3
- import { parseLenientJsonishWithNative } from '../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
1
+ import { createSnapshotWriter } from '../snapshot-utils.js';
2
+ import { normalizeSnapshotStagePayloadWithNative } from '../../router/virtual-router/engine-selection/native-snapshot-hooks.js';
4
3
  export class SnapshotStageRecorder {
5
4
  options;
6
5
  writer;
@@ -22,7 +21,7 @@ export class SnapshotStageRecorder {
22
21
  if (!this.writer) {
23
22
  return;
24
23
  }
25
- const normalized = normalizeStagePayload(stage, payload);
24
+ const normalized = normalizeSnapshotStagePayloadWithNative(stage, payload);
26
25
  if (!normalized) {
27
26
  return;
28
27
  }
@@ -37,91 +36,3 @@ export class SnapshotStageRecorder {
37
36
  export function createSnapshotRecorder(context, endpoint) {
38
37
  return new SnapshotStageRecorder({ context, endpoint });
39
38
  }
40
- const STAGE_KIND_MAP = {
41
- req_inbound_stage2_semantic_map: 'request_inbound',
42
- 'chat_process.req.stage2.semantic_map': 'request_inbound',
43
- req_outbound_stage1_semantic_map: 'request_outbound',
44
- 'chat_process.req.stage6.outbound.semantic_map': 'request_outbound',
45
- resp_inbound_stage3_semantic_map: 'response_inbound',
46
- 'chat_process.resp.stage4.semantic_map_to_chat': 'response_inbound',
47
- resp_outbound_stage1_client_remap: 'response_outbound',
48
- 'chat_process.resp.stage9.client_remap': 'response_outbound'
49
- };
50
- function normalizeStagePayload(stage, payload) {
51
- const kind = STAGE_KIND_MAP[stage];
52
- if (!kind) {
53
- return payload;
54
- }
55
- if ((kind === 'request_inbound' || kind === 'request_outbound') && isChatEnvelope(payload)) {
56
- return buildOpenAIChatSnapshot(payload);
57
- }
58
- if (kind === 'response_inbound' || kind === 'response_outbound') {
59
- return cloneJson(payload);
60
- }
61
- return payload;
62
- }
63
- function isChatEnvelope(value) {
64
- return Boolean(value &&
65
- typeof value === 'object' &&
66
- Array.isArray(value.messages) &&
67
- value.metadata &&
68
- typeof value.metadata === 'object');
69
- }
70
- function buildOpenAIChatSnapshot(envelope) {
71
- const snapshot = {};
72
- if (envelope.parameters && Object.keys(envelope.parameters).length) {
73
- Object.assign(snapshot, jsonClone(envelope.parameters));
74
- }
75
- snapshot.messages = jsonClone(envelope.messages);
76
- if (envelope.tools && envelope.tools.length) {
77
- snapshot.tools = jsonClone(envelope.tools);
78
- }
79
- if (envelope.toolOutputs && envelope.toolOutputs.length) {
80
- snapshot.tool_outputs = jsonClone(envelope.toolOutputs);
81
- }
82
- const meta = buildMetaSnapshot(envelope.metadata);
83
- if (meta) {
84
- snapshot.meta = meta;
85
- }
86
- return snapshot;
87
- }
88
- function buildMetaSnapshot(metadata) {
89
- const meta = {};
90
- if (metadata.context) {
91
- meta.context = jsonClone(metadata.context);
92
- }
93
- if (Array.isArray(metadata.missingFields) && metadata.missingFields.length) {
94
- meta.missing_fields = jsonClone(metadata.missingFields);
95
- }
96
- const extraKeys = Object.keys(metadata).filter((key) => key !== 'context' && key !== 'missingFields');
97
- if (extraKeys.length) {
98
- const extras = {};
99
- for (const key of extraKeys) {
100
- const value = metadata[key];
101
- if (value !== undefined) {
102
- extras[key] = jsonClone(value);
103
- }
104
- }
105
- if (Object.keys(extras).length) {
106
- meta.extra = extras;
107
- }
108
- }
109
- return Object.keys(meta).length ? meta : undefined;
110
- }
111
- function cloneJson(payload) {
112
- try {
113
- const nativeCloned = parseLenientJsonishWithNative(payload);
114
- if (nativeCloned && typeof nativeCloned === 'object' && !Array.isArray(nativeCloned)) {
115
- return nativeCloned;
116
- }
117
- }
118
- catch {
119
- // native clone is best-effort
120
- }
121
- try {
122
- return JSON.parse(JSON.stringify(payload));
123
- }
124
- catch {
125
- return payload;
126
- }
127
- }
@@ -1,6 +1,14 @@
1
1
  import type { JsonObject } from '../types/json.js';
2
2
  import type { StandardizedRequest } from '../types/standardized.js';
3
3
  import type { GovernedChatCompletionPayload, GovernedStandardizedRequest, ToolGovernanceProtocol, ToolGovernanceRegistry } from './types.js';
4
+ /**
5
+ * Hybrid governance engine:
6
+ * - request path: native-primary
7
+ * - response path: native-primary
8
+ *
9
+ * Legacy-only snapshot retained at:
10
+ * - src/conversion/hub/tool-governance/archive/engine.legacy.ts
11
+ */
4
12
  export declare class ToolGovernanceError extends Error {
5
13
  readonly protocol: ToolGovernanceProtocol;
6
14
  readonly direction: 'request' | 'response';