@jsonstudio/llms 0.6.2979 → 0.6.3214

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 (242) 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/chat-mapper.js +7 -4
  28. package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +2 -2
  29. package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +2 -8
  30. package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +1 -0
  31. package/dist/conversion/hub/pipeline/hub-pipeline.js +50 -3
  32. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.d.ts +1 -1
  33. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +62 -0
  34. package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage2_route_select/index.js +3 -1
  35. package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js +1 -1
  36. package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/chat-process-semantics-bridge.d.ts +1 -1
  37. package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +42 -29
  38. package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage2_finalize/index.js +12 -0
  39. package/dist/conversion/hub/policy/protocol-spec.js +1 -1
  40. package/dist/conversion/hub/process/chat-process-clock-reminders.js +1 -1
  41. package/dist/conversion/hub/process/chat-process-clock-tools.js +1 -1
  42. package/dist/conversion/hub/process/chat-process-continue-execution.js +1 -1
  43. package/dist/conversion/hub/process/chat-process-servertool-orchestration.js +1 -1
  44. package/dist/conversion/hub/process/chat-process-web-search.js +1 -1
  45. package/dist/conversion/hub/response/provider-response.js +14 -5
  46. package/dist/conversion/hub/response/response-mappers.js +23 -1
  47. package/dist/conversion/hub/response/response-runtime.js +28 -5
  48. package/dist/conversion/hub/snapshot-recorder.js +1 -1
  49. package/dist/conversion/hub/tool-governance/engine.d.ts +8 -0
  50. package/dist/conversion/hub/tool-governance/engine.js +25 -68
  51. package/dist/conversion/hub/tool-governance/rules.js +73 -69
  52. package/dist/conversion/hub/tool-surface/tool-surface-engine.js +1 -1
  53. package/dist/conversion/index.d.ts +1 -2
  54. package/dist/conversion/index.js +1 -2
  55. package/dist/conversion/{shared/jsonish.js → jsonish.js} +1 -1
  56. package/dist/conversion/{shared/mcp-injection.js → mcp-injection.js} +1 -1
  57. package/dist/conversion/media.js +4 -0
  58. package/dist/conversion/{shared/metadata-passthrough.d.ts → metadata-passthrough.d.ts} +1 -1
  59. package/dist/conversion/{shared/metadata-passthrough.js → metadata-passthrough.js} +2 -2
  60. package/dist/conversion/payload-budget.js +47 -0
  61. package/dist/conversion/protocol-field-allowlists.d.ts +7 -0
  62. package/dist/conversion/protocol-field-allowlists.js +9 -0
  63. package/dist/conversion/{shared/protocol-state.d.ts → protocol-state.d.ts} +2 -2
  64. package/dist/conversion/{shared/protocol-state.js → protocol-state.js} +2 -2
  65. package/dist/conversion/{shared/errors.d.ts → provider-protocol-error.d.ts} +0 -3
  66. package/dist/conversion/provider-protocol-error.js +25 -0
  67. package/dist/conversion/responses/responses-openai-bridge/response-payload.js +8 -5
  68. package/dist/conversion/responses/responses-openai-bridge/types.d.ts +1 -1
  69. package/dist/conversion/responses/responses-openai-bridge.d.ts +1 -1
  70. package/dist/conversion/responses/responses-openai-bridge.js +43 -10
  71. package/dist/conversion/{shared/runtime-metadata.d.ts → runtime-metadata.d.ts} +1 -1
  72. package/dist/conversion/{shared/runtime-metadata.js → runtime-metadata.js} +2 -2
  73. package/dist/conversion/shared/anthropic-message-utils.js +19 -8
  74. package/dist/conversion/shared/chat-request-filters.d.ts +3 -4
  75. package/dist/conversion/shared/chat-request-filters.js +22 -78
  76. package/dist/conversion/shared/gemini-tool-utils.d.ts +1 -1
  77. package/dist/conversion/shared/openai-finalizer.js +1 -0
  78. package/dist/conversion/shared/openai-message-normalize.js +2 -2
  79. package/dist/conversion/shared/reasoning-normalizer.js +6 -0
  80. package/dist/conversion/shared/reasoning-utils.js +5 -2
  81. package/dist/conversion/shared/responses-conversation-store.js +1 -1
  82. package/dist/conversion/shared/responses-output-builder.js +55 -11
  83. package/dist/conversion/shared/responses-reasoning-registry.d.ts +14 -2
  84. package/dist/conversion/shared/responses-reasoning-registry.js +34 -6
  85. package/dist/conversion/shared/responses-response-utils.js +99 -9
  86. package/dist/conversion/shared/responses-tool-utils.js +1 -1
  87. package/dist/conversion/shared/text-markup-normalizer/normalize.d.ts +1 -1
  88. package/dist/conversion/shared/text-markup-normalizer.d.ts +2 -2
  89. package/dist/conversion/shared/text-markup-normalizer.js +1 -1
  90. package/dist/conversion/shared/tool-filter-pipeline.js +1 -1
  91. package/dist/conversion/shared/tool-governor.js +3 -3
  92. package/dist/conversion/shared/tool-mapping.d.ts +1 -1
  93. package/dist/conversion/{shared/snapshot-utils.d.ts → snapshot-utils.d.ts} +11 -0
  94. package/dist/conversion/{shared/snapshot-utils.js → snapshot-utils.js} +14 -23
  95. package/dist/conversion/types/text-markup-normalizer.d.ts +13 -0
  96. package/dist/conversion/types/text-markup-normalizer.js +1 -0
  97. package/dist/filters/special/request-tools-normalize.js +1 -1
  98. package/dist/filters/special/response-tool-text-canonicalize.js +2 -2
  99. package/dist/native/router_hotpath_napi.node +0 -0
  100. package/dist/quota/quota-manager.js +31 -59
  101. package/dist/quota/quota-state.js +14 -7
  102. package/dist/router/virtual-router/bootstrap/profile-builder.d.ts +1 -0
  103. package/dist/router/virtual-router/bootstrap/profile-builder.js +13 -0
  104. package/dist/router/virtual-router/bootstrap/provider-normalization.d.ts +2 -0
  105. package/dist/router/virtual-router/bootstrap/provider-normalization.js +4 -1
  106. package/dist/router/virtual-router/bootstrap/streaming-helpers.d.ts +7 -0
  107. package/dist/router/virtual-router/bootstrap/streaming-helpers.js +44 -0
  108. package/dist/router/virtual-router/bootstrap.js +2 -0
  109. package/dist/router/virtual-router/engine/routing-state/store.d.ts +1 -2
  110. package/dist/router/virtual-router/engine/routing-state/store.js +2 -2
  111. package/dist/router/virtual-router/engine-legacy/config.d.ts +11 -0
  112. package/dist/router/virtual-router/engine-legacy/config.js +108 -0
  113. package/dist/router/virtual-router/engine-legacy/direct-model.d.ts +10 -0
  114. package/dist/router/virtual-router/engine-legacy/direct-model.js +38 -0
  115. package/dist/router/virtual-router/engine-legacy/health.d.ts +13 -0
  116. package/dist/router/virtual-router/engine-legacy/health.js +104 -0
  117. package/dist/router/virtual-router/engine-legacy/helpers.d.ts +16 -0
  118. package/dist/router/virtual-router/engine-legacy/helpers.js +226 -0
  119. package/dist/router/virtual-router/engine-legacy/route-finalize.d.ts +9 -0
  120. package/dist/router/virtual-router/engine-legacy/route-finalize.js +84 -0
  121. package/dist/router/virtual-router/engine-legacy/route-selection.d.ts +17 -0
  122. package/dist/router/virtual-router/engine-legacy/route-selection.js +205 -0
  123. package/dist/router/virtual-router/engine-legacy/route-state-allowlist.d.ts +3 -0
  124. package/dist/router/virtual-router/engine-legacy/route-state-allowlist.js +36 -0
  125. package/dist/router/virtual-router/engine-legacy/route-state.d.ts +12 -0
  126. package/dist/router/virtual-router/engine-legacy/route-state.js +386 -0
  127. package/dist/router/virtual-router/engine-legacy/route-utils.d.ts +19 -0
  128. package/dist/router/virtual-router/engine-legacy/route-utils.js +212 -0
  129. package/dist/router/virtual-router/engine-legacy/routing.d.ts +8 -0
  130. package/dist/router/virtual-router/engine-legacy/routing.js +8 -0
  131. package/dist/router/virtual-router/engine-legacy/selection-core.d.ts +28 -0
  132. package/dist/router/virtual-router/engine-legacy/selection-core.js +112 -0
  133. package/dist/router/virtual-router/engine-legacy/selection-state.d.ts +16 -0
  134. package/dist/router/virtual-router/engine-legacy/selection-state.js +187 -0
  135. package/dist/router/virtual-router/engine-legacy/state-accessors.d.ts +21 -0
  136. package/dist/router/virtual-router/engine-legacy/state-accessors.js +118 -0
  137. package/dist/router/virtual-router/engine-legacy.d.ts +123 -0
  138. package/dist/router/virtual-router/engine-legacy.js +194 -0
  139. package/dist/router/virtual-router/engine-logging.d.ts +2 -0
  140. package/dist/router/virtual-router/engine-logging.js +7 -2
  141. package/dist/router/virtual-router/engine-selection/key-parsing.js +0 -3
  142. package/dist/router/virtual-router/engine-selection/native-chat-request-filter-semantics.d.ts +1 -0
  143. package/dist/router/virtual-router/engine-selection/native-chat-request-filter-semantics.js +54 -0
  144. package/dist/router/virtual-router/engine-selection/native-hub-bridge-policy-semantics.d.ts +10 -0
  145. package/dist/router/virtual-router/engine-selection/native-hub-bridge-policy-semantics.js +67 -0
  146. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-governance-semantics.d.ts +22 -0
  147. package/dist/router/virtual-router/engine-selection/native-hub-pipeline-governance-semantics.js +154 -0
  148. package/dist/router/virtual-router/engine-selection/native-router-hotpath-loader.js +38 -2
  149. package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.d.ts +75 -0
  150. package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.js +205 -0
  151. package/dist/router/virtual-router/engine-selection/native-snapshot-hooks.d.ts +2 -0
  152. package/dist/router/virtual-router/engine-selection/native-snapshot-hooks.js +69 -0
  153. package/dist/router/virtual-router/engine-selection/native-virtual-router-engine-proxy.d.ts +16 -0
  154. package/dist/router/virtual-router/engine-selection/native-virtual-router-engine-proxy.js +14 -0
  155. package/dist/router/virtual-router/engine-selection/native-virtual-router-routing-instructions-semantics.d.ts +2 -0
  156. package/dist/router/virtual-router/engine-selection/native-virtual-router-routing-instructions-semantics.js +86 -0
  157. package/dist/router/virtual-router/engine-selection/tier-selection-quota-integration.js +100 -0
  158. package/dist/router/virtual-router/engine-selection/tier-selection-select.js +99 -0
  159. package/dist/router/virtual-router/engine.d.ts +22 -105
  160. package/dist/router/virtual-router/engine.js +274 -1641
  161. package/dist/router/virtual-router/load-balancer.d.ts +8 -0
  162. package/dist/router/virtual-router/load-balancer.js +65 -2
  163. package/dist/router/virtual-router/provider-registry.js +2 -0
  164. package/dist/router/virtual-router/routing-instructions/clean.d.ts +3 -0
  165. package/dist/router/virtual-router/routing-instructions/clean.js +34 -0
  166. package/dist/router/virtual-router/routing-instructions/parse.d.ts +18 -0
  167. package/dist/router/virtual-router/routing-instructions/parse.js +377 -0
  168. package/dist/router/virtual-router/routing-instructions/state.d.ts +4 -0
  169. package/dist/router/virtual-router/routing-instructions/state.js +245 -0
  170. package/dist/router/virtual-router/routing-instructions/types.d.ts +70 -0
  171. package/dist/router/virtual-router/routing-instructions/types.js +2 -0
  172. package/dist/router/virtual-router/routing-instructions.d.ts +5 -89
  173. package/dist/router/virtual-router/routing-instructions.js +4 -655
  174. package/dist/router/virtual-router/sticky-session-store.d.ts +4 -0
  175. package/dist/router/virtual-router/sticky-session-store.js +19 -81
  176. package/dist/router/virtual-router/tool-signals.js +21 -3
  177. package/dist/router/virtual-router/types.d.ts +4 -0
  178. package/dist/servertool/clock/session-scope.js +32 -1
  179. package/dist/servertool/engine.js +79 -8
  180. package/dist/servertool/handlers/antigravity-thought-signature-bootstrap.js +1 -1
  181. package/dist/servertool/handlers/clock-auto.js +1 -1
  182. package/dist/servertool/handlers/clock.js +1 -1
  183. package/dist/servertool/handlers/compaction-detect.d.ts +1 -1
  184. package/dist/servertool/handlers/compaction-detect.js +1 -1
  185. package/dist/servertool/handlers/gemini-empty-reply-continue.js +1 -1
  186. package/dist/servertool/handlers/iflow-model-error-retry.js +1 -1
  187. package/dist/servertool/handlers/recursive-detection-guard.js +1 -1
  188. package/dist/servertool/handlers/review.js +1 -1
  189. package/dist/servertool/handlers/stop-message-auto/iflow-followup.js +1 -1
  190. package/dist/servertool/handlers/stop-message-auto/runtime-utils.js +1 -1
  191. package/dist/servertool/handlers/stop-message-auto.js +1 -1
  192. package/dist/servertool/handlers/vision.js +1 -1
  193. package/dist/servertool/handlers/web-search.js +1 -1
  194. package/dist/servertool/reenter-backend.js +1 -1
  195. package/dist/servertool/server-side-tools.js +2 -2
  196. package/dist/servertool/stop-gateway-context.js +1 -1
  197. package/dist/servertool/stop-message-compare-context.js +1 -1
  198. package/dist/sse/json-to-sse/event-generators/responses.d.ts +4 -0
  199. package/dist/sse/json-to-sse/event-generators/responses.js +95 -1
  200. package/dist/sse/json-to-sse/sequencers/responses-sequencer.js +6 -4
  201. package/dist/sse/sse-to-json/builders/response-builder.d.ts +8 -0
  202. package/dist/sse/sse-to-json/builders/response-builder.js +162 -4
  203. package/dist/sse/sse-to-json/responses-sse-to-json-converter.js +2 -0
  204. package/dist/sse/types/responses-types.d.ts +6 -2
  205. package/dist/tools/apply-patch/structured/coercion.js +5 -0
  206. package/dist/tools/args-json.js +29 -0
  207. package/package.json +8 -5
  208. package/dist/conversion/shared/args-mapping.js +0 -77
  209. package/dist/conversion/shared/compaction-detect.js +0 -4
  210. package/dist/conversion/shared/errors.js +0 -31
  211. package/dist/conversion/shared/media.js +0 -4
  212. package/dist/conversion/shared/payload-budget.js +0 -165
  213. package/dist/conversion/shared/protocol-field-allowlists.d.ts +0 -7
  214. package/dist/conversion/shared/protocol-field-allowlists.js +0 -149
  215. package/dist/conversion/shared/snapshot-hooks.d.ts +0 -11
  216. package/dist/conversion/shared/snapshot-hooks.js +0 -503
  217. package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.d.ts +0 -2
  218. package/dist/conversion/shared/text-markup-normalizer/extractors-apply-patch.js +0 -129
  219. package/dist/conversion/shared/text-markup-normalizer/extractors-json.d.ts +0 -4
  220. package/dist/conversion/shared/text-markup-normalizer/extractors-json.js +0 -637
  221. package/dist/conversion/shared/text-markup-normalizer/extractors-shared.d.ts +0 -21
  222. package/dist/conversion/shared/text-markup-normalizer/extractors-shared.js +0 -177
  223. package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.d.ts +0 -5
  224. package/dist/conversion/shared/text-markup-normalizer/extractors-transcript.js +0 -385
  225. package/dist/conversion/shared/text-markup-normalizer/extractors-xml.d.ts +0 -10
  226. package/dist/conversion/shared/text-markup-normalizer/extractors-xml.js +0 -602
  227. package/dist/conversion/shared/text-markup-normalizer/extractors.d.ts +0 -5
  228. package/dist/conversion/shared/text-markup-normalizer/extractors.js +0 -4
  229. package/dist/conversion/shared/tool-canonicalizer.d.ts +0 -2
  230. package/dist/conversion/shared/tool-canonicalizer.js +0 -38
  231. /package/dist/conversion/{shared/args-mapping.d.ts → args-mapping.d.ts} +0 -0
  232. /package/dist/conversion/{shared/bridge-actions.d.ts → bridge-actions.d.ts} +0 -0
  233. /package/dist/conversion/{shared/bridge-id-utils.d.ts → bridge-id-utils.d.ts} +0 -0
  234. /package/dist/conversion/{shared/bridge-instructions.d.ts → bridge-instructions.d.ts} +0 -0
  235. /package/dist/conversion/{shared/bridge-metadata.d.ts → bridge-metadata.d.ts} +0 -0
  236. /package/dist/conversion/{shared/bridge-policies.d.ts → bridge-policies.d.ts} +0 -0
  237. /package/dist/conversion/{shared/jsonish.d.ts → jsonish.d.ts} +0 -0
  238. /package/dist/conversion/{shared/mcp-injection.d.ts → mcp-injection.d.ts} +0 -0
  239. /package/dist/conversion/{shared/media.d.ts → media.d.ts} +0 -0
  240. /package/dist/conversion/{shared/payload-budget.d.ts → payload-budget.d.ts} +0 -0
  241. /package/dist/conversion/{shared → types}/bridge-message-types.d.ts +0 -0
  242. /package/dist/conversion/{shared → types}/bridge-message-types.js +0 -0
