@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.
Files changed (159) hide show
  1. package/dist/conversion/codec-registry.js +11 -1
  2. package/dist/conversion/codecs/anthropic-openai-codec.d.ts +13 -0
  3. package/dist/conversion/codecs/anthropic-openai-codec.js +18 -473
  4. package/dist/conversion/codecs/gemini-openai-codec.js +91 -48
  5. package/dist/conversion/codecs/responses-openai-codec.js +9 -2
  6. package/dist/conversion/hub/format-adapters/anthropic-format-adapter.js +3 -0
  7. package/dist/conversion/hub/format-adapters/chat-format-adapter.js +3 -0
  8. package/dist/conversion/hub/format-adapters/gemini-format-adapter.js +3 -0
  9. package/dist/conversion/hub/format-adapters/responses-format-adapter.d.ts +19 -0
  10. package/dist/conversion/hub/format-adapters/responses-format-adapter.js +9 -0
  11. package/dist/conversion/hub/node-support.js +3 -1
  12. package/dist/conversion/hub/pipeline/hub-pipeline.js +37 -32
  13. package/dist/conversion/hub/response/provider-response.js +1 -1
  14. package/dist/conversion/hub/response/response-mappers.js +1 -1
  15. package/dist/conversion/hub/response/response-runtime.js +109 -10
  16. package/dist/conversion/hub/semantic-mappers/anthropic-mapper.js +70 -156
  17. package/dist/conversion/hub/semantic-mappers/chat-mapper.js +63 -52
  18. package/dist/conversion/hub/semantic-mappers/gemini-mapper.js +76 -143
  19. package/dist/conversion/hub/semantic-mappers/responses-mapper.js +40 -160
  20. package/dist/conversion/hub/standardized-bridge.js +3 -0
  21. package/dist/conversion/hub/tool-governance/rules.js +2 -2
  22. package/dist/conversion/index.d.ts +5 -0
  23. package/dist/conversion/index.js +5 -0
  24. package/dist/conversion/pipeline/codecs/v2/anthropic-openai-pipeline.d.ts +12 -0
  25. package/dist/conversion/pipeline/codecs/v2/anthropic-openai-pipeline.js +100 -0
  26. package/dist/conversion/pipeline/codecs/v2/openai-openai-pipeline.d.ts +15 -0
  27. package/dist/conversion/pipeline/codecs/v2/openai-openai-pipeline.js +174 -0
  28. package/dist/conversion/pipeline/codecs/v2/responses-openai-pipeline.d.ts +14 -0
  29. package/dist/conversion/pipeline/codecs/v2/responses-openai-pipeline.js +166 -0
  30. package/dist/conversion/pipeline/codecs/v2/shared/openai-chat-helpers.d.ts +13 -0
  31. package/dist/conversion/pipeline/codecs/v2/shared/openai-chat-helpers.js +66 -0
  32. package/dist/conversion/pipeline/hooks/adapter-context.d.ts +7 -0
  33. package/dist/conversion/pipeline/hooks/adapter-context.js +18 -0
  34. package/dist/conversion/pipeline/hooks/protocol-hooks.d.ts +67 -0
  35. package/dist/conversion/pipeline/hooks/protocol-hooks.js +1 -0
  36. package/dist/conversion/pipeline/index.d.ts +35 -0
  37. package/dist/conversion/pipeline/index.js +103 -0
  38. package/dist/conversion/pipeline/meta/meta-bag.d.ts +20 -0
  39. package/dist/conversion/pipeline/meta/meta-bag.js +81 -0
  40. package/dist/conversion/pipeline/schema/canonical-chat.d.ts +18 -0
  41. package/dist/conversion/pipeline/schema/canonical-chat.js +1 -0
  42. package/dist/conversion/pipeline/schema/index.d.ts +1 -0
  43. package/dist/conversion/pipeline/schema/index.js +1 -0
  44. package/dist/conversion/responses/responses-openai-bridge.d.ts +48 -0
  45. package/dist/conversion/responses/responses-openai-bridge.js +157 -1146
  46. package/dist/conversion/shared/anthropic-message-utils.d.ts +12 -0
  47. package/dist/conversion/shared/anthropic-message-utils.js +587 -0
  48. package/dist/conversion/shared/bridge-actions.d.ts +39 -0
  49. package/dist/conversion/shared/bridge-actions.js +709 -0
  50. package/dist/conversion/shared/bridge-conversation-store.d.ts +41 -0
  51. package/dist/conversion/shared/bridge-conversation-store.js +279 -0
  52. package/dist/conversion/shared/bridge-id-utils.d.ts +7 -0
  53. package/dist/conversion/shared/bridge-id-utils.js +42 -0
  54. package/dist/conversion/shared/bridge-instructions.d.ts +1 -0
  55. package/dist/conversion/shared/bridge-instructions.js +113 -0
  56. package/dist/conversion/shared/bridge-message-types.d.ts +39 -0
  57. package/dist/conversion/shared/bridge-message-types.js +1 -0
  58. package/dist/conversion/shared/bridge-message-utils.d.ts +22 -0
  59. package/dist/conversion/shared/bridge-message-utils.js +473 -0
  60. package/dist/conversion/shared/bridge-metadata.d.ts +1 -0
  61. package/dist/conversion/shared/bridge-metadata.js +1 -0
  62. package/dist/conversion/shared/bridge-policies.d.ts +18 -0
  63. package/dist/conversion/shared/bridge-policies.js +276 -0
  64. package/dist/conversion/shared/bridge-request-adapter.d.ts +28 -0
  65. package/dist/conversion/shared/bridge-request-adapter.js +430 -0
  66. package/dist/conversion/shared/chat-output-normalizer.d.ts +4 -0
  67. package/dist/conversion/shared/chat-output-normalizer.js +56 -0
  68. package/dist/conversion/shared/chat-request-filters.js +24 -1
  69. package/dist/conversion/shared/gemini-tool-utils.d.ts +5 -0
  70. package/dist/conversion/shared/gemini-tool-utils.js +130 -0
  71. package/dist/conversion/shared/metadata-passthrough.d.ts +11 -0
  72. package/dist/conversion/shared/metadata-passthrough.js +57 -0
  73. package/dist/conversion/shared/output-content-normalizer.d.ts +12 -0
  74. package/dist/conversion/shared/output-content-normalizer.js +119 -0
  75. package/dist/conversion/shared/reasoning-normalizer.d.ts +21 -0
  76. package/dist/conversion/shared/reasoning-normalizer.js +368 -0
  77. package/dist/conversion/shared/reasoning-tool-normalizer.d.ts +12 -0
  78. package/dist/conversion/shared/reasoning-tool-normalizer.js +132 -0
  79. package/dist/conversion/shared/reasoning-tool-parser.d.ts +10 -0
  80. package/dist/conversion/shared/reasoning-tool-parser.js +95 -0
  81. package/dist/conversion/shared/reasoning-utils.d.ts +2 -0
  82. package/dist/conversion/shared/reasoning-utils.js +42 -0
  83. package/dist/conversion/shared/responses-conversation-store.js +5 -11
  84. package/dist/conversion/shared/responses-message-utils.d.ts +15 -0
  85. package/dist/conversion/shared/responses-message-utils.js +206 -0
  86. package/dist/conversion/shared/responses-output-builder.d.ts +15 -0
  87. package/dist/conversion/shared/responses-output-builder.js +179 -0
  88. package/dist/conversion/shared/responses-output-utils.d.ts +7 -0
  89. package/dist/conversion/shared/responses-output-utils.js +108 -0
  90. package/dist/conversion/shared/responses-request-adapter.d.ts +28 -0
  91. package/dist/conversion/shared/responses-request-adapter.js +9 -40
  92. package/dist/conversion/shared/responses-response-utils.d.ts +3 -0
  93. package/dist/conversion/shared/responses-response-utils.js +209 -0
  94. package/dist/conversion/shared/responses-tool-utils.d.ts +12 -0
  95. package/dist/conversion/shared/responses-tool-utils.js +90 -0
  96. package/dist/conversion/shared/responses-types.d.ts +33 -0
  97. package/dist/conversion/shared/responses-types.js +1 -0
  98. package/dist/conversion/shared/tool-call-utils.d.ts +11 -0
  99. package/dist/conversion/shared/tool-call-utils.js +56 -0
  100. package/dist/conversion/shared/tool-mapping.d.ts +19 -0
  101. package/dist/conversion/shared/tool-mapping.js +124 -0
  102. package/dist/conversion/shared/tool-normalizers.d.ts +4 -0
  103. package/dist/conversion/shared/tool-normalizers.js +84 -0
  104. package/dist/router/virtual-router/bootstrap.js +18 -3
  105. package/dist/router/virtual-router/provider-registry.js +4 -2
  106. package/dist/router/virtual-router/types.d.ts +212 -0
  107. package/dist/sse/index.d.ts +38 -2
  108. package/dist/sse/index.js +27 -0
  109. package/dist/sse/json-to-sse/anthropic-json-to-sse-converter.d.ts +14 -0
  110. package/dist/sse/json-to-sse/anthropic-json-to-sse-converter.js +106 -73
  111. package/dist/sse/json-to-sse/chat-json-to-sse-converter.js +6 -2
  112. package/dist/sse/json-to-sse/gemini-json-to-sse-converter.d.ts +14 -0
  113. package/dist/sse/json-to-sse/gemini-json-to-sse-converter.js +99 -0
  114. package/dist/sse/json-to-sse/index.d.ts +7 -0
  115. package/dist/sse/json-to-sse/index.js +2 -0
  116. package/dist/sse/json-to-sse/sequencers/anthropic-sequencer.d.ts +13 -0
  117. package/dist/sse/json-to-sse/sequencers/anthropic-sequencer.js +150 -0
  118. package/dist/sse/json-to-sse/sequencers/chat-sequencer.d.ts +39 -0
  119. package/dist/sse/json-to-sse/sequencers/chat-sequencer.js +49 -3
  120. package/dist/sse/json-to-sse/sequencers/gemini-sequencer.d.ts +10 -0
  121. package/dist/sse/json-to-sse/sequencers/gemini-sequencer.js +95 -0
  122. package/dist/sse/json-to-sse/sequencers/responses-sequencer.js +31 -5
  123. package/dist/sse/registry/sse-codec-registry.d.ts +32 -0
  124. package/dist/sse/registry/sse-codec-registry.js +30 -1
  125. package/dist/sse/shared/reasoning-dispatcher.d.ts +10 -0
  126. package/dist/sse/shared/reasoning-dispatcher.js +25 -0
  127. package/dist/sse/shared/responses-output-normalizer.d.ts +12 -0
  128. package/dist/sse/shared/responses-output-normalizer.js +45 -0
  129. package/dist/sse/shared/serializers/anthropic-event-serializer.d.ts +2 -0
  130. package/dist/sse/shared/serializers/anthropic-event-serializer.js +9 -0
  131. package/dist/sse/shared/serializers/gemini-event-serializer.d.ts +2 -0
  132. package/dist/sse/shared/serializers/gemini-event-serializer.js +5 -0
  133. package/dist/sse/shared/serializers/index.d.ts +41 -0
  134. package/dist/sse/shared/serializers/index.js +2 -0
  135. package/dist/sse/shared/writer.d.ts +127 -0
  136. package/dist/sse/shared/writer.js +37 -1
  137. package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.d.ts +11 -0
  138. package/dist/sse/sse-to-json/anthropic-sse-to-json-converter.js +92 -127
  139. package/dist/sse/sse-to-json/builders/anthropic-response-builder.d.ts +16 -0
  140. package/dist/sse/sse-to-json/builders/anthropic-response-builder.js +151 -0
  141. package/dist/sse/sse-to-json/builders/response-builder.d.ts +165 -0
  142. package/dist/sse/sse-to-json/builders/response-builder.js +27 -6
  143. package/dist/sse/sse-to-json/chat-sse-to-json-converter.d.ts +114 -0
  144. package/dist/sse/sse-to-json/chat-sse-to-json-converter.js +79 -3
  145. package/dist/sse/sse-to-json/gemini-sse-to-json-converter.d.ts +13 -0
  146. package/dist/sse/sse-to-json/gemini-sse-to-json-converter.js +160 -0
  147. package/dist/sse/sse-to-json/index.d.ts +7 -0
  148. package/dist/sse/sse-to-json/index.js +2 -0
  149. package/dist/sse/sse-to-json/parsers/sse-parser.js +53 -1
  150. package/dist/sse/types/anthropic-types.d.ts +170 -0
  151. package/dist/sse/types/anthropic-types.js +8 -5
  152. package/dist/sse/types/chat-types.d.ts +10 -0
  153. package/dist/sse/types/chat-types.js +2 -1
  154. package/dist/sse/types/core-interfaces.d.ts +1 -1
  155. package/dist/sse/types/gemini-types.d.ts +116 -0
  156. package/dist/sse/types/gemini-types.js +5 -0
  157. package/dist/sse/types/index.d.ts +5 -2
  158. package/dist/sse/types/index.js +2 -0
  159. 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
- outputItem = this.buildMessageItem(state);
640
- break;
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
- messageBuilder.content += delta.reasoning;
296
- choiceBuilder.accumulatedContent += delta.reasoning;
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
- if (messageBuilder.content) {
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
+ }