@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.
- package/dist/conversion/hub/operation-table/operation-table-runner.d.ts +18 -0
- package/dist/conversion/hub/operation-table/operation-table-runner.js +158 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.d.ts +8 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.js +303 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.d.ts +8 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.js +413 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.d.ts +7 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/gemini-mapper.js +841 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.d.ts +21 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/responses-mapper.js +535 -0
- package/dist/conversion/hub/ops/operations.d.ts +19 -0
- package/dist/conversion/hub/ops/operations.js +126 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +9 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +489 -19
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +6 -0
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.js +11 -0
- package/dist/conversion/hub/policy/policy-engine.js +41 -9
- package/dist/conversion/hub/policy/protocol-spec.d.ts +25 -0
- package/dist/conversion/hub/policy/protocol-spec.js +73 -23
- package/dist/conversion/hub/process/chat-process.js +252 -41
- package/dist/conversion/hub/response/provider-response.js +175 -2
- package/dist/conversion/hub/response/response-runtime.js +1 -1
- package/dist/conversion/hub/semantic-mappers/anthropic-mapper.d.ts +1 -8
- package/dist/conversion/hub/semantic-mappers/anthropic-mapper.js +1 -365
- package/dist/conversion/hub/semantic-mappers/chat-mapper.d.ts +1 -8
- package/dist/conversion/hub/semantic-mappers/chat-mapper.js +1 -467
- package/dist/conversion/hub/semantic-mappers/gemini-mapper.d.ts +1 -7
- package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +1 -903
- package/dist/conversion/hub/semantic-mappers/responses-mapper.d.ts +1 -21
- package/dist/conversion/hub/semantic-mappers/responses-mapper.js +1 -593
- package/dist/conversion/hub/tool-surface/tool-surface-engine.d.ts +18 -0
- package/dist/conversion/hub/tool-surface/tool-surface-engine.js +571 -0
- package/dist/conversion/responses/responses-openai-bridge.js +14 -2
- package/dist/conversion/shared/bridge-message-utils.js +2 -8
- package/dist/conversion/shared/bridge-policies.js +5 -105
- package/dist/conversion/shared/gemini-tool-utils.js +89 -15
- package/dist/conversion/shared/protocol-field-allowlists.d.ts +7 -0
- package/dist/conversion/shared/protocol-field-allowlists.js +145 -0
- package/dist/conversion/shared/reasoning-tool-normalizer.js +4 -2
- package/dist/conversion/shared/snapshot-hooks.js +166 -3
- package/dist/conversion/shared/text-markup-normalizer.d.ts +2 -0
- package/dist/conversion/shared/text-markup-normalizer.js +345 -9
- package/dist/conversion/shared/thought-signature-validator.d.ts +52 -0
- package/dist/conversion/shared/thought-signature-validator.js +170 -0
- package/dist/conversion/shared/tool-argument-repairer.d.ts +39 -0
- package/dist/conversion/shared/tool-argument-repairer.js +56 -0
- package/dist/conversion/shared/tool-call-id-manager.d.ts +113 -0
- package/dist/conversion/shared/tool-call-id-manager.js +231 -0
- package/dist/conversion/shared/tool-canonicalizer.js +2 -11
- package/dist/router/virtual-router/bootstrap.js +54 -5
- package/dist/router/virtual-router/engine-selection.js +132 -42
- package/dist/router/virtual-router/engine.d.ts +3 -0
- package/dist/router/virtual-router/engine.js +142 -33
- package/dist/router/virtual-router/health-weighted.d.ts +25 -0
- package/dist/router/virtual-router/health-weighted.js +63 -0
- package/dist/router/virtual-router/load-balancer.d.ts +2 -0
- package/dist/router/virtual-router/load-balancer.js +45 -16
- package/dist/router/virtual-router/routing-instructions.js +17 -1
- package/dist/router/virtual-router/sticky-session-store.js +136 -24
- package/dist/router/virtual-router/stop-message-file-resolver.d.ts +1 -0
- package/dist/router/virtual-router/stop-message-file-resolver.js +74 -0
- package/dist/router/virtual-router/stop-message-state-sync.d.ts +15 -0
- package/dist/router/virtual-router/stop-message-state-sync.js +57 -0
- package/dist/router/virtual-router/types.d.ts +70 -0
- package/dist/servertool/clock/config.d.ts +7 -0
- package/dist/servertool/clock/config.js +27 -0
- package/dist/servertool/clock/daemon.d.ts +3 -0
- package/dist/servertool/clock/daemon.js +79 -0
- package/dist/servertool/clock/io.d.ts +2 -0
- package/dist/servertool/clock/io.js +13 -0
- package/dist/servertool/clock/paths.d.ts +4 -0
- package/dist/servertool/clock/paths.js +25 -0
- package/dist/servertool/clock/session-store.d.ts +3 -0
- package/dist/servertool/clock/session-store.js +56 -0
- package/dist/servertool/clock/state.d.ts +5 -0
- package/dist/servertool/clock/state.js +62 -0
- package/dist/servertool/clock/task-store.d.ts +5 -0
- package/dist/servertool/clock/task-store.js +4 -0
- package/dist/servertool/clock/tasks.d.ts +17 -0
- package/dist/servertool/clock/tasks.js +221 -0
- package/dist/servertool/clock/types.d.ts +36 -0
- package/dist/servertool/clock/types.js +1 -0
- package/dist/servertool/engine.d.ts +2 -0
- package/dist/servertool/engine.js +161 -7
- package/dist/servertool/followup-shadow.d.ts +16 -0
- package/dist/servertool/followup-shadow.js +145 -0
- package/dist/servertool/handlers/apply-patch-guard.js +1 -265
- package/dist/servertool/handlers/clock-auto.d.ts +1 -0
- package/dist/servertool/handlers/clock-auto.js +160 -0
- package/dist/servertool/handlers/clock.d.ts +1 -0
- package/dist/servertool/handlers/clock.js +197 -0
- package/dist/servertool/handlers/exec-command-guard.js +7 -555
- package/dist/servertool/handlers/followup-request-builder.d.ts +15 -7
- package/dist/servertool/handlers/followup-request-builder.js +248 -28
- package/dist/servertool/handlers/gemini-empty-reply-continue.js +62 -169
- package/dist/servertool/handlers/iflow-model-error-retry.js +18 -28
- package/dist/servertool/handlers/recursive-detection-guard.d.ts +1 -0
- package/dist/servertool/handlers/recursive-detection-guard.js +333 -0
- package/dist/servertool/handlers/stop-message-auto.js +47 -175
- package/dist/servertool/handlers/vision.d.ts +7 -1
- package/dist/servertool/handlers/vision.js +61 -117
- package/dist/servertool/handlers/web-search.d.ts +7 -1
- package/dist/servertool/handlers/web-search.js +122 -105
- package/dist/servertool/reenter-backend.d.ts +23 -0
- package/dist/servertool/reenter-backend.js +18 -0
- package/dist/servertool/server-side-tools.d.ts +3 -2
- package/dist/servertool/server-side-tools.js +64 -10
- package/dist/servertool/types.d.ts +92 -3
- package/dist/sse/json-to-sse/event-generators/responses.js +3 -21
- package/dist/sse/shared/serializers/responses-event-serializer.d.ts +8 -0
- package/dist/sse/shared/serializers/responses-event-serializer.js +19 -0
- package/dist/sse/shared/writer.js +24 -7
- package/dist/tools/apply-patch/execution-capturer.js +3 -1
- package/dist/tools/apply-patch/json/parse-loose.d.ts +3 -0
- package/dist/tools/apply-patch/json/parse-loose.js +139 -0
- package/dist/tools/apply-patch/patch-text/context-diff.d.ts +1 -0
- package/dist/tools/apply-patch/patch-text/context-diff.js +173 -0
- package/dist/tools/apply-patch/patch-text/git-diff.d.ts +1 -0
- package/dist/tools/apply-patch/patch-text/git-diff.js +138 -0
- package/dist/tools/apply-patch/patch-text/looks-like-patch.d.ts +1 -0
- package/dist/tools/apply-patch/patch-text/looks-like-patch.js +13 -0
- package/dist/tools/apply-patch/patch-text/normalize.d.ts +3 -0
- package/dist/tools/apply-patch/patch-text/normalize.js +262 -0
- package/dist/tools/apply-patch/structured/coercion.d.ts +3 -0
- package/dist/tools/apply-patch/structured/coercion.js +82 -0
- package/dist/tools/apply-patch/validation/shared.d.ts +3 -0
- package/dist/tools/apply-patch/validation/shared.js +6 -0
- package/dist/tools/apply-patch/validator.d.ts +2 -2
- package/dist/tools/apply-patch/validator.js +6 -556
- package/package.json +1 -1
|
@@ -1,467 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { createBridgeActionState, runBridgeActionPipeline } from '../../shared/bridge-actions.js';
|
|
3
|
-
import { resolveBridgePolicy, resolvePolicyActions } from '../../shared/bridge-policies.js';
|
|
4
|
-
import { normalizeChatMessageContent } from '../../shared/chat-output-normalizer.js';
|
|
5
|
-
import { ensureProtocolState } from '../../shared/protocol-state.js';
|
|
6
|
-
const CHAT_PARAMETER_KEYS = [
|
|
7
|
-
'model',
|
|
8
|
-
'temperature',
|
|
9
|
-
'top_p',
|
|
10
|
-
'top_k',
|
|
11
|
-
'max_tokens',
|
|
12
|
-
'frequency_penalty',
|
|
13
|
-
'presence_penalty',
|
|
14
|
-
'logit_bias',
|
|
15
|
-
'response_format',
|
|
16
|
-
'parallel_tool_calls',
|
|
17
|
-
'tool_choice',
|
|
18
|
-
'seed',
|
|
19
|
-
'user',
|
|
20
|
-
'metadata',
|
|
21
|
-
'stop',
|
|
22
|
-
'stop_sequences',
|
|
23
|
-
'stream'
|
|
24
|
-
];
|
|
25
|
-
const KNOWN_TOP_LEVEL_FIELDS = new Set([
|
|
26
|
-
'messages',
|
|
27
|
-
'tools',
|
|
28
|
-
'tool_outputs',
|
|
29
|
-
...CHAT_PARAMETER_KEYS,
|
|
30
|
-
'stageExpectations',
|
|
31
|
-
'stages'
|
|
32
|
-
]);
|
|
33
|
-
function flattenSystemContent(content) {
|
|
34
|
-
if (typeof content === 'string')
|
|
35
|
-
return content;
|
|
36
|
-
if (Array.isArray(content)) {
|
|
37
|
-
return content.map(flattenSystemContent).filter(Boolean).join('\n');
|
|
38
|
-
}
|
|
39
|
-
if (content && typeof content === 'object') {
|
|
40
|
-
const obj = content;
|
|
41
|
-
if (typeof obj.text === 'string')
|
|
42
|
-
return obj.text;
|
|
43
|
-
if (typeof obj.content === 'string')
|
|
44
|
-
return obj.content;
|
|
45
|
-
if (Array.isArray(obj.content))
|
|
46
|
-
return obj.content.map(flattenSystemContent).join('\n');
|
|
47
|
-
}
|
|
48
|
-
return '';
|
|
49
|
-
}
|
|
50
|
-
function normalizeToolContent(content) {
|
|
51
|
-
if (typeof content === 'string')
|
|
52
|
-
return content;
|
|
53
|
-
if (content === null || content === undefined)
|
|
54
|
-
return '';
|
|
55
|
-
try {
|
|
56
|
-
return JSON.stringify(content);
|
|
57
|
-
}
|
|
58
|
-
catch {
|
|
59
|
-
return String(content ?? '');
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
function maybeAugmentRouteCodexApplyPatchPrecheck(content) {
|
|
63
|
-
if (!content || typeof content !== 'string') {
|
|
64
|
-
return content;
|
|
65
|
-
}
|
|
66
|
-
if (content.includes('[RouteCodex precheck]')) {
|
|
67
|
-
return content;
|
|
68
|
-
}
|
|
69
|
-
const lower = content.toLowerCase();
|
|
70
|
-
if (!lower.includes('failed to parse function arguments')) {
|
|
71
|
-
return content;
|
|
72
|
-
}
|
|
73
|
-
if (content.includes('missing field `input`')) {
|
|
74
|
-
return `${content}\n\n[RouteCodex precheck] apply_patch 参数解析失败:缺少字段 "input"。当前 RouteCodex 期望 { input, patch } 形态,并且两个字段都应包含完整统一 diff 文本。`;
|
|
75
|
-
}
|
|
76
|
-
if (content.includes('invalid type: map, expected a string')) {
|
|
77
|
-
return `${content}\n\n[RouteCodex precheck] apply_patch 参数类型错误:检测到 JSON 对象(map),但客户端期望字符串。请先对参数做 JSON.stringify 再写入 arguments,或直接提供 { patch: "<统一 diff>" } 形式。`;
|
|
78
|
-
}
|
|
79
|
-
return content;
|
|
80
|
-
}
|
|
81
|
-
export function maybeAugmentApplyPatchErrorContent(content, toolName) {
|
|
82
|
-
if (!content)
|
|
83
|
-
return content;
|
|
84
|
-
const lower = content.toLowerCase();
|
|
85
|
-
const isApplyPatch = (typeof toolName === 'string' && toolName.trim() === 'apply_patch') ||
|
|
86
|
-
lower.includes('apply_patch verification failed');
|
|
87
|
-
if (!isApplyPatch) {
|
|
88
|
-
return content;
|
|
89
|
-
}
|
|
90
|
-
// 避免重复追加提示。
|
|
91
|
-
if (content.includes('[apply_patch hint]')) {
|
|
92
|
-
return content;
|
|
93
|
-
}
|
|
94
|
-
const hint = '\n\n[apply_patch hint] 在使用 apply_patch 之前,请先读取目标文件的最新内容,并基于该内容生成补丁;同时确保补丁格式符合工具规范(统一补丁格式或结构化参数),避免上下文不匹配或语法错误。';
|
|
95
|
-
return content + hint;
|
|
96
|
-
}
|
|
97
|
-
function recordToolCallIssues(message, messageIndex, missing) {
|
|
98
|
-
const toolCalls = Array.isArray(message.tool_calls) ? message.tool_calls : undefined;
|
|
99
|
-
if (!toolCalls?.length)
|
|
100
|
-
return;
|
|
101
|
-
toolCalls.forEach((entry, callIndex) => {
|
|
102
|
-
if (!isJsonObject(entry)) {
|
|
103
|
-
missing.push({
|
|
104
|
-
path: `messages[${messageIndex}].tool_calls[${callIndex}]`,
|
|
105
|
-
reason: 'invalid_tool_call_entry',
|
|
106
|
-
originalValue: jsonClone(entry)
|
|
107
|
-
});
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
const fnBlock = entry.function;
|
|
111
|
-
if (!isJsonObject(fnBlock)) {
|
|
112
|
-
missing.push({
|
|
113
|
-
path: `messages[${messageIndex}].tool_calls[${callIndex}].function`,
|
|
114
|
-
reason: 'missing_tool_function',
|
|
115
|
-
originalValue: jsonClone(fnBlock)
|
|
116
|
-
});
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
const fnName = fnBlock.name;
|
|
120
|
-
if (typeof fnName !== 'string' || !fnName.trim().length) {
|
|
121
|
-
missing.push({
|
|
122
|
-
path: `messages[${messageIndex}].tool_calls[${callIndex}].function.name`,
|
|
123
|
-
reason: 'missing_tool_name'
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
function collectSystemRawBlocks(raw) {
|
|
129
|
-
if (!Array.isArray(raw))
|
|
130
|
-
return undefined;
|
|
131
|
-
const blocks = [];
|
|
132
|
-
raw.forEach((entry) => {
|
|
133
|
-
if (!isJsonObject(entry))
|
|
134
|
-
return;
|
|
135
|
-
if (String(entry.role ?? '').toLowerCase() !== 'system')
|
|
136
|
-
return;
|
|
137
|
-
blocks.push(jsonClone(entry));
|
|
138
|
-
});
|
|
139
|
-
return blocks.length ? blocks : undefined;
|
|
140
|
-
}
|
|
141
|
-
function normalizeChatMessages(raw) {
|
|
142
|
-
const norm = {
|
|
143
|
-
messages: [],
|
|
144
|
-
systemSegments: [],
|
|
145
|
-
toolOutputs: [],
|
|
146
|
-
missingFields: []
|
|
147
|
-
};
|
|
148
|
-
if (raw === undefined) {
|
|
149
|
-
norm.missingFields.push({ path: 'messages', reason: 'absent' });
|
|
150
|
-
return norm;
|
|
151
|
-
}
|
|
152
|
-
if (!Array.isArray(raw)) {
|
|
153
|
-
norm.missingFields.push({ path: 'messages', reason: 'invalid_type', originalValue: jsonClone(raw) });
|
|
154
|
-
return norm;
|
|
155
|
-
}
|
|
156
|
-
raw.forEach((value, index) => {
|
|
157
|
-
if (!isJsonObject(value)) {
|
|
158
|
-
norm.missingFields.push({ path: `messages[${index}]`, reason: 'invalid_entry', originalValue: jsonClone(value) });
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
const roleValue = value.role;
|
|
162
|
-
if (typeof roleValue !== 'string') {
|
|
163
|
-
norm.missingFields.push({ path: `messages[${index}].role`, reason: 'missing_role' });
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
const chatMessage = value;
|
|
167
|
-
if (roleValue !== 'system' && roleValue !== 'tool') {
|
|
168
|
-
const normalizedContent = normalizeChatMessageContent(chatMessage.content);
|
|
169
|
-
const shouldOverwriteContent = !Array.isArray(chatMessage.content);
|
|
170
|
-
if (shouldOverwriteContent && normalizedContent.contentText !== undefined) {
|
|
171
|
-
chatMessage.content = normalizedContent.contentText;
|
|
172
|
-
}
|
|
173
|
-
if (typeof normalizedContent.reasoningText === 'string' && normalizedContent.reasoningText.trim().length) {
|
|
174
|
-
chatMessage.reasoning_content = normalizedContent.reasoningText.trim();
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
norm.messages.push(chatMessage);
|
|
178
|
-
const toolCallCandidate = value.tool_calls;
|
|
179
|
-
if (Array.isArray(toolCallCandidate) && toolCallCandidate.length) {
|
|
180
|
-
recordToolCallIssues(value, index, norm.missingFields);
|
|
181
|
-
}
|
|
182
|
-
if (roleValue === 'system') {
|
|
183
|
-
const segment = flattenSystemContent(chatMessage.content);
|
|
184
|
-
if (segment.trim().length) {
|
|
185
|
-
norm.systemSegments.push(segment);
|
|
186
|
-
}
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
if (roleValue === 'tool') {
|
|
190
|
-
const rawCallId = (value.tool_call_id ?? value.call_id ?? value.id);
|
|
191
|
-
const toolCallId = typeof rawCallId === 'string' && rawCallId.trim().length ? rawCallId.trim() : undefined;
|
|
192
|
-
if (!toolCallId) {
|
|
193
|
-
norm.missingFields.push({ path: `messages[${index}].tool_call_id`, reason: 'missing_tool_call_id' });
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
const nameValue = typeof value.name === 'string' && value.name.trim().length ? value.name : undefined;
|
|
197
|
-
const normalizedToolOutput = normalizeToolContent(value.content ?? value.output);
|
|
198
|
-
const routeCodexPrechecked = maybeAugmentRouteCodexApplyPatchPrecheck(normalizedToolOutput);
|
|
199
|
-
if (routeCodexPrechecked !== normalizedToolOutput) {
|
|
200
|
-
// Keep tool role message content aligned with outbound provider requests (e.g. Chat→Responses),
|
|
201
|
-
// while avoiding double-injection.
|
|
202
|
-
if (typeof chatMessage.content === 'string' || chatMessage.content === undefined || chatMessage.content === null) {
|
|
203
|
-
chatMessage.content = routeCodexPrechecked;
|
|
204
|
-
}
|
|
205
|
-
else if (typeof chatMessage.output === 'string') {
|
|
206
|
-
chatMessage.output = routeCodexPrechecked;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
const outputEntry = {
|
|
210
|
-
tool_call_id: toolCallId,
|
|
211
|
-
content: routeCodexPrechecked,
|
|
212
|
-
name: nameValue
|
|
213
|
-
};
|
|
214
|
-
outputEntry.content = maybeAugmentApplyPatchErrorContent(outputEntry.content, outputEntry.name);
|
|
215
|
-
norm.toolOutputs.push(outputEntry);
|
|
216
|
-
}
|
|
217
|
-
});
|
|
218
|
-
return norm;
|
|
219
|
-
}
|
|
220
|
-
function normalizeStandaloneToolOutputs(raw, missing) {
|
|
221
|
-
if (!Array.isArray(raw) || raw.length === 0)
|
|
222
|
-
return [];
|
|
223
|
-
const outputs = [];
|
|
224
|
-
raw.forEach((entry, index) => {
|
|
225
|
-
if (!isJsonObject(entry)) {
|
|
226
|
-
missing.push({ path: `tool_outputs[${index}]`, reason: 'invalid_entry', originalValue: jsonClone(entry) });
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
const rawCallId = entry.tool_call_id ?? entry.call_id ?? entry.id;
|
|
230
|
-
const toolCallId = typeof rawCallId === 'string' && rawCallId.trim().length ? rawCallId.trim() : undefined;
|
|
231
|
-
if (!toolCallId) {
|
|
232
|
-
missing.push({ path: `tool_outputs[${index}].tool_call_id`, reason: 'missing_tool_call_id' });
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
const nameValue = typeof entry.name === 'string' && entry.name.trim().length ? entry.name : undefined;
|
|
236
|
-
const rawContent = normalizeToolContent(entry.content ?? entry.output);
|
|
237
|
-
const content = maybeAugmentApplyPatchErrorContent(rawContent, nameValue);
|
|
238
|
-
outputs.push({
|
|
239
|
-
tool_call_id: toolCallId,
|
|
240
|
-
content,
|
|
241
|
-
name: nameValue
|
|
242
|
-
});
|
|
243
|
-
});
|
|
244
|
-
return outputs;
|
|
245
|
-
}
|
|
246
|
-
function normalizeTools(raw, missing) {
|
|
247
|
-
if (!Array.isArray(raw) || raw.length === 0)
|
|
248
|
-
return undefined;
|
|
249
|
-
const tools = [];
|
|
250
|
-
raw.forEach((entry, index) => {
|
|
251
|
-
if (!isJsonObject(entry)) {
|
|
252
|
-
missing.push({ path: `tools[${index}]`, reason: 'invalid_entry', originalValue: jsonClone(entry) });
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
tools.push(entry);
|
|
256
|
-
});
|
|
257
|
-
return tools.length ? tools : undefined;
|
|
258
|
-
}
|
|
259
|
-
function extractParameters(body) {
|
|
260
|
-
const params = {};
|
|
261
|
-
for (const key of CHAT_PARAMETER_KEYS) {
|
|
262
|
-
if (body[key] !== undefined) {
|
|
263
|
-
params[key] = body[key];
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
return Object.keys(params).length ? params : undefined;
|
|
267
|
-
}
|
|
268
|
-
function collectExtraFields(body) {
|
|
269
|
-
const extras = {};
|
|
270
|
-
for (const [key, value] of Object.entries(body)) {
|
|
271
|
-
if (KNOWN_TOP_LEVEL_FIELDS.has(key)) {
|
|
272
|
-
continue;
|
|
273
|
-
}
|
|
274
|
-
if (value !== undefined) {
|
|
275
|
-
extras[key] = jsonClone(value);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
return Object.keys(extras).length ? extras : undefined;
|
|
279
|
-
}
|
|
280
|
-
function extractOpenAIExtraFieldsFromSemantics(semantics) {
|
|
281
|
-
if (!semantics || !semantics.providerExtras || !isJsonObject(semantics.providerExtras)) {
|
|
282
|
-
return undefined;
|
|
283
|
-
}
|
|
284
|
-
const openaiExtras = semantics.providerExtras.openaiChat;
|
|
285
|
-
if (!openaiExtras || !isJsonObject(openaiExtras)) {
|
|
286
|
-
return undefined;
|
|
287
|
-
}
|
|
288
|
-
const stored = openaiExtras.extraFields;
|
|
289
|
-
if (!stored || !isJsonObject(stored)) {
|
|
290
|
-
return undefined;
|
|
291
|
-
}
|
|
292
|
-
return stored;
|
|
293
|
-
}
|
|
294
|
-
function hasExplicitEmptyToolsSemantics(semantics) {
|
|
295
|
-
if (!semantics || !semantics.tools || !isJsonObject(semantics.tools)) {
|
|
296
|
-
return false;
|
|
297
|
-
}
|
|
298
|
-
const flag = semantics.tools.explicitEmpty;
|
|
299
|
-
return flag === true;
|
|
300
|
-
}
|
|
301
|
-
function buildOpenAISemantics(options) {
|
|
302
|
-
const semantics = {};
|
|
303
|
-
if (options.systemSegments && options.systemSegments.length) {
|
|
304
|
-
semantics.system = {
|
|
305
|
-
textBlocks: options.systemSegments.map((segment) => segment)
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
if (options.extraFields && Object.keys(options.extraFields).length) {
|
|
309
|
-
semantics.providerExtras = {
|
|
310
|
-
openaiChat: {
|
|
311
|
-
extraFields: jsonClone(options.extraFields)
|
|
312
|
-
}
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
if (options.explicitEmptyTools) {
|
|
316
|
-
semantics.tools = {
|
|
317
|
-
explicitEmpty: true
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
return Object.keys(semantics).length ? semantics : undefined;
|
|
321
|
-
}
|
|
322
|
-
function applyExtraFields(body, metadata, semantics) {
|
|
323
|
-
const sources = [];
|
|
324
|
-
const semanticsExtras = extractOpenAIExtraFieldsFromSemantics(semantics);
|
|
325
|
-
if (semanticsExtras) {
|
|
326
|
-
sources.push(semanticsExtras);
|
|
327
|
-
}
|
|
328
|
-
if (metadata?.extraFields && isJsonObject(metadata.extraFields)) {
|
|
329
|
-
sources.push(metadata.extraFields);
|
|
330
|
-
}
|
|
331
|
-
if (!sources.length) {
|
|
332
|
-
return;
|
|
333
|
-
}
|
|
334
|
-
for (const source of sources) {
|
|
335
|
-
for (const [key, value] of Object.entries(source)) {
|
|
336
|
-
if (body[key] !== undefined) {
|
|
337
|
-
continue;
|
|
338
|
-
}
|
|
339
|
-
body[key] = jsonClone(value);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
export class ChatSemanticMapper {
|
|
344
|
-
async toChat(format, ctx) {
|
|
345
|
-
const payload = (format.payload ?? {});
|
|
346
|
-
const normalized = normalizeChatMessages(payload.messages);
|
|
347
|
-
const topLevelOutputs = normalizeStandaloneToolOutputs(payload.tool_outputs, normalized.missingFields);
|
|
348
|
-
const toolOutputs = [...normalized.toolOutputs];
|
|
349
|
-
for (const entry of topLevelOutputs) {
|
|
350
|
-
if (!toolOutputs.find(item => item.tool_call_id === entry.tool_call_id)) {
|
|
351
|
-
toolOutputs.push(entry);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
const metadata = { context: ctx };
|
|
355
|
-
if (normalized.systemSegments.length) {
|
|
356
|
-
metadata.systemInstructions = normalized.systemSegments;
|
|
357
|
-
}
|
|
358
|
-
const rawSystemBlocks = collectSystemRawBlocks(payload.messages);
|
|
359
|
-
if (rawSystemBlocks) {
|
|
360
|
-
const protocolState = ensureProtocolState(metadata, 'openai');
|
|
361
|
-
protocolState.systemMessages = jsonClone(rawSystemBlocks);
|
|
362
|
-
}
|
|
363
|
-
if (normalized.missingFields.length) {
|
|
364
|
-
metadata.missingFields = normalized.missingFields;
|
|
365
|
-
}
|
|
366
|
-
const extraFields = collectExtraFields(payload);
|
|
367
|
-
if (extraFields) {
|
|
368
|
-
metadata.extraFields = extraFields;
|
|
369
|
-
}
|
|
370
|
-
try {
|
|
371
|
-
const bridgePolicy = resolveBridgePolicy({ protocol: 'openai-chat' });
|
|
372
|
-
const actions = resolvePolicyActions(bridgePolicy, 'request_inbound');
|
|
373
|
-
if (actions?.length) {
|
|
374
|
-
const actionState = createBridgeActionState({
|
|
375
|
-
messages: normalized.messages,
|
|
376
|
-
rawRequest: payload,
|
|
377
|
-
metadata: metadata
|
|
378
|
-
});
|
|
379
|
-
runBridgeActionPipeline({
|
|
380
|
-
stage: 'request_inbound',
|
|
381
|
-
actions,
|
|
382
|
-
protocol: bridgePolicy?.protocol ?? 'openai-chat',
|
|
383
|
-
moduleType: bridgePolicy?.moduleType ?? 'openai-chat',
|
|
384
|
-
requestId: ctx.requestId,
|
|
385
|
-
state: actionState
|
|
386
|
-
});
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
catch {
|
|
390
|
-
// noop: best-effort policy application
|
|
391
|
-
}
|
|
392
|
-
const explicitEmptyTools = Array.isArray(payload.tools) && payload.tools.length === 0;
|
|
393
|
-
if (explicitEmptyTools) {
|
|
394
|
-
metadata.toolsFieldPresent = true;
|
|
395
|
-
}
|
|
396
|
-
const semantics = buildOpenAISemantics({
|
|
397
|
-
systemSegments: normalized.systemSegments,
|
|
398
|
-
extraFields,
|
|
399
|
-
explicitEmptyTools
|
|
400
|
-
});
|
|
401
|
-
return {
|
|
402
|
-
messages: normalized.messages,
|
|
403
|
-
tools: normalizeTools(payload.tools, normalized.missingFields),
|
|
404
|
-
toolOutputs: toolOutputs.length ? toolOutputs : undefined,
|
|
405
|
-
parameters: extractParameters(payload),
|
|
406
|
-
semantics,
|
|
407
|
-
metadata
|
|
408
|
-
};
|
|
409
|
-
}
|
|
410
|
-
async fromChat(chat, ctx) {
|
|
411
|
-
const shouldEmitEmptyTools = hasExplicitEmptyToolsSemantics(chat.semantics) || chat.metadata?.toolsFieldPresent === true;
|
|
412
|
-
const payload = {
|
|
413
|
-
messages: chat.messages,
|
|
414
|
-
tools: chat.tools ?? (shouldEmitEmptyTools ? [] : undefined),
|
|
415
|
-
...(chat.parameters || {})
|
|
416
|
-
};
|
|
417
|
-
applyExtraFields(payload, chat.metadata, chat.semantics);
|
|
418
|
-
try {
|
|
419
|
-
const bridgePolicy = resolveBridgePolicy({ protocol: 'openai-chat' });
|
|
420
|
-
const actions = resolvePolicyActions(bridgePolicy, 'request_outbound');
|
|
421
|
-
if (actions?.length && Array.isArray(payload.messages)) {
|
|
422
|
-
const capturedToolResults = Array.isArray(chat.toolOutputs)
|
|
423
|
-
? chat.toolOutputs.map((entry) => ({
|
|
424
|
-
tool_call_id: entry.tool_call_id,
|
|
425
|
-
output: entry.content,
|
|
426
|
-
name: entry.name
|
|
427
|
-
}))
|
|
428
|
-
: undefined;
|
|
429
|
-
const actionState = createBridgeActionState({
|
|
430
|
-
messages: payload.messages,
|
|
431
|
-
rawRequest: payload,
|
|
432
|
-
metadata: chat.metadata,
|
|
433
|
-
capturedToolResults
|
|
434
|
-
});
|
|
435
|
-
runBridgeActionPipeline({
|
|
436
|
-
stage: 'request_outbound',
|
|
437
|
-
actions,
|
|
438
|
-
protocol: bridgePolicy?.protocol ?? 'openai-chat',
|
|
439
|
-
moduleType: bridgePolicy?.moduleType ?? 'openai-chat',
|
|
440
|
-
requestId: ctx.requestId,
|
|
441
|
-
state: actionState
|
|
442
|
-
});
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
catch {
|
|
446
|
-
// ignore policy failures
|
|
447
|
-
}
|
|
448
|
-
// Do not forward tool_outputs to provider wire formats. OpenAI Chat
|
|
449
|
-
// endpoints expect tool results to appear as tool role messages, and
|
|
450
|
-
// sending the legacy top-level field causes upstream HTTP 400 responses.
|
|
451
|
-
// Concrete translation happens earlier when responses input is unfolded
|
|
452
|
-
// into ChatEnvelope.messages, so the provider request only needs the
|
|
453
|
-
// canonical message list.
|
|
454
|
-
if (payload.max_tokens === undefined && typeof payload.max_output_tokens === 'number') {
|
|
455
|
-
payload.max_tokens = payload.max_output_tokens;
|
|
456
|
-
delete payload.max_output_tokens;
|
|
457
|
-
}
|
|
458
|
-
return {
|
|
459
|
-
protocol: 'openai-chat',
|
|
460
|
-
direction: 'response',
|
|
461
|
-
payload,
|
|
462
|
-
meta: {
|
|
463
|
-
context: ctx
|
|
464
|
-
}
|
|
465
|
-
};
|
|
466
|
-
}
|
|
467
|
-
}
|
|
1
|
+
export { ChatSemanticMapper, maybeAugmentApplyPatchErrorContent } from '../operation-table/semantic-mappers/chat-mapper.js';
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import type { AdapterContext, ChatEnvelope } from '../types/chat-envelope.js';
|
|
3
|
-
import type { FormatEnvelope } from '../types/format-envelope.js';
|
|
4
|
-
export declare class GeminiSemanticMapper implements SemanticMapper {
|
|
5
|
-
toChat(format: FormatEnvelope, ctx: AdapterContext): Promise<ChatEnvelope>;
|
|
6
|
-
fromChat(chat: ChatEnvelope, ctx: AdapterContext): Promise<FormatEnvelope>;
|
|
7
|
-
}
|
|
1
|
+
export { GeminiSemanticMapper } from '../operation-table/semantic-mappers/gemini-mapper.js';
|