@@ -1,3 +1,4 @@
1
+ import { isJsonObject, jsonClone } from '../../../../types/json.js';
1
2
  import { applyHubOperationTableInbound } from '../../../../operation-table/operation-table-runner.js';
2
3
  import { recordStage } from '../../../stages/utils.js';
3
4
  import { liftReqInboundSemantics } from './semantic-lift.js';
@@ -5,6 +6,19 @@ import { validateChatEnvelopeWithNative } from '../../../../../../router/virtual
5
6
  import { chatEnvelopeToStandardizedWithNative } from '../../../../../../router/virtual-router/engine-selection/native-hub-pipeline-req-inbound-semantics.js';
6
7
  export async function runReqInboundStage2SemanticMap(options) {
7
8
  const chatEnvelope = await options.semanticMapper.toChat(options.formatEnvelope, options.adapterContext);
9
+ const preservedResponsesContext = (() => {
10
+ if (!chatEnvelope.semantics || typeof chatEnvelope.semantics !== 'object') {
11
+ return undefined;
12
+ }
13
+ const semantics = chatEnvelope.semantics;
14
+ const responsesNode = isJsonObject(semantics.responses)
15
+ ? semantics.responses
16
+ : undefined;
17
+ const contextNode = responsesNode && isJsonObject(responsesNode.context)
18
+ ? responsesNode.context
19
+ : undefined;
20
+ return contextNode ? jsonClone(contextNode) : undefined;
21
+ })();
8
22
  applyHubOperationTableInbound({
9
23
  formatEnvelope: options.formatEnvelope,
10
24
  chatEnvelope,
@@ -18,6 +32,27 @@ export async function runReqInboundStage2SemanticMap(options) {
18
32
  adapterContext: options.adapterContext,
19
33
  responsesResume: options.responsesResume
20
34
  });
35
+ if (preservedResponsesContext) {
36
+ const currentSemantics = chatEnvelope.semantics;
37
+ if (!currentSemantics || typeof currentSemantics !== 'object') {
38
+ chatEnvelope.semantics = { responses: { context: jsonClone(preservedResponsesContext) } };
39
+ }
40
+ else {
41
+ const semantics = currentSemantics;
42
+ const responsesNode = isJsonObject(semantics.responses)
43
+ ? semantics.responses
44
+ : {};
45
+ if (!isJsonObject(responsesNode.context)) {
46
+ chatEnvelope.semantics = {
47
+ ...semantics,
48
+ responses: {
49
+ ...responsesNode,
50
+ context: jsonClone(preservedResponsesContext)
51
+ }
52
+ };
53
+ }
54
+ }
55
+ }
21
56
  validateChatEnvelopeWithNative(chatEnvelope, {
22
57
  stage: 'req_inbound',
23
58
  direction: 'request'
@@ -29,5 +64,32 @@ export async function runReqInboundStage2SemanticMap(options) {
29
64
  endpoint: options.adapterContext.entryEndpoint,
30
65
  requestId: options.adapterContext.requestId
31
66
  });
67
+ // Ensure responses semantics (context) survive into standardized request for VirtualRouter parsing.
68
+ if (chatEnvelope.semantics && typeof chatEnvelope.semantics === 'object') {
69
+ const envelopeSemantics = chatEnvelope.semantics;
70
+ const existing = standardizedRequest.semantics;
71
+ if (!existing || typeof existing !== 'object') {
72
+ standardizedRequest.semantics = jsonClone(envelopeSemantics);
73
+ }
74
+ else {
75
+ const existingObj = existing;
76
+ const envelopeResponses = isJsonObject(envelopeSemantics.responses)
77
+ ? envelopeSemantics.responses
78
+ : undefined;
79
+ const envelopeContext = envelopeResponses && isJsonObject(envelopeResponses.context)
80
+ ? envelopeResponses.context
81
+ : undefined;
82
+ if (envelopeContext) {
83
+ const nextResponses = {
84
+ ...(isJsonObject(existingObj.responses) ? existingObj.responses : {}),
85
+ context: jsonClone(envelopeContext)
86
+ };
87
+ standardizedRequest.semantics = {
88
+ ...existingObj,
89
+ responses: nextResponses
90
+ };
91
+ }
92
+ }
93
+ }
32
94
  return { chatEnvelope, standardizedRequest };
33
95
  }
@@ -1,5 +1,6 @@
1
1
  import { recordStage } from '../../../stages/utils.js';
2
2
  import { applyReqProcessRouteSelectionWithNative } from '../../../../../../router/virtual-router/engine-selection/native-hub-pipeline-req-process-semantics.js';
3
+ import { cleanRoutingInstructionMarkersWithNative } from '../../../../../../router/virtual-router/engine-selection/native-virtual-router-routing-instructions-semantics.js';
3
4
  function replaceRecordInPlace(target, source) {
4
5
  for (const key of Object.keys(target)) {
5
6
  if (!Object.prototype.hasOwnProperty.call(source, key)) {
@@ -18,7 +19,8 @@ export function runReqProcessStage2RouteSelect(options) {
18
19
  routeName: result.decision.routeName,
19
20
  originalModel: previousModel
20
21
  });
21
- replaceRecordInPlace(options.request, nativeApplied.request);
22
+ const cleanedRequest = cleanRoutingInstructionMarkersWithNative(nativeApplied.request);
23
+ replaceRecordInPlace(options.request, cleanedRequest);
22
24
  replaceRecordInPlace(options.normalizedMetadata, nativeApplied.normalizedMetadata);
23
25
  recordStage(options.stageRecorder, 'chat_process.req.stage5.route_select', {
24
26
  target: result.target,
@@ -1,6 +1,6 @@
1
1
  import { defaultSseCodecRegistry } from '../../../../../../sse/index.js';
2
2
  import { recordStage } from '../../../stages/utils.js';
3
- import { ProviderProtocolError } from '../../../../../shared/errors.js';
3
+ import { ProviderProtocolError } from '../../../../../provider-protocol-error.js';
4
4
  import { extractContextLengthDiagnosticsWithNative, extractSseWrapperErrorWithNative, isContextLengthExceededSignalWithNative, parseJsonObjectCandidateWithNative } from '../../../../../../router/virtual-router/engine-selection/native-hub-pipeline-resp-semantics.js';
5
5
  import { tryDecodeJsonBodyFromStream } from './stream-json-sniffer.js';
6
6
  function resolveProviderType(protocol) {
@@ -1,5 +1,5 @@
1
1
  import type { JsonObject } from '../../../../types/json.js';
2
- import type { BridgeToolDefinition } from '../../../../../shared/bridge-message-types.js';
2
+ import type { BridgeToolDefinition } from '../../../../../types/bridge-message-types.js';
3
3
  export declare function resolveAliasMapFromSemantics(semantics?: JsonObject): Record<string, string> | undefined;
4
4
  export declare function normalizeAliasMap(candidate: unknown): Record<string, string> | undefined;
5
5
  export declare function resolveClientToolsRawFromSemantics(semantics?: JsonObject): BridgeToolDefinition[] | undefined;
@@ -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,4 +1,4 @@
1
- import { createSnapshotWriter } from '../shared/snapshot-utils.js';
1
+ import { createSnapshotWriter } from '../snapshot-utils.js';
2
2
  import { jsonClone } from './types/json.js';
3
3
  import { parseLenientJsonishWithNative } from '../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
4
4
  export class SnapshotStageRecorder {
@@ -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: legacy TS rules (until native response-governance export is available)
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';
@@ -1,5 +1,13 @@
1
1
  import { DEFAULT_TOOL_GOVERNANCE_RULES } from './rules.js';
2
- import { sanitizeResponsesFunctionNameWithNative } from '../../../router/virtual-router/engine-selection/native-hub-pipeline-resp-semantics.js';
2
+ import { governRequestWithNative } from '../../../router/virtual-router/engine-selection/native-hub-pipeline-governance-semantics.js';
3
+ /**
4
+ * Hybrid governance engine:
5
+ * - request path: native-primary
6
+ * - response path: legacy TS rules (until native response-governance export is available)
7
+ *
8
+ * Legacy-only snapshot retained at:
9
+ * - src/conversion/hub/tool-governance/archive/engine.legacy.ts
10
+ */
3
11
  export class ToolGovernanceError extends Error {
4
12
  protocol;
5
13
  direction;
@@ -43,24 +51,24 @@ export class ToolGovernanceEngine {
43
51
  summary: buildSummary(protocol, 'request', false)
44
52
  };
45
53
  }
46
- const stats = createStats(protocol, 'request');
47
- const sanitizedMessages = request.messages.map((msg) => sanitizeStandardizedMessage(msg, rules, stats));
48
- const sanitizedTools = request.tools?.map((tool) => sanitizeStandardizedTool(tool, rules, stats));
49
- const governed = {
50
- ...request,
51
- messages: sanitizedMessages,
52
- tools: sanitizedTools,
53
- metadata: {
54
- ...request.metadata,
55
- toolGovernance: {
56
- ...request.metadata?.toolGovernance,
57
- request: finalizeSummary(stats)
58
- }
54
+ let governed;
55
+ try {
56
+ governed = governRequestWithNative({
57
+ request: request,
58
+ protocol,
59
+ registry: this.registry
60
+ });
61
+ }
62
+ catch (error) {
63
+ const message = error instanceof Error ? error.message : String(error ?? 'unknown error');
64
+ if (message.includes('Tool name exceeds max length')) {
65
+ throw new ToolGovernanceError(message, protocol, 'request', 'tool.function.name');
59
66
  }
60
- };
67
+ throw error;
68
+ }
61
69
  return {
62
- request: governed,
63
- summary: finalizeSummary(stats)
70
+ request: governed.request,
71
+ summary: governed.summary
64
72
  };
65
73
  }
66
74
  governResponse(payload, protocol) {
@@ -91,53 +99,6 @@ export class ToolGovernanceEngine {
91
99
  return entry?.[direction];
92
100
  }
93
101
  }
94
- function sanitizeStandardizedMessage(message, rules, stats) {
95
- let changed = false;
96
- const next = { ...message };
97
- if (Array.isArray(message.tool_calls) && message.tool_calls.length) {
98
- next.tool_calls = message.tool_calls.map((call) => sanitizeToolCall(call, rules, stats));
99
- if (next.tool_calls !== message.tool_calls) {
100
- changed = true;
101
- }
102
- }
103
- if (typeof message.name === 'string' || message.role === 'tool') {
104
- const sanitizedName = sanitizeName(message.name, rules, stats, 'message.name');
105
- if (sanitizedName !== message.name) {
106
- next.name = sanitizedName;
107
- changed = true;
108
- }
109
- }
110
- return changed ? next : message;
111
- }
112
- function sanitizeStandardizedTool(tool, rules, stats) {
113
- const sanitizedName = sanitizeName(tool.function?.name, rules, stats, 'tool.function.name');
114
- if (sanitizedName === tool.function?.name) {
115
- return tool;
116
- }
117
- return {
118
- ...tool,
119
- function: {
120
- ...tool.function,
121
- name: sanitizedName
122
- }
123
- };
124
- }
125
- function sanitizeToolCall(call, rules, stats) {
126
- if (!call?.function) {
127
- return call;
128
- }
129
- const sanitizedName = sanitizeName(call.function.name, rules, stats, 'tool_call.function.name');
130
- if (sanitizedName === call.function.name) {
131
- return call;
132
- }
133
- return {
134
- ...call,
135
- function: {
136
- ...call.function,
137
- name: sanitizedName
138
- }
139
- };
140
- }
141
102
  function sanitizeChatCompletionChoice(choice, rules, stats) {
142
103
  const message = choice?.message;
143
104
  if (!message || typeof message !== 'object') {
@@ -189,10 +150,6 @@ function createStats(protocol, direction) {
189
150
  function sanitizeName(rawName, rules, stats, field) {
190
151
  const defaultName = rules.defaultName ?? 'tool';
191
152
  let next = typeof rawName === 'string' ? rawName : '';
192
- const nativeSanitized = sanitizeResponsesFunctionNameWithNative(next);
193
- if (typeof nativeSanitized === 'string' && nativeSanitized.trim().length) {
194
- next = nativeSanitized;
195
- }
196
153
  let changed = false;
197
154
  if (rules.trimWhitespace !== false) {
198
155
  next = next.trim();