@jsonstudio/llms 0.4.4 → 0.4.5
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/codec-registry.js +11 -1
- package/dist/conversion/codecs/anthropic-openai-codec.d.ts +13 -0
- package/dist/conversion/codecs/anthropic-openai-codec.js +18 -473
- package/dist/conversion/codecs/gemini-openai-codec.js +91 -48
- package/dist/conversion/codecs/responses-openai-codec.js +9 -2
- package/dist/conversion/hub/format-adapters/anthropic-format-adapter.js +3 -0
- package/dist/conversion/hub/format-adapters/chat-format-adapter.js +3 -0
- package/dist/conversion/hub/format-adapters/gemini-format-adapter.js +3 -0
- package/dist/conversion/hub/format-adapters/responses-format-adapter.d.ts +19 -0
- package/dist/conversion/hub/format-adapters/responses-format-adapter.js +9 -0
- package/dist/conversion/hub/node-support.js +3 -1
- package/dist/conversion/hub/pipeline/hub-pipeline.js +37 -32
- package/dist/conversion/hub/response/provider-response.js +1 -1
- package/dist/conversion/hub/response/response-mappers.js +1 -1
- package/dist/conversion/hub/response/response-runtime.js +109 -10
- package/dist/conversion/hub/semantic-mappers/anthropic-mapper.js +70 -156
- package/dist/conversion/hub/semantic-mappers/chat-mapper.js +63 -52
- package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +76 -143
- package/dist/conversion/hub/semantic-mappers/responses-mapper.js +40 -160
- package/dist/conversion/hub/standardized-bridge.js +3 -0
- package/dist/conversion/hub/tool-governance/rules.js +2 -2
- package/dist/conversion/index.d.ts +5 -0
- package/dist/conversion/index.js +5 -0
- package/dist/conversion/pipeline/codecs/v2/anthropic-openai-pipeline.d.ts +12 -0
- package/dist/conversion/pipeline/codecs/v2/anthropic-openai-pipeline.js +100 -0
- package/dist/conversion/pipeline/codecs/v2/openai-openai-pipeline.d.ts +15 -0
- package/dist/conversion/pipeline/codecs/v2/openai-openai-pipeline.js +174 -0
- package/dist/conversion/pipeline/codecs/v2/responses-openai-pipeline.d.ts +14 -0
- package/dist/conversion/pipeline/codecs/v2/responses-openai-pipeline.js +166 -0
- package/dist/conversion/pipeline/codecs/v2/shared/openai-chat-helpers.d.ts +13 -0
- package/dist/conversion/pipeline/codecs/v2/shared/openai-chat-helpers.js +66 -0
- package/dist/conversion/pipeline/hooks/adapter-context.d.ts +7 -0
- package/dist/conversion/pipeline/hooks/adapter-context.js +18 -0
- package/dist/conversion/pipeline/hooks/protocol-hooks.d.ts +67 -0
- package/dist/conversion/pipeline/hooks/protocol-hooks.js +1 -0
- package/dist/conversion/pipeline/index.d.ts +35 -0
- package/dist/conversion/pipeline/index.js +103 -0
- package/dist/conversion/pipeline/meta/meta-bag.d.ts +20 -0
- package/dist/conversion/pipeline/meta/meta-bag.js +81 -0
- package/dist/conversion/pipeline/schema/canonical-chat.d.ts +18 -0
- package/dist/conversion/pipeline/schema/canonical-chat.js +1 -0
- package/dist/conversion/pipeline/schema/index.d.ts +1 -0
- package/dist/conversion/pipeline/schema/index.js +1 -0
- package/dist/conversion/responses/responses-openai-bridge.d.ts +48 -0
- package/dist/conversion/responses/responses-openai-bridge.js +157 -1146
- package/dist/conversion/shared/anthropic-message-utils.d.ts +12 -0
- package/dist/conversion/shared/anthropic-message-utils.js +587 -0
- package/dist/conversion/shared/bridge-actions.d.ts +39 -0
- package/dist/conversion/shared/bridge-actions.js +709 -0
- package/dist/conversion/shared/bridge-conversation-store.d.ts +41 -0
- package/dist/conversion/shared/bridge-conversation-store.js +279 -0
- package/dist/conversion/shared/bridge-id-utils.d.ts +7 -0
- package/dist/conversion/shared/bridge-id-utils.js +42 -0
- package/dist/conversion/shared/bridge-instructions.d.ts +1 -0
- package/dist/conversion/shared/bridge-instructions.js +113 -0
- package/dist/conversion/shared/bridge-message-types.d.ts +39 -0
- package/dist/conversion/shared/bridge-message-types.js +1 -0
- package/dist/conversion/shared/bridge-message-utils.d.ts +22 -0
- package/dist/conversion/shared/bridge-message-utils.js +473 -0
- package/dist/conversion/shared/bridge-metadata.d.ts +1 -0
- package/dist/conversion/shared/bridge-metadata.js +1 -0
- package/dist/conversion/shared/bridge-policies.d.ts +18 -0
- package/dist/conversion/shared/bridge-policies.js +276 -0
- package/dist/conversion/shared/bridge-request-adapter.d.ts +28 -0
- package/dist/conversion/shared/bridge-request-adapter.js +430 -0
- package/dist/conversion/shared/chat-output-normalizer.d.ts +4 -0
- package/dist/conversion/shared/chat-output-normalizer.js +56 -0
- package/dist/conversion/shared/chat-request-filters.js +24 -1
- package/dist/conversion/shared/gemini-tool-utils.d.ts +5 -0
- package/dist/conversion/shared/gemini-tool-utils.js +130 -0
- package/dist/conversion/shared/metadata-passthrough.d.ts +11 -0
- package/dist/conversion/shared/metadata-passthrough.js +57 -0
- package/dist/conversion/shared/output-content-normalizer.d.ts +12 -0
- package/dist/conversion/shared/output-content-normalizer.js +119 -0
- package/dist/conversion/shared/reasoning-normalizer.d.ts +21 -0
- package/dist/conversion/shared/reasoning-normalizer.js +368 -0
- package/dist/conversion/shared/reasoning-tool-normalizer.d.ts +12 -0
- package/dist/conversion/shared/reasoning-tool-normalizer.js +132 -0
- package/dist/conversion/shared/reasoning-tool-parser.d.ts +10 -0
- package/dist/conversion/shared/reasoning-tool-parser.js +95 -0
- package/dist/conversion/shared/reasoning-utils.d.ts +2 -0
- package/dist/conversion/shared/reasoning-utils.js +42 -0
- package/dist/conversion/shared/responses-conversation-store.js +5 -11
- package/dist/conversion/shared/responses-message-utils.d.ts +15 -0
- package/dist/conversion/shared/responses-message-utils.js +206 -0
- package/dist/conversion/shared/responses-output-builder.d.ts +15 -0
- package/dist/conversion/shared/responses-output-builder.js +179 -0
- package/dist/conversion/shared/responses-output-utils.d.ts +7 -0
- package/dist/conversion/shared/responses-output-utils.js +108 -0
- package/dist/conversion/shared/responses-request-adapter.d.ts +28 -0
- package/dist/conversion/shared/responses-request-adapter.js +9 -40
- package/dist/conversion/shared/responses-response-utils.d.ts +3 -0
- package/dist/conversion/shared/responses-response-utils.js +209 -0
- package/dist/conversion/shared/responses-tool-utils.d.ts +12 -0
- package/dist/conversion/shared/responses-tool-utils.js +90 -0
- package/dist/conversion/shared/responses-types.d.ts +33 -0
- package/dist/conversion/shared/responses-types.js +1 -0
- package/dist/conversion/shared/tool-call-utils.d.ts +11 -0
- package/dist/conversion/shared/tool-call-utils.js +56 -0
- package/dist/conversion/shared/tool-mapping.d.ts +19 -0
- package/dist/conversion/shared/tool-mapping.js +124 -0
- package/dist/conversion/shared/tool-normalizers.d.ts +4 -0
- package/dist/conversion/shared/tool-normalizers.js +84 -0
- package/dist/router/virtual-router/bootstrap.js +18 -3
- package/dist/router/virtual-router/provider-registry.js +4 -2
- package/dist/router/virtual-router/types.d.ts +212 -0
- package/dist/sse/index.d.ts +38 -2
- package/dist/sse/index.js +27 -0
- package/dist/sse/json-to-sse/anthropic-json-to-sse-converter.d.ts +14 -0
- package/dist/sse/json-to-sse/anthropic-json-to-sse-converter.js +106 -73
- package/dist/sse/json-to-sse/chat-json-to-sse-converter.js +6 -2
- package/dist/sse/json-to-sse/gemini-json-to-sse-converter.d.ts +14 -0
- package/dist/sse/json-to-sse/gemini-json-to-sse-converter.js +99 -0
- package/dist/sse/json-to-sse/index.d.ts +7 -0
- package/dist/sse/json-to-sse/index.js +2 -0
- package/dist/sse/json-to-sse/sequencers/anthropic-sequencer.d.ts +13 -0
- package/dist/sse/json-to-sse/sequencers/anthropic-sequencer.js +150 -0
- package/dist/sse/json-to-sse/sequencers/chat-sequencer.d.ts +39 -0
- package/dist/sse/json-to-sse/sequencers/chat-sequencer.js +49 -3
- package/dist/sse/json-to-sse/sequencers/gemini-sequencer.d.ts +10 -0
- package/dist/sse/json-to-sse/sequencers/gemini-sequencer.js +95 -0
- package/dist/sse/json-to-sse/sequencers/responses-sequencer.js +31 -5
- package/dist/sse/registry/sse-codec-registry.d.ts +32 -0
- package/dist/sse/registry/sse-codec-registry.js +30 -1
- package/dist/sse/shared/reasoning-dispatcher.d.ts +10 -0
- package/dist/sse/shared/reasoning-dispatcher.js +25 -0
- package/dist/sse/shared/responses-output-normalizer.d.ts +12 -0
- package/dist/sse/shared/responses-output-normalizer.js +45 -0
- package/dist/sse/shared/serializers/anthropic-event-serializer.d.ts +2 -0
- package/dist/sse/shared/serializers/anthropic-event-serializer.js +9 -0
- package/dist/sse/shared/serializers/gemini-event-serializer.d.ts +2 -0
- package/dist/sse/shared/serializers/gemini-event-serializer.js +5 -0
- package/dist/sse/shared/serializers/index.d.ts +41 -0
- package/dist/sse/shared/serializers/index.js +2 -0
- package/dist/sse/shared/writer.d.ts +127 -0
- package/dist/sse/shared/writer.js +37 -1
- package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +11 -0
- package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.js +92 -127
- package/dist/sse/sse-to-json/builders/anthropic-response-builder.d.ts +16 -0
- package/dist/sse/sse-to-json/builders/anthropic-response-builder.js +151 -0
- package/dist/sse/sse-to-json/builders/response-builder.d.ts +165 -0
- package/dist/sse/sse-to-json/builders/response-builder.js +27 -6
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.d.ts +114 -0
- package/dist/sse/sse-to-json/chat-sse-to-json-converter.js +79 -3
- package/dist/sse/sse-to-json/gemini-sse-to-json-converter.d.ts +13 -0
- package/dist/sse/sse-to-json/gemini-sse-to-json-converter.js +160 -0
- package/dist/sse/sse-to-json/index.d.ts +7 -0
- package/dist/sse/sse-to-json/index.js +2 -0
- package/dist/sse/sse-to-json/parsers/sse-parser.js +53 -1
- package/dist/sse/types/anthropic-types.d.ts +170 -0
- package/dist/sse/types/anthropic-types.js +8 -5
- package/dist/sse/types/chat-types.d.ts +10 -0
- package/dist/sse/types/chat-types.js +2 -1
- package/dist/sse/types/core-interfaces.d.ts +1 -1
- package/dist/sse/types/gemini-types.d.ts +116 -0
- package/dist/sse/types/gemini-types.js +5 -0
- package/dist/sse/types/index.d.ts +5 -2
- package/dist/sse/types/index.js +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { isJsonObject, jsonClone } from '../hub/types/json.js';
|
|
2
|
+
function isValidKey(value) {
|
|
3
|
+
return typeof value === 'string' && value.trim().length > 0;
|
|
4
|
+
}
|
|
5
|
+
export function encodeMetadataPassthrough(parameters, options) {
|
|
6
|
+
if (!parameters)
|
|
7
|
+
return undefined;
|
|
8
|
+
const encoded = {};
|
|
9
|
+
const { prefix, keys } = options;
|
|
10
|
+
for (const key of keys) {
|
|
11
|
+
if (!isValidKey(key))
|
|
12
|
+
continue;
|
|
13
|
+
const value = parameters[key];
|
|
14
|
+
if (value === undefined)
|
|
15
|
+
continue;
|
|
16
|
+
try {
|
|
17
|
+
encoded[`${prefix}${key}`] = JSON.stringify(value);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return Object.keys(encoded).length ? encoded : undefined;
|
|
24
|
+
}
|
|
25
|
+
export function extractMetadataPassthrough(metadataField, options) {
|
|
26
|
+
if (!metadataField || !isJsonObject(metadataField)) {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
const cloned = jsonClone(metadataField);
|
|
30
|
+
const passthrough = {};
|
|
31
|
+
const { prefix, keys } = options;
|
|
32
|
+
const allowedKeys = new Set(keys.filter(isValidKey));
|
|
33
|
+
let mutated = false;
|
|
34
|
+
for (const rawKey of Object.keys(cloned)) {
|
|
35
|
+
if (!rawKey.startsWith(prefix))
|
|
36
|
+
continue;
|
|
37
|
+
const suffix = rawKey.slice(prefix.length);
|
|
38
|
+
if (!allowedKeys.has(suffix))
|
|
39
|
+
continue;
|
|
40
|
+
const rawValue = cloned[rawKey];
|
|
41
|
+
if (typeof rawValue !== 'string')
|
|
42
|
+
continue;
|
|
43
|
+
try {
|
|
44
|
+
const parsed = rawValue ? JSON.parse(rawValue) : undefined;
|
|
45
|
+
passthrough[suffix] = parsed;
|
|
46
|
+
delete cloned[rawKey];
|
|
47
|
+
mutated = true;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
metadata: mutated ? (Object.keys(cloned).length ? cloned : undefined) : cloned,
|
|
55
|
+
passthrough: Object.keys(passthrough).length ? passthrough : undefined
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
type UnknownRecord = Record<string, unknown>;
|
|
2
|
+
export interface OutputContentExtractionResult {
|
|
3
|
+
textParts: string[];
|
|
4
|
+
reasoningParts: string[];
|
|
5
|
+
}
|
|
6
|
+
export declare function extractOutputSegments(source: UnknownRecord | undefined, itemsKey?: string): OutputContentExtractionResult;
|
|
7
|
+
export declare function normalizeContentPart(part: unknown, reasoningCollector: string[]): UnknownRecord | null;
|
|
8
|
+
export declare function normalizeMessageContentParts(parts: unknown, reasoningCollector?: string[]): {
|
|
9
|
+
normalizedParts: UnknownRecord[];
|
|
10
|
+
reasoningChunks: string[];
|
|
11
|
+
};
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { extractReasoningSegments, sanitizeReasoningTaggedText } from './reasoning-utils.js';
|
|
2
|
+
function collectTextAndReasoning(blocks, collector) {
|
|
3
|
+
const pushText = (value) => {
|
|
4
|
+
if (typeof value === 'string' && value.trim().length) {
|
|
5
|
+
const cleaned = extractReasoningSegments(value, collector.reasoningParts);
|
|
6
|
+
if (cleaned.length) {
|
|
7
|
+
collector.textParts.push(cleaned);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
if (typeof blocks === 'string') {
|
|
12
|
+
pushText(blocks);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (!Array.isArray(blocks))
|
|
16
|
+
return;
|
|
17
|
+
for (const block of blocks) {
|
|
18
|
+
if (!block || typeof block !== 'object')
|
|
19
|
+
continue;
|
|
20
|
+
const type = typeof block.type === 'string' ? String(block.type).toLowerCase() : '';
|
|
21
|
+
if (type === 'text' || type === 'input_text' || type === 'output_text' || type === 'commentary') {
|
|
22
|
+
pushText(block.text ?? block.content);
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (Array.isArray(block.content)) {
|
|
26
|
+
collectTextAndReasoning(block.content, collector);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (typeof block.text === 'string') {
|
|
30
|
+
pushText(block.text);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function extractOutputSegments(source, itemsKey = 'output') {
|
|
35
|
+
if (!source || typeof source !== 'object') {
|
|
36
|
+
return { textParts: [], reasoningParts: [] };
|
|
37
|
+
}
|
|
38
|
+
const outputItems = Array.isArray(source[itemsKey]) ? source[itemsKey] : [];
|
|
39
|
+
const result = { textParts: [], reasoningParts: [] };
|
|
40
|
+
for (const item of outputItems) {
|
|
41
|
+
if (!item || typeof item !== 'object')
|
|
42
|
+
continue;
|
|
43
|
+
const type = typeof item.type === 'string' ? String(item.type).toLowerCase() : '';
|
|
44
|
+
if (type === 'message') {
|
|
45
|
+
const message = item.message && typeof item.message === 'object'
|
|
46
|
+
? item.message
|
|
47
|
+
: item;
|
|
48
|
+
const content = Array.isArray(message.content) ? message.content : [];
|
|
49
|
+
collectTextAndReasoning(content, result);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (type === 'output_text' && typeof item.text === 'string') {
|
|
53
|
+
const cleaned = extractReasoningSegments(item.text, result.reasoningParts);
|
|
54
|
+
if (cleaned.length) {
|
|
55
|
+
result.textParts.push(cleaned);
|
|
56
|
+
}
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (type === 'reasoning') {
|
|
60
|
+
const content = Array.isArray(item.content) ? item.content : [];
|
|
61
|
+
for (const block of content) {
|
|
62
|
+
if (block && typeof block === 'object' && typeof block.text === 'string') {
|
|
63
|
+
const sanitized = sanitizeReasoningTaggedText(block.text);
|
|
64
|
+
if (sanitized.length)
|
|
65
|
+
result.reasoningParts.push(sanitized);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
export function normalizeContentPart(part, reasoningCollector) {
|
|
73
|
+
if (part == null)
|
|
74
|
+
return null;
|
|
75
|
+
if (typeof part === 'string') {
|
|
76
|
+
const cleaned = extractReasoningSegments(part, reasoningCollector);
|
|
77
|
+
return { type: 'output_text', text: cleaned };
|
|
78
|
+
}
|
|
79
|
+
if (typeof part !== 'object') {
|
|
80
|
+
return { type: 'output_text', text: sanitizeReasoningTaggedText(String(part)) };
|
|
81
|
+
}
|
|
82
|
+
const clone = { ...part };
|
|
83
|
+
delete clone._initialText;
|
|
84
|
+
delete clone._hasDelta;
|
|
85
|
+
if (typeof clone.text === 'string') {
|
|
86
|
+
clone.text = extractReasoningSegments(clone.text, reasoningCollector);
|
|
87
|
+
}
|
|
88
|
+
if (clone.output_text && typeof clone.output_text === 'object' && typeof clone.output_text.text === 'string') {
|
|
89
|
+
clone.output_text = {
|
|
90
|
+
...clone.output_text,
|
|
91
|
+
text: extractReasoningSegments(clone.output_text.text, reasoningCollector)
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (typeof clone.content === 'string') {
|
|
95
|
+
clone.content = extractReasoningSegments(clone.content, reasoningCollector);
|
|
96
|
+
}
|
|
97
|
+
if (!clone.type)
|
|
98
|
+
clone.type = 'output_text';
|
|
99
|
+
if (clone.type === 'output_text' && typeof clone.text !== 'string') {
|
|
100
|
+
clone.text = '';
|
|
101
|
+
}
|
|
102
|
+
return clone;
|
|
103
|
+
}
|
|
104
|
+
export function normalizeMessageContentParts(parts, reasoningCollector) {
|
|
105
|
+
const reasoningChunks = reasoningCollector ?? [];
|
|
106
|
+
const normalizedParts = [];
|
|
107
|
+
if (!Array.isArray(parts)) {
|
|
108
|
+
const normalized = normalizeContentPart(parts, reasoningChunks);
|
|
109
|
+
if (normalized)
|
|
110
|
+
normalizedParts.push(normalized);
|
|
111
|
+
return { normalizedParts, reasoningChunks };
|
|
112
|
+
}
|
|
113
|
+
for (const part of parts) {
|
|
114
|
+
const normalized = normalizeContentPart(part, reasoningChunks);
|
|
115
|
+
if (normalized)
|
|
116
|
+
normalizedParts.push(normalized);
|
|
117
|
+
}
|
|
118
|
+
return { normalizedParts, reasoningChunks };
|
|
119
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { JsonObject, JsonValue } from '../hub/types/json.js';
|
|
2
|
+
export declare const RESPONSES_INSTRUCTIONS_REASONING_FIELD = "__rcc_reasoning_instructions";
|
|
3
|
+
interface ResponsesReasoningNormalizeOptions {
|
|
4
|
+
includeInput?: boolean;
|
|
5
|
+
includeOutput?: boolean;
|
|
6
|
+
includeRequiredAction?: boolean;
|
|
7
|
+
includeInstructions?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function normalizeReasoningInChatPayload(payload: {
|
|
10
|
+
messages?: JsonValue[];
|
|
11
|
+
} | null | undefined): void;
|
|
12
|
+
export declare function normalizeReasoningInResponsesPayload(payload: {
|
|
13
|
+
output?: JsonValue[];
|
|
14
|
+
id?: string;
|
|
15
|
+
input?: JsonValue[];
|
|
16
|
+
instructions?: unknown;
|
|
17
|
+
required_action?: JsonObject;
|
|
18
|
+
} | null | undefined, options?: ResponsesReasoningNormalizeOptions): void;
|
|
19
|
+
export declare function normalizeReasoningInGeminiPayload(payload: JsonObject | null | undefined): void;
|
|
20
|
+
export declare function normalizeReasoningInAnthropicPayload(payload: JsonObject | null | undefined): void;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import { normalizeChatMessageContent } from './chat-output-normalizer.js';
|
|
2
|
+
import { extractReasoningSegments } from './reasoning-utils.js';
|
|
3
|
+
import { expandResponsesMessageItem } from '../../sse/shared/responses-output-normalizer.js';
|
|
4
|
+
export const RESPONSES_INSTRUCTIONS_REASONING_FIELD = '__rcc_reasoning_instructions';
|
|
5
|
+
function isRecord(value) {
|
|
6
|
+
return Boolean(value && typeof value === 'object' && !Array.isArray(value));
|
|
7
|
+
}
|
|
8
|
+
export function normalizeReasoningInChatPayload(payload) {
|
|
9
|
+
if (!payload || !Array.isArray(payload.messages)) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
payload.messages = payload.messages.map((entry) => {
|
|
13
|
+
if (!entry || typeof entry !== 'object') {
|
|
14
|
+
return entry;
|
|
15
|
+
}
|
|
16
|
+
const msg = entry;
|
|
17
|
+
const normalized = normalizeChatMessageContent(msg.content);
|
|
18
|
+
if (normalized.contentText !== undefined) {
|
|
19
|
+
msg.content = normalized.contentText;
|
|
20
|
+
}
|
|
21
|
+
if (normalized.reasoningText && normalized.reasoningText.trim().length) {
|
|
22
|
+
msg.reasoning_content = normalized.reasoningText.trim();
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
delete msg.reasoning_content;
|
|
26
|
+
}
|
|
27
|
+
return msg;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
export function normalizeReasoningInResponsesPayload(payload, options = { includeOutput: true }) {
|
|
31
|
+
if (!payload) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const includeOutput = options.includeOutput !== false;
|
|
35
|
+
if (includeOutput) {
|
|
36
|
+
normalizeResponsesOutput(payload);
|
|
37
|
+
}
|
|
38
|
+
if (options.includeInput) {
|
|
39
|
+
normalizeResponsesInput(payload);
|
|
40
|
+
}
|
|
41
|
+
if (options.includeInstructions) {
|
|
42
|
+
normalizeResponsesInstructions(payload);
|
|
43
|
+
}
|
|
44
|
+
if (options.includeRequiredAction) {
|
|
45
|
+
normalizeResponsesRequiredAction(payload);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function normalizeResponsesOutput(payload) {
|
|
49
|
+
if (!Array.isArray(payload.output)) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const normalized = [];
|
|
53
|
+
payload.output.forEach((entry, index) => {
|
|
54
|
+
if (isResponsesMessageItem(entry)) {
|
|
55
|
+
const expanded = expandResponsesMessageItem(entry, {
|
|
56
|
+
requestId: typeof payload.id === 'string' ? payload.id : 'responses',
|
|
57
|
+
outputIndex: index
|
|
58
|
+
});
|
|
59
|
+
expanded.forEach((item) => {
|
|
60
|
+
normalized.push(item);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
normalized.push(entry);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
payload.output = normalized;
|
|
68
|
+
}
|
|
69
|
+
function isResponsesMessageItem(entry) {
|
|
70
|
+
if (!isRecord(entry)) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
const type = typeof entry.type === 'string' ? entry.type : undefined;
|
|
74
|
+
if (type !== 'message') {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
if (!Array.isArray(entry.content)) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
const status = typeof entry.status === 'string' ? entry.status : undefined;
|
|
81
|
+
const role = typeof entry.role === 'string' ? entry.role : undefined;
|
|
82
|
+
return Boolean(status && role);
|
|
83
|
+
}
|
|
84
|
+
function normalizeResponsesInput(payload) {
|
|
85
|
+
if (!Array.isArray(payload.input)) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
payload.input.forEach((entry) => {
|
|
89
|
+
if (!isRecord(entry))
|
|
90
|
+
return;
|
|
91
|
+
const reasoningSegments = [];
|
|
92
|
+
if (typeof entry.content === 'string') {
|
|
93
|
+
const { cleaned, segments } = stripReasoningFromString(entry.content);
|
|
94
|
+
entry.content = cleaned;
|
|
95
|
+
reasoningSegments.push(...segments);
|
|
96
|
+
}
|
|
97
|
+
else if (Array.isArray(entry.content)) {
|
|
98
|
+
entry.content = entry.content.map((block) => normalizeResponsesContentBlock(block, reasoningSegments));
|
|
99
|
+
}
|
|
100
|
+
if (isRecord(entry.message)) {
|
|
101
|
+
normalizeResponsesMessageBlock(entry.message, reasoningSegments);
|
|
102
|
+
}
|
|
103
|
+
if (typeof entry.text === 'string') {
|
|
104
|
+
const { cleaned, segments } = stripReasoningFromString(entry.text);
|
|
105
|
+
entry.text = cleaned;
|
|
106
|
+
reasoningSegments.push(...segments);
|
|
107
|
+
}
|
|
108
|
+
if (reasoningSegments.length) {
|
|
109
|
+
entry.reasoning_content = mergeReasoningText(entry.reasoning_content, reasoningSegments);
|
|
110
|
+
}
|
|
111
|
+
else if ('reasoning_content' in entry) {
|
|
112
|
+
delete entry.reasoning_content;
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
function normalizeResponsesMessageBlock(message, collector) {
|
|
117
|
+
const localSegments = [];
|
|
118
|
+
if (Array.isArray(message.content)) {
|
|
119
|
+
message.content = message.content.map((block) => normalizeResponsesContentBlock(block, localSegments));
|
|
120
|
+
}
|
|
121
|
+
else if (typeof message.content === 'string') {
|
|
122
|
+
const { cleaned, segments } = stripReasoningFromString(message.content);
|
|
123
|
+
message.content = cleaned;
|
|
124
|
+
localSegments.push(...segments);
|
|
125
|
+
}
|
|
126
|
+
if (typeof message.text === 'string') {
|
|
127
|
+
const { cleaned, segments } = stripReasoningFromString(message.text);
|
|
128
|
+
message.text = cleaned;
|
|
129
|
+
localSegments.push(...segments);
|
|
130
|
+
}
|
|
131
|
+
if (localSegments.length) {
|
|
132
|
+
collector.push(...localSegments);
|
|
133
|
+
message.reasoning_content = mergeReasoningText(message.reasoning_content, localSegments);
|
|
134
|
+
}
|
|
135
|
+
else if ('reasoning_content' in message) {
|
|
136
|
+
delete message.reasoning_content;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function normalizeResponsesContentBlock(block, collector) {
|
|
140
|
+
if (typeof block === 'string') {
|
|
141
|
+
const { cleaned, segments } = stripReasoningFromString(block);
|
|
142
|
+
collector.push(...segments);
|
|
143
|
+
return cleaned;
|
|
144
|
+
}
|
|
145
|
+
if (!isRecord(block)) {
|
|
146
|
+
return block;
|
|
147
|
+
}
|
|
148
|
+
const type = typeof block.type === 'string' ? block.type.toLowerCase() : '';
|
|
149
|
+
if ((type === 'input_text' || type === 'output_text' || type === 'text' || type === 'commentary') && typeof block.text === 'string') {
|
|
150
|
+
const { cleaned, segments } = stripReasoningFromString(block.text);
|
|
151
|
+
block.text = cleaned;
|
|
152
|
+
if (segments.length) {
|
|
153
|
+
collector.push(...segments);
|
|
154
|
+
block.reasoning_content = mergeReasoningText(block.reasoning_content, segments);
|
|
155
|
+
}
|
|
156
|
+
else if ('reasoning_content' in block) {
|
|
157
|
+
delete block.reasoning_content;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (Array.isArray(block.content)) {
|
|
161
|
+
block.content = block.content.map((nested) => normalizeResponsesContentBlock(nested, collector));
|
|
162
|
+
}
|
|
163
|
+
else if (typeof block.content === 'string') {
|
|
164
|
+
const { cleaned, segments } = stripReasoningFromString(block.content);
|
|
165
|
+
block.content = cleaned;
|
|
166
|
+
if (segments.length) {
|
|
167
|
+
collector.push(...segments);
|
|
168
|
+
block.reasoning_content = mergeReasoningText(block.reasoning_content, segments);
|
|
169
|
+
}
|
|
170
|
+
else if ('reasoning_content' in block) {
|
|
171
|
+
delete block.reasoning_content;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return block;
|
|
175
|
+
}
|
|
176
|
+
function normalizeResponsesInstructions(payload) {
|
|
177
|
+
if (typeof payload.instructions !== 'string') {
|
|
178
|
+
if (RESPONSES_INSTRUCTIONS_REASONING_FIELD in payload) {
|
|
179
|
+
delete payload[RESPONSES_INSTRUCTIONS_REASONING_FIELD];
|
|
180
|
+
}
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const { cleaned, segments } = stripReasoningFromString(payload.instructions);
|
|
184
|
+
payload.instructions = cleaned;
|
|
185
|
+
if (segments.length) {
|
|
186
|
+
payload[RESPONSES_INSTRUCTIONS_REASONING_FIELD] = segments.join('\n');
|
|
187
|
+
}
|
|
188
|
+
else if (RESPONSES_INSTRUCTIONS_REASONING_FIELD in payload) {
|
|
189
|
+
delete payload[RESPONSES_INSTRUCTIONS_REASONING_FIELD];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function normalizeResponsesRequiredAction(payload) {
|
|
193
|
+
if (!isRecord(payload.required_action)) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const submit = payload.required_action.submit_tool_outputs;
|
|
197
|
+
if (!submit || typeof submit !== 'object') {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
const toolCalls = Array.isArray(submit.tool_calls)
|
|
201
|
+
? submit.tool_calls
|
|
202
|
+
: [];
|
|
203
|
+
toolCalls.forEach((call) => {
|
|
204
|
+
if (!isRecord(call))
|
|
205
|
+
return;
|
|
206
|
+
if (typeof call.instructions === 'string') {
|
|
207
|
+
const { cleaned, segments } = stripReasoningFromString(call.instructions);
|
|
208
|
+
call.instructions = cleaned;
|
|
209
|
+
if (segments.length) {
|
|
210
|
+
call.reasoning_content = mergeReasoningText(call.reasoning_content, segments);
|
|
211
|
+
}
|
|
212
|
+
else if ('reasoning_content' in call) {
|
|
213
|
+
delete call.reasoning_content;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
function stripReasoningFromString(value) {
|
|
219
|
+
if (typeof value !== 'string') {
|
|
220
|
+
return { cleaned: typeof value === 'string' ? value : '', segments: [] };
|
|
221
|
+
}
|
|
222
|
+
const segments = [];
|
|
223
|
+
const cleaned = extractReasoningSegments(value, segments);
|
|
224
|
+
return { cleaned, segments };
|
|
225
|
+
}
|
|
226
|
+
function mergeReasoningText(existing, segments) {
|
|
227
|
+
const combined = [];
|
|
228
|
+
if (typeof existing === 'string' && existing.trim().length) {
|
|
229
|
+
combined.push(existing.trim());
|
|
230
|
+
}
|
|
231
|
+
for (const segment of segments) {
|
|
232
|
+
if (typeof segment === 'string' && segment.trim().length) {
|
|
233
|
+
combined.push(segment.trim());
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return combined.join('\n');
|
|
237
|
+
}
|
|
238
|
+
export function normalizeReasoningInGeminiPayload(payload) {
|
|
239
|
+
if (!payload) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const contents = Array.isArray(payload.contents) ? payload.contents : [];
|
|
243
|
+
contents.forEach((content) => {
|
|
244
|
+
if (!isRecord(content))
|
|
245
|
+
return;
|
|
246
|
+
const parts = Array.isArray(content.parts) ? content.parts : [];
|
|
247
|
+
parts.forEach((part) => {
|
|
248
|
+
if (!isRecord(part) || typeof part.text !== 'string') {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const reasoningSegments = [];
|
|
252
|
+
const cleaned = extractReasoningSegments(part.text, reasoningSegments);
|
|
253
|
+
part.text = cleaned;
|
|
254
|
+
if (reasoningSegments.length) {
|
|
255
|
+
part.reasoning = reasoningSegments.join('\n');
|
|
256
|
+
}
|
|
257
|
+
else if ('reasoning' in part) {
|
|
258
|
+
delete part.reasoning;
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
export function normalizeReasoningInAnthropicPayload(payload) {
|
|
264
|
+
if (!payload) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
const responseContent = Array.isArray(payload.content) ? payload.content : undefined;
|
|
268
|
+
if (responseContent) {
|
|
269
|
+
const responseReasoning = [];
|
|
270
|
+
responseContent.forEach((block) => normalizeAnthropicBlock(block, responseReasoning));
|
|
271
|
+
if (responseReasoning.length) {
|
|
272
|
+
payload.reasoning_content = mergeReasoningText(payload.reasoning_content, responseReasoning);
|
|
273
|
+
}
|
|
274
|
+
else if ('reasoning_content' in payload) {
|
|
275
|
+
delete payload.reasoning_content;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
const messages = Array.isArray(payload.messages) ? payload.messages : [];
|
|
279
|
+
messages.forEach((message) => {
|
|
280
|
+
if (!isRecord(message))
|
|
281
|
+
return;
|
|
282
|
+
normalizeAnthropicMessage(message);
|
|
283
|
+
});
|
|
284
|
+
const systemField = payload.system;
|
|
285
|
+
if (typeof systemField === 'string') {
|
|
286
|
+
const { cleaned } = stripReasoningFromString(systemField);
|
|
287
|
+
payload.system = cleaned;
|
|
288
|
+
}
|
|
289
|
+
else if (Array.isArray(systemField)) {
|
|
290
|
+
systemField.forEach((entry) => normalizeAnthropicBlock(entry, []));
|
|
291
|
+
}
|
|
292
|
+
else if (isRecord(systemField) && Array.isArray(systemField.content)) {
|
|
293
|
+
const sysBlocks = systemField.content;
|
|
294
|
+
systemField.content = sysBlocks.map((block) => {
|
|
295
|
+
normalizeAnthropicBlock(block, []);
|
|
296
|
+
return block;
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
function normalizeAnthropicMessage(message) {
|
|
301
|
+
const reasoningSegments = [];
|
|
302
|
+
if (Array.isArray(message.content)) {
|
|
303
|
+
message.content.forEach((block) => normalizeAnthropicBlock(block, reasoningSegments));
|
|
304
|
+
}
|
|
305
|
+
else if (typeof message.content === 'string') {
|
|
306
|
+
const { cleaned, segments } = stripReasoningFromString(message.content);
|
|
307
|
+
message.content = cleaned;
|
|
308
|
+
reasoningSegments.push(...segments);
|
|
309
|
+
}
|
|
310
|
+
if (reasoningSegments.length) {
|
|
311
|
+
message.reasoning_content = mergeReasoningText(message.reasoning_content, reasoningSegments);
|
|
312
|
+
}
|
|
313
|
+
else if ('reasoning_content' in message) {
|
|
314
|
+
delete message.reasoning_content;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
function normalizeAnthropicBlock(block, collector) {
|
|
318
|
+
if (typeof block === 'string') {
|
|
319
|
+
const { cleaned, segments } = stripReasoningFromString(block);
|
|
320
|
+
collector.push(...segments);
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
if (!isRecord(block)) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
const type = typeof block.type === 'string' ? block.type.toLowerCase() : '';
|
|
327
|
+
if (type === 'text' && typeof block.text === 'string') {
|
|
328
|
+
const { cleaned, segments } = stripReasoningFromString(block.text);
|
|
329
|
+
block.text = cleaned;
|
|
330
|
+
collector.push(...segments);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (type === 'thinking' || type === 'reasoning') {
|
|
334
|
+
const flattened = flattenAnthropicText(block);
|
|
335
|
+
if (flattened.trim().length) {
|
|
336
|
+
collector.push(flattened.trim());
|
|
337
|
+
}
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
if (Array.isArray(block.content)) {
|
|
341
|
+
block.content.forEach((nested) => normalizeAnthropicBlock(nested, collector));
|
|
342
|
+
}
|
|
343
|
+
else if (typeof block.content === 'string') {
|
|
344
|
+
const { cleaned, segments } = stripReasoningFromString(block.content);
|
|
345
|
+
block.content = cleaned;
|
|
346
|
+
collector.push(...segments);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
function flattenAnthropicText(source) {
|
|
350
|
+
if (typeof source === 'string') {
|
|
351
|
+
return source;
|
|
352
|
+
}
|
|
353
|
+
if (Array.isArray(source)) {
|
|
354
|
+
return source.map((entry) => flattenAnthropicText(entry)).filter(Boolean).join('');
|
|
355
|
+
}
|
|
356
|
+
if (isRecord(source)) {
|
|
357
|
+
if (typeof source.text === 'string') {
|
|
358
|
+
return source.text;
|
|
359
|
+
}
|
|
360
|
+
if (typeof source.content === 'string') {
|
|
361
|
+
return source.content;
|
|
362
|
+
}
|
|
363
|
+
if (Array.isArray(source.content)) {
|
|
364
|
+
return source.content.map((entry) => flattenAnthropicText(entry)).filter(Boolean).join('');
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return '';
|
|
368
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
type UnknownRecord = Record<string, unknown>;
|
|
2
|
+
export interface ReasoningNormalizationResult {
|
|
3
|
+
toolCallsAdded: number;
|
|
4
|
+
cleanedReasoning?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function normalizeMessageReasoningTools(message: UnknownRecord | null | undefined, options?: {
|
|
7
|
+
idPrefix?: string;
|
|
8
|
+
}): ReasoningNormalizationResult;
|
|
9
|
+
export declare function normalizeChatResponseReasoningTools(response: UnknownRecord | null | undefined, options?: {
|
|
10
|
+
idPrefixBase?: string;
|
|
11
|
+
}): void;
|
|
12
|
+
export {};
|