@jsonstudio/llms 0.6.1164 → 0.6.1354

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 (164) hide show
  1. package/dist/conversion/codecs/gemini-openai-codec.d.ts +3 -1
  2. package/dist/conversion/codecs/gemini-openai-codec.js +10 -4
  3. package/dist/conversion/compat/actions/gemini-web-search.d.ts +1 -1
  4. package/dist/conversion/compat/actions/gemini-web-search.js +5 -2
  5. package/dist/conversion/compat/actions/iflow-tool-text-fallback.d.ts +12 -0
  6. package/dist/conversion/compat/actions/iflow-tool-text-fallback.js +199 -0
  7. package/dist/conversion/compat/actions/iflow-web-search.d.ts +1 -1
  8. package/dist/conversion/compat/actions/iflow-web-search.js +5 -2
  9. package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.js +47 -56
  10. package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.js +1 -13
  11. package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +523 -50
  12. package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +18 -38
  13. package/dist/conversion/hub/pipeline/compat/compat-pipeline-executor.js +6 -0
  14. package/dist/conversion/hub/pipeline/compat/compat-types.d.ts +3 -0
  15. package/dist/conversion/hub/pipeline/hub-pipeline/adapter-context.d.ts +10 -0
  16. package/dist/conversion/hub/pipeline/hub-pipeline/adapter-context.js +134 -0
  17. package/dist/conversion/hub/pipeline/hub-pipeline/anthropic-alias-map.d.ts +6 -0
  18. package/dist/conversion/hub/pipeline/hub-pipeline/anthropic-alias-map.js +79 -0
  19. package/dist/conversion/hub/pipeline/hub-pipeline/apply-patch-tool-mode.d.ts +3 -0
  20. package/dist/conversion/hub/pipeline/hub-pipeline/apply-patch-tool-mode.js +46 -0
  21. package/dist/conversion/hub/pipeline/hub-pipeline/execute-chat-process-entry.d.ts +8 -0
  22. package/dist/conversion/hub/pipeline/hub-pipeline/execute-chat-process-entry.js +366 -0
  23. package/dist/conversion/hub/pipeline/hub-pipeline/execute-request-stage.d.ts +9 -0
  24. package/dist/conversion/hub/pipeline/hub-pipeline/execute-request-stage.js +384 -0
  25. package/dist/conversion/hub/pipeline/hub-pipeline/node-results.d.ts +3 -0
  26. package/dist/conversion/hub/pipeline/hub-pipeline/node-results.js +14 -0
  27. package/dist/conversion/hub/pipeline/hub-pipeline/payload-normalize.d.ts +2 -0
  28. package/dist/conversion/hub/pipeline/hub-pipeline/payload-normalize.js +144 -0
  29. package/dist/conversion/hub/pipeline/hub-pipeline/policy.d.ts +4 -0
  30. package/dist/conversion/hub/pipeline/hub-pipeline/policy.js +32 -0
  31. package/dist/conversion/hub/pipeline/hub-pipeline/protocol.d.ts +8 -0
  32. package/dist/conversion/hub/pipeline/hub-pipeline/protocol.js +63 -0
  33. package/dist/conversion/hub/pipeline/hub-pipeline/resolve-protocol-hooks.d.ts +2 -0
  34. package/dist/conversion/hub/pipeline/hub-pipeline/resolve-protocol-hooks.js +43 -0
  35. package/dist/conversion/hub/pipeline/hub-pipeline/semantic-gate.d.ts +1 -0
  36. package/dist/conversion/hub/pipeline/hub-pipeline/semantic-gate.js +29 -0
  37. package/dist/conversion/hub/pipeline/hub-pipeline/servertool-runtime-config.d.ts +2 -0
  38. package/dist/conversion/hub/pipeline/hub-pipeline/servertool-runtime-config.js +16 -0
  39. package/dist/conversion/hub/pipeline/hub-pipeline/types.d.ts +116 -0
  40. package/dist/conversion/hub/pipeline/hub-pipeline/types.js +1 -0
  41. package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +3 -95
  42. package/dist/conversion/hub/pipeline/hub-pipeline.js +19 -1281
  43. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage1_format_parse/index.js +1 -1
  44. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.d.ts +7 -0
  45. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +65 -1
  46. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +25 -22
  47. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.js +1 -1
  48. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage2_format_build/index.d.ts +1 -1
  49. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage2_format_build/index.js +2 -2
  50. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage3_compat/index.js +2 -2
  51. package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage1_tool_governance/index.js +1 -1
  52. package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage2_route_select/index.js +1 -1
  53. package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js +11 -11
  54. package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage2_format_parse/index.js +1 -1
  55. package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage3_semantic_map/index.d.ts +1 -0
  56. package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage3_semantic_map/index.js +4 -2
  57. package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.d.ts +1 -0
  58. package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +17 -9
  59. package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage2_sse_stream/index.js +2 -2
  60. package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +40 -2
  61. package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage2_finalize/index.js +1 -1
  62. package/dist/conversion/hub/pipeline/target-utils.js +9 -5
  63. package/dist/conversion/hub/process/chat-process.js +256 -16
  64. package/dist/conversion/hub/response/provider-response.d.ts +8 -0
  65. package/dist/conversion/hub/response/provider-response.js +85 -27
  66. package/dist/conversion/hub/response/response-mappers.d.ts +10 -3
  67. package/dist/conversion/hub/response/response-mappers.js +30 -6
  68. package/dist/conversion/hub/response/response-runtime.js +4 -38
  69. package/dist/conversion/hub/snapshot-recorder.js +5 -1
  70. package/dist/conversion/hub/standardized-bridge.js +23 -15
  71. package/dist/conversion/pipeline/codecs/v2/anthropic-openai-pipeline.js +36 -5
  72. package/dist/conversion/responses/responses-openai-bridge.js +20 -4
  73. package/dist/conversion/shared/gemini-tool-utils.d.ts +8 -1
  74. package/dist/conversion/shared/gemini-tool-utils.js +580 -108
  75. package/dist/conversion/shared/jsonish.js +1 -1
  76. package/dist/conversion/shared/mcp-injection.js +67 -33
  77. package/dist/conversion/shared/openai-finalizer.js +2 -1
  78. package/dist/conversion/shared/openai-message-normalize.js +76 -21
  79. package/dist/conversion/shared/responses-output-builder.js +6 -0
  80. package/dist/conversion/shared/runtime-metadata.d.ts +7 -0
  81. package/dist/conversion/shared/runtime-metadata.js +23 -0
  82. package/dist/conversion/shared/text-markup-normalizer.d.ts +2 -0
  83. package/dist/conversion/shared/text-markup-normalizer.js +284 -4
  84. package/dist/conversion/shared/tool-canonicalizer.js +2 -1
  85. package/dist/conversion/shared/tool-governor.js +3 -3
  86. package/dist/filters/engine.js +5 -5
  87. package/dist/filters/special/request-tool-list-filter.js +194 -60
  88. package/dist/filters/special/request-tools-normalize.js +1 -1
  89. package/dist/filters/special/response-tool-text-canonicalize.d.ts +4 -7
  90. package/dist/filters/special/response-tool-text-canonicalize.js +7 -35
  91. package/dist/filters/special/tool-filter-hooks.js +58 -62
  92. package/dist/guidance/index.js +5 -1
  93. package/dist/http/sse-response.js +6 -6
  94. package/dist/router/virtual-router/bootstrap.js +65 -5
  95. package/dist/router/virtual-router/context-advisor.d.ts +4 -0
  96. package/dist/router/virtual-router/context-advisor.js +3 -0
  97. package/dist/router/virtual-router/context-weighted.d.ts +31 -0
  98. package/dist/router/virtual-router/context-weighted.js +54 -0
  99. package/dist/router/virtual-router/engine-health.d.ts +1 -1
  100. package/dist/router/virtual-router/engine-health.js +11 -110
  101. package/dist/router/virtual-router/engine-selection/alias-selection.d.ts +15 -0
  102. package/dist/router/virtual-router/engine-selection/alias-selection.js +156 -0
  103. package/dist/router/virtual-router/engine-selection/context-weight-multipliers.d.ts +11 -0
  104. package/dist/router/virtual-router/engine-selection/context-weight-multipliers.js +23 -0
  105. package/dist/router/virtual-router/engine-selection/direct-provider-model.d.ts +9 -0
  106. package/dist/router/virtual-router/engine-selection/direct-provider-model.js +49 -0
  107. package/dist/router/virtual-router/engine-selection/instruction-target.d.ts +6 -0
  108. package/dist/router/virtual-router/engine-selection/instruction-target.js +54 -0
  109. package/dist/router/virtual-router/engine-selection/key-parsing.d.ts +8 -0
  110. package/dist/router/virtual-router/engine-selection/key-parsing.js +64 -0
  111. package/dist/router/virtual-router/engine-selection/route-utils.d.ts +12 -0
  112. package/dist/router/virtual-router/engine-selection/route-utils.js +150 -0
  113. package/dist/router/virtual-router/engine-selection/routing-state-filter.d.ts +4 -0
  114. package/dist/router/virtual-router/engine-selection/routing-state-filter.js +50 -0
  115. package/dist/router/virtual-router/engine-selection/selection-deps.d.ts +39 -0
  116. package/dist/router/virtual-router/engine-selection/selection-deps.js +1 -0
  117. package/dist/router/virtual-router/engine-selection/sticky-pool.d.ts +11 -0
  118. package/dist/router/virtual-router/engine-selection/sticky-pool.js +109 -0
  119. package/dist/router/virtual-router/engine-selection/tier-priority.d.ts +12 -0
  120. package/dist/router/virtual-router/engine-selection/tier-priority.js +55 -0
  121. package/dist/router/virtual-router/engine-selection/tier-selection-select.d.ts +22 -0
  122. package/dist/router/virtual-router/engine-selection/tier-selection-select.js +400 -0
  123. package/dist/router/virtual-router/engine-selection/tier-selection.d.ts +3 -0
  124. package/dist/router/virtual-router/engine-selection/tier-selection.js +225 -0
  125. package/dist/router/virtual-router/engine-selection.d.ts +4 -30
  126. package/dist/router/virtual-router/engine-selection.js +10 -815
  127. package/dist/router/virtual-router/engine.d.ts +1 -0
  128. package/dist/router/virtual-router/engine.js +55 -10
  129. package/dist/router/virtual-router/routing-instructions.js +6 -1
  130. package/dist/router/virtual-router/stop-message-state-sync.d.ts +5 -0
  131. package/dist/router/virtual-router/stop-message-state-sync.js +6 -14
  132. package/dist/router/virtual-router/types.d.ts +53 -1
  133. package/dist/servertool/clock/config.d.ts +8 -0
  134. package/dist/servertool/clock/config.js +22 -0
  135. package/dist/servertool/clock/log.d.ts +3 -0
  136. package/dist/servertool/clock/log.js +13 -0
  137. package/dist/servertool/clock/task-store.d.ts +1 -1
  138. package/dist/servertool/clock/task-store.js +1 -1
  139. package/dist/servertool/clock/tasks.js +1 -1
  140. package/dist/servertool/engine.js +146 -21
  141. package/dist/servertool/handlers/clock-auto.js +11 -6
  142. package/dist/servertool/handlers/clock.js +36 -10
  143. package/dist/servertool/handlers/followup-request-builder.js +8 -2
  144. package/dist/servertool/handlers/gemini-empty-reply-continue.js +15 -9
  145. package/dist/servertool/handlers/iflow-model-error-retry.js +6 -4
  146. package/dist/servertool/handlers/recursive-detection-guard.js +4 -2
  147. package/dist/servertool/handlers/stop-message-auto.js +100 -10
  148. package/dist/servertool/handlers/vision.js +4 -1
  149. package/dist/servertool/handlers/web-search.js +3 -1
  150. package/dist/servertool/pending-session.d.ts +19 -0
  151. package/dist/servertool/pending-session.js +97 -0
  152. package/dist/servertool/reenter-backend.js +5 -3
  153. package/dist/servertool/server-side-tools.js +235 -6
  154. package/dist/servertool/types.d.ts +13 -0
  155. package/dist/sse/json-to-sse/event-generators/responses.js +1 -1
  156. package/dist/sse/shared/chat-serializer.js +2 -2
  157. package/dist/sse/shared/constants.js +1 -1
  158. package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +7 -1
  159. package/dist/sse/sse-to-json/builders/response-builder.js +16 -0
  160. package/dist/sse/sse-to-json/responses-sse-to-json-converter.d.ts +1 -1
  161. package/dist/tools/apply-patch/execution-capturer.js +1 -1
  162. package/dist/tools/exec-command/normalize.js +4 -0
  163. package/dist/tools/exec-command/regression-capturer.js +1 -1
  164. package/package.json +10 -5
