@huyooo/ai-chat-core 0.3.7 → 0.3.8
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/adapter/index.d.ts +0 -1
- package/dist/adapter/model-adapter.d.ts +0 -1
- package/dist/adapter/model-options.d.ts +0 -1
- package/dist/adapter/types.d.ts +0 -1
- package/dist/chat-runtime.d.ts +0 -1
- package/dist/constants.d.ts +0 -1
- package/dist/events.d.ts +0 -1
- package/dist/extension/index.d.ts +0 -1
- package/dist/extension/types.d.ts +0 -1
- package/dist/families/index.d.ts +0 -1
- package/dist/families/presets.d.ts +0 -1
- package/dist/families/resolver.d.ts +0 -1
- package/dist/families/types.d.ts +0 -1
- package/dist/governance/command-safety.d.ts +0 -1
- package/dist/governance/governance.d.ts +0 -1
- package/dist/governance/index.d.ts +0 -1
- package/dist/governance/types.d.ts +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/internal/management-args.d.ts +0 -1
- package/dist/internal/management-results.d.ts +0 -1
- package/dist/llm-config.d.ts +0 -1
- package/dist/logger/core.d.ts +0 -1
- package/dist/logger/index.d.ts +0 -1
- package/dist/orchestrator/compression-handler.d.ts +0 -1
- package/dist/orchestrator/context-compressor.d.ts +0 -1
- package/dist/orchestrator/context-summarizer.d.ts +0 -1
- package/dist/orchestrator/index.d.ts +0 -1
- package/dist/orchestrator/orchestrator.d.ts +0 -1
- package/dist/orchestrator/types.d.ts +0 -1
- package/dist/parts/index.d.ts +0 -1
- package/dist/parts/registry.d.ts +0 -1
- package/dist/parts/summaries.d.ts +0 -1
- package/dist/parts/types.d.ts +0 -1
- package/dist/platform.d.ts +0 -1
- package/dist/protocols/anthropic.d.ts +0 -1
- package/dist/protocols/ark.d.ts +0 -1
- package/dist/protocols/deepseek.d.ts +0 -1
- package/dist/protocols/error-utils.d.ts +0 -1
- package/dist/protocols/gemini.d.ts +0 -1
- package/dist/protocols/glm.d.ts +0 -1
- package/dist/protocols/grok.d.ts +0 -1
- package/dist/protocols/index.d.ts +0 -1
- package/dist/protocols/minimax.d.ts +0 -1
- package/dist/protocols/moonshot.d.ts +0 -1
- package/dist/protocols/openai-sse.d.ts +0 -1
- package/dist/protocols/openai.d.ts +0 -1
- package/dist/protocols/qwen.d.ts +0 -1
- package/dist/protocols/responses-sse.d.ts +0 -1
- package/dist/protocols/sse-reader.d.ts +0 -1
- package/dist/protocols/tool-arguments.d.ts +0 -1
- package/dist/protocols/types.d.ts +0 -1
- package/dist/protocols/vercel-gateway.d.ts +0 -1
- package/dist/runtime.d.ts +0 -1
- package/dist/skills/index.d.ts +0 -1
- package/dist/skills/management/admin.d.ts +0 -1
- package/dist/skills/management/index.d.ts +0 -1
- package/dist/skills/management/inputs.d.ts +0 -1
- package/dist/skills/management/operations.d.ts +0 -1
- package/dist/skills/management/types.d.ts +0 -1
- package/dist/skills/registry.d.ts +0 -1
- package/dist/skills/summaries.d.ts +0 -1
- package/dist/skills/types.d.ts +0 -1
- package/dist/test-utils/mock-sse.d.ts +0 -1
- package/dist/tool-manager/define-tool.d.ts +0 -1
- package/dist/tool-manager/formats.d.ts +0 -1
- package/dist/tool-manager/identity.d.ts +0 -1
- package/dist/tool-manager/in-process-provider.d.ts +0 -1
- package/dist/tool-manager/index.d.ts +0 -1
- package/dist/tool-manager/manager.d.ts +0 -1
- package/dist/tool-manager/mcp-provider.d.ts +0 -1
- package/dist/tool-manager/summaries.d.ts +0 -1
- package/dist/tool-manager/types.d.ts +0 -1
- package/dist/types.d.ts +0 -1
- package/package.json +2 -3
- package/dist/adapter/index.d.ts.map +0 -1
- package/dist/adapter/model-adapter.d.ts.map +0 -1
- package/dist/adapter/model-options.d.ts.map +0 -1
- package/dist/adapter/types.d.ts.map +0 -1
- package/dist/chat-runtime.d.ts.map +0 -1
- package/dist/constants.d.ts.map +0 -1
- package/dist/events.d.ts.map +0 -1
- package/dist/extension/index.d.ts.map +0 -1
- package/dist/extension/types.d.ts.map +0 -1
- package/dist/families/index.d.ts.map +0 -1
- package/dist/families/presets.d.ts.map +0 -1
- package/dist/families/resolver.d.ts.map +0 -1
- package/dist/families/types.d.ts.map +0 -1
- package/dist/governance/command-safety.d.ts.map +0 -1
- package/dist/governance/governance.d.ts.map +0 -1
- package/dist/governance/index.d.ts.map +0 -1
- package/dist/governance/types.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/internal/management-args.d.ts.map +0 -1
- package/dist/internal/management-results.d.ts.map +0 -1
- package/dist/llm-config.d.ts.map +0 -1
- package/dist/logger/core.d.ts.map +0 -1
- package/dist/logger/index.d.ts.map +0 -1
- package/dist/orchestrator/compression-handler.d.ts.map +0 -1
- package/dist/orchestrator/context-compressor.d.ts.map +0 -1
- package/dist/orchestrator/context-summarizer.d.ts.map +0 -1
- package/dist/orchestrator/index.d.ts.map +0 -1
- package/dist/orchestrator/orchestrator.d.ts.map +0 -1
- package/dist/orchestrator/types.d.ts.map +0 -1
- package/dist/parts/index.d.ts.map +0 -1
- package/dist/parts/registry.d.ts.map +0 -1
- package/dist/parts/summaries.d.ts.map +0 -1
- package/dist/parts/types.d.ts.map +0 -1
- package/dist/platform.d.ts.map +0 -1
- package/dist/protocols/anthropic.d.ts.map +0 -1
- package/dist/protocols/ark.d.ts.map +0 -1
- package/dist/protocols/deepseek.d.ts.map +0 -1
- package/dist/protocols/error-utils.d.ts.map +0 -1
- package/dist/protocols/gemini.d.ts.map +0 -1
- package/dist/protocols/glm.d.ts.map +0 -1
- package/dist/protocols/grok.d.ts.map +0 -1
- package/dist/protocols/index.d.ts.map +0 -1
- package/dist/protocols/minimax.d.ts.map +0 -1
- package/dist/protocols/moonshot.d.ts.map +0 -1
- package/dist/protocols/openai-sse.d.ts.map +0 -1
- package/dist/protocols/openai.d.ts.map +0 -1
- package/dist/protocols/qwen.d.ts.map +0 -1
- package/dist/protocols/responses-sse.d.ts.map +0 -1
- package/dist/protocols/sse-reader.d.ts.map +0 -1
- package/dist/protocols/tool-arguments.d.ts.map +0 -1
- package/dist/protocols/types.d.ts.map +0 -1
- package/dist/protocols/vercel-gateway.d.ts.map +0 -1
- package/dist/runtime.d.ts.map +0 -1
- package/dist/skills/index.d.ts.map +0 -1
- package/dist/skills/management/admin.d.ts.map +0 -1
- package/dist/skills/management/index.d.ts.map +0 -1
- package/dist/skills/management/inputs.d.ts.map +0 -1
- package/dist/skills/management/operations.d.ts.map +0 -1
- package/dist/skills/management/types.d.ts.map +0 -1
- package/dist/skills/registry.d.ts.map +0 -1
- package/dist/skills/summaries.d.ts.map +0 -1
- package/dist/skills/types.d.ts.map +0 -1
- package/dist/test-utils/mock-sse.d.ts.map +0 -1
- package/dist/tool-manager/define-tool.d.ts.map +0 -1
- package/dist/tool-manager/formats.d.ts.map +0 -1
- package/dist/tool-manager/identity.d.ts.map +0 -1
- package/dist/tool-manager/in-process-provider.d.ts.map +0 -1
- package/dist/tool-manager/index.d.ts.map +0 -1
- package/dist/tool-manager/manager.d.ts.map +0 -1
- package/dist/tool-manager/mcp-provider.d.ts.map +0 -1
- package/dist/tool-manager/summaries.d.ts.map +0 -1
- package/dist/tool-manager/types.d.ts.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/src/adapter/index.ts +0 -25
- package/src/adapter/model-adapter.ts +0 -196
- package/src/adapter/model-options.ts +0 -143
- package/src/adapter/types.ts +0 -41
- package/src/chat-runtime.ts +0 -515
- package/src/constants.ts +0 -32
- package/src/events.ts +0 -1084
- package/src/extension/index.ts +0 -24
- package/src/extension/types.ts +0 -49
- package/src/families/index.ts +0 -28
- package/src/families/presets.ts +0 -124
- package/src/families/resolver.ts +0 -22
- package/src/families/types.ts +0 -55
- package/src/governance/command-safety.ts +0 -224
- package/src/governance/governance.ts +0 -125
- package/src/governance/index.ts +0 -38
- package/src/governance/types.ts +0 -44
- package/src/index.ts +0 -426
- package/src/internal/management-args.ts +0 -39
- package/src/internal/management-results.ts +0 -60
- package/src/llm-config.ts +0 -137
- package/src/logger/core.ts +0 -96
- package/src/logger/index.ts +0 -8
- package/src/orchestrator/compression-handler.ts +0 -137
- package/src/orchestrator/context-compressor.ts +0 -249
- package/src/orchestrator/context-summarizer.ts +0 -123
- package/src/orchestrator/index.ts +0 -20
- package/src/orchestrator/orchestrator.ts +0 -1002
- package/src/orchestrator/types.ts +0 -70
- package/src/parts/index.ts +0 -20
- package/src/parts/registry.ts +0 -95
- package/src/parts/summaries.ts +0 -40
- package/src/parts/types.ts +0 -63
- package/src/platform.ts +0 -73
- package/src/protocols/anthropic.ts +0 -377
- package/src/protocols/ark.ts +0 -300
- package/src/protocols/deepseek.ts +0 -192
- package/src/protocols/error-utils.ts +0 -71
- package/src/protocols/gemini.ts +0 -352
- package/src/protocols/glm.ts +0 -212
- package/src/protocols/grok.ts +0 -98
- package/src/protocols/index.ts +0 -48
- package/src/protocols/minimax.ts +0 -308
- package/src/protocols/moonshot.ts +0 -186
- package/src/protocols/openai-sse.ts +0 -156
- package/src/protocols/openai.ts +0 -97
- package/src/protocols/qwen.ts +0 -358
- package/src/protocols/responses-sse.ts +0 -224
- package/src/protocols/sse-reader.ts +0 -54
- package/src/protocols/tool-arguments.ts +0 -32
- package/src/protocols/types.ts +0 -198
- package/src/protocols/vercel-gateway.ts +0 -391
- package/src/runtime.ts +0 -167
- package/src/skills/index.ts +0 -29
- package/src/skills/management/admin.ts +0 -170
- package/src/skills/management/index.ts +0 -27
- package/src/skills/management/inputs.ts +0 -79
- package/src/skills/management/operations.ts +0 -256
- package/src/skills/management/types.ts +0 -57
- package/src/skills/registry.ts +0 -120
- package/src/skills/summaries.ts +0 -48
- package/src/skills/types.ts +0 -65
- package/src/test-utils/mock-sse.ts +0 -32
- package/src/tool-manager/define-tool.ts +0 -201
- package/src/tool-manager/formats.ts +0 -146
- package/src/tool-manager/identity.ts +0 -80
- package/src/tool-manager/in-process-provider.ts +0 -164
- package/src/tool-manager/index.ts +0 -63
- package/src/tool-manager/manager.ts +0 -562
- package/src/tool-manager/mcp-provider.ts +0 -509
- package/src/tool-manager/summaries.ts +0 -136
- package/src/tool-manager/types.ts +0 -389
- package/src/types.ts +0 -1142
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Moonshot Protocol(Kimi K2.5 OpenAI 兼容 API)
|
|
3
|
-
*
|
|
4
|
-
* 完全兼容 OpenAI Chat Completions 格式,主要区别:
|
|
5
|
-
* - thinking 参数:`"reasoning": {"enabled": true}` + `temperature: 1.0`
|
|
6
|
-
* - 默认 URL:https://api.moonshot.cn/v1
|
|
7
|
-
* - 流式 thinking 输出:delta.reasoning_content(与 DeepSeek/GLM 一致)
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type {
|
|
11
|
-
Protocol,
|
|
12
|
-
ProtocolConfig,
|
|
13
|
-
ProtocolMessage,
|
|
14
|
-
ProtocolToolDefinition,
|
|
15
|
-
ProtocolRequestOptions,
|
|
16
|
-
RawEvent,
|
|
17
|
-
} from './types';
|
|
18
|
-
import { createModuleLogger } from '../logger';
|
|
19
|
-
import { friendlyHttpError } from './error-utils';
|
|
20
|
-
import { readSSEJsonStream } from './sse-reader';
|
|
21
|
-
import { mapOpenAIStream } from './openai-sse';
|
|
22
|
-
import type { OpenAIStreamConfig } from './openai-sse';
|
|
23
|
-
|
|
24
|
-
const logger = createModuleLogger('MoonshotProtocol');
|
|
25
|
-
|
|
26
|
-
const DEFAULT_MOONSHOT_URL = 'https://api.moonshot.cn/v1';
|
|
27
|
-
|
|
28
|
-
const MOONSHOT_SSE_CONFIG: OpenAIStreamConfig = {
|
|
29
|
-
thinkingField: (delta) => delta.reasoning_content as string | undefined,
|
|
30
|
-
errorFinishReasons: ['content_filter'],
|
|
31
|
-
protocolName: 'Moonshot',
|
|
32
|
-
parseUsage: (usage) => ({
|
|
33
|
-
promptTokens: (usage.prompt_tokens as number) ?? 0,
|
|
34
|
-
completionTokens: (usage.completion_tokens as number) ?? 0,
|
|
35
|
-
totalTokens: (usage.total_tokens as number) ?? 0,
|
|
36
|
-
cachedTokens: (usage.prompt_tokens_details as Record<string, number> | undefined)?.cached_tokens ?? 0,
|
|
37
|
-
}),
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export class MoonshotProtocol implements Protocol {
|
|
41
|
-
readonly name = 'moonshot';
|
|
42
|
-
|
|
43
|
-
private apiKey: string;
|
|
44
|
-
private apiUrl: string;
|
|
45
|
-
|
|
46
|
-
constructor(config: ProtocolConfig) {
|
|
47
|
-
this.apiKey = config.apiKey;
|
|
48
|
-
this.apiUrl = config.apiUrl || DEFAULT_MOONSHOT_URL;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async *stream(
|
|
52
|
-
messages: ProtocolMessage[],
|
|
53
|
-
tools: ProtocolToolDefinition[],
|
|
54
|
-
options: ProtocolRequestOptions
|
|
55
|
-
): AsyncGenerator<RawEvent> {
|
|
56
|
-
const requestBody = this.buildRequestBody(messages, tools, options);
|
|
57
|
-
const url = `${this.apiUrl}/chat/completions`;
|
|
58
|
-
|
|
59
|
-
logger.debug({
|
|
60
|
-
url,
|
|
61
|
-
model: options.model,
|
|
62
|
-
enableThinking: options.enableThinking,
|
|
63
|
-
toolsCount: tools.length,
|
|
64
|
-
}, '发送 Moonshot 请求');
|
|
65
|
-
|
|
66
|
-
const response = await fetch(url, {
|
|
67
|
-
method: 'POST',
|
|
68
|
-
headers: {
|
|
69
|
-
'Authorization': `Bearer ${this.apiKey}`,
|
|
70
|
-
'Content-Type': 'application/json',
|
|
71
|
-
},
|
|
72
|
-
body: JSON.stringify(requestBody),
|
|
73
|
-
signal: options.signal,
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
if (!response.ok) {
|
|
77
|
-
const errorText = await response.text();
|
|
78
|
-
logger.error({ status: response.status, body: errorText.slice(0, 500) }, 'Moonshot API 错误');
|
|
79
|
-
yield { type: 'error', error: friendlyHttpError(response.status, errorText, 'Moonshot') };
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const reader = response.body?.getReader();
|
|
84
|
-
if (!reader) {
|
|
85
|
-
yield { type: 'error', error: '无法获取响应流' };
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
yield* mapOpenAIStream(readSSEJsonStream(reader), MOONSHOT_SSE_CONFIG);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
private buildRequestBody(
|
|
93
|
-
messages: ProtocolMessage[],
|
|
94
|
-
tools: ProtocolToolDefinition[],
|
|
95
|
-
options: ProtocolRequestOptions
|
|
96
|
-
): Record<string, unknown> {
|
|
97
|
-
const convertedMessages = this.convertMessages(messages);
|
|
98
|
-
|
|
99
|
-
const body: Record<string, unknown> = {
|
|
100
|
-
model: options.model,
|
|
101
|
-
messages: convertedMessages,
|
|
102
|
-
stream: true,
|
|
103
|
-
stream_options: { include_usage: true },
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
// Moonshot thinking 格式:reasoning: {enabled: true},需 temperature=1.0
|
|
107
|
-
if (options.enableThinking) {
|
|
108
|
-
body.reasoning = { enabled: true };
|
|
109
|
-
body.temperature = 1.0;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if (tools.length > 0) {
|
|
113
|
-
body.tools = tools.map(t => ({
|
|
114
|
-
type: 'function',
|
|
115
|
-
function: {
|
|
116
|
-
name: t.name,
|
|
117
|
-
description: t.description,
|
|
118
|
-
parameters: t.parameters,
|
|
119
|
-
},
|
|
120
|
-
}));
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return body;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
private convertMessages(messages: ProtocolMessage[]): unknown[] {
|
|
127
|
-
const result: unknown[] = [];
|
|
128
|
-
|
|
129
|
-
for (const msg of messages) {
|
|
130
|
-
switch (msg.role) {
|
|
131
|
-
case 'system':
|
|
132
|
-
result.push({ role: 'system', content: msg.content });
|
|
133
|
-
break;
|
|
134
|
-
|
|
135
|
-
case 'user': {
|
|
136
|
-
const textContent = msg.content || (msg.images?.length ? '请分析这张图片' : '');
|
|
137
|
-
if (msg.images?.length) {
|
|
138
|
-
const content: unknown[] = [{ type: 'text', text: textContent }];
|
|
139
|
-
for (const img of msg.images) {
|
|
140
|
-
content.push({
|
|
141
|
-
type: 'image_url',
|
|
142
|
-
image_url: { url: img.startsWith('data:') ? img : `data:image/jpeg;base64,${img}` },
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
result.push({ role: 'user', content });
|
|
146
|
-
} else {
|
|
147
|
-
result.push({ role: 'user', content: textContent });
|
|
148
|
-
}
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
case 'assistant':
|
|
153
|
-
if (msg.toolCalls?.length) {
|
|
154
|
-
result.push({
|
|
155
|
-
role: 'assistant',
|
|
156
|
-
content: msg.content || null,
|
|
157
|
-
...(msg.thinkingContent ? { reasoning_content: msg.thinkingContent } : {}),
|
|
158
|
-
tool_calls: msg.toolCalls.map(tc => ({
|
|
159
|
-
id: tc.id,
|
|
160
|
-
type: 'function',
|
|
161
|
-
function: { name: tc.name, arguments: tc.arguments },
|
|
162
|
-
})),
|
|
163
|
-
});
|
|
164
|
-
} else {
|
|
165
|
-
result.push({ role: 'assistant', content: msg.content });
|
|
166
|
-
}
|
|
167
|
-
break;
|
|
168
|
-
|
|
169
|
-
case 'tool':
|
|
170
|
-
result.push({
|
|
171
|
-
role: 'tool',
|
|
172
|
-
tool_call_id: msg.toolCallId,
|
|
173
|
-
content: msg.content,
|
|
174
|
-
});
|
|
175
|
-
break;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return result;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
export function createMoonshotProtocol(config: ProtocolConfig): MoonshotProtocol {
|
|
185
|
-
return new MoonshotProtocol(config);
|
|
186
|
-
}
|
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Layer 2: OpenAI 兼容 SSE 语义映射器
|
|
3
|
-
*
|
|
4
|
-
* 消费 Layer 1 的 JSON 流,映射为 RawEvent。
|
|
5
|
-
* 通过 config 注入协议差异,零 if/else 分支。
|
|
6
|
-
*
|
|
7
|
-
* 共享逻辑:
|
|
8
|
-
* - choices[0].delta.content → text_delta
|
|
9
|
-
* - delta.tool_calls → tool_call_start / tool_call_done
|
|
10
|
-
* - thinking 状态机(首段 text 自动关闭 thinking)
|
|
11
|
-
* - [流结束] tool_call_done 发射 + done 事件
|
|
12
|
-
*
|
|
13
|
-
* 使用方:deepseek, glm, moonshot, grok, openai
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import type { RawEvent, RawToolCall, RawTokenUsage } from './types';
|
|
17
|
-
import { createModuleLogger } from '../logger';
|
|
18
|
-
|
|
19
|
-
const logger = createModuleLogger('OpenAISSE');
|
|
20
|
-
|
|
21
|
-
// ==================== 配置接口 ====================
|
|
22
|
-
|
|
23
|
-
export interface OpenAIStreamConfig {
|
|
24
|
-
/** 从 delta 提取 thinking 内容(不提供 = 不支持 thinking) */
|
|
25
|
-
thinkingField?: (delta: Record<string, unknown>) => string | undefined;
|
|
26
|
-
/** 厂商特有的 finish_reason → error 映射(列出视为 error 的 reason) */
|
|
27
|
-
errorFinishReasons?: string[];
|
|
28
|
-
/** 协议名(用于错误消息) */
|
|
29
|
-
protocolName?: string;
|
|
30
|
-
/** 自定义 usage 提取(不提供则用默认 OpenAI 格式) */
|
|
31
|
-
parseUsage?: (usage: Record<string, unknown>) => RawTokenUsage;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// ==================== 默认 usage 提取 ====================
|
|
35
|
-
|
|
36
|
-
function defaultParseUsage(usage: Record<string, unknown>): RawTokenUsage {
|
|
37
|
-
const details = usage.completion_tokens_details as Record<string, number> | undefined;
|
|
38
|
-
const promptDetails = usage.prompt_tokens_details as Record<string, number> | undefined;
|
|
39
|
-
return {
|
|
40
|
-
promptTokens: (usage.prompt_tokens as number) ?? 0,
|
|
41
|
-
completionTokens: (usage.completion_tokens as number) ?? 0,
|
|
42
|
-
totalTokens: (usage.total_tokens as number) ?? 0,
|
|
43
|
-
reasoningTokens: details?.reasoning_tokens ?? 0,
|
|
44
|
-
cachedTokens: promptDetails?.cached_tokens ?? (usage.prompt_cache_hit_tokens as number) ?? 0,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// ==================== finish_reason 映射 ====================
|
|
49
|
-
|
|
50
|
-
function mapFinishReason(
|
|
51
|
-
reason: string | undefined,
|
|
52
|
-
errorReasons?: string[],
|
|
53
|
-
): RawEvent['finishReason'] {
|
|
54
|
-
if (!reason) return 'stop';
|
|
55
|
-
if (reason === 'tool_calls' || reason === 'length' || reason === 'error') return reason;
|
|
56
|
-
if (errorReasons?.includes(reason)) return 'error';
|
|
57
|
-
return 'stop';
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// ==================== 核心映射器 ====================
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* 将 OpenAI 兼容的 JSON 流映射为 RawEvent 流
|
|
64
|
-
*
|
|
65
|
-
* @param jsonStream - Layer 1 的 readSSEJsonStream 输出
|
|
66
|
-
* @param config - 协议差异配置(可选,不传则为标准 OpenAI 行为)
|
|
67
|
-
*/
|
|
68
|
-
export async function* mapOpenAIStream(
|
|
69
|
-
jsonStream: AsyncGenerator<Record<string, unknown>>,
|
|
70
|
-
config?: OpenAIStreamConfig,
|
|
71
|
-
): AsyncGenerator<RawEvent> {
|
|
72
|
-
const toolCallsMap = new Map<number, RawToolCall>();
|
|
73
|
-
let textStarted = false;
|
|
74
|
-
let thinkingDone = false;
|
|
75
|
-
let lastUsage: RawTokenUsage | undefined;
|
|
76
|
-
let lastFinishReason: string | undefined;
|
|
77
|
-
|
|
78
|
-
const parseUsage = config?.parseUsage ?? defaultParseUsage;
|
|
79
|
-
const thinkingField = config?.thinkingField;
|
|
80
|
-
|
|
81
|
-
for await (const json of jsonStream) {
|
|
82
|
-
// Usage
|
|
83
|
-
if (json.usage) {
|
|
84
|
-
lastUsage = parseUsage(json.usage as Record<string, unknown>);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const choices = json.choices as Array<Record<string, unknown>> | undefined;
|
|
88
|
-
const choice = choices?.[0];
|
|
89
|
-
if (!choice) continue;
|
|
90
|
-
|
|
91
|
-
const delta = choice.delta as Record<string, unknown> | undefined;
|
|
92
|
-
if (!delta) continue;
|
|
93
|
-
|
|
94
|
-
// Thinking
|
|
95
|
-
if (thinkingField && !thinkingDone) {
|
|
96
|
-
const thinking = thinkingField(delta);
|
|
97
|
-
if (thinking) {
|
|
98
|
-
yield { type: 'thinking_delta', delta: thinking };
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Text
|
|
103
|
-
const content = delta.content as string | undefined;
|
|
104
|
-
if (content) {
|
|
105
|
-
if (!textStarted && !thinkingDone && thinkingField) {
|
|
106
|
-
thinkingDone = true;
|
|
107
|
-
yield { type: 'thinking_done' };
|
|
108
|
-
}
|
|
109
|
-
textStarted = true;
|
|
110
|
-
yield { type: 'text_delta', delta: content };
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Tool calls
|
|
114
|
-
const toolCalls = delta.tool_calls as Array<Record<string, unknown>> | undefined;
|
|
115
|
-
if (toolCalls?.length) {
|
|
116
|
-
for (const tc of toolCalls) {
|
|
117
|
-
const index = (tc.index as number) ?? 0;
|
|
118
|
-
const fn = tc.function as Record<string, string> | undefined;
|
|
119
|
-
const existing = toolCallsMap.get(index);
|
|
120
|
-
|
|
121
|
-
if (existing) {
|
|
122
|
-
if (fn?.arguments) {
|
|
123
|
-
existing.arguments += fn.arguments;
|
|
124
|
-
}
|
|
125
|
-
} else {
|
|
126
|
-
const id = (tc.id as string) || `call_${index}`;
|
|
127
|
-
const name = fn?.name || '';
|
|
128
|
-
toolCallsMap.set(index, { id, name, arguments: fn?.arguments || '' });
|
|
129
|
-
yield { type: 'tool_call_start', toolCall: { id, name } };
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Finish reason
|
|
135
|
-
const finishReason = choice.finish_reason as string | undefined;
|
|
136
|
-
if (finishReason) {
|
|
137
|
-
lastFinishReason = finishReason;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// 流结束:发射累积的 tool calls + done
|
|
142
|
-
const allToolCalls = Array.from(toolCallsMap.values());
|
|
143
|
-
if (allToolCalls.length > 0) {
|
|
144
|
-
for (const tc of allToolCalls) {
|
|
145
|
-
yield { type: 'tool_call_done', toolCall: tc };
|
|
146
|
-
}
|
|
147
|
-
yield { type: 'done', finishReason: 'tool_calls', usage: lastUsage };
|
|
148
|
-
} else {
|
|
149
|
-
const reason = mapFinishReason(lastFinishReason, config?.errorFinishReasons);
|
|
150
|
-
if (reason === 'error') {
|
|
151
|
-
const name = config?.protocolName ?? 'LLM';
|
|
152
|
-
yield { type: 'error', error: `${name} 推理异常 (finish_reason: ${lastFinishReason})` };
|
|
153
|
-
}
|
|
154
|
-
yield { type: 'done', finishReason: reason, usage: lastUsage };
|
|
155
|
-
}
|
|
156
|
-
}
|
package/src/protocols/openai.ts
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OpenAI Protocol(Responses API)
|
|
3
|
-
*
|
|
4
|
-
* 使用 /v1/responses 端点,统一支持所有 OpenAI 模型(GPT、Codex、o-series)。
|
|
5
|
-
*
|
|
6
|
-
* 支持直连或代理(如 llm.huyooo.com):
|
|
7
|
-
* - 直连:apiUrl = https://api.openai.com/v1,Key 走 Authorization
|
|
8
|
-
* - 代理:apiUrl = https://llm.huyooo.com/openai,Key 为代理认证
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import type {
|
|
12
|
-
Protocol,
|
|
13
|
-
ProtocolConfig,
|
|
14
|
-
ProtocolMessage,
|
|
15
|
-
ProtocolToolDefinition,
|
|
16
|
-
ProtocolRequestOptions,
|
|
17
|
-
RawEvent,
|
|
18
|
-
} from './types';
|
|
19
|
-
import { createModuleLogger } from '../logger';
|
|
20
|
-
import { friendlyHttpError } from './error-utils';
|
|
21
|
-
import { convertToResponsesInput, convertToResponsesTools, mapResponsesStream } from './responses-sse';
|
|
22
|
-
|
|
23
|
-
const logger = createModuleLogger('OpenAIProtocol');
|
|
24
|
-
|
|
25
|
-
const DEFAULT_OPENAI_URL = 'https://api.openai.com/v1';
|
|
26
|
-
|
|
27
|
-
export class OpenAIProtocol implements Protocol {
|
|
28
|
-
readonly name = 'openai';
|
|
29
|
-
|
|
30
|
-
private apiKey: string;
|
|
31
|
-
private apiUrl: string;
|
|
32
|
-
|
|
33
|
-
constructor(config: ProtocolConfig) {
|
|
34
|
-
this.apiKey = config.apiKey;
|
|
35
|
-
this.apiUrl = config.apiUrl ?? DEFAULT_OPENAI_URL;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async *stream(
|
|
39
|
-
messages: ProtocolMessage[],
|
|
40
|
-
tools: ProtocolToolDefinition[],
|
|
41
|
-
options: ProtocolRequestOptions,
|
|
42
|
-
): AsyncGenerator<RawEvent> {
|
|
43
|
-
const body: Record<string, unknown> = {
|
|
44
|
-
model: options.model,
|
|
45
|
-
input: convertToResponsesInput(messages),
|
|
46
|
-
stream: true,
|
|
47
|
-
max_output_tokens: options.maxOutputTokens,
|
|
48
|
-
store: false,
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
if (options.enableThinking) {
|
|
52
|
-
body.reasoning = { effort: 'high' };
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (tools.length > 0) {
|
|
56
|
-
body.tools = convertToResponsesTools(tools);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const url = `${this.apiUrl}/responses`;
|
|
60
|
-
|
|
61
|
-
logger.debug({
|
|
62
|
-
url: url.replace(this.apiKey, '***'),
|
|
63
|
-
model: options.model,
|
|
64
|
-
enableThinking: options.enableThinking,
|
|
65
|
-
toolsCount: tools.length,
|
|
66
|
-
}, 'OpenAI Responses 请求');
|
|
67
|
-
|
|
68
|
-
const response = await fetch(url, {
|
|
69
|
-
method: 'POST',
|
|
70
|
-
headers: {
|
|
71
|
-
'Authorization': `Bearer ${this.apiKey}`,
|
|
72
|
-
'Content-Type': 'application/json',
|
|
73
|
-
},
|
|
74
|
-
body: JSON.stringify(body),
|
|
75
|
-
signal: options.signal,
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
if (!response.ok) {
|
|
79
|
-
const errorText = await response.text();
|
|
80
|
-
logger.error({ status: response.status, body: errorText.slice(0, 500) }, 'OpenAI API 错误');
|
|
81
|
-
yield { type: 'error', error: friendlyHttpError(response.status, errorText, 'OpenAI') };
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const reader = response.body?.getReader();
|
|
86
|
-
if (!reader) {
|
|
87
|
-
yield { type: 'error', error: '无法获取响应流' };
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
yield* mapResponsesStream(reader, { protocolName: 'OpenAI' });
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export function createOpenAIProtocol(config: ProtocolConfig): OpenAIProtocol {
|
|
96
|
-
return new OpenAIProtocol(config);
|
|
97
|
-
}
|