@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
|
@@ -223,8 +223,7 @@ export function buildOpenAIChatFromAnthropicMessage(payload, options) {
|
|
|
223
223
|
};
|
|
224
224
|
const includeToolCallIds = options?.includeToolCallIds === true;
|
|
225
225
|
const canonicalToolCalls = toolCalls.map((tc) => ({
|
|
226
|
-
id: tc.id,
|
|
227
|
-
...(includeToolCallIds ? { call_id: tc.id, tool_call_id: tc.id } : {}),
|
|
226
|
+
...(includeToolCallIds ? { id: tc.id, call_id: tc.id, tool_call_id: tc.id } : {}),
|
|
228
227
|
type: 'function',
|
|
229
228
|
function: { name: tc.name, arguments: tc.args }
|
|
230
229
|
}));
|
|
@@ -246,6 +245,14 @@ export function buildOpenAIChatFromAnthropicMessage(payload, options) {
|
|
|
246
245
|
if (!("tool_call_id" in inferred))
|
|
247
246
|
inferred.tool_call_id = inferredId;
|
|
248
247
|
}
|
|
248
|
+
else if (!includeToolCallIds) {
|
|
249
|
+
if ("id" in inferred)
|
|
250
|
+
delete inferred.id;
|
|
251
|
+
if ("call_id" in inferred)
|
|
252
|
+
delete inferred.call_id;
|
|
253
|
+
if ("tool_call_id" in inferred)
|
|
254
|
+
delete inferred.tool_call_id;
|
|
255
|
+
}
|
|
249
256
|
canonicalToolCalls.push(inferred);
|
|
250
257
|
if (key)
|
|
251
258
|
seen.add(key);
|
|
@@ -259,9 +266,13 @@ export function buildOpenAIChatFromAnthropicMessage(payload, options) {
|
|
|
259
266
|
call.call_id = cid;
|
|
260
267
|
if (!("tool_call_id" in call))
|
|
261
268
|
call.tool_call_id = cid;
|
|
269
|
+
if (!("id" in call))
|
|
270
|
+
call.id = cid;
|
|
262
271
|
}
|
|
263
272
|
}
|
|
264
273
|
else {
|
|
274
|
+
if ("id" in call)
|
|
275
|
+
delete call.id;
|
|
265
276
|
if ("call_id" in call)
|
|
266
277
|
delete call.call_id;
|
|
267
278
|
if ("tool_call_id" in call)
|
|
@@ -443,10 +454,7 @@ function sanitizeAnthropicMessage(message) {
|
|
|
443
454
|
.filter((block) => block !== null);
|
|
444
455
|
const usage = message.usage;
|
|
445
456
|
if (usage && typeof usage === 'object') {
|
|
446
|
-
sanitized.usage =
|
|
447
|
-
input_tokens: usage.input_tokens ?? 0,
|
|
448
|
-
output_tokens: usage.output_tokens ?? 0
|
|
449
|
-
};
|
|
457
|
+
sanitized.usage = JSON.parse(JSON.stringify(usage));
|
|
450
458
|
}
|
|
451
459
|
return sanitized;
|
|
452
460
|
}
|
|
@@ -238,12 +238,6 @@ function buildClientToolIndex(toolsRaw) {
|
|
|
238
238
|
}
|
|
239
239
|
return index;
|
|
240
240
|
}
|
|
241
|
-
const CLIENT_TOOL_NAME_ALIASES = new Map([
|
|
242
|
-
['shell_command', 'exec_command'],
|
|
243
|
-
['shell', 'exec_command'],
|
|
244
|
-
['bash', 'exec_command'],
|
|
245
|
-
['terminal', 'exec_command']
|
|
246
|
-
]);
|
|
247
241
|
function resolveClientToolName(toolIndex, rawToolName) {
|
|
248
242
|
const trimmed = rawToolName.trim();
|
|
249
243
|
if (!trimmed.length)
|
|
@@ -256,12 +250,18 @@ function resolveClientToolName(toolIndex, rawToolName) {
|
|
|
256
250
|
return key;
|
|
257
251
|
}
|
|
258
252
|
}
|
|
259
|
-
const
|
|
260
|
-
if (
|
|
253
|
+
const hasBash = Array.from(toolIndex.keys()).some((key) => key.toLowerCase() === 'bash');
|
|
254
|
+
if (hasBash)
|
|
261
255
|
return undefined;
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
256
|
+
if (!['shell_command', 'exec_command', 'shell', 'terminal', 'bash'].includes(lower)) {
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
259
|
+
const preferred = ['shell_command', 'exec_command', 'shell', 'terminal'];
|
|
260
|
+
for (const candidate of preferred) {
|
|
261
|
+
for (const key of toolIndex.keys()) {
|
|
262
|
+
if (key.toLowerCase() === candidate) {
|
|
263
|
+
return key;
|
|
264
|
+
}
|
|
265
265
|
}
|
|
266
266
|
}
|
|
267
267
|
return undefined;
|
|
@@ -186,12 +186,7 @@ function requireSystemText(block, context) {
|
|
|
186
186
|
}
|
|
187
187
|
return text;
|
|
188
188
|
}
|
|
189
|
-
const ANTHROPIC_TOOL_NAME_ALIASES = new Map(
|
|
190
|
-
['bash', 'shell_command'],
|
|
191
|
-
['shell', 'shell_command'],
|
|
192
|
-
['terminal', 'shell_command'],
|
|
193
|
-
['exec_command', 'shell_command']
|
|
194
|
-
]);
|
|
189
|
+
const ANTHROPIC_TOOL_NAME_ALIASES = new Map();
|
|
195
190
|
const CANONICAL_TO_ANTHROPIC_TOOL_NAMES = new Map([['shell_command', 'Bash']]);
|
|
196
191
|
const ANTHROPIC_TOP_LEVEL_FIELDS = new Set([
|
|
197
192
|
'model',
|
|
@@ -1398,12 +1393,7 @@ export function buildAnthropicToolAliasMap(rawTools) {
|
|
|
1398
1393
|
continue;
|
|
1399
1394
|
}
|
|
1400
1395
|
aliasMap.set(canonicalKey, rawName);
|
|
1401
|
-
|
|
1402
|
-
// Keep an explicit exec_command key so reverse mapping can preserve
|
|
1403
|
-
// canonical exec_command when upstream already uses that name.
|
|
1404
|
-
if (canonicalKey === 'shell_command' && !aliasMap.has('exec_command')) {
|
|
1405
|
-
aliasMap.set('exec_command', rawName);
|
|
1406
|
-
}
|
|
1396
|
+
const lowered = canonicalKey.toLowerCase();
|
|
1407
1397
|
const lowerKey = canonicalKey.toLowerCase();
|
|
1408
1398
|
if (lowerKey !== canonicalKey && !aliasMap.has(lowerKey)) {
|
|
1409
1399
|
aliasMap.set(lowerKey, rawName);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { normalizeChatRequest } from '../index.js';
|
|
2
2
|
import { createSnapshotWriter } from '../snapshot-utils.js';
|
|
3
3
|
import { buildGovernedFilterPayloadWithNativeFallback } from '../../router/virtual-router/engine-selection/native-chat-request-filter-semantics.js';
|
|
4
|
+
import { pruneChatRequestPayloadWithNative } from '../../router/virtual-router/engine-selection/native-hub-pipeline-req-inbound-semantics.js';
|
|
4
5
|
/**
|
|
5
6
|
* Native-primary Chat request filters.
|
|
6
7
|
*
|
|
@@ -56,67 +57,7 @@ export async function runStandardChatRequestFilters(chatRequest, profile, contex
|
|
|
56
57
|
normalized.__rcc_disable_mcp_tools = true;
|
|
57
58
|
}
|
|
58
59
|
const preserveStreamField = profile.incomingProtocol === 'openai-chat' && profile.outgoingProtocol === 'openai-chat';
|
|
59
|
-
const pruned =
|
|
60
|
+
const pruned = pruneChatRequestPayloadWithNative(normalized, preserveStreamField);
|
|
60
61
|
snapshotStage('req_process_filters_output', pruned);
|
|
61
62
|
return pruned;
|
|
62
63
|
}
|
|
63
|
-
function pruneChatRequestPayload(chatRequest, options) {
|
|
64
|
-
if (!chatRequest || typeof chatRequest !== 'object')
|
|
65
|
-
return chatRequest;
|
|
66
|
-
const stripped = { ...chatRequest };
|
|
67
|
-
stripSentinelKeys(stripped);
|
|
68
|
-
if ('originalStream' in stripped) {
|
|
69
|
-
delete stripped.originalStream;
|
|
70
|
-
}
|
|
71
|
-
if ('_originalStreamOptions' in stripped) {
|
|
72
|
-
delete stripped._originalStreamOptions;
|
|
73
|
-
}
|
|
74
|
-
if ('metadata' in stripped) {
|
|
75
|
-
delete stripped.metadata;
|
|
76
|
-
}
|
|
77
|
-
if (!options?.preserveStreamField && 'stream' in stripped && stripped.stream !== true) {
|
|
78
|
-
delete stripped.stream;
|
|
79
|
-
}
|
|
80
|
-
if (Array.isArray(stripped.messages)) {
|
|
81
|
-
stripped.messages = stripped.messages.map((message) => sanitizeMessageEntry(message));
|
|
82
|
-
}
|
|
83
|
-
return stripped;
|
|
84
|
-
}
|
|
85
|
-
function sanitizeMessageEntry(message) {
|
|
86
|
-
if (!message || typeof message !== 'object')
|
|
87
|
-
return message;
|
|
88
|
-
const clone = { ...message };
|
|
89
|
-
if (Array.isArray(clone.tool_calls) && clone.tool_calls.length) {
|
|
90
|
-
clone.tool_calls = clone.tool_calls.map((call) => sanitizeToolCallEntry(call));
|
|
91
|
-
}
|
|
92
|
-
if (clone.role === 'tool') {
|
|
93
|
-
if (typeof clone.tool_call_id !== 'string' && typeof clone.call_id === 'string') {
|
|
94
|
-
clone.tool_call_id = clone.call_id;
|
|
95
|
-
}
|
|
96
|
-
if ('id' in clone) {
|
|
97
|
-
delete clone.id;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
if ('call_id' in clone) {
|
|
101
|
-
delete clone.call_id;
|
|
102
|
-
}
|
|
103
|
-
return clone;
|
|
104
|
-
}
|
|
105
|
-
function sanitizeToolCallEntry(call) {
|
|
106
|
-
if (!call || typeof call !== 'object')
|
|
107
|
-
return call;
|
|
108
|
-
const clone = { ...call };
|
|
109
|
-
delete clone.call_id;
|
|
110
|
-
delete clone.tool_call_id;
|
|
111
|
-
if (clone.function && typeof clone.function === 'object') {
|
|
112
|
-
clone.function = { ...clone.function };
|
|
113
|
-
}
|
|
114
|
-
return clone;
|
|
115
|
-
}
|
|
116
|
-
function stripSentinelKeys(record) {
|
|
117
|
-
Object.keys(record).forEach((key) => {
|
|
118
|
-
if (key.startsWith('__rcc_')) {
|
|
119
|
-
delete record[key];
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { mapReasoningContentToResponsesOutputWithNative } from '../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
|
|
2
2
|
export function mapReasoningContentToResponsesOutput(reasoningContent) {
|
|
3
|
+
if (typeof mapReasoningContentToResponsesOutputWithNative !== 'function') {
|
|
4
|
+
throw new Error('[reasoning-mapping] native bindings unavailable');
|
|
5
|
+
}
|
|
3
6
|
return mapReasoningContentToResponsesOutputWithNative(reasoningContent);
|
|
4
7
|
}
|
|
@@ -19,4 +19,5 @@ export declare function normalizeReasoningInResponsesPayload(payload: {
|
|
|
19
19
|
} | null | undefined, options?: ResponsesReasoningNormalizeOptions): void;
|
|
20
20
|
export declare function normalizeReasoningInGeminiPayload(payload: JsonObject | null | undefined): void;
|
|
21
21
|
export declare function normalizeReasoningInAnthropicPayload(payload: JsonObject | null | undefined): void;
|
|
22
|
+
export declare function normalizeReasoningInOpenAIPayload(payload: JsonObject | null | undefined): void;
|
|
22
23
|
export {};
|
|
@@ -1,409 +1,56 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { extractReasoningSegments } from './reasoning-utils.js';
|
|
3
|
-
import { expandResponsesMessageItem } from '../../sse/shared/responses-output-normalizer.js';
|
|
4
|
-
import { sanitizeReasoningTaggedTextWithNative } from '../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
|
|
1
|
+
import { normalizeReasoningInAnthropicPayloadWithNative, normalizeReasoningInChatPayloadWithNative, normalizeReasoningInGeminiPayloadWithNative, normalizeReasoningInOpenAIPayloadWithNative, normalizeReasoningInResponsesPayloadWithNative } from '../../router/virtual-router/engine-selection/native-shared-conversion-semantics.js';
|
|
5
2
|
export const RESPONSES_INSTRUCTIONS_REASONING_FIELD = '__rcc_reasoning_instructions';
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if (Array.isArray(payload.messages)) {
|
|
14
|
-
payload.messages = payload.messages.map(entry => normalizeChatMessageEntry(entry));
|
|
15
|
-
}
|
|
16
|
-
if (Array.isArray(payload.choices)) {
|
|
17
|
-
payload.choices.forEach(choice => {
|
|
18
|
-
normalizeChatChoice(choice);
|
|
19
|
-
});
|
|
3
|
+
function assertReasoningNormalizerNativeAvailable() {
|
|
4
|
+
if (typeof normalizeReasoningInChatPayloadWithNative !== 'function' ||
|
|
5
|
+
typeof normalizeReasoningInResponsesPayloadWithNative !== 'function' ||
|
|
6
|
+
typeof normalizeReasoningInGeminiPayloadWithNative !== 'function' ||
|
|
7
|
+
typeof normalizeReasoningInAnthropicPayloadWithNative !== 'function' ||
|
|
8
|
+
typeof normalizeReasoningInOpenAIPayloadWithNative !== 'function') {
|
|
9
|
+
throw new Error('[reasoning-normalizer] native bindings unavailable');
|
|
20
10
|
}
|
|
21
11
|
}
|
|
22
|
-
function
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
const msg = entry;
|
|
27
|
-
applyNormalizedChatContent(msg);
|
|
28
|
-
return msg;
|
|
29
|
-
}
|
|
30
|
-
function normalizeChatChoice(choice) {
|
|
31
|
-
if (!choice || typeof choice !== 'object') {
|
|
12
|
+
export function normalizeReasoningInChatPayload(payload) {
|
|
13
|
+
assertReasoningNormalizerNativeAvailable();
|
|
14
|
+
if (!payload)
|
|
32
15
|
return;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (record.message && typeof record.message === 'object') {
|
|
37
|
-
containers.push(record.message);
|
|
38
|
-
}
|
|
39
|
-
if (record.delta && typeof record.delta === 'object') {
|
|
40
|
-
containers.push(record.delta);
|
|
41
|
-
}
|
|
42
|
-
containers.forEach(container => applyNormalizedChatContent(container));
|
|
43
|
-
}
|
|
44
|
-
function applyNormalizedChatContent(container) {
|
|
45
|
-
const existingReasoning = typeof container.reasoning_content === 'string' && container.reasoning_content.trim().length
|
|
46
|
-
? container.reasoning_content.trim()
|
|
47
|
-
: undefined;
|
|
48
|
-
const normalized = normalizeChatMessageContent(container.content);
|
|
49
|
-
const role = typeof container.role === 'string' ? container.role : undefined;
|
|
50
|
-
if (normalized.contentText !== undefined && normalized.contentText.trim().length) {
|
|
51
|
-
container.content = normalized.contentText;
|
|
52
|
-
}
|
|
53
|
-
else if (typeof container.reasoning_content === 'string' && container.reasoning_content.trim().length) {
|
|
54
|
-
container.content = container.reasoning_content.trim();
|
|
55
|
-
}
|
|
56
|
-
else if (role && role !== 'system' && role !== 'tool') {
|
|
57
|
-
container.content = '';
|
|
58
|
-
}
|
|
59
|
-
if (normalized.reasoningText && normalized.reasoningText.trim().length) {
|
|
60
|
-
container.reasoning_content = normalized.reasoningText.trim();
|
|
61
|
-
}
|
|
62
|
-
else if (existingReasoning) {
|
|
63
|
-
container.reasoning_content = existingReasoning;
|
|
64
|
-
}
|
|
65
|
-
else if ('reasoning_content' in container) {
|
|
66
|
-
delete container.reasoning_content;
|
|
16
|
+
const normalized = normalizeReasoningInChatPayloadWithNative(payload);
|
|
17
|
+
if (normalized && typeof normalized === 'object') {
|
|
18
|
+
Object.assign(payload, normalized);
|
|
67
19
|
}
|
|
68
20
|
}
|
|
69
21
|
export function normalizeReasoningInResponsesPayload(payload, options = { includeOutput: true }) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
const includeOutput = options.includeOutput !== false;
|
|
74
|
-
if (includeOutput) {
|
|
75
|
-
normalizeResponsesOutput(payload);
|
|
76
|
-
}
|
|
77
|
-
if (options.includeInput) {
|
|
78
|
-
normalizeResponsesInput(payload);
|
|
79
|
-
}
|
|
80
|
-
if (options.includeInstructions) {
|
|
81
|
-
normalizeResponsesInstructions(payload);
|
|
82
|
-
}
|
|
83
|
-
if (options.includeRequiredAction) {
|
|
84
|
-
normalizeResponsesRequiredAction(payload);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
function normalizeResponsesOutput(payload) {
|
|
88
|
-
if (!Array.isArray(payload.output)) {
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
const normalized = [];
|
|
92
|
-
payload.output.forEach((entry, index) => {
|
|
93
|
-
if (isResponsesMessageItem(entry)) {
|
|
94
|
-
const expanded = expandResponsesMessageItem(entry, {
|
|
95
|
-
requestId: typeof payload.id === 'string' ? payload.id : 'responses',
|
|
96
|
-
outputIndex: index
|
|
97
|
-
});
|
|
98
|
-
expanded.forEach((item) => {
|
|
99
|
-
normalized.push(item);
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
else {
|
|
103
|
-
normalized.push(entry);
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
payload.output = normalized;
|
|
107
|
-
}
|
|
108
|
-
function isResponsesMessageItem(entry) {
|
|
109
|
-
if (!isRecord(entry)) {
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
const type = typeof entry.type === 'string' ? entry.type : undefined;
|
|
113
|
-
if (type !== 'message') {
|
|
114
|
-
return false;
|
|
115
|
-
}
|
|
116
|
-
if (!Array.isArray(entry.content)) {
|
|
117
|
-
return false;
|
|
118
|
-
}
|
|
119
|
-
const status = typeof entry.status === 'string' ? entry.status : undefined;
|
|
120
|
-
const role = typeof entry.role === 'string' ? entry.role : undefined;
|
|
121
|
-
return Boolean(status && role);
|
|
122
|
-
}
|
|
123
|
-
function normalizeResponsesInput(payload) {
|
|
124
|
-
if (!Array.isArray(payload.input)) {
|
|
22
|
+
assertReasoningNormalizerNativeAvailable();
|
|
23
|
+
if (!payload)
|
|
125
24
|
return;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
return;
|
|
130
|
-
const reasoningSegments = [];
|
|
131
|
-
if (typeof entry.content === 'string') {
|
|
132
|
-
const { cleaned, segments } = stripReasoningFromString(entry.content);
|
|
133
|
-
entry.content = cleaned;
|
|
134
|
-
reasoningSegments.push(...segments);
|
|
135
|
-
}
|
|
136
|
-
else if (Array.isArray(entry.content)) {
|
|
137
|
-
entry.content = entry.content.map((block) => normalizeResponsesContentBlock(block, reasoningSegments));
|
|
138
|
-
}
|
|
139
|
-
if (isRecord(entry.message)) {
|
|
140
|
-
normalizeResponsesMessageBlock(entry.message, reasoningSegments);
|
|
141
|
-
}
|
|
142
|
-
if (typeof entry.text === 'string') {
|
|
143
|
-
const { cleaned, segments } = stripReasoningFromString(entry.text);
|
|
144
|
-
entry.text = cleaned;
|
|
145
|
-
reasoningSegments.push(...segments);
|
|
146
|
-
}
|
|
147
|
-
if (reasoningSegments.length) {
|
|
148
|
-
entry.reasoning_content = mergeReasoningText(entry.reasoning_content, reasoningSegments);
|
|
149
|
-
}
|
|
150
|
-
else if ('reasoning_content' in entry) {
|
|
151
|
-
delete entry.reasoning_content;
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
function normalizeResponsesMessageBlock(message, collector) {
|
|
156
|
-
const localSegments = [];
|
|
157
|
-
if (Array.isArray(message.content)) {
|
|
158
|
-
message.content = message.content.map((block) => normalizeResponsesContentBlock(block, localSegments));
|
|
159
|
-
}
|
|
160
|
-
else if (typeof message.content === 'string') {
|
|
161
|
-
const { cleaned, segments } = stripReasoningFromString(message.content);
|
|
162
|
-
message.content = cleaned;
|
|
163
|
-
localSegments.push(...segments);
|
|
164
|
-
}
|
|
165
|
-
if (typeof message.text === 'string') {
|
|
166
|
-
const { cleaned, segments } = stripReasoningFromString(message.text);
|
|
167
|
-
message.text = cleaned;
|
|
168
|
-
localSegments.push(...segments);
|
|
169
|
-
}
|
|
170
|
-
if (localSegments.length) {
|
|
171
|
-
collector.push(...localSegments);
|
|
172
|
-
message.reasoning_content = mergeReasoningText(message.reasoning_content, localSegments);
|
|
173
|
-
}
|
|
174
|
-
else if ('reasoning_content' in message) {
|
|
175
|
-
delete message.reasoning_content;
|
|
25
|
+
const normalized = normalizeReasoningInResponsesPayloadWithNative(payload, options);
|
|
26
|
+
if (normalized && typeof normalized === 'object') {
|
|
27
|
+
Object.assign(payload, normalized);
|
|
176
28
|
}
|
|
177
29
|
}
|
|
178
|
-
function normalizeResponsesContentBlock(block, collector) {
|
|
179
|
-
if (typeof block === 'string') {
|
|
180
|
-
const { cleaned, segments } = stripReasoningFromString(block);
|
|
181
|
-
collector.push(...segments);
|
|
182
|
-
return cleaned;
|
|
183
|
-
}
|
|
184
|
-
if (!isRecord(block)) {
|
|
185
|
-
return block;
|
|
186
|
-
}
|
|
187
|
-
const type = typeof block.type === 'string' ? block.type.toLowerCase() : '';
|
|
188
|
-
if ((type === 'input_text' || type === 'output_text' || type === 'text' || type === 'commentary') && typeof block.text === 'string') {
|
|
189
|
-
const { cleaned, segments } = stripReasoningFromString(block.text);
|
|
190
|
-
block.text = cleaned;
|
|
191
|
-
if (segments.length) {
|
|
192
|
-
collector.push(...segments);
|
|
193
|
-
block.reasoning_content = mergeReasoningText(block.reasoning_content, segments);
|
|
194
|
-
}
|
|
195
|
-
else if ('reasoning_content' in block) {
|
|
196
|
-
delete block.reasoning_content;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
if (Array.isArray(block.content)) {
|
|
200
|
-
block.content = block.content.map((nested) => normalizeResponsesContentBlock(nested, collector));
|
|
201
|
-
}
|
|
202
|
-
else if (typeof block.content === 'string') {
|
|
203
|
-
const { cleaned, segments } = stripReasoningFromString(block.content);
|
|
204
|
-
block.content = cleaned;
|
|
205
|
-
if (segments.length) {
|
|
206
|
-
collector.push(...segments);
|
|
207
|
-
block.reasoning_content = mergeReasoningText(block.reasoning_content, segments);
|
|
208
|
-
}
|
|
209
|
-
else if ('reasoning_content' in block) {
|
|
210
|
-
delete block.reasoning_content;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
return block;
|
|
214
|
-
}
|
|
215
|
-
function normalizeResponsesInstructions(payload) {
|
|
216
|
-
if (typeof payload.instructions !== 'string') {
|
|
217
|
-
if (RESPONSES_INSTRUCTIONS_REASONING_FIELD in payload) {
|
|
218
|
-
delete payload[RESPONSES_INSTRUCTIONS_REASONING_FIELD];
|
|
219
|
-
}
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
|
-
const { cleaned, segments } = stripReasoningFromString(payload.instructions);
|
|
223
|
-
payload.instructions = cleaned;
|
|
224
|
-
if (segments.length) {
|
|
225
|
-
payload[RESPONSES_INSTRUCTIONS_REASONING_FIELD] = segments.join('\n');
|
|
226
|
-
}
|
|
227
|
-
else if (RESPONSES_INSTRUCTIONS_REASONING_FIELD in payload) {
|
|
228
|
-
delete payload[RESPONSES_INSTRUCTIONS_REASONING_FIELD];
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
function normalizeResponsesRequiredAction(payload) {
|
|
232
|
-
if (!isRecord(payload.required_action)) {
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
const submit = payload.required_action.submit_tool_outputs;
|
|
236
|
-
if (!submit || typeof submit !== 'object') {
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
const toolCalls = Array.isArray(submit.tool_calls)
|
|
240
|
-
? submit.tool_calls
|
|
241
|
-
: [];
|
|
242
|
-
toolCalls.forEach((call) => {
|
|
243
|
-
if (!isRecord(call))
|
|
244
|
-
return;
|
|
245
|
-
if (typeof call.instructions === 'string') {
|
|
246
|
-
const { cleaned, segments } = stripReasoningFromString(call.instructions);
|
|
247
|
-
call.instructions = cleaned;
|
|
248
|
-
if (segments.length) {
|
|
249
|
-
call.reasoning_content = mergeReasoningText(call.reasoning_content, segments);
|
|
250
|
-
}
|
|
251
|
-
else if ('reasoning_content' in call) {
|
|
252
|
-
delete call.reasoning_content;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
function stripReasoningFromString(value) {
|
|
258
|
-
if (typeof value !== 'string') {
|
|
259
|
-
return { cleaned: typeof value === 'string' ? value : '', segments: [] };
|
|
260
|
-
}
|
|
261
|
-
const segments = [];
|
|
262
|
-
const cleaned = extractReasoningSegments(value, segments);
|
|
263
|
-
const cleanedNative = sanitizeReasoningTaggedTextWithNative(value);
|
|
264
|
-
const stableCleaned = typeof cleanedNative === 'string' ? cleanedNative : cleaned;
|
|
265
|
-
return { cleaned: stableCleaned, segments };
|
|
266
|
-
}
|
|
267
|
-
function mergeReasoningText(existing, segments) {
|
|
268
|
-
const combined = [];
|
|
269
|
-
if (typeof existing === 'string' && existing.trim().length) {
|
|
270
|
-
combined.push(existing.trim());
|
|
271
|
-
}
|
|
272
|
-
for (const segment of segments) {
|
|
273
|
-
if (typeof segment === 'string' && segment.trim().length) {
|
|
274
|
-
combined.push(segment.trim());
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
return combined.join('\n');
|
|
278
|
-
}
|
|
279
30
|
export function normalizeReasoningInGeminiPayload(payload) {
|
|
280
|
-
|
|
31
|
+
assertReasoningNormalizerNativeAvailable();
|
|
32
|
+
if (!payload)
|
|
281
33
|
return;
|
|
34
|
+
const normalized = normalizeReasoningInGeminiPayloadWithNative(payload);
|
|
35
|
+
if (normalized && typeof normalized === 'object') {
|
|
36
|
+
Object.assign(payload, normalized);
|
|
282
37
|
}
|
|
283
|
-
const contents = Array.isArray(payload.contents) ? payload.contents : [];
|
|
284
|
-
contents.forEach((content) => {
|
|
285
|
-
if (!isRecord(content))
|
|
286
|
-
return;
|
|
287
|
-
const parts = Array.isArray(content.parts) ? content.parts : [];
|
|
288
|
-
parts.forEach((part) => {
|
|
289
|
-
if (!isRecord(part) || typeof part.text !== 'string') {
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
const reasoningSegments = [];
|
|
293
|
-
const cleaned = extractReasoningSegments(part.text, reasoningSegments);
|
|
294
|
-
part.text = cleaned;
|
|
295
|
-
if (reasoningSegments.length) {
|
|
296
|
-
part.reasoning = reasoningSegments.join('\n');
|
|
297
|
-
}
|
|
298
|
-
else if ('reasoning' in part) {
|
|
299
|
-
delete part.reasoning;
|
|
300
|
-
}
|
|
301
|
-
});
|
|
302
|
-
});
|
|
303
38
|
}
|
|
304
39
|
export function normalizeReasoningInAnthropicPayload(payload) {
|
|
305
|
-
|
|
40
|
+
assertReasoningNormalizerNativeAvailable();
|
|
41
|
+
if (!payload)
|
|
306
42
|
return;
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
const responseReasoning = [];
|
|
311
|
-
responseContent.forEach((block) => normalizeAnthropicBlock(block, responseReasoning));
|
|
312
|
-
if (responseReasoning.length) {
|
|
313
|
-
payload.reasoning_content = mergeReasoningText(payload.reasoning_content, responseReasoning);
|
|
314
|
-
}
|
|
315
|
-
else if ('reasoning_content' in payload) {
|
|
316
|
-
delete payload.reasoning_content;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
320
|
-
messages.forEach((message) => {
|
|
321
|
-
if (!isRecord(message))
|
|
322
|
-
return;
|
|
323
|
-
normalizeAnthropicMessage(message);
|
|
324
|
-
});
|
|
325
|
-
const systemField = payload.system;
|
|
326
|
-
if (typeof systemField === 'string') {
|
|
327
|
-
const { cleaned } = stripReasoningFromString(systemField);
|
|
328
|
-
payload.system = cleaned;
|
|
329
|
-
}
|
|
330
|
-
else if (Array.isArray(systemField)) {
|
|
331
|
-
systemField.forEach((entry) => normalizeAnthropicBlock(entry, []));
|
|
332
|
-
}
|
|
333
|
-
else if (isRecord(systemField) && Array.isArray(systemField.content)) {
|
|
334
|
-
const sysBlocks = systemField.content;
|
|
335
|
-
systemField.content = sysBlocks.map((block) => {
|
|
336
|
-
normalizeAnthropicBlock(block, []);
|
|
337
|
-
return block;
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
function normalizeAnthropicMessage(message) {
|
|
342
|
-
const reasoningSegments = [];
|
|
343
|
-
if (Array.isArray(message.content)) {
|
|
344
|
-
message.content.forEach((block) => normalizeAnthropicBlock(block, reasoningSegments));
|
|
345
|
-
}
|
|
346
|
-
else if (typeof message.content === 'string') {
|
|
347
|
-
const { cleaned, segments } = stripReasoningFromString(message.content);
|
|
348
|
-
message.content = cleaned;
|
|
349
|
-
reasoningSegments.push(...segments);
|
|
350
|
-
}
|
|
351
|
-
if (reasoningSegments.length) {
|
|
352
|
-
message.reasoning_content = mergeReasoningText(message.reasoning_content, reasoningSegments);
|
|
353
|
-
}
|
|
354
|
-
else if ('reasoning_content' in message) {
|
|
355
|
-
delete message.reasoning_content;
|
|
43
|
+
const normalized = normalizeReasoningInAnthropicPayloadWithNative(payload);
|
|
44
|
+
if (normalized && typeof normalized === 'object') {
|
|
45
|
+
Object.assign(payload, normalized);
|
|
356
46
|
}
|
|
357
47
|
}
|
|
358
|
-
function
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
collector.push(...segments);
|
|
48
|
+
export function normalizeReasoningInOpenAIPayload(payload) {
|
|
49
|
+
assertReasoningNormalizerNativeAvailable();
|
|
50
|
+
if (!payload)
|
|
362
51
|
return;
|
|
52
|
+
const normalized = normalizeReasoningInOpenAIPayloadWithNative(payload);
|
|
53
|
+
if (normalized && typeof normalized === 'object') {
|
|
54
|
+
Object.assign(payload, normalized);
|
|
363
55
|
}
|
|
364
|
-
if (!isRecord(block)) {
|
|
365
|
-
return;
|
|
366
|
-
}
|
|
367
|
-
const type = typeof block.type === 'string' ? block.type.toLowerCase() : '';
|
|
368
|
-
if (type === 'text' && typeof block.text === 'string') {
|
|
369
|
-
const { cleaned, segments } = stripReasoningFromString(block.text);
|
|
370
|
-
block.text = cleaned;
|
|
371
|
-
collector.push(...segments);
|
|
372
|
-
return;
|
|
373
|
-
}
|
|
374
|
-
if (type === 'thinking' || type === 'reasoning') {
|
|
375
|
-
const flattened = flattenAnthropicText(block);
|
|
376
|
-
if (flattened.trim().length) {
|
|
377
|
-
collector.push(flattened.trim());
|
|
378
|
-
}
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
if (Array.isArray(block.content)) {
|
|
382
|
-
block.content.forEach((nested) => normalizeAnthropicBlock(nested, collector));
|
|
383
|
-
}
|
|
384
|
-
else if (typeof block.content === 'string') {
|
|
385
|
-
const { cleaned, segments } = stripReasoningFromString(block.content);
|
|
386
|
-
block.content = cleaned;
|
|
387
|
-
collector.push(...segments);
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
function flattenAnthropicText(source) {
|
|
391
|
-
if (typeof source === 'string') {
|
|
392
|
-
return source;
|
|
393
|
-
}
|
|
394
|
-
if (Array.isArray(source)) {
|
|
395
|
-
return source.map((entry) => flattenAnthropicText(entry)).filter(Boolean).join('');
|
|
396
|
-
}
|
|
397
|
-
if (isRecord(source)) {
|
|
398
|
-
if (typeof source.text === 'string') {
|
|
399
|
-
return source.text;
|
|
400
|
-
}
|
|
401
|
-
if (typeof source.content === 'string') {
|
|
402
|
-
return source.content;
|
|
403
|
-
}
|
|
404
|
-
if (Array.isArray(source.content)) {
|
|
405
|
-
return source.content.map((entry) => flattenAnthropicText(entry)).filter(Boolean).join('');
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
return '';
|
|
409
56
|
}
|