@@ -0,0 +1,366 @@
1
+ import { jsonClone } from '../../types/json.js';
2
+ import { ensureRuntimeMetadata, readRuntimeMetadata } from '../../../shared/runtime-metadata.js';
3
+ import { computeRequestTokens } from '../../../../router/virtual-router/token-estimator.js';
4
+ import { recordHubPolicyObservation, applyHubProviderOutboundPolicy } from '../../policy/policy-engine.js';
5
+ import { applyProviderOutboundToolSurface } from '../../tool-surface/tool-surface-engine.js';
6
+ import { extractSessionIdentifiersFromMetadata } from '../session-identifiers.js';
7
+ import { runReqProcessStage1ToolGovernance } from '../stages/req_process/req_process_stage1_tool_governance/index.js';
8
+ import { runReqProcessStage2RouteSelect } from '../stages/req_process/req_process_stage2_route_select/index.js';
9
+ import { runReqOutboundStage1SemanticMap } from '../stages/req_outbound/req_outbound_stage1_semantic_map/index.js';
10
+ import { runReqOutboundStage2FormatBuild } from '../stages/req_outbound/req_outbound_stage2_format_build/index.js';
11
+ import { runReqOutboundStage3Compat } from '../stages/req_outbound/req_outbound_stage3_compat/index.js';
12
+ import { buildAdapterContext, maybeCreateStageRecorder, resolveOutboundStreamIntent, applyOutboundStreamPreference } from './adapter-context.js';
13
+ import { assertNoMappableSemanticsInMetadata } from './semantic-gate.js';
14
+ import { convertProcessNodeResult } from './node-results.js';
15
+ import { injectServerToolRuntimeConfig } from './servertool-runtime-config.js';
16
+ function asJsonObject(value) {
17
+ if (!value || typeof value !== 'object') {
18
+ throw new Error('Responses pipeline requires JSON object payload');
19
+ }
20
+ return value;
21
+ }
22
+ function readResponsesResumeFromSemantics(request) {
23
+ try {
24
+ const semantics = request?.semantics;
25
+ const node = semantics && typeof semantics === 'object' && !Array.isArray(semantics) ? semantics.responses : undefined;
26
+ const resume = node && typeof node === 'object' && !Array.isArray(node) ? node.resume : undefined;
27
+ return resume && typeof resume === 'object' && !Array.isArray(resume) ? resume : undefined;
28
+ }
29
+ catch {
30
+ return undefined;
31
+ }
32
+ }
33
+ function coerceStandardizedRequestFromPayload(payload, normalized) {
34
+ const model = typeof payload.model === 'string' && payload.model.trim().length ? payload.model.trim() : '';
35
+ if (!model) {
36
+ throw new Error('[HubPipeline] outbound stage requires payload.model');
37
+ }
38
+ const messages = Array.isArray(payload.messages) ? payload.messages : null;
39
+ if (!messages) {
40
+ throw new Error('[HubPipeline] outbound stage requires payload.messages[]');
41
+ }
42
+ const tools = Array.isArray(payload.tools) ? payload.tools : undefined;
43
+ const parameters = payload.parameters && typeof payload.parameters === 'object' && !Array.isArray(payload.parameters)
44
+ ? payload.parameters
45
+ : {};
46
+ const semanticsFromPayload = payload.semantics && typeof payload.semantics === 'object' && !Array.isArray(payload.semantics)
47
+ ? jsonClone(payload.semantics)
48
+ : undefined;
49
+ const metadataFromPayload = payload.metadata && typeof payload.metadata === 'object' && !Array.isArray(payload.metadata)
50
+ ? payload.metadata
51
+ : undefined;
52
+ const standardizedRequest = {
53
+ model,
54
+ messages,
55
+ ...(tools ? { tools } : {}),
56
+ parameters,
57
+ metadata: {
58
+ originalEndpoint: normalized.entryEndpoint,
59
+ ...(metadataFromPayload ? metadataFromPayload : {}),
60
+ requestId: normalized.id,
61
+ stream: normalized.stream,
62
+ processMode: normalized.processMode,
63
+ ...(normalized.routeHint ? { routeHint: normalized.routeHint } : {})
64
+ },
65
+ ...(semanticsFromPayload ? { semantics: semanticsFromPayload } : {})
66
+ };
67
+ // Ensure followup/chat_process entry can still preserve mappable semantics
68
+ // without injecting them into metadata.
69
+ try {
70
+ const semantics = standardizedRequest.semantics && typeof standardizedRequest.semantics === 'object'
71
+ ? standardizedRequest.semantics
72
+ : (standardizedRequest.semantics = {});
73
+ if (!semantics.tools || typeof semantics.tools !== 'object' || Array.isArray(semantics.tools)) {
74
+ semantics.tools = {};
75
+ }
76
+ const toolsNode = semantics.tools;
77
+ if (Array.isArray(payload.tools) && payload.tools.length && toolsNode.clientToolsRaw === undefined) {
78
+ toolsNode.clientToolsRaw = jsonClone(payload.tools);
79
+ }
80
+ }
81
+ catch {
82
+ // best-effort
83
+ }
84
+ const rawPayload = {
85
+ model,
86
+ messages,
87
+ ...(tools ? { tools } : {}),
88
+ ...(parameters && Object.keys(parameters).length ? { parameters } : {})
89
+ };
90
+ return { standardizedRequest, rawPayload };
91
+ }
92
+ export async function executeChatProcessEntryPipeline(options) {
93
+ const { config, routerEngine, normalized } = options;
94
+ const hooks = options.resolveProtocolHooks(normalized.providerProtocol);
95
+ if (!hooks) {
96
+ throw new Error(`Unsupported provider protocol for hub pipeline: ${normalized.providerProtocol}`);
97
+ }
98
+ const nodeResults = [];
99
+ nodeResults.push({
100
+ id: 'req_inbound',
101
+ success: true,
102
+ metadata: {
103
+ node: 'req_inbound',
104
+ skipped: true,
105
+ reason: 'stage=outbound',
106
+ dataProcessed: {}
107
+ }
108
+ });
109
+ const rawPayloadInput = asJsonObject(normalized.payload);
110
+ const { standardizedRequest: standardizedRequestBase, rawPayload } = coerceStandardizedRequestFromPayload(rawPayloadInput, normalized);
111
+ const metaBase = {
112
+ ...(normalized.metadata ?? {})
113
+ };
114
+ injectServerToolRuntimeConfig(config, metaBase);
115
+ normalized.metadata = metaBase;
116
+ const standardizedRequest = standardizedRequestBase;
117
+ try {
118
+ const resumeMeta = metaBase && typeof metaBase.responsesResume === 'object' && metaBase.responsesResume
119
+ ? metaBase.responsesResume
120
+ : undefined;
121
+ if (resumeMeta) {
122
+ standardizedRequest.semantics = standardizedRequest.semantics ?? {};
123
+ const semantics = standardizedRequest.semantics;
124
+ if (!semantics.responses || typeof semantics.responses !== 'object' || Array.isArray(semantics.responses)) {
125
+ semantics.responses = {};
126
+ }
127
+ const responsesNode = semantics.responses;
128
+ if (responsesNode.resume === undefined) {
129
+ responsesNode.resume = jsonClone(resumeMeta);
130
+ }
131
+ delete metaBase.responsesResume;
132
+ }
133
+ }
134
+ catch {
135
+ // best-effort
136
+ }
137
+ try {
138
+ const rt = readRuntimeMetadata(metaBase);
139
+ const mode = String(rt?.applyPatchToolMode || '').trim().toLowerCase();
140
+ if (mode === 'freeform' || mode === 'schema') {
141
+ standardizedRequest.metadata.applyPatchToolMode = mode;
142
+ }
143
+ }
144
+ catch {
145
+ // ignore
146
+ }
147
+ const adapterContext = buildAdapterContext(normalized);
148
+ const stageRecorder = maybeCreateStageRecorder(adapterContext, normalized.entryEndpoint, {
149
+ disableSnapshots: normalized.disableSnapshots === true
150
+ });
151
+ let processedRequest;
152
+ if (normalized.processMode !== 'passthrough') {
153
+ assertNoMappableSemanticsInMetadata(metaBase, 'chat_process.request.entry');
154
+ const processResult = await runReqProcessStage1ToolGovernance({
155
+ request: standardizedRequest,
156
+ rawPayload,
157
+ metadata: metaBase,
158
+ entryEndpoint: normalized.entryEndpoint,
159
+ requestId: normalized.id,
160
+ stageRecorder
161
+ });
162
+ processedRequest = processResult.processedRequest;
163
+ try {
164
+ const reservation = processedRequest?.metadata?.__clockReservation;
165
+ if (reservation && typeof reservation === 'object') {
166
+ metaBase.__clockReservation = reservation;
167
+ }
168
+ }
169
+ catch {
170
+ // best-effort
171
+ }
172
+ if (processResult.nodeResult) {
173
+ nodeResults.push(convertProcessNodeResult('chat_process.req.stage4.tool_governance', processResult.nodeResult));
174
+ }
175
+ }
176
+ let workingRequest = processedRequest ?? standardizedRequest;
177
+ try {
178
+ const estimatedTokens = computeRequestTokens(workingRequest, '');
179
+ if (typeof estimatedTokens === 'number' && Number.isFinite(estimatedTokens) && estimatedTokens > 0) {
180
+ normalized.metadata = normalized.metadata || {};
181
+ normalized.metadata.estimatedInputTokens = estimatedTokens;
182
+ }
183
+ }
184
+ catch {
185
+ // ignore
186
+ }
187
+ const normalizedMeta = normalized.metadata;
188
+ const responsesResume = readResponsesResumeFromSemantics(workingRequest);
189
+ const stdMetadata = workingRequest?.metadata;
190
+ const hasImageAttachment = (stdMetadata?.hasImageAttachment === true || stdMetadata?.hasImageAttachment === 'true') ||
191
+ (normalizedMeta?.hasImageAttachment === true || normalizedMeta?.hasImageAttachment === 'true');
192
+ const serverToolRequired = stdMetadata?.webSearchEnabled === true || stdMetadata?.serverToolRequired === true;
193
+ const sessionIdentifiers = extractSessionIdentifiersFromMetadata(normalized.metadata);
194
+ if (sessionIdentifiers.sessionId && normalized.metadata && typeof normalized.metadata === 'object') {
195
+ normalized.metadata.sessionId = sessionIdentifiers.sessionId;
196
+ }
197
+ if (sessionIdentifiers.conversationId && normalized.metadata && typeof normalized.metadata === 'object') {
198
+ normalized.metadata.conversationId = sessionIdentifiers.conversationId;
199
+ }
200
+ const disableStickyRoutes = readRuntimeMetadata(normalized.metadata)?.disableStickyRoutes === true;
201
+ const shadowCompareForcedProviderKey = normalizedMeta && typeof normalizedMeta.__shadowCompareForcedProviderKey === 'string'
202
+ ? String(normalizedMeta.__shadowCompareForcedProviderKey)
203
+ : '';
204
+ const disabledProviderKeyAliases = normalizedMeta && Array.isArray(normalizedMeta.disabledProviderKeyAliases)
205
+ ? normalizedMeta.disabledProviderKeyAliases
206
+ : null;
207
+ const metadataInput = {
208
+ requestId: normalized.id,
209
+ entryEndpoint: normalized.entryEndpoint,
210
+ processMode: normalized.processMode,
211
+ stream: normalized.stream,
212
+ direction: normalized.direction,
213
+ providerProtocol: normalized.providerProtocol,
214
+ routeHint: normalized.routeHint,
215
+ stage: normalized.stage,
216
+ responsesResume: responsesResume,
217
+ ...(disableStickyRoutes ? { disableStickyRoutes: true } : {}),
218
+ ...(serverToolRequired ? { serverToolRequired: true } : {}),
219
+ ...(sessionIdentifiers.sessionId ? { sessionId: sessionIdentifiers.sessionId } : {}),
220
+ ...(sessionIdentifiers.conversationId ? { conversationId: sessionIdentifiers.conversationId } : {}),
221
+ ...(shadowCompareForcedProviderKey.trim().length
222
+ ? { __shadowCompareForcedProviderKey: shadowCompareForcedProviderKey.trim() }
223
+ : {}),
224
+ ...(disabledProviderKeyAliases && disabledProviderKeyAliases.length
225
+ ? { disabledProviderKeyAliases: disabledProviderKeyAliases }
226
+ : {})
227
+ };
228
+ const routing = runReqProcessStage2RouteSelect({
229
+ routerEngine,
230
+ request: workingRequest,
231
+ metadataInput,
232
+ normalizedMetadata: normalized.metadata,
233
+ stageRecorder
234
+ });
235
+ const stopMessageState = routerEngine.getStopMessageState(metadataInput);
236
+ if (stopMessageState && normalized.metadata && typeof normalized.metadata === 'object') {
237
+ const rt = ensureRuntimeMetadata(normalized.metadata);
238
+ rt.stopMessageState = stopMessageState;
239
+ }
240
+ try {
241
+ const routeName = routing.decision?.routeName;
242
+ const providerKey = routing.target?.providerKey;
243
+ const modelId = workingRequest.model;
244
+ const logger = (normalized.metadata && normalized.metadata.logger);
245
+ if (logger && typeof logger.logVirtualRouterHit === 'function' && routeName && providerKey) {
246
+ logger.logVirtualRouterHit(routeName, providerKey, typeof modelId === 'string' ? modelId : undefined);
247
+ }
248
+ }
249
+ catch {
250
+ // ignore
251
+ }
252
+ const outboundStream = resolveOutboundStreamIntent(routing.target?.streaming);
253
+ workingRequest = applyOutboundStreamPreference(workingRequest, outboundStream);
254
+ const outboundAdapterContext = buildAdapterContext(normalized, routing.target);
255
+ if (routing.target?.compatibilityProfile) {
256
+ outboundAdapterContext.compatibilityProfile = routing.target.compatibilityProfile;
257
+ }
258
+ const outboundProtocol = outboundAdapterContext.providerProtocol;
259
+ const protocolSwitch = outboundProtocol !== normalized.providerProtocol;
260
+ const outboundHooks = protocolSwitch ? options.resolveProtocolHooks(outboundProtocol) : hooks;
261
+ if (!outboundHooks) {
262
+ throw new Error(`[HubPipeline] Unsupported provider protocol for hub pipeline: ${outboundProtocol}`);
263
+ }
264
+ const outboundSemanticMapper = protocolSwitch ? outboundHooks.createSemanticMapper() : hooks.createSemanticMapper();
265
+ const outboundFormatAdapter = protocolSwitch ? outboundHooks.createFormatAdapter() : hooks.createFormatAdapter();
266
+ const outboundContextMetadataKey = protocolSwitch ? outboundHooks.contextMetadataKey : hooks.contextMetadataKey;
267
+ const outboundContextSnapshot = undefined;
268
+ const outboundRecorder = maybeCreateStageRecorder(outboundAdapterContext, normalized.entryEndpoint, {
269
+ disableSnapshots: normalized.disableSnapshots === true
270
+ });
271
+ const outboundStart = Date.now();
272
+ const outboundStage1 = await runReqOutboundStage1SemanticMap({
273
+ request: workingRequest,
274
+ adapterContext: outboundAdapterContext,
275
+ semanticMapper: outboundSemanticMapper,
276
+ contextSnapshot: outboundContextSnapshot,
277
+ contextMetadataKey: outboundContextMetadataKey,
278
+ stageRecorder: outboundRecorder
279
+ });
280
+ let formattedPayload = await runReqOutboundStage2FormatBuild({
281
+ formatEnvelope: outboundStage1.formatEnvelope,
282
+ adapterContext: outboundAdapterContext,
283
+ formatAdapter: outboundFormatAdapter,
284
+ stageRecorder: outboundRecorder
285
+ });
286
+ formattedPayload = await runReqOutboundStage3Compat({
287
+ payload: formattedPayload,
288
+ adapterContext: outboundAdapterContext,
289
+ stageRecorder: outboundRecorder
290
+ });
291
+ const effectivePolicy = normalized.policyOverride ?? config.policy;
292
+ recordHubPolicyObservation({
293
+ policy: effectivePolicy,
294
+ providerProtocol: outboundProtocol,
295
+ payload: formattedPayload,
296
+ stageRecorder: outboundRecorder,
297
+ requestId: normalized.id
298
+ });
299
+ let providerPayload = applyHubProviderOutboundPolicy({
300
+ policy: effectivePolicy,
301
+ providerProtocol: outboundProtocol,
302
+ payload: formattedPayload,
303
+ stageRecorder: outboundRecorder,
304
+ requestId: normalized.id
305
+ });
306
+ providerPayload = applyProviderOutboundToolSurface({
307
+ config: config.toolSurface,
308
+ providerProtocol: outboundProtocol,
309
+ payload: providerPayload,
310
+ stageRecorder: outboundRecorder,
311
+ requestId: normalized.id
312
+ });
313
+ recordHubPolicyObservation({
314
+ policy: effectivePolicy,
315
+ providerProtocol: outboundProtocol,
316
+ payload: providerPayload,
317
+ stageRecorder: outboundRecorder,
318
+ requestId: normalized.id
319
+ });
320
+ const outboundEnd = Date.now();
321
+ nodeResults.push({
322
+ id: 'req_outbound',
323
+ success: true,
324
+ metadata: {
325
+ node: 'req_outbound',
326
+ executionTime: outboundEnd - outboundStart,
327
+ startTime: outboundStart,
328
+ endTime: outboundEnd,
329
+ dataProcessed: {
330
+ messages: workingRequest.messages.length,
331
+ tools: workingRequest.tools?.length ?? 0
332
+ }
333
+ }
334
+ });
335
+ const capturedChatRequest = {
336
+ model: workingRequest.model,
337
+ messages: jsonClone(workingRequest.messages),
338
+ tools: workingRequest.tools ? jsonClone(workingRequest.tools) : workingRequest.tools,
339
+ parameters: workingRequest.parameters
340
+ ? jsonClone(workingRequest.parameters)
341
+ : workingRequest.parameters
342
+ };
343
+ const metadata = {
344
+ ...normalized.metadata,
345
+ ...(hasImageAttachment ? { hasImageAttachment: true } : {}),
346
+ capturedChatRequest,
347
+ entryEndpoint: normalized.entryEndpoint,
348
+ providerProtocol: outboundProtocol,
349
+ stream: normalized.stream,
350
+ processMode: normalized.processMode,
351
+ routeHint: normalized.routeHint,
352
+ target: routing.target,
353
+ ...(typeof outboundStream === 'boolean' ? { providerStream: outboundStream } : {})
354
+ };
355
+ return {
356
+ requestId: normalized.id,
357
+ providerPayload,
358
+ standardizedRequest,
359
+ processedRequest,
360
+ routingDecision: routing.decision,
361
+ routingDiagnostics: routing.diagnostics,
362
+ target: routing.target,
363
+ metadata,
364
+ nodeResults
365
+ };
366
+ }
@@ -0,0 +1,9 @@
1
+ import type { VirtualRouterEngine } from '../../../../router/virtual-router/engine.js';
2
+ import type { HubPipelineConfig, HubPipelineResult, NormalizedRequest, ProviderProtocol, RequestStageHooks } from './types.js';
3
+ export declare function executeRequestStagePipeline<TContext = Record<string, unknown>>(options: {
4
+ config: HubPipelineConfig;
5
+ routerEngine: VirtualRouterEngine;
6
+ normalized: NormalizedRequest;
7
+ hooks: RequestStageHooks<TContext>;
8
+ resolveProtocolHooks: (protocol: ProviderProtocol) => RequestStageHooks<Record<string, unknown>> | undefined;
9
+ }): Promise<HubPipelineResult>;