@jsonstudio/llms 0.4.6 → 0.6.2
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/codecs/anthropic-openai-codec.js +28 -2
- package/dist/conversion/codecs/gemini-openai-codec.js +23 -0
- package/dist/conversion/codecs/responses-openai-codec.js +8 -1
- package/dist/conversion/hub/node-support.js +14 -1
- package/dist/conversion/hub/pipeline/hub-pipeline.d.ts +66 -0
- package/dist/conversion/hub/pipeline/hub-pipeline.js +284 -193
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage1_format_parse/index.d.ts +11 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage1_format_parse/index.js +6 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.d.ts +16 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage2_semantic_map/index.js +17 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/context-factories.d.ts +5 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/context-factories.js +17 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.d.ts +19 -0
- package/dist/conversion/hub/pipeline/stages/req_inbound/req_inbound_stage3_context_capture/index.js +269 -0
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.d.ts +18 -0
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage1_semantic_map/index.js +141 -0
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage2_format_build/index.d.ts +11 -0
- package/dist/conversion/hub/pipeline/stages/req_outbound/req_outbound_stage2_format_build/index.js +29 -0
- package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage1_tool_governance/index.d.ts +16 -0
- package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage1_tool_governance/index.js +15 -0
- package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage2_route_select/index.d.ts +17 -0
- package/dist/conversion/hub/pipeline/stages/req_process/req_process_stage2_route_select/index.js +18 -0
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.d.ts +17 -0
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage1_sse_decode/index.js +63 -0
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage2_format_parse/index.d.ts +11 -0
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage2_format_parse/index.js +6 -0
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage3_semantic_map/index.d.ts +12 -0
- package/dist/conversion/hub/pipeline/stages/resp_inbound/resp_inbound_stage3_semantic_map/index.js +6 -0
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.d.ts +13 -0
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage1_client_remap/index.js +43 -0
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage2_sse_stream/index.d.ts +17 -0
- package/dist/conversion/hub/pipeline/stages/resp_outbound/resp_outbound_stage2_sse_stream/index.js +22 -0
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.d.ts +16 -0
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage1_tool_governance/index.js +19 -0
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage2_finalize/index.d.ts +17 -0
- package/dist/conversion/hub/pipeline/stages/resp_process/resp_process_stage2_finalize/index.js +19 -0
- package/dist/conversion/hub/pipeline/stages/utils.d.ts +2 -0
- package/dist/conversion/hub/pipeline/stages/utils.js +11 -0
- package/dist/conversion/hub/pipeline/target-utils.d.ts +5 -0
- package/dist/conversion/hub/pipeline/target-utils.js +87 -0
- package/dist/conversion/hub/process/chat-process.js +23 -17
- package/dist/conversion/hub/response/provider-response.js +69 -122
- package/dist/conversion/hub/response/response-mappers.d.ts +19 -0
- package/dist/conversion/hub/response/response-mappers.js +22 -2
- package/dist/conversion/hub/response/response-runtime.d.ts +8 -0
- package/dist/conversion/hub/response/response-runtime.js +239 -6
- package/dist/conversion/hub/semantic-mappers/anthropic-mapper.d.ts +8 -0
- package/dist/conversion/hub/semantic-mappers/anthropic-mapper.js +135 -55
- package/dist/conversion/hub/semantic-mappers/chat-mapper.js +80 -40
- package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +5 -29
- package/dist/conversion/hub/semantic-mappers/responses-mapper.js +16 -13
- package/dist/conversion/hub/snapshot-recorder.d.ts +13 -0
- package/dist/conversion/hub/snapshot-recorder.js +90 -50
- package/dist/conversion/hub/standardized-bridge.js +49 -38
- package/dist/conversion/hub/types/chat-envelope.d.ts +68 -0
- package/dist/conversion/hub/types/standardized.d.ts +97 -0
- package/dist/conversion/pipeline/codecs/v2/anthropic-openai-pipeline.js +29 -2
- package/dist/conversion/pipeline/codecs/v2/responses-openai-pipeline.js +68 -1
- package/dist/conversion/responses/responses-openai-bridge.d.ts +6 -1
- package/dist/conversion/responses/responses-openai-bridge.js +132 -10
- package/dist/conversion/shared/anthropic-message-utils.d.ts +9 -1
- package/dist/conversion/shared/anthropic-message-utils.js +414 -26
- package/dist/conversion/shared/bridge-actions.js +267 -95
- package/dist/conversion/shared/bridge-message-utils.js +54 -8
- package/dist/conversion/shared/bridge-policies.js +21 -2
- package/dist/conversion/shared/chat-envelope-validator.d.ts +8 -0
- package/dist/conversion/shared/chat-envelope-validator.js +128 -0
- package/dist/conversion/shared/chat-request-filters.js +109 -28
- package/dist/conversion/shared/mcp-injection.js +41 -20
- package/dist/conversion/shared/openai-finalizer.d.ts +11 -0
- package/dist/conversion/shared/openai-finalizer.js +73 -0
- package/dist/conversion/shared/openai-message-normalize.js +32 -31
- package/dist/conversion/shared/protocol-state.d.ts +4 -0
- package/dist/conversion/shared/protocol-state.js +23 -0
- package/dist/conversion/shared/reasoning-normalizer.d.ts +1 -0
- package/dist/conversion/shared/reasoning-normalizer.js +50 -18
- package/dist/conversion/shared/responses-output-builder.d.ts +1 -1
- package/dist/conversion/shared/responses-output-builder.js +76 -25
- package/dist/conversion/shared/responses-reasoning-registry.d.ts +8 -0
- package/dist/conversion/shared/responses-reasoning-registry.js +61 -0
- package/dist/conversion/shared/responses-response-utils.js +32 -2
- package/dist/conversion/shared/responses-tool-utils.js +28 -2
- package/dist/conversion/shared/snapshot-hooks.d.ts +9 -0
- package/dist/conversion/shared/snapshot-hooks.js +60 -6
- package/dist/conversion/shared/snapshot-utils.d.ts +16 -0
- package/dist/conversion/shared/snapshot-utils.js +84 -0
- package/dist/conversion/shared/tool-filter-pipeline.js +46 -7
- package/dist/conversion/shared/tool-mapping.js +13 -2
- package/dist/filters/index.d.ts +18 -0
- package/dist/filters/index.js +0 -1
- package/dist/filters/special/request-streaming-to-nonstreaming.d.ts +13 -0
- package/dist/filters/special/request-streaming-to-nonstreaming.js +13 -1
- package/dist/filters/special/request-tool-choice-policy.js +3 -1
- package/dist/filters/special/request-tool-list-filter.d.ts +11 -0
- package/dist/filters/special/request-tool-list-filter.js +20 -7
- package/dist/sse/shared/responses-output-normalizer.js +5 -4
- package/dist/sse/sse-to-json/builders/response-builder.js +24 -1
- package/dist/sse/types/responses-types.d.ts +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export type ChatRole = 'system' | 'user' | 'assistant' | 'tool';
|
|
2
|
+
import type { JsonObject, JsonValue } from './json.js';
|
|
3
|
+
export interface ChatMessageContentPart {
|
|
4
|
+
type: string;
|
|
5
|
+
text?: string;
|
|
6
|
+
[key: string]: JsonValue;
|
|
7
|
+
}
|
|
8
|
+
export interface ChatToolCall {
|
|
9
|
+
id: string;
|
|
10
|
+
type: 'function';
|
|
11
|
+
function: {
|
|
12
|
+
name: string;
|
|
13
|
+
arguments: string;
|
|
14
|
+
};
|
|
15
|
+
[key: string]: JsonValue;
|
|
16
|
+
}
|
|
17
|
+
export interface ChatMessage {
|
|
18
|
+
role: ChatRole;
|
|
19
|
+
content?: string | ChatMessageContentPart[] | null;
|
|
20
|
+
tool_calls?: ChatToolCall[];
|
|
21
|
+
name?: string;
|
|
22
|
+
[key: string]: JsonValue;
|
|
23
|
+
}
|
|
24
|
+
export interface ChatToolDefinition {
|
|
25
|
+
type: 'function' | string;
|
|
26
|
+
function: {
|
|
27
|
+
name: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
parameters?: JsonValue;
|
|
30
|
+
strict?: boolean;
|
|
31
|
+
};
|
|
32
|
+
[key: string]: JsonValue;
|
|
33
|
+
}
|
|
34
|
+
export interface ChatToolOutput {
|
|
35
|
+
tool_call_id: string;
|
|
36
|
+
content: string;
|
|
37
|
+
name?: string;
|
|
38
|
+
[key: string]: JsonValue;
|
|
39
|
+
}
|
|
40
|
+
export interface MissingField extends JsonObject {
|
|
41
|
+
path: string;
|
|
42
|
+
reason: string;
|
|
43
|
+
originalValue?: JsonValue;
|
|
44
|
+
}
|
|
45
|
+
export interface AdapterContext {
|
|
46
|
+
requestId: string;
|
|
47
|
+
entryEndpoint: string;
|
|
48
|
+
providerProtocol: string;
|
|
49
|
+
providerId?: string;
|
|
50
|
+
routeId?: string;
|
|
51
|
+
profileId?: string;
|
|
52
|
+
streamingHint?: 'auto' | 'force' | 'disable';
|
|
53
|
+
originalModelId?: string;
|
|
54
|
+
clientModelId?: string;
|
|
55
|
+
toolCallIdStyle?: 'fc' | 'preserve';
|
|
56
|
+
[key: string]: JsonValue;
|
|
57
|
+
}
|
|
58
|
+
export interface ChatEnvelope {
|
|
59
|
+
messages: ChatMessage[];
|
|
60
|
+
tools?: ChatToolDefinition[];
|
|
61
|
+
toolOutputs?: ChatToolOutput[];
|
|
62
|
+
parameters?: JsonObject;
|
|
63
|
+
metadata: {
|
|
64
|
+
context: AdapterContext;
|
|
65
|
+
missingFields?: MissingField[];
|
|
66
|
+
[key: string]: JsonValue;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { ChatMessageContentPart } from './chat-envelope.js';
|
|
2
|
+
import type { JsonObject } from './json.js';
|
|
3
|
+
export type ToolChoice = 'none' | 'auto' | 'required' | {
|
|
4
|
+
type: 'function';
|
|
5
|
+
function: {
|
|
6
|
+
name: string;
|
|
7
|
+
};
|
|
8
|
+
} | Record<string, unknown>;
|
|
9
|
+
export interface StandardizedTool {
|
|
10
|
+
type: 'function';
|
|
11
|
+
function: {
|
|
12
|
+
name: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
parameters: {
|
|
15
|
+
type?: string | string[];
|
|
16
|
+
properties?: Record<string, unknown>;
|
|
17
|
+
required?: string[];
|
|
18
|
+
additionalProperties?: boolean;
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
};
|
|
21
|
+
strict?: boolean;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export interface ToolCall {
|
|
25
|
+
id: string;
|
|
26
|
+
type: 'function';
|
|
27
|
+
function: {
|
|
28
|
+
name: string;
|
|
29
|
+
arguments: string;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export interface ToolCallResult {
|
|
33
|
+
tool_call_id: string;
|
|
34
|
+
status: 'success' | 'error' | 'timeout' | 'pending';
|
|
35
|
+
result?: JsonObject | JsonObject[] | string | number | boolean | null;
|
|
36
|
+
error?: string;
|
|
37
|
+
executionTime?: number;
|
|
38
|
+
}
|
|
39
|
+
export type StandardizedMessageContent = string | ChatMessageContentPart[] | null;
|
|
40
|
+
export interface StandardizedMessage {
|
|
41
|
+
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
42
|
+
content: StandardizedMessageContent;
|
|
43
|
+
tool_calls?: ToolCall[];
|
|
44
|
+
tool_call_id?: string;
|
|
45
|
+
name?: string;
|
|
46
|
+
metadata?: Record<string, unknown>;
|
|
47
|
+
}
|
|
48
|
+
export interface StandardizedParameters {
|
|
49
|
+
temperature?: number;
|
|
50
|
+
max_tokens?: number;
|
|
51
|
+
top_p?: number;
|
|
52
|
+
frequency_penalty?: number;
|
|
53
|
+
presence_penalty?: number;
|
|
54
|
+
stop?: string | string[];
|
|
55
|
+
stream?: boolean;
|
|
56
|
+
[key: string]: unknown;
|
|
57
|
+
}
|
|
58
|
+
export interface StandardizedMetadata {
|
|
59
|
+
originalEndpoint: string;
|
|
60
|
+
capturedContext?: Record<string, unknown>;
|
|
61
|
+
requestId?: string;
|
|
62
|
+
stream?: boolean;
|
|
63
|
+
toolChoice?: ToolChoice;
|
|
64
|
+
providerKey?: string;
|
|
65
|
+
providerType?: string;
|
|
66
|
+
processMode?: 'chat' | 'passthrough';
|
|
67
|
+
routeHint?: string;
|
|
68
|
+
[key: string]: unknown;
|
|
69
|
+
}
|
|
70
|
+
export interface StandardizedRequest {
|
|
71
|
+
model: string;
|
|
72
|
+
messages: StandardizedMessage[];
|
|
73
|
+
tools?: StandardizedTool[];
|
|
74
|
+
parameters: StandardizedParameters;
|
|
75
|
+
metadata: StandardizedMetadata;
|
|
76
|
+
}
|
|
77
|
+
export interface ProcessedRequest extends StandardizedRequest {
|
|
78
|
+
processed: {
|
|
79
|
+
timestamp: number;
|
|
80
|
+
appliedRules: string[];
|
|
81
|
+
status: 'success' | 'partial' | 'failed';
|
|
82
|
+
};
|
|
83
|
+
processingMetadata: {
|
|
84
|
+
toolCalls?: ToolCallResult[];
|
|
85
|
+
streaming?: {
|
|
86
|
+
enabled: boolean;
|
|
87
|
+
chunkCount?: number;
|
|
88
|
+
totalTokens?: number;
|
|
89
|
+
};
|
|
90
|
+
context?: {
|
|
91
|
+
systemPrompt?: string;
|
|
92
|
+
conversationHistory?: string[];
|
|
93
|
+
relevantContext?: Record<string, unknown>;
|
|
94
|
+
};
|
|
95
|
+
passthrough?: boolean;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
@@ -14,6 +14,23 @@ function assertJsonObject(value, stage) {
|
|
|
14
14
|
}
|
|
15
15
|
return value;
|
|
16
16
|
}
|
|
17
|
+
function coerceAliasMap(candidate) {
|
|
18
|
+
if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate)) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
let populated = false;
|
|
22
|
+
const result = {};
|
|
23
|
+
for (const [key, value] of Object.entries(candidate)) {
|
|
24
|
+
if (typeof key !== 'string' || typeof value !== 'string')
|
|
25
|
+
continue;
|
|
26
|
+
const trimmedKey = key.trim();
|
|
27
|
+
if (!trimmedKey.length)
|
|
28
|
+
continue;
|
|
29
|
+
result[trimmedKey] = value;
|
|
30
|
+
populated = true;
|
|
31
|
+
}
|
|
32
|
+
return populated ? result : undefined;
|
|
33
|
+
}
|
|
17
34
|
function createAnthropicHooks() {
|
|
18
35
|
const formatAdapter = new AnthropicFormatAdapter();
|
|
19
36
|
const semanticMapper = new AnthropicSemanticMapper();
|
|
@@ -28,6 +45,12 @@ function createAnthropicHooks() {
|
|
|
28
45
|
});
|
|
29
46
|
const formatEnvelope = await formatAdapter.parseRequest(wire, adapterContext);
|
|
30
47
|
const chatEnvelope = await semanticMapper.toChat(formatEnvelope, adapterContext);
|
|
48
|
+
const aliasMap = coerceAliasMap(adapterContext.anthropicToolNameMap) ??
|
|
49
|
+
coerceAliasMap(chatEnvelope.metadata?.anthropicToolNameMap);
|
|
50
|
+
if (aliasMap) {
|
|
51
|
+
context.metadata = context.metadata ?? {};
|
|
52
|
+
context.metadata.anthropicToolNameMap = aliasMap;
|
|
53
|
+
}
|
|
31
54
|
const canonical = chatEnvelopeToStandardized(chatEnvelope, {
|
|
32
55
|
adapterContext,
|
|
33
56
|
endpoint: context.entryEndpoint ?? DEFAULT_ANTHROPIC_ENDPOINT,
|
|
@@ -37,8 +60,12 @@ function createAnthropicHooks() {
|
|
|
37
60
|
}
|
|
38
61
|
},
|
|
39
62
|
outbound: {
|
|
40
|
-
serialize: async ({ canonical }) => {
|
|
41
|
-
const
|
|
63
|
+
serialize: async ({ canonical, context }) => {
|
|
64
|
+
const aliasMap = coerceAliasMap(context.metadata?.anthropicToolNameMap);
|
|
65
|
+
const anthropicPayload = buildAnthropicFromOpenAIChat(canonical, {
|
|
66
|
+
toolNameMap: aliasMap,
|
|
67
|
+
requestId: context.requestId
|
|
68
|
+
});
|
|
42
69
|
return { payload: assertJsonObject(anthropicPayload, 'anthropic_outbound_serialize') };
|
|
43
70
|
}
|
|
44
71
|
}
|
|
@@ -14,6 +14,71 @@ function assertJsonObject(value, stage) {
|
|
|
14
14
|
}
|
|
15
15
|
return value;
|
|
16
16
|
}
|
|
17
|
+
function sanitizeResponsesMessages(payload) {
|
|
18
|
+
const messages = Array.isArray(payload?.messages) ? payload.messages : [];
|
|
19
|
+
if (!messages.length)
|
|
20
|
+
return;
|
|
21
|
+
const sanitized = [];
|
|
22
|
+
let counter = 0;
|
|
23
|
+
const normalizeId = (raw) => {
|
|
24
|
+
if (typeof raw !== 'string')
|
|
25
|
+
return undefined;
|
|
26
|
+
const trimmed = raw.trim();
|
|
27
|
+
if (!trimmed.length)
|
|
28
|
+
return undefined;
|
|
29
|
+
if (trimmed.startsWith('fc_'))
|
|
30
|
+
return trimmed;
|
|
31
|
+
const stripped = trimmed.replace(/^call[_-]?/i, '');
|
|
32
|
+
const normalized = stripped.length ? stripped : trimmed;
|
|
33
|
+
return normalized.startsWith('fc_') ? normalized : `fc_${normalized}`;
|
|
34
|
+
};
|
|
35
|
+
for (const message of messages) {
|
|
36
|
+
if (!message || typeof message !== 'object')
|
|
37
|
+
continue;
|
|
38
|
+
const role = String(message.role || '').toLowerCase();
|
|
39
|
+
if (role === 'assistant' && Array.isArray(message.tool_calls) && message.tool_calls.length) {
|
|
40
|
+
message.tool_calls = message.tool_calls.map((call) => {
|
|
41
|
+
if (!call || typeof call !== 'object')
|
|
42
|
+
return call;
|
|
43
|
+
const existing = normalizeId(call.id) ?? normalizeId(call.call_id) ?? `fc_function_call_${counter++}`;
|
|
44
|
+
if (existing) {
|
|
45
|
+
call.id = existing;
|
|
46
|
+
}
|
|
47
|
+
if (call.call_id !== undefined)
|
|
48
|
+
delete call.call_id;
|
|
49
|
+
if (call.tool_call_id !== undefined)
|
|
50
|
+
delete call.tool_call_id;
|
|
51
|
+
return call;
|
|
52
|
+
});
|
|
53
|
+
sanitized.push(message);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (role === 'tool') {
|
|
57
|
+
const clone = { ...message };
|
|
58
|
+
const normalizedToolId = normalizeId(clone.tool_call_id ?? clone.call_id);
|
|
59
|
+
if (normalizedToolId) {
|
|
60
|
+
clone.tool_call_id = normalizedToolId;
|
|
61
|
+
}
|
|
62
|
+
else if (typeof clone.tool_call_id === 'string') {
|
|
63
|
+
const trimmed = clone.tool_call_id.trim();
|
|
64
|
+
if (!trimmed.length) {
|
|
65
|
+
delete clone.tool_call_id;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
clone.tool_call_id = trimmed;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if ('call_id' in clone)
|
|
72
|
+
delete clone.call_id;
|
|
73
|
+
if ('id' in clone)
|
|
74
|
+
delete clone.id;
|
|
75
|
+
sanitized.push(clone);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
sanitized.push(message);
|
|
79
|
+
}
|
|
80
|
+
payload.messages = sanitized;
|
|
81
|
+
}
|
|
17
82
|
function cloneResponsesContext(context) {
|
|
18
83
|
try {
|
|
19
84
|
return JSON.parse(JSON.stringify(context ?? {}));
|
|
@@ -143,7 +208,9 @@ export class ResponsesOpenAIPipelineCodec {
|
|
|
143
208
|
entryEndpoint: context.entryEndpoint ?? DEFAULT_RESPONSES_ENDPOINT,
|
|
144
209
|
endpoint: context.endpoint ?? DEFAULT_RESPONSES_ENDPOINT
|
|
145
210
|
};
|
|
146
|
-
|
|
211
|
+
const filtered = await runStandardChatRequestFilters(openaiPayload, profile, filterContext);
|
|
212
|
+
sanitizeResponsesMessages(filtered);
|
|
213
|
+
return filtered;
|
|
147
214
|
}
|
|
148
215
|
async convertResponse(payload, profile, context) {
|
|
149
216
|
this.ensureInitialized();
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { BridgeInputItem, BridgeToolDefinition } from '../shared/bridge-message-types.js';
|
|
2
2
|
import type { ChatToolDefinition } from '../hub/types/chat-envelope.js';
|
|
3
3
|
import type { BridgeInputBuildResult } from '../shared/bridge-message-utils.js';
|
|
4
|
-
|
|
4
|
+
import type { ToolCallIdStyle } from '../shared/responses-tool-utils.js';
|
|
5
|
+
type Unknown = Record<string, unknown>;
|
|
6
|
+
export interface ResponsesRequestContext extends Unknown {
|
|
5
7
|
requestId?: string;
|
|
6
8
|
originalSystemMessages?: string[];
|
|
7
9
|
input?: BridgeInputItem[];
|
|
@@ -24,6 +26,9 @@ export interface ResponsesRequestContext {
|
|
|
24
26
|
} | null;
|
|
25
27
|
toolsRaw?: BridgeToolDefinition[];
|
|
26
28
|
toolsNormalized?: Array<Record<string, unknown>>;
|
|
29
|
+
parameters?: Record<string, unknown>;
|
|
30
|
+
systemInstruction?: string;
|
|
31
|
+
toolCallIdStyle?: ToolCallIdStyle;
|
|
27
32
|
}
|
|
28
33
|
export interface BuildChatRequestResult {
|
|
29
34
|
request: Record<string, unknown>;
|
|
@@ -17,10 +17,11 @@ function isObject(v) {
|
|
|
17
17
|
// NOTE: 自修复提示已移除(统一标准:不做模糊兜底)。
|
|
18
18
|
// --- Public bridge functions ---
|
|
19
19
|
export function captureResponsesContext(payload, dto) {
|
|
20
|
+
const preservedInput = cloneBridgeEntries(payload.input);
|
|
20
21
|
ensureBridgeInstructions(payload);
|
|
21
22
|
const context = {
|
|
22
23
|
requestId: dto?.route?.requestId,
|
|
23
|
-
input:
|
|
24
|
+
input: preservedInput,
|
|
24
25
|
include: payload.include,
|
|
25
26
|
store: payload.store,
|
|
26
27
|
toolChoice: payload.tool_choice,
|
|
@@ -30,8 +31,14 @@ export function captureResponsesContext(payload, dto) {
|
|
|
30
31
|
stream: typeof payload.stream === 'boolean' ? payload.stream : undefined,
|
|
31
32
|
isChatPayload: Array.isArray(payload.messages)
|
|
32
33
|
};
|
|
34
|
+
if (payload.parameters && typeof payload.parameters === 'object') {
|
|
35
|
+
context.parameters = { ...payload.parameters };
|
|
36
|
+
}
|
|
37
|
+
if (typeof payload.instructions === 'string' && payload.instructions.trim().length) {
|
|
38
|
+
context.systemInstruction = payload.instructions;
|
|
39
|
+
}
|
|
33
40
|
if (Array.isArray(payload.tools)) {
|
|
34
|
-
context.toolsRaw = payload.tools;
|
|
41
|
+
context.toolsRaw = cloneBridgeEntries(payload.tools);
|
|
35
42
|
}
|
|
36
43
|
context.isResponsesPayload = !context.isChatPayload && Array.isArray(context.input);
|
|
37
44
|
return context;
|
|
@@ -154,7 +161,6 @@ export function buildResponsesRequestFromChat(payload, ctx, extras) {
|
|
|
154
161
|
'response_format',
|
|
155
162
|
'user',
|
|
156
163
|
'top_p',
|
|
157
|
-
'max_output_tokens',
|
|
158
164
|
'logit_bias',
|
|
159
165
|
'seed'
|
|
160
166
|
];
|
|
@@ -162,9 +168,6 @@ export function buildResponsesRequestFromChat(payload, ctx, extras) {
|
|
|
162
168
|
if (chat[key] !== undefined)
|
|
163
169
|
out[key] = chat[key];
|
|
164
170
|
}
|
|
165
|
-
if (typeof chat.max_tokens === 'number' && chat.max_output_tokens === undefined) {
|
|
166
|
-
out.max_output_tokens = chat.max_tokens;
|
|
167
|
-
}
|
|
168
171
|
let messages = Array.isArray(chat.messages) ? chat.messages : [];
|
|
169
172
|
let bridgeMetadata;
|
|
170
173
|
try {
|
|
@@ -193,8 +196,21 @@ export function buildResponsesRequestFromChat(payload, ctx, extras) {
|
|
|
193
196
|
// ignore policy errors
|
|
194
197
|
}
|
|
195
198
|
const envelopeMetadata = ctx?.metadata && typeof ctx.metadata === 'object' ? ctx.metadata : undefined;
|
|
196
|
-
const
|
|
197
|
-
const
|
|
199
|
+
const metadataExtraFields = extractMetadataExtraFields(envelopeMetadata);
|
|
200
|
+
const contextToolCallIdStyle = readToolCallIdStyleFromContext(ctx);
|
|
201
|
+
const toolCallIdStyle = contextToolCallIdStyle ?? resolveToolCallIdStyle(envelopeMetadata);
|
|
202
|
+
const fallbackHistory = ctx?.input && Array.isArray(ctx.input)
|
|
203
|
+
? {
|
|
204
|
+
input: ctx.input,
|
|
205
|
+
originalSystemMessages: ctx.originalSystemMessages,
|
|
206
|
+
combinedSystemInstruction: ctx.systemInstruction
|
|
207
|
+
}
|
|
208
|
+
: undefined;
|
|
209
|
+
const historySeed = normalizeBridgeHistory(extras?.bridgeHistory) ??
|
|
210
|
+
normalizeBridgeHistory(fallbackHistory) ??
|
|
211
|
+
normalizeBridgeHistory(bridgeMetadata?.bridgeHistory) ??
|
|
212
|
+
normalizeBridgeHistory(envelopeMetadata?.bridgeHistory) ??
|
|
213
|
+
fallbackHistory;
|
|
198
214
|
const history = historySeed ??
|
|
199
215
|
convertMessagesToBridgeInput({
|
|
200
216
|
messages,
|
|
@@ -206,6 +222,7 @@ export function buildResponsesRequestFromChat(payload, ctx, extras) {
|
|
|
206
222
|
}
|
|
207
223
|
const { input, combinedSystemInstruction, originalSystemMessages } = history;
|
|
208
224
|
const instructionCandidates = [
|
|
225
|
+
typeof ctx?.systemInstruction === 'string' && ctx.systemInstruction.trim().length ? ctx.systemInstruction.trim() : undefined,
|
|
209
226
|
typeof extras?.systemInstruction === 'string' && extras.systemInstruction.trim().length ? extras.systemInstruction.trim() : undefined,
|
|
210
227
|
typeof envelopeMetadata?.systemInstruction === 'string' && envelopeMetadata.systemInstruction.trim().length ? envelopeMetadata.systemInstruction.trim() : undefined,
|
|
211
228
|
combinedSystemInstruction && combinedSystemInstruction.length > 0 ? combinedSystemInstruction : undefined
|
|
@@ -233,9 +250,112 @@ export function buildResponsesRequestFromChat(payload, ctx, extras) {
|
|
|
233
250
|
else if (resolvedStream === false) {
|
|
234
251
|
out.stream = false;
|
|
235
252
|
}
|
|
253
|
+
if (ctx?.include !== undefined && out.include === undefined) {
|
|
254
|
+
out.include = ctx.include;
|
|
255
|
+
}
|
|
256
|
+
else if (metadataExtraFields?.include !== undefined && out.include === undefined) {
|
|
257
|
+
out.include = metadataExtraFields.include;
|
|
258
|
+
}
|
|
259
|
+
if (ctx?.store !== undefined && out.store === undefined) {
|
|
260
|
+
out.store = ctx.store;
|
|
261
|
+
}
|
|
262
|
+
else if (metadataExtraFields?.store !== undefined && out.store === undefined) {
|
|
263
|
+
out.store = metadataExtraFields.store;
|
|
264
|
+
}
|
|
265
|
+
if (ctx?.toolChoice !== undefined && out.tool_choice === undefined) {
|
|
266
|
+
out.tool_choice = ctx.toolChoice;
|
|
267
|
+
}
|
|
268
|
+
else if (metadataExtraFields?.tool_choice !== undefined && out.tool_choice === undefined) {
|
|
269
|
+
out.tool_choice = metadataExtraFields.tool_choice;
|
|
270
|
+
}
|
|
271
|
+
if (typeof ctx?.parallelToolCalls === 'boolean' && out.parallel_tool_calls === undefined) {
|
|
272
|
+
out.parallel_tool_calls = ctx.parallelToolCalls;
|
|
273
|
+
}
|
|
274
|
+
else if (typeof metadataExtraFields?.parallel_tool_calls === 'boolean' && out.parallel_tool_calls === undefined) {
|
|
275
|
+
out.parallel_tool_calls = metadataExtraFields.parallel_tool_calls;
|
|
276
|
+
}
|
|
277
|
+
if (ctx?.responseFormat !== undefined && out.response_format === undefined) {
|
|
278
|
+
out.response_format = ctx.responseFormat;
|
|
279
|
+
}
|
|
280
|
+
else if (metadataExtraFields?.response_format !== undefined && out.response_format === undefined) {
|
|
281
|
+
out.response_format = metadataExtraFields.response_format;
|
|
282
|
+
}
|
|
283
|
+
if (ctx?.metadata && Object.keys(ctx.metadata).length) {
|
|
284
|
+
out.metadata = { ...ctx.metadata };
|
|
285
|
+
}
|
|
286
|
+
else if (isPlainObject(metadataExtraFields?.metadata)) {
|
|
287
|
+
out.metadata = { ...metadataExtraFields.metadata };
|
|
288
|
+
}
|
|
289
|
+
if (ctx?.parameters && Object.keys(ctx.parameters).length) {
|
|
290
|
+
out.parameters = { ...ctx.parameters };
|
|
291
|
+
}
|
|
292
|
+
else if (chat.parameters && typeof chat.parameters === 'object') {
|
|
293
|
+
out.parameters = { ...chat.parameters };
|
|
294
|
+
}
|
|
295
|
+
else if (isPlainObject(metadataExtraFields?.parameters)) {
|
|
296
|
+
out.parameters = { ...metadataExtraFields.parameters };
|
|
297
|
+
}
|
|
236
298
|
ensureBridgeInstructions(out);
|
|
237
299
|
return { request: out, originalSystemMessages };
|
|
238
300
|
}
|
|
301
|
+
function readToolCallIdStyleFromContext(ctx) {
|
|
302
|
+
if (!ctx) {
|
|
303
|
+
return undefined;
|
|
304
|
+
}
|
|
305
|
+
const direct = normalizeToolCallIdStyleCandidate(ctx.toolCallIdStyle);
|
|
306
|
+
if (direct) {
|
|
307
|
+
return direct;
|
|
308
|
+
}
|
|
309
|
+
if (ctx.metadata && typeof ctx.metadata === 'object') {
|
|
310
|
+
const fromMetadata = normalizeToolCallIdStyleCandidate(ctx.metadata.toolCallIdStyle);
|
|
311
|
+
if (fromMetadata) {
|
|
312
|
+
return fromMetadata;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return undefined;
|
|
316
|
+
}
|
|
317
|
+
function normalizeToolCallIdStyleCandidate(candidate) {
|
|
318
|
+
if (typeof candidate !== 'string') {
|
|
319
|
+
return undefined;
|
|
320
|
+
}
|
|
321
|
+
const normalized = candidate.trim().toLowerCase();
|
|
322
|
+
if (normalized === 'fc') {
|
|
323
|
+
return 'fc';
|
|
324
|
+
}
|
|
325
|
+
if (normalized === 'preserve') {
|
|
326
|
+
return 'preserve';
|
|
327
|
+
}
|
|
328
|
+
return undefined;
|
|
329
|
+
}
|
|
330
|
+
function cloneBridgeEntries(entries) {
|
|
331
|
+
if (!Array.isArray(entries)) {
|
|
332
|
+
return undefined;
|
|
333
|
+
}
|
|
334
|
+
return entries.map((entry) => {
|
|
335
|
+
if (!entry || typeof entry !== 'object') {
|
|
336
|
+
return entry;
|
|
337
|
+
}
|
|
338
|
+
try {
|
|
339
|
+
return JSON.parse(JSON.stringify(entry));
|
|
340
|
+
}
|
|
341
|
+
catch {
|
|
342
|
+
return entry;
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
function extractMetadataExtraFields(metadata) {
|
|
347
|
+
if (!metadata) {
|
|
348
|
+
return undefined;
|
|
349
|
+
}
|
|
350
|
+
const extras = metadata.extraFields;
|
|
351
|
+
if (extras && typeof extras === 'object' && !Array.isArray(extras)) {
|
|
352
|
+
return extras;
|
|
353
|
+
}
|
|
354
|
+
return undefined;
|
|
355
|
+
}
|
|
356
|
+
function isPlainObject(value) {
|
|
357
|
+
return Boolean(value && typeof value === 'object' && !Array.isArray(value));
|
|
358
|
+
}
|
|
239
359
|
export function buildResponsesPayloadFromChat(payload, context) {
|
|
240
360
|
if (!payload || typeof payload !== 'object')
|
|
241
361
|
return payload;
|
|
@@ -297,9 +417,11 @@ export function buildResponsesPayloadFromChat(payload, context) {
|
|
|
297
417
|
created_at: response.created_at || response.created || Math.floor(Date.now() / 1000),
|
|
298
418
|
model: response.model,
|
|
299
419
|
status: outputBuild.status,
|
|
300
|
-
output: outputBuild.outputItems
|
|
301
|
-
output_text: outputBuild.outputText || ''
|
|
420
|
+
output: outputBuild.outputItems
|
|
302
421
|
};
|
|
422
|
+
if (typeof outputBuild.outputText === 'string') {
|
|
423
|
+
out.output_text = outputBuild.outputText;
|
|
424
|
+
}
|
|
303
425
|
if (outputBuild.usage !== undefined)
|
|
304
426
|
out.usage = outputBuild.usage;
|
|
305
427
|
if (outputBuild.requiredAction)
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import type { ChatToolDefinition, MissingField } from '../hub/types/chat-envelope.js';
|
|
2
|
+
import { type JsonObject } from '../hub/types/json.js';
|
|
2
3
|
type Unknown = Record<string, unknown>;
|
|
3
4
|
type UnknownArray = Unknown[];
|
|
4
5
|
interface OpenAIChatPayload extends Unknown {
|
|
5
6
|
messages: UnknownArray;
|
|
6
7
|
}
|
|
8
|
+
export declare function normalizeAnthropicToolName(value: unknown): string | undefined;
|
|
9
|
+
export declare function denormalizeAnthropicToolName(value: unknown): string | undefined;
|
|
7
10
|
export declare function buildOpenAIChatFromAnthropic(payload: unknown): OpenAIChatPayload;
|
|
8
|
-
export
|
|
11
|
+
export interface BuildAnthropicFromOpenAIOptions {
|
|
12
|
+
toolNameMap?: Record<string, string>;
|
|
13
|
+
requestId?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function buildAnthropicFromOpenAIChat(oa: unknown, options?: BuildAnthropicFromOpenAIOptions): Unknown;
|
|
9
16
|
export declare function buildAnthropicRequestFromOpenAIChat(chatReq: unknown): Unknown;
|
|
10
17
|
export declare function mapAnthropicToolsToChat(rawTools: unknown, missing?: MissingField[]): ChatToolDefinition[] | undefined;
|
|
11
18
|
export declare function mapChatToolsToAnthropicTools(rawTools: unknown): UnknownArray | undefined;
|
|
19
|
+
export declare function buildAnthropicToolAliasMap(rawTools: unknown): JsonObject | undefined;
|
|
12
20
|
export {};
|