@jsonstudio/llms 0.6.3275 → 0.6.3405
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/actions/claude-thinking-tools.d.ts +1 -14
- package/dist/conversion/compat/actions/claude-thinking-tools.js +3 -71
- package/dist/conversion/compat/actions/lmstudio-responses-fc-ids.d.ts +0 -8
- package/dist/conversion/compat/actions/lmstudio-responses-fc-ids.js +2 -57
- package/dist/conversion/compat/actions/normalize-tool-call-ids.d.ts +0 -9
- package/dist/conversion/compat/actions/normalize-tool-call-ids.js +6 -136
- package/dist/conversion/compat/actions/request-rules.js +2 -61
- package/dist/conversion/compat/actions/response-blacklist.d.ts +0 -4
- package/dist/conversion/compat/actions/response-blacklist.js +2 -77
- package/dist/conversion/compat/actions/response-normalize.js +2 -119
- package/dist/conversion/compat/actions/response-validate.js +2 -74
- package/dist/conversion/compat/actions/strip-orphan-function-calls-tag.js +2 -150
- package/dist/conversion/compat/profiles/responses-crs.json +15 -0
- package/dist/conversion/hub/operation-table/semantic-mappers/anthropic-mapper.js +24 -1
- package/dist/conversion/hub/operation-table/semantic-mappers/chat-mapper.js +16 -5
- package/dist/conversion/hub/pipeline/hub-pipeline.js +91 -0
- 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-tool-parser.js +7 -8
- package/dist/conversion/shared/reasoning-utils.js +13 -35
- package/dist/conversion/shared/responses-response-utils.js +3 -48
- package/dist/conversion/shared/responses-tool-utils.d.ts +1 -1
- package/dist/conversion/shared/responses-tool-utils.js +74 -180
- 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/bootstrap/web-search-config.js +25 -0
- package/dist/router/virtual-router/bootstrap.js +21 -16
- package/dist/router/virtual-router/engine-legacy/helpers.js +1 -1
- package/dist/router/virtual-router/engine-selection/native-compat-action-semantics.d.ts +6 -0
- package/dist/router/virtual-router/engine-selection/native-compat-action-semantics.js +171 -0
- 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 +45 -0
- package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.d.ts +70 -1
- package/dist/router/virtual-router/engine-selection/native-shared-conversion-semantics.js +993 -55
- package/dist/router/virtual-router/engine.js +3 -2
- package/dist/router/virtual-router/routing-instructions/parse.js +30 -3
- package/dist/router/virtual-router/types.d.ts +23 -0
- package/dist/servertool/handlers/web-search.js +26 -1
- package/dist/servertool/server-side-tools.js +11 -2
- package/dist/servertool/types.d.ts +4 -0
- 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,48 +1,86 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createToolCallIdTransformerWithNative, normalizeResponsesToolCallIdsWithNative, normalizeFunctionCallIdWithNative, normalizeFunctionCallOutputIdWithNative, normalizeResponsesCallIdWithNative, resolveToolCallIdStyleWithNative, stripInternalToolingMetadataWithNative } from '../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
|
|
2
2
|
import { sanitizeResponsesFunctionNameWithNative } from '../../router/virtual-router/engine-selection/native-hub-pipeline-resp-semantics.js';
|
|
3
|
+
function assertResponsesToolUtilsNativeAvailable() {
|
|
4
|
+
if (typeof createToolCallIdTransformerWithNative !== 'function' ||
|
|
5
|
+
typeof normalizeResponsesToolCallIdsWithNative !== 'function' ||
|
|
6
|
+
typeof normalizeFunctionCallIdWithNative !== 'function' ||
|
|
7
|
+
typeof normalizeFunctionCallOutputIdWithNative !== 'function' ||
|
|
8
|
+
typeof normalizeResponsesCallIdWithNative !== 'function' ||
|
|
9
|
+
typeof resolveToolCallIdStyleWithNative !== 'function' ||
|
|
10
|
+
typeof stripInternalToolingMetadataWithNative !== 'function' ||
|
|
11
|
+
typeof sanitizeResponsesFunctionNameWithNative !== 'function') {
|
|
12
|
+
throw new Error('[responses-tool-utils] native bindings unavailable');
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function replaceMutableRecord(target, next) {
|
|
16
|
+
for (const key of Object.keys(target)) {
|
|
17
|
+
delete target[key];
|
|
18
|
+
}
|
|
19
|
+
Object.assign(target, next);
|
|
20
|
+
}
|
|
3
21
|
export function createToolCallIdTransformer(style) {
|
|
22
|
+
assertResponsesToolUtilsNativeAvailable();
|
|
4
23
|
if (style !== 'fc') {
|
|
5
24
|
return null;
|
|
6
25
|
}
|
|
7
|
-
|
|
8
|
-
let itemCounter = 0;
|
|
9
|
-
let outputCounter = 0;
|
|
10
|
-
const callAlias = new Map();
|
|
11
|
-
const normalizeCallId = (raw) => {
|
|
12
|
-
const rawStr = typeof raw === 'string' && raw.trim().length ? raw.trim() : undefined;
|
|
13
|
-
if (rawStr && callAlias.has(rawStr)) {
|
|
14
|
-
return callAlias.get(rawStr);
|
|
15
|
-
}
|
|
16
|
-
const normalized = normalizeResponsesCallId({
|
|
17
|
-
callId: rawStr,
|
|
18
|
-
fallback: `call_${++callCounter}`
|
|
19
|
-
});
|
|
20
|
-
if (rawStr) {
|
|
21
|
-
callAlias.set(rawStr, normalized);
|
|
22
|
-
}
|
|
23
|
-
return normalized;
|
|
24
|
-
};
|
|
25
|
-
const normalizeItemId = (raw, callId) => {
|
|
26
|
-
const rawStr = typeof raw === 'string' && raw.trim().length ? raw.trim() : undefined;
|
|
27
|
-
return normalizeFunctionCallId({
|
|
28
|
-
callId: rawStr ?? callId,
|
|
29
|
-
fallback: `fc_item_${++itemCounter}`
|
|
30
|
-
});
|
|
31
|
-
};
|
|
32
|
-
const normalizeOutputId = (callId, raw) => {
|
|
33
|
-
const rawStr = typeof raw === 'string' && raw.trim().length ? raw.trim() : undefined;
|
|
34
|
-
return normalizeFunctionCallOutputId({
|
|
35
|
-
callId,
|
|
36
|
-
fallback: rawStr ?? `fc_tool_${++outputCounter}`
|
|
37
|
-
});
|
|
38
|
-
};
|
|
26
|
+
const state = createToolCallIdTransformerWithNative(style);
|
|
39
27
|
return {
|
|
40
|
-
normalizeCallId
|
|
41
|
-
|
|
42
|
-
|
|
28
|
+
normalizeCallId(raw) {
|
|
29
|
+
return normalizeResponsesCallIdWithNative({
|
|
30
|
+
callId: typeof raw === 'string' && raw.trim().length ? raw.trim() : undefined,
|
|
31
|
+
fallback: transformCounter(state, 'call')
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
normalizeItemId(raw, callId) {
|
|
35
|
+
return normalizeFunctionCallIdWithNative({
|
|
36
|
+
callId: typeof raw === 'string' && raw.trim().length ? raw.trim() : callId,
|
|
37
|
+
fallback: transformCounter(state, 'item')
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
normalizeOutputId(callId, raw) {
|
|
41
|
+
return normalizeFunctionCallOutputIdWithNative({
|
|
42
|
+
callId,
|
|
43
|
+
fallback: typeof raw === 'string' && raw.trim().length ? raw.trim() : transformCounter(state, 'tool')
|
|
44
|
+
});
|
|
45
|
+
}
|
|
43
46
|
};
|
|
44
47
|
}
|
|
48
|
+
function transformCounter(state, prefix) {
|
|
49
|
+
const current = typeof state.__counter === 'number' ? state.__counter : 0;
|
|
50
|
+
const next = current + 1;
|
|
51
|
+
state.__counter = next;
|
|
52
|
+
return `${prefix}_${next}`;
|
|
53
|
+
}
|
|
54
|
+
export function normalizeResponsesToolCallIds(payload) {
|
|
55
|
+
assertResponsesToolUtilsNativeAvailable();
|
|
56
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const normalized = normalizeResponsesToolCallIdsWithNative(payload);
|
|
60
|
+
if (normalized && typeof normalized === 'object' && !Array.isArray(normalized)) {
|
|
61
|
+
replaceMutableRecord(payload, normalized);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export function resolveToolCallIdStyle(metadata) {
|
|
65
|
+
assertResponsesToolUtilsNativeAvailable();
|
|
66
|
+
const style = resolveToolCallIdStyleWithNative(metadata ?? null);
|
|
67
|
+
return style === 'preserve' ? 'preserve' : 'fc';
|
|
68
|
+
}
|
|
69
|
+
export function stripInternalToolingMetadata(metadata) {
|
|
70
|
+
assertResponsesToolUtilsNativeAvailable();
|
|
71
|
+
if (!metadata || typeof metadata !== 'object' || Array.isArray(metadata))
|
|
72
|
+
return;
|
|
73
|
+
const normalized = stripInternalToolingMetadataWithNative(metadata);
|
|
74
|
+
if (normalized && typeof normalized === 'object' && !Array.isArray(normalized)) {
|
|
75
|
+
replaceMutableRecord(metadata, normalized);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export function sanitizeResponsesFunctionName(rawName) {
|
|
79
|
+
assertResponsesToolUtilsNativeAvailable();
|
|
80
|
+
return sanitizeResponsesFunctionNameWithNative(rawName);
|
|
81
|
+
}
|
|
45
82
|
export function enforceToolCallIdStyle(input, transformer) {
|
|
83
|
+
assertResponsesToolUtilsNativeAvailable();
|
|
46
84
|
for (const entry of input) {
|
|
47
85
|
if (!entry || typeof entry !== 'object')
|
|
48
86
|
continue;
|
|
@@ -56,9 +94,6 @@ export function enforceToolCallIdStyle(input, transformer) {
|
|
|
56
94
|
if (type === 'function_call_output' || type === 'tool_result' || type === 'tool_message') {
|
|
57
95
|
const normalizedCallId = transformer.normalizeCallId(entry.call_id ?? entry.tool_call_id ?? entry.id);
|
|
58
96
|
entry.call_id = normalizedCallId;
|
|
59
|
-
// OpenAI `/v1/responses` request schema uses `call_id` for tool outputs.
|
|
60
|
-
// Some internal carriers may include `tool_call_id`; strip it before sending upstream
|
|
61
|
-
// to avoid strict schema errors (e.g. "Unknown parameter: input[N].tool_call_id").
|
|
62
97
|
if (entry.tool_call_id !== undefined) {
|
|
63
98
|
delete entry.tool_call_id;
|
|
64
99
|
}
|
|
@@ -66,144 +101,3 @@ export function enforceToolCallIdStyle(input, transformer) {
|
|
|
66
101
|
}
|
|
67
102
|
}
|
|
68
103
|
}
|
|
69
|
-
function isStableToolCallId(raw) {
|
|
70
|
-
return /^((fc|call)_[A-Za-z0-9_-]+)$/i.test(raw);
|
|
71
|
-
}
|
|
72
|
-
export function normalizeResponsesToolCallIds(payload) {
|
|
73
|
-
if (!payload || typeof payload !== 'object') {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
let counter = 0;
|
|
77
|
-
const aliasMap = new Map();
|
|
78
|
-
const nextFallback = (prefix) => `${prefix}_${++counter}`;
|
|
79
|
-
const normalizeCallId = (raw, fallbackPrefix) => {
|
|
80
|
-
const trimmed = typeof raw === 'string' ? raw.trim() : '';
|
|
81
|
-
if (trimmed) {
|
|
82
|
-
const cached = aliasMap.get(trimmed);
|
|
83
|
-
if (cached)
|
|
84
|
-
return cached;
|
|
85
|
-
}
|
|
86
|
-
const normalized = trimmed && isStableToolCallId(trimmed)
|
|
87
|
-
? trimmed
|
|
88
|
-
: normalizeFunctionCallId({
|
|
89
|
-
callId: trimmed || undefined,
|
|
90
|
-
fallback: nextFallback(fallbackPrefix)
|
|
91
|
-
});
|
|
92
|
-
if (trimmed) {
|
|
93
|
-
aliasMap.set(trimmed, normalized);
|
|
94
|
-
}
|
|
95
|
-
return normalized;
|
|
96
|
-
};
|
|
97
|
-
const output = Array.isArray(payload.output) ? payload.output : [];
|
|
98
|
-
for (const item of output) {
|
|
99
|
-
if (!item || typeof item !== 'object')
|
|
100
|
-
continue;
|
|
101
|
-
const type = typeof item.type === 'string' ? String(item.type).toLowerCase() : '';
|
|
102
|
-
if (type === 'function_call') {
|
|
103
|
-
const normalizedCallId = normalizeCallId(item.call_id ?? item.tool_call_id ?? item.id, 'fc_call');
|
|
104
|
-
item.call_id = normalizedCallId;
|
|
105
|
-
if (item.tool_call_id !== undefined) {
|
|
106
|
-
item.tool_call_id = normalizedCallId;
|
|
107
|
-
}
|
|
108
|
-
const rawOutputId = typeof item.id === 'string' ? item.id : undefined;
|
|
109
|
-
item.id = normalizeFunctionCallOutputId({
|
|
110
|
-
callId: normalizedCallId,
|
|
111
|
-
fallback: rawOutputId ?? nextFallback('fc')
|
|
112
|
-
});
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
if (type === 'function_call_output' || type === 'tool_result' || type === 'tool_message') {
|
|
116
|
-
const normalizedCallId = normalizeCallId(item.call_id ?? item.tool_call_id ?? item.id, 'fc_call');
|
|
117
|
-
item.call_id = normalizedCallId;
|
|
118
|
-
if (item.tool_call_id !== undefined) {
|
|
119
|
-
item.tool_call_id = normalizedCallId;
|
|
120
|
-
}
|
|
121
|
-
const rawOutputId = typeof item.id === 'string' ? item.id : undefined;
|
|
122
|
-
item.id = normalizeFunctionCallOutputId({
|
|
123
|
-
callId: normalizedCallId,
|
|
124
|
-
fallback: rawOutputId ?? nextFallback('fc')
|
|
125
|
-
});
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
if (Array.isArray(item.tool_calls)) {
|
|
129
|
-
for (const call of item.tool_calls) {
|
|
130
|
-
if (!call || typeof call !== 'object')
|
|
131
|
-
continue;
|
|
132
|
-
const normalizedCallId = normalizeCallId(call.id ?? call.tool_call_id ?? call.call_id, 'fc_call');
|
|
133
|
-
call.id = normalizedCallId;
|
|
134
|
-
if (call.tool_call_id !== undefined) {
|
|
135
|
-
call.tool_call_id = normalizedCallId;
|
|
136
|
-
}
|
|
137
|
-
if (call.call_id !== undefined) {
|
|
138
|
-
call.call_id = normalizedCallId;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
const submitCalls = payload?.required_action?.submit_tool_outputs?.tool_calls;
|
|
144
|
-
if (Array.isArray(submitCalls)) {
|
|
145
|
-
for (const call of submitCalls) {
|
|
146
|
-
if (!call || typeof call !== 'object')
|
|
147
|
-
continue;
|
|
148
|
-
const normalizedCallId = normalizeCallId(call.tool_call_id ?? call.id ?? call.call_id, 'fc_call');
|
|
149
|
-
call.tool_call_id = normalizedCallId;
|
|
150
|
-
call.id = normalizedCallId;
|
|
151
|
-
if (call.call_id !== undefined) {
|
|
152
|
-
call.call_id = normalizedCallId;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
export function resolveToolCallIdStyle(metadata) {
|
|
158
|
-
// Standard OpenAI `/v1/responses` requires function_call item ids to start with `fc_`.
|
|
159
|
-
// Default to `fc` unless explicitly overridden (e.g. LM Studio compat).
|
|
160
|
-
if (!metadata)
|
|
161
|
-
return 'fc';
|
|
162
|
-
const raw = metadata.toolCallIdStyle;
|
|
163
|
-
if (typeof raw === 'string') {
|
|
164
|
-
const lowered = raw.trim().toLowerCase();
|
|
165
|
-
if (lowered === 'fc') {
|
|
166
|
-
return 'fc';
|
|
167
|
-
}
|
|
168
|
-
if (lowered === 'preserve') {
|
|
169
|
-
return 'preserve';
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
return 'fc';
|
|
173
|
-
}
|
|
174
|
-
export function stripInternalToolingMetadata(metadata) {
|
|
175
|
-
if (!metadata || typeof metadata !== 'object')
|
|
176
|
-
return;
|
|
177
|
-
const record = metadata;
|
|
178
|
-
if ('toolCallIdStyle' in record) {
|
|
179
|
-
delete record.toolCallIdStyle;
|
|
180
|
-
}
|
|
181
|
-
if (RAW_SYSTEM_SENTINEL in record) {
|
|
182
|
-
delete record[RAW_SYSTEM_SENTINEL];
|
|
183
|
-
}
|
|
184
|
-
if (record.extraFields && typeof record.extraFields === 'object') {
|
|
185
|
-
prunePrivateExtraFields(record.extraFields);
|
|
186
|
-
if (!Object.keys(record.extraFields).length) {
|
|
187
|
-
delete record.extraFields;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
function prunePrivateExtraFields(target) {
|
|
192
|
-
for (const key of Object.keys(target)) {
|
|
193
|
-
const value = target[key];
|
|
194
|
-
if (typeof key === 'string' && key.startsWith('__rcc_')) {
|
|
195
|
-
delete target[key];
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
if (value && typeof value === 'object') {
|
|
199
|
-
prunePrivateExtraFields(value);
|
|
200
|
-
if (!Object.keys(value).length) {
|
|
201
|
-
delete target[key];
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
const RAW_SYSTEM_SENTINEL = '__rcc_raw_system';
|
|
207
|
-
export function sanitizeResponsesFunctionName(rawName) {
|
|
208
|
-
return sanitizeResponsesFunctionNameWithNative(rawName);
|
|
209
|
-
}
|
|
@@ -16,10 +16,5 @@ export declare class StreamingTextToolExtractor {
|
|
|
16
16
|
constructor(opts?: StreamingToolExtractorOptions);
|
|
17
17
|
reset(): void;
|
|
18
18
|
feedText(text: string): StreamingToolCall[];
|
|
19
|
-
private genId;
|
|
20
|
-
private toToolCall;
|
|
21
|
-
private tryExtractStructuredBlocks;
|
|
22
|
-
private tryExtractFunctionExecuteBlocks;
|
|
23
|
-
private splitCommand;
|
|
24
19
|
}
|
|
25
20
|
export declare function createStreamingToolExtractor(opts?: StreamingToolExtractorOptions): StreamingTextToolExtractor;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// Streaming textual tool intent extractor (对齐)
|
|
2
2
|
// Detects <function=execute> blocks and structured apply_patch payloads
|
|
3
3
|
// and converts them into OpenAI tool_calls incrementally.
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
import { extractStreamingToolCallsWithNative } from '../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
|
|
5
|
+
function assertStreamingToolExtractorNativeAvailable() {
|
|
6
|
+
if (typeof extractStreamingToolCallsWithNative !== 'function') {
|
|
7
|
+
throw new Error('[streaming-text-extractor] native bindings unavailable');
|
|
8
|
+
}
|
|
8
9
|
}
|
|
9
10
|
export class StreamingTextToolExtractor {
|
|
10
11
|
opts;
|
|
@@ -18,114 +19,20 @@ export class StreamingTextToolExtractor {
|
|
|
18
19
|
this.idCounter = 0;
|
|
19
20
|
}
|
|
20
21
|
feedText(text) {
|
|
21
|
-
const out = [];
|
|
22
22
|
if (typeof text !== 'string' || !text)
|
|
23
|
-
return
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const argStr = repairArgumentsToStringWithNative(argsObj);
|
|
37
|
-
return { id: this.genId(), type: 'function', function: { name, arguments: argStr } };
|
|
38
|
-
}
|
|
39
|
-
tryExtractStructuredBlocks() {
|
|
40
|
-
const out = [];
|
|
41
|
-
let searchIdx = 0;
|
|
42
|
-
while (searchIdx < this.buffer.length) {
|
|
43
|
-
const startIdx = this.buffer.indexOf('```', searchIdx);
|
|
44
|
-
if (startIdx < 0)
|
|
45
|
-
break;
|
|
46
|
-
const headerEnd = this.buffer.indexOf('\n', startIdx + 3);
|
|
47
|
-
if (headerEnd < 0)
|
|
48
|
-
break;
|
|
49
|
-
const language = this.buffer.slice(startIdx + 3, headerEnd).trim().toLowerCase();
|
|
50
|
-
const endIdx = this.buffer.indexOf('```', headerEnd + 1);
|
|
51
|
-
if (endIdx < 0)
|
|
52
|
-
break;
|
|
53
|
-
const body = this.buffer.slice(headerEnd + 1, endIdx);
|
|
54
|
-
if (!language || language === 'json' || language === 'apply_patch' || language === 'toon') {
|
|
55
|
-
try {
|
|
56
|
-
const parsed = JSON.parse(body);
|
|
57
|
-
if (isStructuredApplyPatchPayload(parsed)) {
|
|
58
|
-
out.push(this.toToolCall('apply_patch', parsed));
|
|
59
|
-
this.buffer = this.buffer.slice(0, startIdx) + this.buffer.slice(endIdx + 3);
|
|
60
|
-
searchIdx = 0;
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
/* ignore parse errors */
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
searchIdx = endIdx + 3;
|
|
69
|
-
}
|
|
70
|
-
return out;
|
|
71
|
-
}
|
|
72
|
-
// rcc.tool.v1 JSON detection removed
|
|
73
|
-
tryExtractFunctionExecuteBlocks() {
|
|
74
|
-
const out = [];
|
|
75
|
-
// Very lightweight parser for <function=execute> <parameter=command>...</parameter>
|
|
76
|
-
const execRe = /<function=execute>[\s\S]*?<parameter=command>([\s\S]*?)<\/parameter>[\s\S]*?<\/function=execute>/gi;
|
|
77
|
-
let m;
|
|
78
|
-
while ((m = execRe.exec(this.buffer)) !== null) {
|
|
79
|
-
const cmd = (m[1] || '').trim();
|
|
80
|
-
if (cmd) {
|
|
81
|
-
// split a shell command string into argv best-effort
|
|
82
|
-
const argv = this.splitCommand(cmd);
|
|
83
|
-
out.push(this.toToolCall('shell', { command: argv }));
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if (out.length > 0) {
|
|
87
|
-
this.buffer = this.buffer.replace(execRe, '');
|
|
88
|
-
}
|
|
89
|
-
return out;
|
|
90
|
-
}
|
|
91
|
-
splitCommand(s) {
|
|
92
|
-
try {
|
|
93
|
-
// basic quotes-aware split
|
|
94
|
-
const out = [];
|
|
95
|
-
let cur = '';
|
|
96
|
-
let quote = null;
|
|
97
|
-
for (let i = 0; i < s.length; i++) {
|
|
98
|
-
const ch = s[i];
|
|
99
|
-
if (quote) {
|
|
100
|
-
if (ch === quote) {
|
|
101
|
-
quote = null;
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
cur += ch;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
if (ch === '"' || ch === '\'') {
|
|
109
|
-
quote = ch;
|
|
110
|
-
}
|
|
111
|
-
else if (/\s/.test(ch)) {
|
|
112
|
-
if (cur) {
|
|
113
|
-
out.push(cur);
|
|
114
|
-
cur = '';
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
else {
|
|
118
|
-
cur += ch;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
if (cur)
|
|
123
|
-
out.push(cur);
|
|
124
|
-
return out;
|
|
125
|
-
}
|
|
126
|
-
catch {
|
|
127
|
-
return [s];
|
|
128
|
-
}
|
|
23
|
+
return [];
|
|
24
|
+
assertStreamingToolExtractorNativeAvailable();
|
|
25
|
+
const idPrefix = this.opts.idPrefix || 'call';
|
|
26
|
+
const output = extractStreamingToolCallsWithNative({
|
|
27
|
+
buffer: this.buffer,
|
|
28
|
+
text,
|
|
29
|
+
idPrefix,
|
|
30
|
+
idCounter: this.idCounter,
|
|
31
|
+
nowMs: Date.now()
|
|
32
|
+
});
|
|
33
|
+
this.buffer = typeof output.buffer === 'string' ? output.buffer : this.buffer;
|
|
34
|
+
this.idCounter = typeof output.idCounter === 'number' ? output.idCounter : this.idCounter;
|
|
35
|
+
return Array.isArray(output.toolCalls) ? output.toolCalls : [];
|
|
129
36
|
}
|
|
130
37
|
}
|
|
131
38
|
export function createStreamingToolExtractor(opts) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { TextMarkupNormalizeOptions } from '../../types/text-markup-normalizer.js';
|
|
2
|
-
export declare function normalizeAssistantTextToToolCalls(message: Record<string, any>,
|
|
2
|
+
export declare function normalizeAssistantTextToToolCalls(message: Record<string, any>, options?: TextMarkupNormalizeOptions): Record<string, any>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizeAssistantTextToToolCallsWithNative } from '../../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
|
|
2
2
|
function enabled() {
|
|
3
3
|
try {
|
|
4
4
|
return String(process?.env?.RCC_TEXT_MARKUP_COMPAT ?? '1').trim() !== '0';
|
|
@@ -7,96 +7,8 @@ function enabled() {
|
|
|
7
7
|
return true;
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
|
-
export function normalizeAssistantTextToToolCalls(message,
|
|
10
|
+
export function normalizeAssistantTextToToolCalls(message, options) {
|
|
11
11
|
if (!enabled())
|
|
12
12
|
return message;
|
|
13
|
-
|
|
14
|
-
if (!message || typeof message !== 'object')
|
|
15
|
-
return message;
|
|
16
|
-
if (Array.isArray(message.tool_calls) && message.tool_calls.length)
|
|
17
|
-
return message;
|
|
18
|
-
const content = message.content;
|
|
19
|
-
const candidates = [];
|
|
20
|
-
if (typeof content === 'string') {
|
|
21
|
-
candidates.push(content);
|
|
22
|
-
}
|
|
23
|
-
else if (Array.isArray(content)) {
|
|
24
|
-
for (const part of content) {
|
|
25
|
-
if (!part || typeof part !== 'object')
|
|
26
|
-
continue;
|
|
27
|
-
const p = part;
|
|
28
|
-
if (typeof p.text === 'string' && p.text.trim()) {
|
|
29
|
-
candidates.push(p.text);
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
if (typeof p.content === 'string' && p.content.trim()) {
|
|
33
|
-
candidates.push(p.content);
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
if (typeof message.reasoning === 'string' && message.reasoning.trim()) {
|
|
39
|
-
candidates.push(String(message.reasoning));
|
|
40
|
-
}
|
|
41
|
-
if (typeof message.thinking === 'string' && message.thinking.trim()) {
|
|
42
|
-
candidates.push(String(message.thinking));
|
|
43
|
-
}
|
|
44
|
-
if (!candidates.length)
|
|
45
|
-
return message;
|
|
46
|
-
let calls = null;
|
|
47
|
-
const mapNativeToolCalls = (raw) => {
|
|
48
|
-
const mapped = [];
|
|
49
|
-
raw.forEach((entry, index) => {
|
|
50
|
-
if (!entry || typeof entry !== 'object')
|
|
51
|
-
return;
|
|
52
|
-
const functionNode = entry.function && typeof entry.function === 'object' && !Array.isArray(entry.function)
|
|
53
|
-
? entry.function
|
|
54
|
-
: undefined;
|
|
55
|
-
const name = (typeof functionNode?.name === 'string' && functionNode.name.trim()) ||
|
|
56
|
-
(typeof entry.name === 'string' && entry.name.trim()) ||
|
|
57
|
-
undefined;
|
|
58
|
-
if (!name)
|
|
59
|
-
return;
|
|
60
|
-
const argsCandidate = functionNode?.arguments ?? entry.arguments ?? entry.args ?? '{}';
|
|
61
|
-
let args = '{}';
|
|
62
|
-
if (typeof argsCandidate === 'string') {
|
|
63
|
-
args = argsCandidate;
|
|
64
|
-
}
|
|
65
|
-
else {
|
|
66
|
-
try {
|
|
67
|
-
args = JSON.stringify(argsCandidate ?? {});
|
|
68
|
-
}
|
|
69
|
-
catch {
|
|
70
|
-
args = '{}';
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
const id = (typeof entry.id === 'string' && entry.id.trim()) ||
|
|
74
|
-
(typeof entry.call_id === 'string' && entry.call_id.trim()) ||
|
|
75
|
-
`call_${index + 1}`;
|
|
76
|
-
mapped.push({ id, name, args });
|
|
77
|
-
});
|
|
78
|
-
return mapped;
|
|
79
|
-
};
|
|
80
|
-
for (const text of candidates) {
|
|
81
|
-
const nativeParsed = extractToolCallsFromReasoningTextWithNative(text);
|
|
82
|
-
if (nativeParsed.toolCalls.length) {
|
|
83
|
-
const nativeCalls = mapNativeToolCalls(nativeParsed.toolCalls);
|
|
84
|
-
if (nativeCalls.length) {
|
|
85
|
-
calls = nativeCalls;
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
if (calls && calls.length) {
|
|
91
|
-
const toolCalls = calls.map((c) => ({ id: c.id, type: 'function', function: { name: c.name, arguments: c.args } }));
|
|
92
|
-
const copy = { ...message };
|
|
93
|
-
copy.tool_calls = toolCalls;
|
|
94
|
-
copy.content = '';
|
|
95
|
-
return copy;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
catch {
|
|
99
|
-
// ignore normalization failures
|
|
100
|
-
}
|
|
101
|
-
return message;
|
|
13
|
+
return normalizeAssistantTextToToolCallsWithNative(message, options);
|
|
102
14
|
}
|