@jsonstudio/llms 0.6.3275 → 0.6.3379
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/bridge-message-utils.d.ts +4 -4
- package/dist/conversion/bridge-message-utils.js +28 -538
- package/dist/conversion/compat/profiles/responses-crs.json +15 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.js +16 -5
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +1 -6
- package/dist/conversion/hub/response/response-runtime.js +14 -6
- package/dist/conversion/responses/responses-openai-bridge/response-payload.js +11 -11
- package/dist/conversion/shared/anthropic-message-utils.js +2 -12
- package/dist/conversion/shared/chat-request-filters.js +2 -61
- package/dist/conversion/shared/reasoning-mapping.js +3 -0
- package/dist/conversion/shared/reasoning-normalizer.d.ts +1 -0
- package/dist/conversion/shared/reasoning-normalizer.js +35 -388
- package/dist/conversion/shared/reasoning-tool-normalizer.js +8 -15
- package/dist/conversion/shared/reasoning-utils.js +13 -35
- package/dist/conversion/shared/responses-tool-utils.d.ts +1 -1
- package/dist/conversion/shared/responses-tool-utils.js +63 -65
- package/dist/conversion/shared/streaming-text-extractor.d.ts +0 -5
- package/dist/conversion/shared/streaming-text-extractor.js +18 -111
- package/dist/conversion/shared/text-markup-normalizer/normalize.d.ts +1 -1
- package/dist/conversion/shared/text-markup-normalizer/normalize.js +3 -91
- package/dist/conversion/shared/thought-signature-validator.js +19 -133
- package/dist/conversion/shared/tool-argument-repairer.js +16 -19
- package/dist/conversion/shared/tool-call-id-manager.d.ts +1 -5
- package/dist/conversion/shared/tool-call-id-manager.js +74 -98
- package/dist/conversion/shared/tool-harvester.js +19 -382
- package/dist/conversion/shared/tool-mapping.d.ts +2 -3
- package/dist/conversion/shared/tool-mapping.js +28 -184
- package/dist/conversion/shared/tooling.js +20 -151
- package/dist/filters/special/response-tool-arguments-stringify.js +9 -1
- package/dist/guidance/index.js +2 -2
- package/dist/native/router_hotpath_napi.node +0 -0
- package/dist/router/virtual-router/engine-legacy/helpers.js +1 -1
- package/dist/router/virtual-router/engine-selection/native-hub-bridge-action-semantics.d.ts +39 -0
- package/dist/router/virtual-router/engine-selection/native-hub-bridge-action-semantics.js +196 -0
- package/dist/router/virtual-router/engine-selection/native-hub-pipeline-req-inbound-semantics.d.ts +1 -0
- package/dist/router/virtual-router/engine-selection/native-hub-pipeline-req-inbound-semantics.js +27 -0
- package/dist/router/virtual-router/engine-selection/native-router-hotpath-loader.js +34 -0
- package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.d.ts +65 -1
- package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.js +836 -35
- package/dist/router/virtual-router/engine.js +3 -2
- package/dist/router/virtual-router/routing-instructions/parse.js +30 -3
- package/dist/sse/sse-to-json/builders/anthropic-response-builder.js +28 -3
- package/dist/sse/types/anthropic-types.d.ts +3 -1
- package/dist/tools/apply-patch/args-normalizer/extract-patch.js +2 -2
- package/dist/tools/apply-patch/patch-text/looks-like-patch.js +3 -6
- package/dist/tools/apply-patch/patch-text/normalize.js +14 -3
- package/dist/tools/tool-registry.js +12 -0
- package/package.json +6 -1
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import type { BridgeInputItem } from './types/bridge-message-types.js';
|
|
2
|
-
export declare function coerceBridgeRole(role: unknown): string;
|
|
3
|
-
export declare function serializeToolArguments(argsStringOrObj: unknown, _functionName: string | undefined, _tools: unknown): string;
|
|
4
|
-
export declare function serializeToolOutput(entry: BridgeInputItem): string | null;
|
|
5
2
|
export interface BridgeInputBuildOptions {
|
|
6
3
|
messages: Array<Record<string, unknown>>;
|
|
7
4
|
tools?: Array<Record<string, unknown>> | undefined;
|
|
@@ -12,11 +9,14 @@ export interface BridgeInputBuildResult {
|
|
|
12
9
|
latestUserInstruction?: string;
|
|
13
10
|
originalSystemMessages: string[];
|
|
14
11
|
}
|
|
12
|
+
export declare function coerceBridgeRole(role: unknown): string;
|
|
13
|
+
export declare function serializeToolArguments(argsStringOrObj: unknown, _functionName: string | undefined, _tools: unknown): string;
|
|
14
|
+
export declare function serializeToolOutput(entry: BridgeInputItem): string | null;
|
|
15
15
|
export declare function convertMessagesToBridgeInput(options: BridgeInputBuildOptions): BridgeInputBuildResult;
|
|
16
16
|
export interface BridgeInputToChatOptions {
|
|
17
17
|
input?: BridgeInputItem[];
|
|
18
18
|
tools?: Array<Record<string, unknown>>;
|
|
19
|
-
normalizeFunctionName?: (raw: unknown) => string | undefined;
|
|
19
|
+
normalizeFunctionName?: ((raw: unknown) => string | undefined) | 'default' | 'responses';
|
|
20
20
|
toolResultFallbackText?: string;
|
|
21
21
|
}
|
|
22
22
|
export declare function convertBridgeInputToChatMessages(options: BridgeInputToChatOptions): Array<Record<string, unknown>>;
|
|
@@ -1,555 +1,45 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
(
|
|
10
|
-
|
|
11
|
-
: undefined) ??
|
|
12
|
-
fallbackId;
|
|
13
|
-
call.id = resolved;
|
|
14
|
-
call.tool_call_id = resolved;
|
|
15
|
-
call.call_id = resolved;
|
|
16
|
-
return resolved;
|
|
1
|
+
import { buildBridgeHistoryWithNative, coerceBridgeRoleWithNative, convertBridgeInputToChatMessagesWithNative, ensureMessagesArrayWithNative, serializeToolArgumentsWithNative, serializeToolOutputWithNative } from '../router/virtual-router/engine-selection/native-hub-bridge-action-semantics.js';
|
|
2
|
+
function assertBridgeMessageUtilsNativeAvailable() {
|
|
3
|
+
if (typeof buildBridgeHistoryWithNative !== 'function' ||
|
|
4
|
+
typeof convertBridgeInputToChatMessagesWithNative !== 'function' ||
|
|
5
|
+
typeof coerceBridgeRoleWithNative !== 'function' ||
|
|
6
|
+
typeof serializeToolArgumentsWithNative !== 'function' ||
|
|
7
|
+
typeof serializeToolOutputWithNative !== 'function' ||
|
|
8
|
+
typeof ensureMessagesArrayWithNative !== 'function') {
|
|
9
|
+
throw new Error('[bridge-message-utils] native bindings unavailable');
|
|
10
|
+
}
|
|
17
11
|
}
|
|
18
12
|
export function coerceBridgeRole(role) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (normalized === 'system' || normalized === 'assistant' || normalized === 'user' || normalized === 'tool') {
|
|
22
|
-
return normalized;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return 'user';
|
|
13
|
+
assertBridgeMessageUtilsNativeAvailable();
|
|
14
|
+
return coerceBridgeRoleWithNative(role);
|
|
26
15
|
}
|
|
27
16
|
export function serializeToolArguments(argsStringOrObj, _functionName, _tools) {
|
|
28
|
-
|
|
17
|
+
assertBridgeMessageUtilsNativeAvailable();
|
|
18
|
+
return serializeToolArgumentsWithNative({ args: argsStringOrObj });
|
|
29
19
|
}
|
|
30
20
|
export function serializeToolOutput(entry) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return out;
|
|
34
|
-
if (out && typeof out === 'object') {
|
|
35
|
-
try {
|
|
36
|
-
return JSON.stringify(out);
|
|
37
|
-
}
|
|
38
|
-
catch {
|
|
39
|
-
return String(out);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
function collectText(value) {
|
|
45
|
-
if (!value)
|
|
46
|
-
return '';
|
|
47
|
-
if (typeof value === 'string')
|
|
48
|
-
return value;
|
|
49
|
-
if (Array.isArray(value)) {
|
|
50
|
-
return value.map(part => collectText(part)).join('');
|
|
51
|
-
}
|
|
52
|
-
if (typeof value === 'object') {
|
|
53
|
-
const record = value;
|
|
54
|
-
if (typeof record.text === 'string')
|
|
55
|
-
return record.text;
|
|
56
|
-
if (Array.isArray(record.content))
|
|
57
|
-
return collectText(record.content);
|
|
58
|
-
if (typeof record.content === 'string')
|
|
59
|
-
return record.content;
|
|
60
|
-
}
|
|
61
|
-
return '';
|
|
62
|
-
}
|
|
63
|
-
function extractMediaBlocksFromContent(content) {
|
|
64
|
-
const media = [];
|
|
65
|
-
const visit = (value) => {
|
|
66
|
-
if (!value)
|
|
67
|
-
return;
|
|
68
|
-
if (Array.isArray(value)) {
|
|
69
|
-
for (const entry of value)
|
|
70
|
-
visit(entry);
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
if (typeof value !== 'object') {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
const record = value;
|
|
77
|
-
const typeValue = typeof record.type === 'string' ? record.type.toLowerCase() : '';
|
|
78
|
-
let kind = null;
|
|
79
|
-
if (typeValue === 'image' || typeValue === 'image_url' || typeValue === 'input_image') {
|
|
80
|
-
kind = 'image';
|
|
81
|
-
}
|
|
82
|
-
else if (typeValue === 'video' || typeValue === 'video_url' || typeValue === 'input_video') {
|
|
83
|
-
kind = 'video';
|
|
84
|
-
}
|
|
85
|
-
else if (record.video_url !== undefined) {
|
|
86
|
-
kind = 'video';
|
|
87
|
-
}
|
|
88
|
-
else if (record.image_url !== undefined) {
|
|
89
|
-
kind = 'image';
|
|
90
|
-
}
|
|
91
|
-
if (kind) {
|
|
92
|
-
let url = '';
|
|
93
|
-
const mediaUrl = kind === 'video' ? record.video_url : record.image_url;
|
|
94
|
-
if (typeof mediaUrl === 'string') {
|
|
95
|
-
url = mediaUrl;
|
|
96
|
-
}
|
|
97
|
-
else if (mediaUrl && typeof mediaUrl === 'object' && typeof mediaUrl.url === 'string') {
|
|
98
|
-
url = mediaUrl.url;
|
|
99
|
-
}
|
|
100
|
-
else if (typeof record.url === 'string') {
|
|
101
|
-
url = record.url;
|
|
102
|
-
}
|
|
103
|
-
else if (typeof record.uri === 'string') {
|
|
104
|
-
url = record.uri;
|
|
105
|
-
}
|
|
106
|
-
else if (typeof record.data === 'string') {
|
|
107
|
-
url = record.data;
|
|
108
|
-
}
|
|
109
|
-
const trimmed = url.trim();
|
|
110
|
-
if (trimmed.length) {
|
|
111
|
-
let detail;
|
|
112
|
-
if (mediaUrl && typeof mediaUrl === 'object' && typeof mediaUrl.detail === 'string') {
|
|
113
|
-
detail = mediaUrl.detail.trim() || undefined;
|
|
114
|
-
}
|
|
115
|
-
else if (typeof record.detail === 'string') {
|
|
116
|
-
detail = record.detail.trim() || undefined;
|
|
117
|
-
}
|
|
118
|
-
media.push({ kind, url: trimmed, detail });
|
|
119
|
-
}
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
if (Array.isArray(record.content)) {
|
|
123
|
-
visit(record.content);
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
visit(content);
|
|
127
|
-
return media;
|
|
128
|
-
}
|
|
129
|
-
function extractUserTextFromEntry(entry) {
|
|
130
|
-
if (!entry || typeof entry !== 'object')
|
|
131
|
-
return '';
|
|
132
|
-
const directContent = entry.content ?? entry.message?.content;
|
|
133
|
-
if (typeof directContent === 'string')
|
|
134
|
-
return directContent.trim();
|
|
135
|
-
if (Array.isArray(directContent)) {
|
|
136
|
-
return directContent.map(block => collectText(block)).join('').trim();
|
|
137
|
-
}
|
|
138
|
-
const text = entry.text ?? entry.message?.text;
|
|
139
|
-
if (typeof text === 'string')
|
|
140
|
-
return text.trim();
|
|
141
|
-
return '';
|
|
21
|
+
assertBridgeMessageUtilsNativeAvailable();
|
|
22
|
+
return serializeToolOutputWithNative({ output: entry?.output });
|
|
142
23
|
}
|
|
143
24
|
export function convertMessagesToBridgeInput(options) {
|
|
25
|
+
assertBridgeMessageUtilsNativeAvailable();
|
|
144
26
|
const { messages, tools } = options;
|
|
145
27
|
const native = buildBridgeHistoryWithNative({ messages, tools });
|
|
146
28
|
return native;
|
|
147
29
|
}
|
|
148
|
-
function defaultNormalizeFunctionName(raw) {
|
|
149
|
-
if (typeof raw !== 'string')
|
|
150
|
-
return undefined;
|
|
151
|
-
const trimmed = raw.trim();
|
|
152
|
-
return trimmed.length ? trimmed : undefined;
|
|
153
|
-
}
|
|
154
|
-
function toReasoningSegments(value) {
|
|
155
|
-
if (Array.isArray(value)) {
|
|
156
|
-
return value.map((entry) => (typeof entry === 'string' ? entry.trim() : '')).filter((entry) => entry.length);
|
|
157
|
-
}
|
|
158
|
-
if (typeof value === 'string') {
|
|
159
|
-
const trimmed = value.trim();
|
|
160
|
-
return trimmed.length ? [trimmed] : [];
|
|
161
|
-
}
|
|
162
|
-
return [];
|
|
163
|
-
}
|
|
164
|
-
function combineReasoningSegments(primary, secondary) {
|
|
165
|
-
const combined = [];
|
|
166
|
-
if (Array.isArray(primary)) {
|
|
167
|
-
combined.push(...primary.filter((entry) => typeof entry === 'string' && entry.trim().length).map((entry) => entry.trim()));
|
|
168
|
-
}
|
|
169
|
-
if (Array.isArray(secondary)) {
|
|
170
|
-
combined.push(...secondary.filter((entry) => typeof entry === 'string' && entry.trim().length).map((entry) => entry.trim()));
|
|
171
|
-
}
|
|
172
|
-
return combined;
|
|
173
|
-
}
|
|
174
|
-
function pushNormalizedChatMessage(target, role, rawContent, options) {
|
|
175
|
-
if (typeof rawContent !== 'string') {
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
const normalized = normalizeChatMessageContent(rawContent);
|
|
179
|
-
const contentText = typeof normalized.contentText === 'string' ? normalized.contentText : '';
|
|
180
|
-
const reasoningText = typeof normalized.reasoningText === 'string' ? normalized.reasoningText.trim() : '';
|
|
181
|
-
const hasContent = contentText.trim().length > 0;
|
|
182
|
-
if (!hasContent && !reasoningText) {
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
const message = {
|
|
186
|
-
role,
|
|
187
|
-
content: contentText
|
|
188
|
-
};
|
|
189
|
-
const combinedReasoning = combineReasoningSegments(reasoningText.length ? [reasoningText] : [], options?.reasoningSegments);
|
|
190
|
-
if (combinedReasoning.length) {
|
|
191
|
-
message.reasoning_content = combinedReasoning.join('\n');
|
|
192
|
-
}
|
|
193
|
-
target.push(message);
|
|
194
|
-
}
|
|
195
|
-
function processMessageBlocks(blocks, normalizeFunctionName, tools, toolNameById, lastToolCallId, toolResultFallbackText) {
|
|
196
|
-
const textParts = [];
|
|
197
|
-
const toolCalls = [];
|
|
198
|
-
const toolMessages = [];
|
|
199
|
-
let currentLastCall = lastToolCallId;
|
|
200
|
-
const reasoningSegments = [];
|
|
201
|
-
const mediaBlocks = [];
|
|
202
|
-
for (const block of blocks) {
|
|
203
|
-
if (!block || typeof block !== 'object')
|
|
204
|
-
continue;
|
|
205
|
-
const type = typeof block.type === 'string' ? block.type.toLowerCase() : '';
|
|
206
|
-
if (type === 'input_text' || type === 'output_text' || type === 'text' || type === 'commentary') {
|
|
207
|
-
if (typeof block.text === 'string')
|
|
208
|
-
textParts.push(block.text);
|
|
209
|
-
else if (typeof block.content === 'string')
|
|
210
|
-
textParts.push(block.content);
|
|
211
|
-
reasoningSegments.push(...toReasoningSegments(block.reasoning_content));
|
|
212
|
-
continue;
|
|
213
|
-
}
|
|
214
|
-
if (type === 'message' && Array.isArray(block.content)) {
|
|
215
|
-
const nested = processMessageBlocks(block.content, normalizeFunctionName, tools, toolNameById, currentLastCall, toolResultFallbackText);
|
|
216
|
-
if (nested.text)
|
|
217
|
-
textParts.push(nested.text);
|
|
218
|
-
for (const tc of nested.toolCalls)
|
|
219
|
-
toolCalls.push(tc);
|
|
220
|
-
for (const tm of nested.toolMessages)
|
|
221
|
-
toolMessages.push(tm);
|
|
222
|
-
currentLastCall = nested.lastCallId;
|
|
223
|
-
reasoningSegments.push(...nested.reasoningSegments);
|
|
224
|
-
if (nested.mediaBlocks.length)
|
|
225
|
-
mediaBlocks.push(...nested.mediaBlocks);
|
|
226
|
-
continue;
|
|
227
|
-
}
|
|
228
|
-
if (type === 'input_image' || type === 'image' || type === 'image_url') {
|
|
229
|
-
let url = '';
|
|
230
|
-
if (typeof block.image_url === 'string') {
|
|
231
|
-
url = block.image_url.trim();
|
|
232
|
-
}
|
|
233
|
-
else if (block.image_url && typeof block.image_url.url === 'string') {
|
|
234
|
-
url = block.image_url.url.trim();
|
|
235
|
-
}
|
|
236
|
-
else if (typeof block.url === 'string') {
|
|
237
|
-
url = block.url.trim();
|
|
238
|
-
}
|
|
239
|
-
if (url) {
|
|
240
|
-
const detail = typeof block.detail === 'string' && block.detail.trim()
|
|
241
|
-
? block.detail.trim()
|
|
242
|
-
: undefined;
|
|
243
|
-
mediaBlocks.push({ kind: 'image', url, detail });
|
|
244
|
-
}
|
|
245
|
-
continue;
|
|
246
|
-
}
|
|
247
|
-
if (type === 'input_video' || type === 'video' || type === 'video_url') {
|
|
248
|
-
let url = '';
|
|
249
|
-
if (typeof block.video_url === 'string') {
|
|
250
|
-
url = block.video_url.trim();
|
|
251
|
-
}
|
|
252
|
-
else if (block.video_url && typeof block.video_url.url === 'string') {
|
|
253
|
-
url = block.video_url.url.trim();
|
|
254
|
-
}
|
|
255
|
-
else if (typeof block.url === 'string') {
|
|
256
|
-
url = block.url.trim();
|
|
257
|
-
}
|
|
258
|
-
if (url) {
|
|
259
|
-
const detail = typeof block.detail === 'string' && block.detail.trim()
|
|
260
|
-
? block.detail.trim()
|
|
261
|
-
: undefined;
|
|
262
|
-
mediaBlocks.push({ kind: 'video', url, detail });
|
|
263
|
-
}
|
|
264
|
-
continue;
|
|
265
|
-
}
|
|
266
|
-
if (type === 'function_call') {
|
|
267
|
-
const rawName = typeof block.name === 'string'
|
|
268
|
-
? block.name
|
|
269
|
-
: (typeof block?.function?.name === 'string'
|
|
270
|
-
? block.function.name
|
|
271
|
-
: undefined);
|
|
272
|
-
const name = normalizeFunctionName(rawName);
|
|
273
|
-
const args = block.arguments ?? block?.function?.arguments ?? {};
|
|
274
|
-
const parsedArgs = args;
|
|
275
|
-
const callIdCandidate = (typeof block.id === 'string' && block.id.trim().length ? block.id.trim() : undefined) ??
|
|
276
|
-
(typeof block.call_id === 'string' && block.call_id.trim().length ? block.call_id.trim() : undefined);
|
|
277
|
-
const callId = callIdCandidate ??
|
|
278
|
-
normalizeFunctionCallId({
|
|
279
|
-
callId: callIdCandidate,
|
|
280
|
-
fallback: `fc_call_${toolCalls.length + 1}`
|
|
281
|
-
});
|
|
282
|
-
if (typeof name !== 'string' || !name.trim()) {
|
|
283
|
-
currentLastCall = null;
|
|
284
|
-
continue;
|
|
285
|
-
}
|
|
286
|
-
const serialized = serializeToolArguments(parsedArgs, name, tools).trim();
|
|
287
|
-
toolNameById.set(callId, name);
|
|
288
|
-
toolCalls.push({ id: callId, type: 'function', function: { name, arguments: serialized } });
|
|
289
|
-
currentLastCall = callId;
|
|
290
|
-
continue;
|
|
291
|
-
}
|
|
292
|
-
if (type === 'function_call_output' || type === 'tool_result' || type === 'tool_message') {
|
|
293
|
-
let toolCallId = block.tool_call_id ||
|
|
294
|
-
block.call_id ||
|
|
295
|
-
block.tool_use_id ||
|
|
296
|
-
block.id ||
|
|
297
|
-
currentLastCall;
|
|
298
|
-
toolCallId = typeof toolCallId === 'string' && toolCallId.trim().length ? toolCallId.trim() : currentLastCall;
|
|
299
|
-
const output = serializeToolOutput(block);
|
|
300
|
-
if (toolCallId) {
|
|
301
|
-
try {
|
|
302
|
-
let contentStr = output != null ? String(output) : '';
|
|
303
|
-
if (!contentStr || contentStr.trim().length === 0) {
|
|
304
|
-
contentStr = toolResultFallbackText;
|
|
305
|
-
}
|
|
306
|
-
const nm = toolNameById.get(String(toolCallId));
|
|
307
|
-
const toolMsg = { role: 'tool', tool_call_id: String(toolCallId), content: contentStr };
|
|
308
|
-
if (typeof nm === 'string' && nm.trim().length)
|
|
309
|
-
toolMsg.name = nm;
|
|
310
|
-
toolMessages.push(toolMsg);
|
|
311
|
-
}
|
|
312
|
-
catch {
|
|
313
|
-
const fallback = (output ?? toolResultFallbackText);
|
|
314
|
-
const nm = toolNameById.get(String(toolCallId));
|
|
315
|
-
const toolMsg = { role: 'tool', tool_call_id: String(toolCallId), content: String(fallback) };
|
|
316
|
-
if (typeof nm === 'string' && nm.trim().length)
|
|
317
|
-
toolMsg.name = nm;
|
|
318
|
-
toolMessages.push(toolMsg);
|
|
319
|
-
}
|
|
320
|
-
currentLastCall = null;
|
|
321
|
-
}
|
|
322
|
-
continue;
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
const text = textParts.length ? textParts.join('\n').trim() : null;
|
|
326
|
-
return { text, mediaBlocks, toolCalls, toolMessages, lastCallId: currentLastCall, reasoningSegments };
|
|
327
|
-
}
|
|
328
30
|
export function convertBridgeInputToChatMessages(options) {
|
|
31
|
+
assertBridgeMessageUtilsNativeAvailable();
|
|
329
32
|
const { input, tools, normalizeFunctionName, toolResultFallbackText } = options;
|
|
330
|
-
const
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
for (let entryIndex = 0; entryIndex < input.length; entryIndex++) {
|
|
338
|
-
const entry = input[entryIndex];
|
|
339
|
-
if (!entry || typeof entry !== 'object')
|
|
340
|
-
continue;
|
|
341
|
-
const entryType = typeof entry.type === 'string' ? entry.type.toLowerCase() : 'message';
|
|
342
|
-
const entryReasoningSegments = toReasoningSegments(entry.reasoning_content);
|
|
343
|
-
let entryReasoningConsumed = false;
|
|
344
|
-
const consumeEntryReasoning = () => {
|
|
345
|
-
if (entryReasoningConsumed || !entryReasoningSegments.length) {
|
|
346
|
-
return undefined;
|
|
347
|
-
}
|
|
348
|
-
entryReasoningConsumed = true;
|
|
349
|
-
return entryReasoningSegments;
|
|
350
|
-
};
|
|
351
|
-
if (typeof entry.content === 'string') {
|
|
352
|
-
const normalizedRole = coerceBridgeRole(entry.role || 'user');
|
|
353
|
-
const directText = (entry.content || '').toString();
|
|
354
|
-
pushNormalizedChatMessage(messages, normalizedRole, directText, {
|
|
355
|
-
reasoningSegments: consumeEntryReasoning()
|
|
356
|
-
});
|
|
357
|
-
continue;
|
|
358
|
-
}
|
|
359
|
-
if (entryType === 'function_call' || entryType === 'tool_call') {
|
|
360
|
-
const rawName = typeof entry.name === 'string'
|
|
361
|
-
? entry.name
|
|
362
|
-
: (typeof entry?.function?.name === 'string' ? entry.function.name : undefined);
|
|
363
|
-
const name = resolveFunctionName(rawName);
|
|
364
|
-
if (typeof name !== 'string' || !name.trim()) {
|
|
365
|
-
continue;
|
|
366
|
-
}
|
|
367
|
-
const args = entry.arguments ?? entry?.function?.arguments ?? {};
|
|
368
|
-
const parsedArgs = args;
|
|
369
|
-
const callIdRaw = typeof entry.id === 'string' ? entry.id : (typeof entry.call_id === 'string' ? entry.call_id : undefined);
|
|
370
|
-
const callIdSource = typeof callIdRaw === 'string' && callIdRaw.trim().length ? callIdRaw.trim() : undefined;
|
|
371
|
-
let callId = callIdSource;
|
|
372
|
-
if (!callId) {
|
|
373
|
-
callId = normalizeFunctionCallId({
|
|
374
|
-
callId: callIdSource,
|
|
375
|
-
fallback: `fc_call_${messages.length + 1}`
|
|
376
|
-
});
|
|
377
|
-
}
|
|
378
|
-
const serialized = serializeToolArguments(parsedArgs, name, tools).trim();
|
|
379
|
-
toolNameById.set(callId, name);
|
|
380
|
-
const toolCall = {
|
|
381
|
-
id: callId,
|
|
382
|
-
call_id: callId,
|
|
383
|
-
tool_call_id: callId,
|
|
384
|
-
type: 'function',
|
|
385
|
-
function: { name, arguments: serialized }
|
|
386
|
-
};
|
|
387
|
-
messages.push({
|
|
388
|
-
role: 'assistant',
|
|
389
|
-
content: '',
|
|
390
|
-
tool_calls: [toolCall]
|
|
391
|
-
});
|
|
392
|
-
lastToolCallId = callId;
|
|
393
|
-
continue;
|
|
394
|
-
}
|
|
395
|
-
if (entryType === 'function_call_output' || entryType === 'tool_result' || entryType === 'tool_message') {
|
|
396
|
-
let toolCallId = entry.tool_call_id ||
|
|
397
|
-
entry.call_id ||
|
|
398
|
-
entry.tool_use_id ||
|
|
399
|
-
entry.id ||
|
|
400
|
-
lastToolCallId;
|
|
401
|
-
toolCallId = typeof toolCallId === 'string' && toolCallId.trim().length ? toolCallId.trim() : (lastToolCallId ?? undefined);
|
|
402
|
-
const output = serializeToolOutput(entry);
|
|
403
|
-
if (toolCallId) {
|
|
404
|
-
try {
|
|
405
|
-
let contentStr = output != null ? String(output) : '';
|
|
406
|
-
if (!contentStr || contentStr.trim().length === 0) {
|
|
407
|
-
contentStr = fallbackText;
|
|
408
|
-
}
|
|
409
|
-
const nm = toolNameById.get(String(toolCallId));
|
|
410
|
-
const toolMsg = {
|
|
411
|
-
role: 'tool',
|
|
412
|
-
tool_call_id: String(toolCallId),
|
|
413
|
-
id: String(toolCallId),
|
|
414
|
-
content: contentStr
|
|
415
|
-
};
|
|
416
|
-
if (typeof nm === 'string' && nm.trim().length)
|
|
417
|
-
toolMsg.name = nm;
|
|
418
|
-
messages.push(toolMsg);
|
|
419
|
-
}
|
|
420
|
-
catch {
|
|
421
|
-
const fallback = (output ?? fallbackText);
|
|
422
|
-
const nm = toolNameById.get(String(toolCallId));
|
|
423
|
-
const toolMsg = {
|
|
424
|
-
role: 'tool',
|
|
425
|
-
tool_call_id: String(toolCallId),
|
|
426
|
-
id: String(toolCallId),
|
|
427
|
-
content: String(fallback)
|
|
428
|
-
};
|
|
429
|
-
if (typeof nm === 'string' && nm.trim().length)
|
|
430
|
-
toolMsg.name = nm;
|
|
431
|
-
messages.push(toolMsg);
|
|
432
|
-
}
|
|
433
|
-
lastToolCallId = null;
|
|
434
|
-
}
|
|
435
|
-
continue;
|
|
436
|
-
}
|
|
437
|
-
let handledViaExplicitMessage = false;
|
|
438
|
-
if (entry && typeof entry.message === 'object' && Array.isArray(entry.message?.content)) {
|
|
439
|
-
const explicit = entry.message;
|
|
440
|
-
const nested = processMessageBlocks(Array.isArray(explicit.content) ? explicit.content : [], resolveFunctionName, tools, toolNameById, lastToolCallId, fallbackText);
|
|
441
|
-
if (nested.toolCalls.length) {
|
|
442
|
-
nested.toolCalls.forEach((call, idx) => ensureAssistantToolCallIdentity(call, `fc_call_${messages.length + idx + 1}`));
|
|
443
|
-
messages.push({
|
|
444
|
-
role: 'assistant',
|
|
445
|
-
content: '',
|
|
446
|
-
tool_calls: nested.toolCalls
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
for (const msg of nested.toolMessages)
|
|
450
|
-
messages.push(msg);
|
|
451
|
-
const normalizedRole = coerceBridgeRole((explicit.role ?? entry.role) || 'user');
|
|
452
|
-
if (nested.mediaBlocks.length) {
|
|
453
|
-
const contentBlocks = [];
|
|
454
|
-
if (typeof nested.text === 'string' && nested.text.trim().length) {
|
|
455
|
-
contentBlocks.push({ type: 'text', text: nested.text });
|
|
456
|
-
}
|
|
457
|
-
for (const media of nested.mediaBlocks) {
|
|
458
|
-
const mediaBlock = media.kind === 'video'
|
|
459
|
-
? { type: 'video_url', video_url: { url: media.url } }
|
|
460
|
-
: { type: 'image_url', image_url: { url: media.url } };
|
|
461
|
-
if (media.detail) {
|
|
462
|
-
const key = media.kind === 'video' ? 'video_url' : 'image_url';
|
|
463
|
-
mediaBlock[key].detail = media.detail;
|
|
464
|
-
}
|
|
465
|
-
contentBlocks.push(mediaBlock);
|
|
466
|
-
}
|
|
467
|
-
const msg = {
|
|
468
|
-
role: normalizedRole,
|
|
469
|
-
content: contentBlocks
|
|
470
|
-
};
|
|
471
|
-
const combinedReasoning = combineReasoningSegments(consumeEntryReasoning(), nested.reasoningSegments);
|
|
472
|
-
if (combinedReasoning.length) {
|
|
473
|
-
msg.reasoning_content = combinedReasoning.join('\n');
|
|
474
|
-
}
|
|
475
|
-
messages.push(msg);
|
|
476
|
-
}
|
|
477
|
-
else if (typeof nested.text === 'string') {
|
|
478
|
-
pushNormalizedChatMessage(messages, normalizedRole, nested.text, {
|
|
479
|
-
reasoningSegments: combineReasoningSegments(consumeEntryReasoning(), nested.reasoningSegments)
|
|
480
|
-
});
|
|
481
|
-
}
|
|
482
|
-
lastToolCallId = nested.lastCallId;
|
|
483
|
-
handledViaExplicitMessage = true;
|
|
484
|
-
}
|
|
485
|
-
if (!handledViaExplicitMessage) {
|
|
486
|
-
const nested = processMessageBlocks(Array.isArray(entry.content) ? entry.content : [], resolveFunctionName, tools, toolNameById, lastToolCallId, fallbackText);
|
|
487
|
-
if (nested.toolCalls.length) {
|
|
488
|
-
nested.toolCalls.forEach((call, idx) => ensureAssistantToolCallIdentity(call, `fc_call_${messages.length + idx + 1}`));
|
|
489
|
-
messages.push({
|
|
490
|
-
role: 'assistant',
|
|
491
|
-
content: '',
|
|
492
|
-
tool_calls: nested.toolCalls
|
|
493
|
-
});
|
|
494
|
-
}
|
|
495
|
-
for (const msg of nested.toolMessages)
|
|
496
|
-
messages.push(msg);
|
|
497
|
-
const normalizedRole = coerceBridgeRole(entry.role || 'user');
|
|
498
|
-
if (nested.mediaBlocks.length) {
|
|
499
|
-
const contentBlocks = [];
|
|
500
|
-
if (typeof nested.text === 'string' && nested.text.trim().length) {
|
|
501
|
-
contentBlocks.push({ type: 'text', text: nested.text });
|
|
502
|
-
}
|
|
503
|
-
for (const media of nested.mediaBlocks) {
|
|
504
|
-
const mediaBlock = media.kind === 'video'
|
|
505
|
-
? { type: 'video_url', video_url: { url: media.url } }
|
|
506
|
-
: { type: 'image_url', image_url: { url: media.url } };
|
|
507
|
-
if (media.detail) {
|
|
508
|
-
const key = media.kind === 'video' ? 'video_url' : 'image_url';
|
|
509
|
-
mediaBlock[key].detail = media.detail;
|
|
510
|
-
}
|
|
511
|
-
contentBlocks.push(mediaBlock);
|
|
512
|
-
}
|
|
513
|
-
const msg = {
|
|
514
|
-
role: normalizedRole,
|
|
515
|
-
content: contentBlocks
|
|
516
|
-
};
|
|
517
|
-
const combinedReasoning = combineReasoningSegments(consumeEntryReasoning(), nested.reasoningSegments);
|
|
518
|
-
if (combinedReasoning.length) {
|
|
519
|
-
msg.reasoning_content = combinedReasoning.join('\n');
|
|
520
|
-
}
|
|
521
|
-
messages.push(msg);
|
|
522
|
-
}
|
|
523
|
-
else if (typeof nested.text === 'string') {
|
|
524
|
-
pushNormalizedChatMessage(messages, normalizedRole, nested.text, {
|
|
525
|
-
reasoningSegments: consumeEntryReasoning()
|
|
526
|
-
});
|
|
527
|
-
}
|
|
528
|
-
lastToolCallId = nested.lastCallId;
|
|
529
|
-
}
|
|
530
|
-
try {
|
|
531
|
-
const t = String(entry.type || '').toLowerCase();
|
|
532
|
-
if ((t === 'input_text' || t === 'text' || t === 'output_text' || t === 'commentary') &&
|
|
533
|
-
typeof entry.text === 'string') {
|
|
534
|
-
const normalizedRole = coerceBridgeRole(entry.role || 'user');
|
|
535
|
-
const s = entry.text;
|
|
536
|
-
if (s && s.length) {
|
|
537
|
-
pushNormalizedChatMessage(messages, normalizedRole, s, {
|
|
538
|
-
reasoningSegments: consumeEntryReasoning()
|
|
539
|
-
});
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
catch {
|
|
544
|
-
/* ignore */
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
return messages;
|
|
33
|
+
const output = convertBridgeInputToChatMessagesWithNative({
|
|
34
|
+
input: Array.isArray(input) ? input : [],
|
|
35
|
+
tools,
|
|
36
|
+
toolResultFallbackText,
|
|
37
|
+
normalizeFunctionName: typeof normalizeFunctionName === 'string' ? normalizeFunctionName : undefined
|
|
38
|
+
});
|
|
39
|
+
return output.messages;
|
|
548
40
|
}
|
|
549
41
|
export function ensureMessagesArray(state) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
state.messages = [];
|
|
554
|
-
return state.messages;
|
|
42
|
+
assertBridgeMessageUtilsNativeAvailable();
|
|
43
|
+
const output = ensureMessagesArrayWithNative({ state });
|
|
44
|
+
return output.messages;
|
|
555
45
|
}
|
|
@@ -4,16 +4,27 @@ export function maybeAugmentApplyPatchErrorContent(content, toolName) {
|
|
|
4
4
|
return content;
|
|
5
5
|
const lower = content.toLowerCase();
|
|
6
6
|
const isApplyPatch = (typeof toolName === 'string' && toolName.trim() === 'apply_patch') ||
|
|
7
|
-
lower.includes('apply_patch verification failed')
|
|
7
|
+
lower.includes('apply_patch verification failed') ||
|
|
8
|
+
lower.includes('failed to apply patch');
|
|
8
9
|
if (!isApplyPatch) {
|
|
9
10
|
return content;
|
|
10
11
|
}
|
|
11
|
-
|
|
12
|
-
if (content.includes('[apply_patch hint]')) {
|
|
12
|
+
if (content.includes('[apply_patch hint]') || content.includes('[RouteCodex hint] apply_patch')) {
|
|
13
13
|
return content;
|
|
14
14
|
}
|
|
15
|
-
const
|
|
16
|
-
|
|
15
|
+
const sandboxSignal = lower.includes('sandbox(signal(9))') || (lower.includes('sandbox') && lower.includes('signal(9)'));
|
|
16
|
+
if (sandboxSignal) {
|
|
17
|
+
return content +
|
|
18
|
+
'\n\n[RouteCodex hint] apply_patch \u88ab sandbox \u7ec8\u6b62 (Signal 9)\u3002\u5e38\u89c1\u539f\u56e0\u662f\u8865\u4e01\u6d89\u53ca workspace \u4e4b\u5916\u7684\u8def\u5f84\u3002\u8bf7\u6539\u7528\u5f53\u524d workspace \u5185\u8def\u5f84\uff0c\u6216\u5c06\u76ee\u6807\u4ed3\u52a0\u5165 workspaces/workdir \u540e\u518d\u8c03\u7528 apply_patch\u3002';
|
|
19
|
+
}
|
|
20
|
+
const missingPath = lower.includes('failed to read file to update') ||
|
|
21
|
+
lower.includes('no such file or directory');
|
|
22
|
+
if (missingPath) {
|
|
23
|
+
return content +
|
|
24
|
+
'\n\n[RouteCodex hint] apply_patch \u8bfb\u53d6\u76ee\u6807\u6587\u4ef6\u5931\u8d25\uff1a\u8def\u5f84\u4e0d\u5b58\u5728\u6216\u4e0d\u5728\u5f53\u524d workspace\u3002\u8bf7\u786e\u8ba4\u8def\u5f84\u5728\u5f53\u524d workspace \u5185\u4e14\u6587\u4ef6\u771f\u5b9e\u5b58\u5728\uff1b\u8def\u5f84\u5fc5\u987b\u4e3a workspace \u76f8\u5bf9\u8def\u5f84\uff08\u5982 src/...\uff09\uff0c\u4e0d\u8981\u4ee5 / \u6216\u76d8\u7b26\u5f00\u5934\u3002\u5fc5\u8981\u65f6\u5207\u6362 workspace/workdir\u3002';
|
|
25
|
+
}
|
|
26
|
+
return content +
|
|
27
|
+
'\n\n[apply_patch hint] \u5728\u4f7f\u7528 apply_patch \u4e4b\u524d\uff0c\u8bf7\u5148\u8bfb\u53d6\u76ee\u6807\u6587\u4ef6\u7684\u6700\u65b0\u5185\u5bb9\uff0c\u5e76\u57fa\u4e8e\u8be5\u5185\u5bb9\u751f\u6210\u8865\u4e01\uff1b\u540c\u65f6\u786e\u4fdd\u8865\u4e01\u683c\u5f0f\u7b26\u5408\u5de5\u5177\u89c4\u8303\uff08\u7edf\u4e00\u8865\u4e01\u683c\u5f0f\u6216\u7ed3\u6784\u5316\u53c2\u6570\uff09\uff0c\u907f\u514d\u4e0a\u4e0b\u6587\u4e0d\u5339\u914d\u6216\u8bed\u6cd5\u9519\u8bef\u3002';
|
|
17
28
|
}
|
|
18
29
|
export class ChatSemanticMapper {
|
|
19
30
|
async toChat(format, ctx) {
|
|
@@ -3,12 +3,7 @@ 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 SHELL_TOOL_NAME_ALIASES = {
|
|
7
|
-
shell_command: 'exec_command',
|
|
8
|
-
shell: 'exec_command',
|
|
9
|
-
bash: 'exec_command',
|
|
10
|
-
terminal: 'exec_command'
|
|
11
|
-
};
|
|
6
|
+
const SHELL_TOOL_NAME_ALIASES = {};
|
|
12
7
|
/**
|
|
13
8
|
* Unified text-to-tool-calls harvest config.
|
|
14
9
|
* Shared across all providers via chat process tool governance.
|