@jsonstudio/llms 0.6.954 → 0.6.1164

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 (130) hide show
  1. package/dist/conversion/hub/operation-table/operation-table-runner.d.ts +18 -0
  2. package/dist/conversion/hub/operation-table/operation-table-runner.js +158 -0
  3. package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.d.ts +8 -0
  4. package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.js +303 -0
  5. package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.d.ts +8 -0
  6. package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.js +413 -0
  7. package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.d.ts +7 -0
  8. package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +841 -0
  9. package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.d.ts +21 -0
  10. package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +535 -0
  11. package/dist/conversion/hub/ops/operations.d.ts +19 -0
  12. package/dist/conversion/hub/ops/operations.js +126 -0
  13. package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +9 -0
  14. package/dist/conversion/hub/pipeline/hub-pipeline.js +489 -19
  15. package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +6 -0
  16. package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.js +11 -0
  17. package/dist/conversion/hub/policy/policy-engine.js +41 -9
  18. package/dist/conversion/hub/policy/protocol-spec.d.ts +25 -0
  19. package/dist/conversion/hub/policy/protocol-spec.js +73 -23
  20. package/dist/conversion/hub/process/chat-process.js +252 -41
  21. package/dist/conversion/hub/response/provider-response.js +175 -2
  22. package/dist/conversion/hub/response/response-runtime.js +1 -1
  23. package/dist/conversion/hub/semantic-mappers/anthropic-mapper.d.ts +1 -8
  24. package/dist/conversion/hub/semantic-mappers/anthropic-mapper.js +1 -365
  25. package/dist/conversion/hub/semantic-mappers/chat-mapper.d.ts +1 -8
  26. package/dist/conversion/hub/semantic-mappers/chat-mapper.js +1 -467
  27. package/dist/conversion/hub/semantic-mappers/gemini-mapper.d.ts +1 -7
  28. package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +1 -903
  29. package/dist/conversion/hub/semantic-mappers/responses-mapper.d.ts +1 -21
  30. package/dist/conversion/hub/semantic-mappers/responses-mapper.js +1 -593
  31. package/dist/conversion/hub/tool-surface/tool-surface-engine.d.ts +18 -0
  32. package/dist/conversion/hub/tool-surface/tool-surface-engine.js +571 -0
  33. package/dist/conversion/responses/responses-openai-bridge.js +14 -2
  34. package/dist/conversion/shared/bridge-message-utils.js +2 -8
  35. package/dist/conversion/shared/bridge-policies.js +5 -105
  36. package/dist/conversion/shared/gemini-tool-utils.js +89 -15
  37. package/dist/conversion/shared/protocol-field-allowlists.d.ts +7 -0
  38. package/dist/conversion/shared/protocol-field-allowlists.js +145 -0
  39. package/dist/conversion/shared/reasoning-tool-normalizer.js +4 -2
  40. package/dist/conversion/shared/snapshot-hooks.js +166 -3
  41. package/dist/conversion/shared/text-markup-normalizer.d.ts +2 -0
  42. package/dist/conversion/shared/text-markup-normalizer.js +345 -9
  43. package/dist/conversion/shared/thought-signature-validator.d.ts +52 -0
  44. package/dist/conversion/shared/thought-signature-validator.js +170 -0
  45. package/dist/conversion/shared/tool-argument-repairer.d.ts +39 -0
  46. package/dist/conversion/shared/tool-argument-repairer.js +56 -0
  47. package/dist/conversion/shared/tool-call-id-manager.d.ts +113 -0
  48. package/dist/conversion/shared/tool-call-id-manager.js +231 -0
  49. package/dist/conversion/shared/tool-canonicalizer.js +2 -11
  50. package/dist/router/virtual-router/bootstrap.js +54 -5
  51. package/dist/router/virtual-router/engine-selection.js +132 -42
  52. package/dist/router/virtual-router/engine.d.ts +3 -0
  53. package/dist/router/virtual-router/engine.js +142 -33
  54. package/dist/router/virtual-router/health-weighted.d.ts +25 -0
  55. package/dist/router/virtual-router/health-weighted.js +63 -0
  56. package/dist/router/virtual-router/load-balancer.d.ts +2 -0
  57. package/dist/router/virtual-router/load-balancer.js +45 -16
  58. package/dist/router/virtual-router/routing-instructions.js +17 -1
  59. package/dist/router/virtual-router/sticky-session-store.js +136 -24
  60. package/dist/router/virtual-router/stop-message-file-resolver.d.ts +1 -0
  61. package/dist/router/virtual-router/stop-message-file-resolver.js +74 -0
  62. package/dist/router/virtual-router/stop-message-state-sync.d.ts +15 -0
  63. package/dist/router/virtual-router/stop-message-state-sync.js +57 -0
  64. package/dist/router/virtual-router/types.d.ts +70 -0
  65. package/dist/servertool/clock/config.d.ts +7 -0
  66. package/dist/servertool/clock/config.js +27 -0
  67. package/dist/servertool/clock/daemon.d.ts +3 -0
  68. package/dist/servertool/clock/daemon.js +79 -0
  69. package/dist/servertool/clock/io.d.ts +2 -0
  70. package/dist/servertool/clock/io.js +13 -0
  71. package/dist/servertool/clock/paths.d.ts +4 -0
  72. package/dist/servertool/clock/paths.js +25 -0
  73. package/dist/servertool/clock/session-store.d.ts +3 -0
  74. package/dist/servertool/clock/session-store.js +56 -0
  75. package/dist/servertool/clock/state.d.ts +5 -0
  76. package/dist/servertool/clock/state.js +62 -0
  77. package/dist/servertool/clock/task-store.d.ts +5 -0
  78. package/dist/servertool/clock/task-store.js +4 -0
  79. package/dist/servertool/clock/tasks.d.ts +17 -0
  80. package/dist/servertool/clock/tasks.js +221 -0
  81. package/dist/servertool/clock/types.d.ts +36 -0
  82. package/dist/servertool/clock/types.js +1 -0
  83. package/dist/servertool/engine.d.ts +2 -0
  84. package/dist/servertool/engine.js +161 -7
  85. package/dist/servertool/followup-shadow.d.ts +16 -0
  86. package/dist/servertool/followup-shadow.js +145 -0
  87. package/dist/servertool/handlers/apply-patch-guard.js +1 -265
  88. package/dist/servertool/handlers/clock-auto.d.ts +1 -0
  89. package/dist/servertool/handlers/clock-auto.js +160 -0
  90. package/dist/servertool/handlers/clock.d.ts +1 -0
  91. package/dist/servertool/handlers/clock.js +197 -0
  92. package/dist/servertool/handlers/exec-command-guard.js +7 -555
  93. package/dist/servertool/handlers/followup-request-builder.d.ts +15 -7
  94. package/dist/servertool/handlers/followup-request-builder.js +248 -28
  95. package/dist/servertool/handlers/gemini-empty-reply-continue.js +62 -169
  96. package/dist/servertool/handlers/iflow-model-error-retry.js +18 -28
  97. package/dist/servertool/handlers/recursive-detection-guard.d.ts +1 -0
  98. package/dist/servertool/handlers/recursive-detection-guard.js +333 -0
  99. package/dist/servertool/handlers/stop-message-auto.js +47 -175
  100. package/dist/servertool/handlers/vision.d.ts +7 -1
  101. package/dist/servertool/handlers/vision.js +61 -117
  102. package/dist/servertool/handlers/web-search.d.ts +7 -1
  103. package/dist/servertool/handlers/web-search.js +122 -105
  104. package/dist/servertool/reenter-backend.d.ts +23 -0
  105. package/dist/servertool/reenter-backend.js +18 -0
  106. package/dist/servertool/server-side-tools.d.ts +3 -2
  107. package/dist/servertool/server-side-tools.js +64 -10
  108. package/dist/servertool/types.d.ts +92 -3
  109. package/dist/sse/json-to-sse/event-generators/responses.js +3 -21
  110. package/dist/sse/shared/serializers/responses-event-serializer.d.ts +8 -0
  111. package/dist/sse/shared/serializers/responses-event-serializer.js +19 -0
  112. package/dist/sse/shared/writer.js +24 -7
  113. package/dist/tools/apply-patch/execution-capturer.js +3 -1
  114. package/dist/tools/apply-patch/json/parse-loose.d.ts +3 -0
  115. package/dist/tools/apply-patch/json/parse-loose.js +139 -0
  116. package/dist/tools/apply-patch/patch-text/context-diff.d.ts +1 -0
  117. package/dist/tools/apply-patch/patch-text/context-diff.js +173 -0
  118. package/dist/tools/apply-patch/patch-text/git-diff.d.ts +1 -0
  119. package/dist/tools/apply-patch/patch-text/git-diff.js +138 -0
  120. package/dist/tools/apply-patch/patch-text/looks-like-patch.d.ts +1 -0
  121. package/dist/tools/apply-patch/patch-text/looks-like-patch.js +13 -0
  122. package/dist/tools/apply-patch/patch-text/normalize.d.ts +3 -0
  123. package/dist/tools/apply-patch/patch-text/normalize.js +262 -0
  124. package/dist/tools/apply-patch/structured/coercion.d.ts +3 -0
  125. package/dist/tools/apply-patch/structured/coercion.js +82 -0
  126. package/dist/tools/apply-patch/validation/shared.d.ts +3 -0
  127. package/dist/tools/apply-patch/validation/shared.js +6 -0
  128. package/dist/tools/apply-patch/validator.d.ts +2 -2
  129. package/dist/tools/apply-patch/validator.js +6 -556
  130. package/package.json +1 -1
