@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,151 @@
|
|
|
1
|
+
import { dispatchReasoning } from '../../shared/reasoning-dispatcher.js';
|
|
2
|
+
export function createAnthropicResponseBuilder(options) {
|
|
3
|
+
const state = {
|
|
4
|
+
content: [],
|
|
5
|
+
role: 'assistant',
|
|
6
|
+
completed: false
|
|
7
|
+
};
|
|
8
|
+
const flushCurrent = () => {
|
|
9
|
+
if (!state.currentBlock)
|
|
10
|
+
return;
|
|
11
|
+
const block = state.currentBlock;
|
|
12
|
+
if (block.kind === 'text' && block.buffer) {
|
|
13
|
+
state.content.push({ type: 'text', text: block.buffer });
|
|
14
|
+
}
|
|
15
|
+
else if (block.kind === 'thinking' && block.buffer) {
|
|
16
|
+
const decision = dispatchReasoning(block.buffer, {
|
|
17
|
+
mode: options?.reasoningMode,
|
|
18
|
+
prefix: options?.reasoningTextPrefix
|
|
19
|
+
});
|
|
20
|
+
if (decision.appendToContent) {
|
|
21
|
+
state.content.push({ type: 'text', text: decision.appendToContent });
|
|
22
|
+
}
|
|
23
|
+
if (decision.channel) {
|
|
24
|
+
state.content.push({ type: 'thinking', text: decision.channel });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else if (block.kind === 'tool_use') {
|
|
28
|
+
let input = {};
|
|
29
|
+
try {
|
|
30
|
+
input = block.buffer ? JSON.parse(block.buffer) : {};
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
input = { _raw: block.buffer };
|
|
34
|
+
}
|
|
35
|
+
state.content.push({
|
|
36
|
+
type: 'tool_use',
|
|
37
|
+
id: block.id,
|
|
38
|
+
name: block.name,
|
|
39
|
+
input
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
else if (block.kind === 'tool_result') {
|
|
43
|
+
state.content.push({
|
|
44
|
+
type: 'tool_result',
|
|
45
|
+
tool_use_id: block.tool_use_id,
|
|
46
|
+
content: block.content,
|
|
47
|
+
is_error: block.is_error
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
state.currentBlock = undefined;
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
processEvent(event) {
|
|
54
|
+
switch (event.type) {
|
|
55
|
+
case 'message_start': {
|
|
56
|
+
const payload = event.data?.message;
|
|
57
|
+
if (payload) {
|
|
58
|
+
state.id = payload.id || state.id;
|
|
59
|
+
state.model = payload.model || state.model;
|
|
60
|
+
state.role = payload.role || state.role;
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
case 'content_block_start': {
|
|
65
|
+
const payload = event.data?.content_block;
|
|
66
|
+
const index = event.data?.index ?? 0;
|
|
67
|
+
if (!payload)
|
|
68
|
+
break;
|
|
69
|
+
if (payload.type === 'text') {
|
|
70
|
+
state.currentBlock = { kind: 'text', buffer: '', index };
|
|
71
|
+
}
|
|
72
|
+
else if (payload.type === 'thinking') {
|
|
73
|
+
state.currentBlock = { kind: 'thinking', buffer: '', index };
|
|
74
|
+
}
|
|
75
|
+
else if (payload.type === 'tool_use') {
|
|
76
|
+
state.currentBlock = {
|
|
77
|
+
kind: 'tool_use',
|
|
78
|
+
id: payload.id,
|
|
79
|
+
name: payload.name,
|
|
80
|
+
buffer: '',
|
|
81
|
+
index
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
else if (payload.type === 'tool_result') {
|
|
85
|
+
state.currentBlock = {
|
|
86
|
+
kind: 'tool_result',
|
|
87
|
+
tool_use_id: payload.tool_use_id,
|
|
88
|
+
content: payload.content,
|
|
89
|
+
is_error: payload.is_error,
|
|
90
|
+
index
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
case 'content_block_delta': {
|
|
96
|
+
if (!state.currentBlock)
|
|
97
|
+
break;
|
|
98
|
+
const delta = event.data?.delta;
|
|
99
|
+
if (!delta)
|
|
100
|
+
break;
|
|
101
|
+
if ((state.currentBlock.kind === 'text' || state.currentBlock.kind === 'thinking') && typeof delta.text === 'string') {
|
|
102
|
+
state.currentBlock.buffer += delta.text;
|
|
103
|
+
}
|
|
104
|
+
else if (state.currentBlock.kind === 'tool_use' && typeof delta.partial_json === 'string') {
|
|
105
|
+
state.currentBlock.buffer += delta.partial_json;
|
|
106
|
+
}
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
case 'content_block_stop': {
|
|
110
|
+
flushCurrent();
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
case 'message_delta': {
|
|
114
|
+
const delta = event.data?.delta;
|
|
115
|
+
if (delta?.stop_reason) {
|
|
116
|
+
state.stopReason = delta.stop_reason;
|
|
117
|
+
}
|
|
118
|
+
if (delta?.usage) {
|
|
119
|
+
state.usage = delta.usage;
|
|
120
|
+
}
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
case 'message_stop': {
|
|
124
|
+
state.completed = true;
|
|
125
|
+
flushCurrent();
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
default:
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
return true;
|
|
132
|
+
},
|
|
133
|
+
getResult() {
|
|
134
|
+
if (!state.completed) {
|
|
135
|
+
return { success: false, error: new Error('Anthropic SSE stream incomplete') };
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
success: true,
|
|
139
|
+
response: {
|
|
140
|
+
id: state.id || `msg_${Date.now()}`,
|
|
141
|
+
type: 'message',
|
|
142
|
+
role: state.role || 'assistant',
|
|
143
|
+
model: state.model || 'unknown',
|
|
144
|
+
content: state.content,
|
|
145
|
+
usage: state.usage,
|
|
146
|
+
stop_reason: state.stopReason ?? 'end_turn'
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Responses响应构建器
|
|
3
|
+
* 负责状态机和事件聚合,从SSE事件构建完整的Responses响应对象
|
|
4
|
+
*/
|
|
5
|
+
import { ResponsesSseEvent, ResponsesResponse } from '../../types/index.js';
|
|
6
|
+
export type ResponseBuilderState = 'initial' | 'building' | 'completed' | 'error';
|
|
7
|
+
export interface ResponseBuilderConfig {
|
|
8
|
+
enableStrictValidation: boolean;
|
|
9
|
+
enableEventRecovery: boolean;
|
|
10
|
+
maxOutputItems: number;
|
|
11
|
+
maxContentParts: number;
|
|
12
|
+
maxSequenceGaps: number;
|
|
13
|
+
}
|
|
14
|
+
export interface OutputItemState {
|
|
15
|
+
id: string;
|
|
16
|
+
type: string;
|
|
17
|
+
status: 'in_progress' | 'completed';
|
|
18
|
+
contentParts: any[];
|
|
19
|
+
currentContentIndex: number;
|
|
20
|
+
accumulatedContent: any[];
|
|
21
|
+
hasContentPartAdded: boolean;
|
|
22
|
+
isTextInProgress: boolean;
|
|
23
|
+
callId?: string;
|
|
24
|
+
name?: string;
|
|
25
|
+
arguments?: string;
|
|
26
|
+
role?: string;
|
|
27
|
+
startTime: number;
|
|
28
|
+
lastEventTime: number;
|
|
29
|
+
}
|
|
30
|
+
export declare const DEFAULT_RESPONSE_BUILDER_CONFIG: ResponseBuilderConfig;
|
|
31
|
+
/**
|
|
32
|
+
* Responses响应构建器
|
|
33
|
+
*/
|
|
34
|
+
export declare class ResponsesResponseBuilder {
|
|
35
|
+
private state;
|
|
36
|
+
private response;
|
|
37
|
+
private outputItemBuilders;
|
|
38
|
+
private lastSequenceNumber;
|
|
39
|
+
private config;
|
|
40
|
+
private error?;
|
|
41
|
+
constructor(config?: Partial<ResponseBuilderConfig>);
|
|
42
|
+
/**
|
|
43
|
+
* 处理SSE事件
|
|
44
|
+
*/
|
|
45
|
+
processEvent(event: ResponsesSseEvent): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* 验证序列号
|
|
48
|
+
*/
|
|
49
|
+
private validateSequenceNumber;
|
|
50
|
+
/**
|
|
51
|
+
* 处理response.start事件
|
|
52
|
+
*/
|
|
53
|
+
private handleResponseStart;
|
|
54
|
+
private handleResponseCreated;
|
|
55
|
+
private handleResponseInProgress;
|
|
56
|
+
/**
|
|
57
|
+
* 处理output_item.start事件
|
|
58
|
+
*/
|
|
59
|
+
private handleOutputItemStart;
|
|
60
|
+
private mapOutputItemAdded;
|
|
61
|
+
/**
|
|
62
|
+
* 处理content_part.start事件
|
|
63
|
+
*/
|
|
64
|
+
private handleContentPartStart;
|
|
65
|
+
private mapContentPartAdded;
|
|
66
|
+
/**
|
|
67
|
+
* 处理content_part.delta事件
|
|
68
|
+
*/
|
|
69
|
+
private handleContentPartDelta;
|
|
70
|
+
private mapOutputTextDelta;
|
|
71
|
+
/**
|
|
72
|
+
* 处理content_part.done事件
|
|
73
|
+
*/
|
|
74
|
+
private handleContentPartDone;
|
|
75
|
+
private mapContentPartDone;
|
|
76
|
+
/**
|
|
77
|
+
* 处理function_call.start事件
|
|
78
|
+
*/
|
|
79
|
+
private handleFunctionCallStart;
|
|
80
|
+
/**
|
|
81
|
+
* 处理function_call.delta事件
|
|
82
|
+
*/
|
|
83
|
+
private handleFunctionCallDelta;
|
|
84
|
+
private mapFunctionCallDelta;
|
|
85
|
+
/**
|
|
86
|
+
* 处理function_call.done事件
|
|
87
|
+
*/
|
|
88
|
+
private handleFunctionCallDone;
|
|
89
|
+
private mapFunctionCallDone;
|
|
90
|
+
/**
|
|
91
|
+
* 处理reasoning.start事件
|
|
92
|
+
*/
|
|
93
|
+
private handleReasoningStart;
|
|
94
|
+
/**
|
|
95
|
+
* 处理reasoning.delta事件
|
|
96
|
+
*/
|
|
97
|
+
private handleReasoningDelta;
|
|
98
|
+
private mapReasoningDelta;
|
|
99
|
+
private mapReasoningDone;
|
|
100
|
+
/**
|
|
101
|
+
* 处理reasoning.done事件
|
|
102
|
+
*/
|
|
103
|
+
private handleReasoningDone;
|
|
104
|
+
/**
|
|
105
|
+
* 处理output_item.done事件
|
|
106
|
+
*/
|
|
107
|
+
private handleOutputItemDone;
|
|
108
|
+
/**
|
|
109
|
+
* 处理required_action事件
|
|
110
|
+
*/
|
|
111
|
+
private handleRequiredAction;
|
|
112
|
+
/**
|
|
113
|
+
* 处理response.done事件
|
|
114
|
+
*/
|
|
115
|
+
private handleResponseDone;
|
|
116
|
+
/**
|
|
117
|
+
* 处理错误事件
|
|
118
|
+
*/
|
|
119
|
+
private handleError;
|
|
120
|
+
private handleResponseCompleted;
|
|
121
|
+
/**
|
|
122
|
+
* 构建输出项列表
|
|
123
|
+
*/
|
|
124
|
+
private buildOutputItems;
|
|
125
|
+
/**
|
|
126
|
+
* 构建消息项并根据需要拆分reasoning
|
|
127
|
+
*/
|
|
128
|
+
private buildMessageItem;
|
|
129
|
+
/**
|
|
130
|
+
* 构建函数调用项
|
|
131
|
+
*/
|
|
132
|
+
private buildFunctionCallItem;
|
|
133
|
+
/**
|
|
134
|
+
* 构建推理项
|
|
135
|
+
*/
|
|
136
|
+
private buildReasoningItem;
|
|
137
|
+
/**
|
|
138
|
+
* 获取构建结果
|
|
139
|
+
*/
|
|
140
|
+
getResult(): {
|
|
141
|
+
success: boolean;
|
|
142
|
+
response?: ResponsesResponse;
|
|
143
|
+
error?: Error;
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* 获取当前状态
|
|
147
|
+
*/
|
|
148
|
+
getState(): ResponseBuilderState;
|
|
149
|
+
/**
|
|
150
|
+
* 重置构建器
|
|
151
|
+
*/
|
|
152
|
+
reset(): void;
|
|
153
|
+
/**
|
|
154
|
+
* 获取输出项构建器
|
|
155
|
+
*/
|
|
156
|
+
getOutputItemBuilders(): Map<string, OutputItemState>;
|
|
157
|
+
/**
|
|
158
|
+
* 获取最后序列号
|
|
159
|
+
*/
|
|
160
|
+
getLastSequenceNumber(): number;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* 创建响应构建器工厂
|
|
164
|
+
*/
|
|
165
|
+
export declare function createResponseBuilder(config?: Partial<ResponseBuilderConfig>): ResponsesResponseBuilder;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Responses响应构建器
|
|
3
3
|
* 负责状态机和事件聚合,从SSE事件构建完整的Responses响应对象
|
|
4
4
|
*/
|
|
5
|
+
import { normalizeResponsesMessageItem } from '../../shared/responses-output-normalizer.js';
|
|
5
6
|
// 默认配置
|
|
6
7
|
export const DEFAULT_RESPONSE_BUILDER_CONFIG = {
|
|
7
8
|
enableStrictValidation: true,
|
|
@@ -636,8 +637,14 @@ export class ResponsesResponseBuilder {
|
|
|
636
637
|
let outputItem;
|
|
637
638
|
switch (state.type) {
|
|
638
639
|
case 'message':
|
|
639
|
-
|
|
640
|
-
|
|
640
|
+
{
|
|
641
|
+
const { message, reasoning } = this.buildMessageItem(state);
|
|
642
|
+
if (reasoning) {
|
|
643
|
+
outputItems.push(reasoning);
|
|
644
|
+
}
|
|
645
|
+
outputItem = message;
|
|
646
|
+
break;
|
|
647
|
+
}
|
|
641
648
|
case 'function_call':
|
|
642
649
|
outputItem = this.buildFunctionCallItem(state);
|
|
643
650
|
break;
|
|
@@ -649,19 +656,33 @@ export class ResponsesResponseBuilder {
|
|
|
649
656
|
}
|
|
650
657
|
outputItems.push(outputItem);
|
|
651
658
|
}
|
|
659
|
+
const hasMessage = outputItems.some(item => item.type === 'message');
|
|
660
|
+
const hasReasoning = outputItems.some(item => item.type === 'reasoning');
|
|
661
|
+
if (!hasMessage && hasReasoning) {
|
|
662
|
+
outputItems.push({
|
|
663
|
+
id: `message_placeholder_${outputItems.length + 1}`,
|
|
664
|
+
type: 'message',
|
|
665
|
+
status: 'completed',
|
|
666
|
+
role: 'assistant',
|
|
667
|
+
content: [{ type: 'output_text', text: '' }]
|
|
668
|
+
});
|
|
669
|
+
}
|
|
652
670
|
return outputItems;
|
|
653
671
|
}
|
|
654
672
|
/**
|
|
655
|
-
*
|
|
673
|
+
* 构建消息项并根据需要拆分reasoning
|
|
656
674
|
*/
|
|
657
675
|
buildMessageItem(state) {
|
|
658
|
-
return {
|
|
676
|
+
return normalizeResponsesMessageItem({
|
|
659
677
|
id: state.id,
|
|
660
678
|
type: 'message',
|
|
661
679
|
status: 'completed',
|
|
662
|
-
role: 'assistant',
|
|
680
|
+
role: state.role || 'assistant',
|
|
663
681
|
content: state.contentParts
|
|
664
|
-
}
|
|
682
|
+
}, {
|
|
683
|
+
requestId: state.id || 'message',
|
|
684
|
+
outputIndex: 0
|
|
685
|
+
});
|
|
665
686
|
}
|
|
666
687
|
/**
|
|
667
688
|
* 构建函数调用项
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat SSE → JSON转换器
|
|
3
|
+
* 将SSE事件流聚合为ChatCompletion响应
|
|
4
|
+
*/
|
|
5
|
+
import { ChatCompletionResponse, ChatSseEvent, SseToChatJsonOptions, ChatEventStats, DEFAULT_CHAT_CONVERSION_CONFIG } from '../types/index.js';
|
|
6
|
+
/**
|
|
7
|
+
* Chat SSE到JSON转换器
|
|
8
|
+
*/
|
|
9
|
+
export declare class ChatSseToJsonConverter {
|
|
10
|
+
private config;
|
|
11
|
+
private contexts;
|
|
12
|
+
constructor(config?: Partial<typeof DEFAULT_CHAT_CONVERSION_CONFIG>);
|
|
13
|
+
/**
|
|
14
|
+
* 将SSE流转换为Chat Completion响应
|
|
15
|
+
*/
|
|
16
|
+
convertSseToJson(sseStream: AsyncIterable<ChatSseEvent> | AsyncIterable<string | Buffer>, options: SseToChatJsonOptions): Promise<ChatCompletionResponse>;
|
|
17
|
+
/**
|
|
18
|
+
* 将SSE流转换为流式响应
|
|
19
|
+
*/
|
|
20
|
+
aggregateSseStream(sseStream: AsyncIterable<ChatSseEvent> | AsyncIterable<string | Buffer>, options: SseToChatJsonOptions): AsyncGenerator<ChatCompletionResponse>;
|
|
21
|
+
/**
|
|
22
|
+
* 确保输入流转换为 ChatSseEvent 流
|
|
23
|
+
*/
|
|
24
|
+
private ensureEventStream;
|
|
25
|
+
/**
|
|
26
|
+
* 将SSE文本块解析为Chat事件
|
|
27
|
+
*/
|
|
28
|
+
private parseSseChunk;
|
|
29
|
+
/**
|
|
30
|
+
* 创建转换上下文
|
|
31
|
+
*/
|
|
32
|
+
private createContext;
|
|
33
|
+
/**
|
|
34
|
+
* 处理SSE事件
|
|
35
|
+
*/
|
|
36
|
+
private processSseEvent;
|
|
37
|
+
/**
|
|
38
|
+
* 处理chat_chunk事件
|
|
39
|
+
*/
|
|
40
|
+
private processChatChunk;
|
|
41
|
+
/**
|
|
42
|
+
* 处理choice
|
|
43
|
+
*/
|
|
44
|
+
private processChoice;
|
|
45
|
+
/**
|
|
46
|
+
* 创建choice构建器
|
|
47
|
+
*/
|
|
48
|
+
private createChoiceBuilder;
|
|
49
|
+
/**
|
|
50
|
+
* 将reasoning文本附加到消息内容
|
|
51
|
+
*/
|
|
52
|
+
private appendReasoningToMessageContent;
|
|
53
|
+
/**
|
|
54
|
+
* 处理delta
|
|
55
|
+
*/
|
|
56
|
+
private processDelta;
|
|
57
|
+
/**
|
|
58
|
+
* 处理tool_call delta
|
|
59
|
+
*/
|
|
60
|
+
private processToolCallDelta;
|
|
61
|
+
/**
|
|
62
|
+
* 更新响应中的choice
|
|
63
|
+
*/
|
|
64
|
+
private updateResponseChoice;
|
|
65
|
+
/**
|
|
66
|
+
* 将reasoning内容规范化为独立字段并抽取工具调用
|
|
67
|
+
*/
|
|
68
|
+
private normalizeReasoning;
|
|
69
|
+
/**
|
|
70
|
+
* 处理done事件
|
|
71
|
+
*/
|
|
72
|
+
private processDoneEvent;
|
|
73
|
+
/**
|
|
74
|
+
* 处理error事件
|
|
75
|
+
*/
|
|
76
|
+
private processErrorEvent;
|
|
77
|
+
/**
|
|
78
|
+
* 构建部分响应
|
|
79
|
+
*/
|
|
80
|
+
private buildPartialResponse;
|
|
81
|
+
/**
|
|
82
|
+
* 完成响应构建
|
|
83
|
+
*/
|
|
84
|
+
private finalizeResponse;
|
|
85
|
+
/**
|
|
86
|
+
* 构建使用量信息
|
|
87
|
+
*/
|
|
88
|
+
private buildUsageInfo;
|
|
89
|
+
/**
|
|
90
|
+
* 验证SSE事件
|
|
91
|
+
*/
|
|
92
|
+
private validateSseEvent;
|
|
93
|
+
/**
|
|
94
|
+
* 验证Chat chunk
|
|
95
|
+
*/
|
|
96
|
+
private validateChatChunk;
|
|
97
|
+
/**
|
|
98
|
+
* 更新统计信息
|
|
99
|
+
*/
|
|
100
|
+
private updateStats;
|
|
101
|
+
/**
|
|
102
|
+
* 获取转换统计
|
|
103
|
+
*/
|
|
104
|
+
getStats(requestId: string): ChatEventStats | undefined;
|
|
105
|
+
/**
|
|
106
|
+
* 清理上下文
|
|
107
|
+
*/
|
|
108
|
+
cleanup(requestId: string): void;
|
|
109
|
+
/**
|
|
110
|
+
* 清理所有上下文
|
|
111
|
+
*/
|
|
112
|
+
cleanupAll(): void;
|
|
113
|
+
}
|
|
114
|
+
export declare const defaultChatSseToJsonConverter: ChatSseToJsonConverter;
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { DEFAULT_CHAT_CONVERSION_CONFIG, CHAT_CONVERSION_ERROR_CODES } from '../types/index.js';
|
|
6
6
|
import { TimeUtils, ErrorUtils } from '../shared/utils.js';
|
|
7
|
+
import { normalizeMessageReasoningTools } from '../../conversion/shared/reasoning-tool-normalizer.js';
|
|
8
|
+
import { normalizeChatMessageContent } from '../../conversion/shared/chat-output-normalizer.js';
|
|
9
|
+
import { dispatchReasoning } from '../shared/reasoning-dispatcher.js';
|
|
7
10
|
/**
|
|
8
11
|
* Chat SSE到JSON转换器
|
|
9
12
|
*/
|
|
@@ -270,6 +273,7 @@ export class ChatSseToJsonConverter {
|
|
|
270
273
|
messageBuilder: {
|
|
271
274
|
role: undefined,
|
|
272
275
|
content: '',
|
|
276
|
+
reasoningContent: '',
|
|
273
277
|
name: undefined,
|
|
274
278
|
functionCall: undefined,
|
|
275
279
|
toolCalls: [],
|
|
@@ -281,6 +285,19 @@ export class ChatSseToJsonConverter {
|
|
|
281
285
|
toolCallBuilders: new Map()
|
|
282
286
|
};
|
|
283
287
|
}
|
|
288
|
+
/**
|
|
289
|
+
* 将reasoning文本附加到消息内容
|
|
290
|
+
*/
|
|
291
|
+
appendReasoningToMessageContent(message, reasoningText) {
|
|
292
|
+
const trimmed = typeof reasoningText === 'string' ? reasoningText.trim() : '';
|
|
293
|
+
if (!trimmed) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const current = typeof message.content === 'string' ? message.content : '';
|
|
297
|
+
const needsSeparator = current.length > 0;
|
|
298
|
+
const separator = !needsSeparator ? '' : current.endsWith('\n') ? '\n' : '\n\n';
|
|
299
|
+
message.content = `${current}${separator}${trimmed}`;
|
|
300
|
+
}
|
|
284
301
|
/**
|
|
285
302
|
* 处理delta
|
|
286
303
|
*/
|
|
@@ -292,8 +309,9 @@ export class ChatSseToJsonConverter {
|
|
|
292
309
|
}
|
|
293
310
|
// 处理reasoning
|
|
294
311
|
if (delta.reasoning) {
|
|
295
|
-
|
|
296
|
-
|
|
312
|
+
const chunk = delta.reasoning;
|
|
313
|
+
messageBuilder.reasoningContent = (messageBuilder.reasoningContent || '') + chunk;
|
|
314
|
+
choiceBuilder.accumulatedContent += chunk;
|
|
297
315
|
}
|
|
298
316
|
// 处理content
|
|
299
317
|
if (delta.content) {
|
|
@@ -379,9 +397,19 @@ export class ChatSseToJsonConverter {
|
|
|
379
397
|
const message = {
|
|
380
398
|
role: messageBuilder.role || 'assistant'
|
|
381
399
|
};
|
|
382
|
-
|
|
400
|
+
const normalizedContent = normalizeChatMessageContent(messageBuilder.content);
|
|
401
|
+
if (normalizedContent.contentText !== undefined) {
|
|
402
|
+
message.content = normalizedContent.contentText;
|
|
403
|
+
}
|
|
404
|
+
else if (messageBuilder.content) {
|
|
383
405
|
message.content = messageBuilder.content;
|
|
384
406
|
}
|
|
407
|
+
const reasoningCandidate = messageBuilder.reasoningContent && messageBuilder.reasoningContent.length
|
|
408
|
+
? messageBuilder.reasoningContent
|
|
409
|
+
: normalizedContent.reasoningText;
|
|
410
|
+
if (reasoningCandidate) {
|
|
411
|
+
message.reasoning_content = reasoningCandidate;
|
|
412
|
+
}
|
|
385
413
|
if (messageBuilder.functionCall) {
|
|
386
414
|
message.function_call = messageBuilder.functionCall;
|
|
387
415
|
}
|
|
@@ -402,10 +430,58 @@ export class ChatSseToJsonConverter {
|
|
|
402
430
|
if (toolCalls.length > 0) {
|
|
403
431
|
message.tool_calls = toolCalls;
|
|
404
432
|
}
|
|
433
|
+
this.normalizeReasoning(choiceBuilder, message, context);
|
|
405
434
|
responseChoice.message = message;
|
|
406
435
|
responseChoice.finish_reason = choiceBuilder.finishReason ?? responseChoice.finish_reason;
|
|
407
436
|
context.eventStats.totalToolCalls += toolCalls.length;
|
|
408
437
|
}
|
|
438
|
+
/**
|
|
439
|
+
* 将reasoning内容规范化为独立字段并抽取工具调用
|
|
440
|
+
*/
|
|
441
|
+
normalizeReasoning(choiceBuilder, message, context) {
|
|
442
|
+
if (!message.reasoning_content && !message.reasoning) {
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
const target = message;
|
|
446
|
+
normalizeMessageReasoningTools(target, {
|
|
447
|
+
idPrefix: `chat_sse_reasoning_${choiceBuilder.index + 1}`
|
|
448
|
+
});
|
|
449
|
+
const reasoningSource = typeof target.reasoning_content === 'string'
|
|
450
|
+
? target.reasoning_content
|
|
451
|
+
: typeof target.reasoning === 'string'
|
|
452
|
+
? target.reasoning
|
|
453
|
+
: undefined;
|
|
454
|
+
const reasoningText = typeof reasoningSource === 'string' ? reasoningSource.trim() : '';
|
|
455
|
+
if (!reasoningText) {
|
|
456
|
+
if ('reasoning_content' in target)
|
|
457
|
+
delete target.reasoning_content;
|
|
458
|
+
if ('reasoning' in target)
|
|
459
|
+
delete target.reasoning;
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
const dispatchResult = dispatchReasoning(reasoningText, {
|
|
463
|
+
mode: context.options.reasoningMode ?? this.config.reasoningMode,
|
|
464
|
+
prefix: context.options.reasoningTextPrefix ?? this.config.reasoningTextPrefix
|
|
465
|
+
});
|
|
466
|
+
if (dispatchResult.appendToContent) {
|
|
467
|
+
this.appendReasoningToMessageContent(message, dispatchResult.appendToContent);
|
|
468
|
+
if ('reasoning_content' in target)
|
|
469
|
+
delete target.reasoning_content;
|
|
470
|
+
if ('reasoning' in target)
|
|
471
|
+
delete target.reasoning;
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
if (dispatchResult.channel) {
|
|
475
|
+
target.reasoning_content = dispatchResult.channel;
|
|
476
|
+
if ('reasoning' in target)
|
|
477
|
+
delete target.reasoning;
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
if ('reasoning_content' in target)
|
|
481
|
+
delete target.reasoning_content;
|
|
482
|
+
if ('reasoning' in target)
|
|
483
|
+
delete target.reasoning;
|
|
484
|
+
}
|
|
409
485
|
/**
|
|
410
486
|
* 处理done事件
|
|
411
487
|
*/
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { GeminiResponse, SseToGeminiJsonOptions, DEFAULT_GEMINI_CONVERSION_CONFIG } from '../types/index.js';
|
|
2
|
+
export declare class GeminiSseToJsonConverter {
|
|
3
|
+
private config;
|
|
4
|
+
private contexts;
|
|
5
|
+
constructor(config?: Partial<typeof DEFAULT_GEMINI_CONVERSION_CONFIG>);
|
|
6
|
+
convertSseToJson(sseStream: AsyncIterable<string | Buffer>, options: SseToGeminiJsonOptions): Promise<GeminiResponse>;
|
|
7
|
+
private processChunkEvent;
|
|
8
|
+
private buildResponse;
|
|
9
|
+
private normalizeStream;
|
|
10
|
+
private createContext;
|
|
11
|
+
private wrapError;
|
|
12
|
+
private normalizeReasoningPart;
|
|
13
|
+
}
|