@@ -1,21 +1 @@
1
- import type { SemanticMapper } from '../format-adapters/index.js';
2
- import type { AdapterContext, ChatEnvelope } from '../types/chat-envelope.js';
3
- import type { FormatEnvelope } from '../types/format-envelope.js';
4
- import { type JsonObject, type JsonValue } from '../types/json.js';
5
- interface ResponsesToolOutputEntry extends JsonObject {
6
- tool_call_id?: string;
7
- call_id?: string;
8
- id?: string;
9
- output?: JsonValue;
10
- name?: string;
11
- }
12
- interface ResponsesPayload extends JsonObject {
13
- input?: JsonValue[];
14
- tools?: JsonValue[];
15
- tool_outputs?: ResponsesToolOutputEntry[];
16
- }
17
- export declare class ResponsesSemanticMapper implements SemanticMapper {
18
- toChat(format: FormatEnvelope<ResponsesPayload>, ctx: AdapterContext): Promise<ChatEnvelope>;
19
- fromChat(chat: ChatEnvelope, ctx: AdapterContext): Promise<FormatEnvelope>;
20
- }
21
- export {};
1
+ export { ResponsesSemanticMapper } from '../operation-table/semantic-mappers/responses-mapper.js';
@@ -1,593 +1 @@
1
- import { isJsonObject, jsonClone } from '../types/json.js';
2
- import { createBridgeActionState, runBridgeActionPipeline } from '../../shared/bridge-actions.js';
3
- import { resolveBridgePolicy, resolvePolicyActions } from '../../shared/bridge-policies.js';
4
- import { captureResponsesContext, buildChatRequestFromResponses, buildResponsesRequestFromChat } from '../../responses/responses-openai-bridge.js';
5
- import { maybeAugmentApplyPatchErrorContent } from './chat-mapper.js';
6
- const RESPONSES_PARAMETER_KEYS = [
7
- 'model',
8
- 'temperature',
9
- 'top_p',
10
- 'top_k',
11
- 'max_tokens',
12
- 'max_output_tokens',
13
- 'response_format',
14
- 'tool_choice',
15
- 'parallel_tool_calls',
16
- 'user',
17
- 'logit_bias',
18
- 'seed',
19
- 'stop',
20
- 'stop_sequences',
21
- 'modalities'
22
- ];
23
- const RESPONSES_SUBMIT_ENDPOINT = '/v1/responses.submit_tool_outputs';
24
- function mapToolOutputs(entries, missing) {
25
- if (!entries || !entries.length)
26
- return undefined;
27
- const outputs = [];
28
- entries.forEach((entry, index) => {
29
- if (!isJsonObject(entry)) {
30
- missing.push({ path: `tool_outputs[${index}]`, reason: 'invalid_entry', originalValue: jsonClone(entry) });
31
- return;
32
- }
33
- const callId = entry.tool_call_id || entry.call_id || entry.id;
34
- if (!callId) {
35
- missing.push({ path: `tool_outputs[${index}].tool_call_id`, reason: 'missing_tool_call_id' });
36
- return;
37
- }
38
- let content = '';
39
- if (typeof entry.output === 'string') {
40
- content = entry.output;
41
- }
42
- else if (entry.output != null) {
43
- try {
44
- content = JSON.stringify(entry.output);
45
- }
46
- catch {
47
- content = String(entry.output);
48
- }
49
- }
50
- const nameValue = typeof entry.name === 'string' ? entry.name : undefined;
51
- const augmented = maybeAugmentApplyPatchErrorContent(content, nameValue);
52
- outputs.push({
53
- tool_call_id: String(callId),
54
- content: augmented,
55
- name: nameValue
56
- });
57
- });
58
- return outputs.length ? outputs : undefined;
59
- }
60
- function deriveResumeToolOutputs(ctx) {
61
- if (!ctx || typeof ctx !== 'object') {
62
- return undefined;
63
- }
64
- const resume = ctx.responsesResume;
65
- if (!resume || typeof resume !== 'object') {
66
- return undefined;
67
- }
68
- const detailed = Array.isArray(resume.toolOutputsDetailed)
69
- ? resume.toolOutputsDetailed
70
- : undefined;
71
- if (!detailed || detailed.length === 0) {
72
- return undefined;
73
- }
74
- const outputs = [];
75
- detailed.forEach((entry, index) => {
76
- if (!entry || typeof entry !== 'object') {
77
- return;
78
- }
79
- const callIdRaw = typeof entry.callId === 'string' && entry.callId.trim().length
80
- ? entry.callId.trim()
81
- : typeof entry.originalId === 'string' && entry.originalId.trim().length
82
- ? entry.originalId.trim()
83
- : `resume_tool_${index}`;
84
- if (!callIdRaw) {
85
- return;
86
- }
87
- const outputText = typeof entry.outputText === 'string' ? entry.outputText : '';
88
- outputs.push({
89
- tool_call_id: callIdRaw,
90
- content: outputText
91
- });
92
- });
93
- return outputs.length ? outputs : undefined;
94
- }
95
- function collectParameters(payload, streamHint) {
96
- const params = {};
97
- for (const key of RESPONSES_PARAMETER_KEYS) {
98
- if (payload[key] !== undefined) {
99
- params[key] = payload[key];
100
- }
101
- }
102
- if (streamHint !== undefined) {
103
- params.stream = streamHint;
104
- }
105
- return Object.keys(params).length ? params : undefined;
106
- }
107
- function normalizeTools(rawTools, missing) {
108
- if (!rawTools || rawTools.length === 0)
109
- return undefined;
110
- const tools = [];
111
- rawTools.forEach((tool, index) => {
112
- if (!tool || typeof tool !== 'object' || Array.isArray(tool)) {
113
- missing.push({ path: `tools[${index}]`, reason: 'invalid_entry', originalValue: jsonClone(tool) });
114
- return;
115
- }
116
- const fn = tool.function;
117
- if (!fn || typeof fn !== 'object' || Array.isArray(fn))
118
- return;
119
- const name = fn.name;
120
- const nameValue = typeof name === 'string' ? name : undefined;
121
- if (!nameValue)
122
- return;
123
- const descriptionValue = fn.description;
124
- const parametersValue = fn.parameters;
125
- const strictValue = fn.strict;
126
- const definition = {
127
- type: 'function',
128
- function: {
129
- name: nameValue,
130
- description: typeof descriptionValue === 'string' ? descriptionValue : undefined,
131
- parameters: parametersValue,
132
- strict: typeof strictValue === 'boolean' ? strictValue : undefined
133
- }
134
- };
135
- tools.push(definition);
136
- });
137
- return tools.length ? tools : undefined;
138
- }
139
- function normalizeMessages(value, missing) {
140
- if (!Array.isArray(value)) {
141
- if (value !== undefined) {
142
- missing.push({ path: 'messages', reason: 'invalid_type', originalValue: jsonClone(value) });
143
- }
144
- else {
145
- missing.push({ path: 'messages', reason: 'absent' });
146
- }
147
- return [];
148
- }
149
- const messages = [];
150
- value.forEach((item, index) => {
151
- if (!item || typeof item !== 'object' || Array.isArray(item)) {
152
- missing.push({ path: `messages[${index}]`, reason: 'invalid_entry', originalValue: jsonClone(item) });
153
- return;
154
- }
155
- messages.push(item);
156
- });
157
- return messages;
158
- }
159
- function serializeSystemContent(message) {
160
- if (!message)
161
- return undefined;
162
- const content = message.content;
163
- if (typeof content === 'string')
164
- return content;
165
- if (Array.isArray(content)) {
166
- const parts = [];
167
- content.forEach(part => {
168
- if (typeof part === 'string') {
169
- parts.push(part);
170
- }
171
- else if (part && typeof part === 'object') {
172
- const text = part.text;
173
- if (typeof text === 'string') {
174
- parts.push(text);
175
- }
176
- }
177
- });
178
- return parts.join('');
179
- }
180
- if (content != null) {
181
- try {
182
- return JSON.stringify(content);
183
- }
184
- catch {
185
- return String(content);
186
- }
187
- }
188
- return undefined;
189
- }
190
- function mergeMetadata(a, b) {
191
- if (!a && !b) {
192
- return undefined;
193
- }
194
- if (!a && b) {
195
- return jsonClone(b);
196
- }
197
- if (a && !b) {
198
- return jsonClone(a);
199
- }
200
- const left = jsonClone(a);
201
- const right = jsonClone(b);
202
- return { ...left, ...right };
203
- }
204
- function isSubmitToolOutputsEndpoint(ctx) {
205
- if (!ctx || typeof ctx !== 'object') {
206
- return false;
207
- }
208
- const entry = typeof ctx.entryEndpoint === 'string' ? ctx.entryEndpoint.trim().toLowerCase() : '';
209
- return entry === RESPONSES_SUBMIT_ENDPOINT;
210
- }
211
- function attachResponsesSemantics(existing, context, resume) {
212
- if (!context && !resume) {
213
- return existing;
214
- }
215
- const next = existing ? { ...existing } : {};
216
- const currentNode = next.responses && isJsonObject(next.responses) ? { ...next.responses } : {};
217
- if (context) {
218
- currentNode.context = jsonClone(context);
219
- }
220
- if (resume) {
221
- currentNode.resume = jsonClone(resume);
222
- }
223
- next.responses = currentNode;
224
- return next;
225
- }
226
- function extractResponsesSemanticsNode(chat) {
227
- if (!chat?.semantics || typeof chat.semantics !== 'object') {
228
- return undefined;
229
- }
230
- const node = chat.semantics.responses;
231
- return node && isJsonObject(node) ? node : undefined;
232
- }
233
- function readResponsesContextFromSemantics(chat) {
234
- const node = extractResponsesSemanticsNode(chat);
235
- if (!node) {
236
- return undefined;
237
- }
238
- const contextNode = node.context;
239
- if (!contextNode || !isJsonObject(contextNode)) {
240
- return undefined;
241
- }
242
- return jsonClone(contextNode);
243
- }
244
- function readResponsesResumeFromSemantics(chat) {
245
- const node = extractResponsesSemanticsNode(chat);
246
- if (!node) {
247
- return undefined;
248
- }
249
- const resumeNode = node.resume;
250
- if (!resumeNode || !isJsonObject(resumeNode)) {
251
- return undefined;
252
- }
253
- return jsonClone(resumeNode);
254
- }
255
- function selectResponsesContextSnapshot(chat, envelopeMetadata) {
256
- const semanticsContext = readResponsesContextFromSemantics(chat);
257
- const metadataContextCandidate = chat.metadata?.responsesContext;
258
- const metadataContext = metadataContextCandidate && isJsonObject(metadataContextCandidate)
259
- ? jsonClone(metadataContextCandidate)
260
- : undefined;
261
- const context = semanticsContext ??
262
- metadataContext ??
263
- {
264
- metadata: envelopeMetadata
265
- };
266
- const mergedMetadata = mergeMetadata(context.metadata ?? undefined, envelopeMetadata);
267
- if (mergedMetadata) {
268
- context.metadata = mergedMetadata;
269
- }
270
- return context;
271
- }
272
- function resolveSubmitResponseId(ctx, responsesContext) {
273
- const resumeMeta = ctx.responsesResume && typeof ctx.responsesResume === 'object'
274
- ? ctx.responsesResume
275
- : undefined;
276
- const resumeId = typeof resumeMeta?.restoredFromResponseId === 'string'
277
- ? resumeMeta.restoredFromResponseId.trim()
278
- : undefined;
279
- if (resumeId) {
280
- return resumeId;
281
- }
282
- const contextRecord = responsesContext && typeof responsesContext === 'object'
283
- ? responsesContext
284
- : undefined;
285
- const previousId = typeof contextRecord?.previous_response_id === 'string'
286
- ? contextRecord.previous_response_id.trim()
287
- : undefined;
288
- if (previousId) {
289
- return previousId;
290
- }
291
- return undefined;
292
- }
293
- function extractSubmitMetadata(responsesContext, resumeMeta) {
294
- if (responsesContext && responsesContext.metadata && isJsonObject(responsesContext.metadata)) {
295
- return jsonClone(responsesContext.metadata);
296
- }
297
- if (resumeMeta && resumeMeta.metadata && isJsonObject(resumeMeta.metadata)) {
298
- return jsonClone(resumeMeta.metadata);
299
- }
300
- return undefined;
301
- }
302
- function coerceOutputText(value) {
303
- if (typeof value === 'string') {
304
- return value;
305
- }
306
- if (value === undefined || value === null) {
307
- return '';
308
- }
309
- try {
310
- return JSON.stringify(value);
311
- }
312
- catch {
313
- return String(value);
314
- }
315
- }
316
- function extractCapturedToolOutputs(responsesContext) {
317
- if (!responsesContext || typeof responsesContext !== 'object') {
318
- return [];
319
- }
320
- const snapshot = responsesContext.__captured_tool_results;
321
- if (!Array.isArray(snapshot) || !snapshot.length) {
322
- return [];
323
- }
324
- const entries = [];
325
- snapshot.forEach((entry) => {
326
- if (!entry || typeof entry !== 'object') {
327
- return;
328
- }
329
- const record = entry;
330
- const toolId = typeof record.tool_call_id === 'string' && record.tool_call_id.trim().length
331
- ? record.tool_call_id.trim()
332
- : typeof record.call_id === 'string' && record.call_id.trim().length
333
- ? record.call_id.trim()
334
- : undefined;
335
- if (!toolId) {
336
- return;
337
- }
338
- entries.push({
339
- tool_call_id: toolId,
340
- id: toolId,
341
- output: typeof record.output === 'string' ? record.output : coerceOutputText(record.output),
342
- name: typeof record.name === 'string' ? record.name : undefined
343
- });
344
- });
345
- return entries;
346
- }
347
- function collectSubmitToolOutputs(chat, ctx, responsesContext) {
348
- const outputs = [];
349
- const seen = new Set();
350
- const append = (idSeed, outputSeed, name) => {
351
- const trimmed = typeof idSeed === 'string' && idSeed.trim().length ? idSeed.trim() : '';
352
- const fallbackId = trimmed || `submit_tool_${outputs.length + 1}`;
353
- if (seen.has(fallbackId)) {
354
- return;
355
- }
356
- seen.add(fallbackId);
357
- outputs.push({
358
- tool_call_id: fallbackId,
359
- id: fallbackId,
360
- output: coerceOutputText(outputSeed),
361
- name
362
- });
363
- };
364
- if (Array.isArray(chat.toolOutputs) && chat.toolOutputs.length) {
365
- chat.toolOutputs.forEach((entry) => {
366
- append(entry.tool_call_id ?? entry.call_id, entry.content, entry.name);
367
- });
368
- }
369
- if (!outputs.length) {
370
- const captured = extractCapturedToolOutputs(responsesContext);
371
- captured.forEach((entry) => append(entry.tool_call_id ?? entry.id, entry.output, entry.name));
372
- }
373
- if (!outputs.length) {
374
- const resume = ctx.responsesResume && typeof ctx.responsesResume === 'object'
375
- ? ctx.responsesResume
376
- : undefined;
377
- const detailed = Array.isArray(resume?.toolOutputsDetailed)
378
- ? resume?.toolOutputsDetailed
379
- : undefined;
380
- if (detailed) {
381
- detailed.forEach((entry, index) => {
382
- if (!entry || typeof entry !== 'object') {
383
- return;
384
- }
385
- const callId = typeof entry.callId === 'string' && entry.callId.trim().length
386
- ? entry.callId.trim()
387
- : typeof entry.originalId === 'string' && entry.originalId.trim().length
388
- ? entry.originalId.trim()
389
- : `resume_tool_${index + 1}`;
390
- append(callId, typeof entry.outputText === 'string' ? entry.outputText : entry.outputText ?? '');
391
- });
392
- }
393
- }
394
- return outputs;
395
- }
396
- function resolveSubmitStreamFlag(chat, ctx, responsesContext) {
397
- if (chat.parameters && typeof chat.parameters.stream === 'boolean') {
398
- return chat.parameters.stream;
399
- }
400
- if (responsesContext && typeof responsesContext.stream === 'boolean') {
401
- return responsesContext.stream;
402
- }
403
- if (ctx.streamingHint === 'force') {
404
- return true;
405
- }
406
- if (ctx.streamingHint === 'disable') {
407
- return false;
408
- }
409
- return undefined;
410
- }
411
- function resolveSubmitModel(chat, responsesContext) {
412
- const direct = chat.parameters && typeof chat.parameters.model === 'string'
413
- ? chat.parameters.model.trim()
414
- : undefined;
415
- if (direct) {
416
- return direct;
417
- }
418
- if (responsesContext && typeof responsesContext.parameters === 'object') {
419
- const params = responsesContext.parameters;
420
- const model = typeof params.model === 'string' ? params.model.trim() : undefined;
421
- if (model) {
422
- return model;
423
- }
424
- }
425
- return undefined;
426
- }
427
- function buildSubmitToolOutputsPayload(chat, ctx, responsesContext) {
428
- const responseId = resolveSubmitResponseId(ctx, responsesContext);
429
- if (!responseId) {
430
- throw new Error('Submit tool outputs requires response_id from Responses resume context');
431
- }
432
- const toolOutputs = collectSubmitToolOutputs(chat, ctx, responsesContext);
433
- if (!toolOutputs.length) {
434
- throw new Error('Submit tool outputs requires at least one tool output entry');
435
- }
436
- const resumeMeta = ctx.responsesResume && typeof ctx.responsesResume === 'object'
437
- ? ctx.responsesResume
438
- : undefined;
439
- const payload = {
440
- response_id: responseId,
441
- tool_outputs: toolOutputs
442
- };
443
- const modelValue = resolveSubmitModel(chat, responsesContext);
444
- if (modelValue) {
445
- payload.model = modelValue;
446
- }
447
- const streamValue = resolveSubmitStreamFlag(chat, ctx, responsesContext);
448
- if (typeof streamValue === 'boolean') {
449
- payload.stream = streamValue;
450
- }
451
- const metadata = extractSubmitMetadata(responsesContext, resumeMeta);
452
- if (metadata) {
453
- payload.metadata = metadata;
454
- }
455
- return payload;
456
- }
457
- export class ResponsesSemanticMapper {
458
- async toChat(format, ctx) {
459
- const payload = format.payload || {};
460
- const responsesContext = captureResponsesContext(payload, { route: { requestId: ctx.requestId } });
461
- const { request, toolsNormalized } = buildChatRequestFromResponses(payload, responsesContext);
462
- const missingFields = [];
463
- const messages = normalizeMessages(request.messages, missingFields);
464
- let toolOutputs = mapToolOutputs(payload.tool_outputs, missingFields);
465
- if (!toolOutputs || toolOutputs.length === 0) {
466
- const resumeToolOutputs = deriveResumeToolOutputs(ctx);
467
- if (resumeToolOutputs && resumeToolOutputs.length) {
468
- toolOutputs = resumeToolOutputs;
469
- }
470
- }
471
- const parameters = collectParameters(payload, responsesContext.stream);
472
- const metadata = { context: ctx };
473
- try {
474
- const bridgePolicy = resolveBridgePolicy({ protocol: 'openai-responses', moduleType: 'openai-responses' });
475
- const actions = resolvePolicyActions(bridgePolicy, 'request_inbound');
476
- if (actions?.length) {
477
- const capturedToolResults = Array.isArray(toolOutputs)
478
- ? toolOutputs.map((entry) => ({
479
- tool_call_id: entry.tool_call_id,
480
- output: entry.content,
481
- name: entry.name
482
- }))
483
- : undefined;
484
- const actionState = createBridgeActionState({
485
- rawRequest: payload,
486
- metadata: metadata,
487
- capturedToolResults
488
- });
489
- runBridgeActionPipeline({
490
- stage: 'request_inbound',
491
- actions,
492
- protocol: bridgePolicy?.protocol ?? 'openai-responses',
493
- moduleType: bridgePolicy?.moduleType ?? 'openai-responses',
494
- requestId: ctx.requestId,
495
- state: actionState
496
- });
497
- }
498
- }
499
- catch {
500
- // ignore policy hook failures
501
- }
502
- if (missingFields.length) {
503
- metadata.missingFields = missingFields;
504
- }
505
- if (responsesContext.responseFormat) {
506
- metadata.responseFormat = jsonClone(responsesContext.responseFormat);
507
- }
508
- metadata.responsesContext = jsonClone(responsesContext);
509
- const resumeNode = ctx.responsesResume && isJsonObject(ctx.responsesResume)
510
- ? ctx.responsesResume
511
- : undefined;
512
- const semantics = attachResponsesSemantics(undefined, responsesContext, resumeNode);
513
- return {
514
- messages,
515
- tools: normalizeTools(toolsNormalized, missingFields),
516
- toolOutputs,
517
- parameters,
518
- semantics,
519
- metadata
520
- };
521
- }
522
- async fromChat(chat, ctx) {
523
- const envelopeMetadata = chat.metadata && isJsonObject(chat.metadata) ? chat.metadata : undefined;
524
- const responsesContext = selectResponsesContextSnapshot(chat, envelopeMetadata);
525
- if (isSubmitToolOutputsEndpoint(ctx)) {
526
- const submitPayload = buildSubmitToolOutputsPayload(chat, ctx, responsesContext);
527
- return {
528
- protocol: 'openai-responses',
529
- direction: 'response',
530
- payload: submitPayload,
531
- meta: {
532
- context: ctx,
533
- submitToolOutputs: true
534
- }
535
- };
536
- }
537
- const modelValue = chat.parameters?.model;
538
- if (typeof modelValue !== 'string' || !modelValue.trim()) {
539
- throw new Error('ChatEnvelope.parameters.model is required for openai-responses outbound conversion');
540
- }
541
- const requestShape = {
542
- ...(chat.parameters || {}),
543
- model: modelValue,
544
- messages: chat.messages,
545
- tools: chat.tools
546
- };
547
- const originalSystemMessages = (chat.messages || [])
548
- .filter((message) => Boolean(message && typeof message === 'object' && message.role === 'system'))
549
- .map(message => serializeSystemContent(message))
550
- .filter((content) => typeof content === 'string' && content.length > 0);
551
- responsesContext.originalSystemMessages = originalSystemMessages;
552
- const responsesResult = buildResponsesRequestFromChat(requestShape, responsesContext);
553
- const responses = responsesResult.request;
554
- if (chat.parameters && chat.parameters.stream !== undefined) {
555
- responses.stream = chat.parameters.stream;
556
- }
557
- // Do not forward ChatEnvelope.toolOutputs to OpenAI Responses create requests.
558
- // Upstream expects historical tool results to remain inside input[] as
559
- // tool role messages; sending the legacy top-level `tool_outputs` field
560
- // causes providers like FAI to reject the request (HTTP 400). Any actual
561
- // submit_tool_outputs call should be issued via the dedicated endpoint
562
- // upstream, not through this mapper.
563
- try {
564
- const bridgePolicy = resolveBridgePolicy({ protocol: 'openai-responses', moduleType: 'openai-responses' });
565
- const actions = resolvePolicyActions(bridgePolicy, 'request_outbound');
566
- if (actions?.length) {
567
- const actionState = createBridgeActionState({
568
- rawRequest: responses,
569
- metadata: chat.metadata
570
- });
571
- runBridgeActionPipeline({
572
- stage: 'request_outbound',
573
- actions,
574
- protocol: bridgePolicy?.protocol ?? 'openai-responses',
575
- moduleType: bridgePolicy?.moduleType ?? 'openai-responses',
576
- requestId: ctx.requestId,
577
- state: actionState
578
- });
579
- }
580
- }
581
- catch {
582
- // ignore metadata propagation failures
583
- }
584
- return {
585
- protocol: 'openai-responses',
586
- direction: 'response',
587
- payload: responses,
588
- meta: {
589
- context: ctx
590
- }
591
- };
592
- }
593
- }
1
+ export { ResponsesSemanticMapper } from '../operation-table/semantic-mappers/responses-mapper.js';
@@ -0,0 +1,18 @@
1
+ import type { StageRecorder } from '../format-adapters/index.js';
2
+ import type { JsonObject } from '../types/json.js';
3
+ export type HubToolSurfaceMode = 'off' | 'observe' | 'shadow' | 'enforce';
4
+ export interface HubToolSurfaceConfig {
5
+ mode: HubToolSurfaceMode;
6
+ /**
7
+ * Range: 0..1. When omitted, defaults to 1 (always on for the selected mode).
8
+ * Sampling is request-id stable to avoid non-deterministic diffs.
9
+ */
10
+ sampleRate?: number;
11
+ }
12
+ export declare function applyProviderOutboundToolSurface(args: {
13
+ config?: HubToolSurfaceConfig;
14
+ providerProtocol: string;
15
+ payload: JsonObject;
16
+ stageRecorder?: StageRecorder;
17
+ requestId?: string;
18
+ }): JsonObject;