@astack-tech/integrations 0.1.1-beta.5 → 0.2.0-beta.10
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/CHANGELOG.md +63 -0
- package/README.md +98 -1
- package/dist/index.cjs +230 -242
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +230 -242
- package/dist/index.js.map +1 -1
- package/dist/model-provider/index.cjs +232 -243
- package/dist/model-provider/index.cjs.map +1 -1
- package/dist/model-provider/index.d.cts +225 -146
- package/dist/model-provider/index.d.ts +225 -146
- package/dist/model-provider/index.js +230 -242
- package/dist/model-provider/index.js.map +1 -1
- package/package.json +48 -27
- package/src/index.ts +5 -3
- package/src/model-provider/deepseek/index.ts +35 -591
- package/src/model-provider/index.ts +23 -2
- package/src/model-provider/openai-compatible/index.ts +531 -0
|
@@ -1,306 +1,294 @@
|
|
|
1
|
-
// src/model-provider/
|
|
1
|
+
// src/model-provider/openai-compatible/index.ts
|
|
2
2
|
import { Component } from "@astack-tech/core";
|
|
3
3
|
import OpenAI from "openai";
|
|
4
|
-
var
|
|
4
|
+
var DEFAULT_BASE_URL = "https://api.openai.com/v1";
|
|
5
|
+
var DEFAULT_NAME = "The model API";
|
|
6
|
+
var DEFAULT_TEMPERATURE = 0.7;
|
|
7
|
+
var FALLBACK_TEXT = "API call failed";
|
|
8
|
+
function isRecord(value) {
|
|
9
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10
|
+
}
|
|
11
|
+
function toApiTool(tool) {
|
|
12
|
+
const raw = isRecord(tool) ? tool : {};
|
|
13
|
+
const definition = raw["function"];
|
|
14
|
+
if (raw["type"] === "function" && isRecord(definition)) {
|
|
15
|
+
const { name: name2, description: description2, parameters: parameters2, strict } = definition;
|
|
16
|
+
return {
|
|
17
|
+
type: "function",
|
|
18
|
+
function: {
|
|
19
|
+
name: typeof name2 === "string" ? name2 : "",
|
|
20
|
+
...typeof description2 === "string" ? { description: description2 } : {},
|
|
21
|
+
...isRecord(parameters2) ? { parameters: parameters2 } : {},
|
|
22
|
+
...typeof strict === "boolean" ? { strict } : {}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const { name, description, parameters } = raw;
|
|
27
|
+
return {
|
|
28
|
+
type: "function",
|
|
29
|
+
function: {
|
|
30
|
+
name: typeof name === "string" ? name : "",
|
|
31
|
+
description: typeof description === "string" ? description : "",
|
|
32
|
+
parameters: isRecord(parameters) ? parameters : {}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function parseArguments(raw) {
|
|
37
|
+
if (raw.trim().length === 0) {
|
|
38
|
+
return {};
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const parsed = JSON.parse(raw);
|
|
42
|
+
return isRecord(parsed) ? parsed : {};
|
|
43
|
+
} catch {
|
|
44
|
+
return {};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function mapUsage(usage) {
|
|
48
|
+
return {
|
|
49
|
+
completion_tokens: usage.completion_tokens ?? 0,
|
|
50
|
+
prompt_tokens: usage.prompt_tokens ?? 0,
|
|
51
|
+
total_tokens: usage.total_tokens ?? 0,
|
|
52
|
+
...usage.prompt_cache_hit_tokens === void 0 ? {} : { prompt_cache_hit_tokens: usage.prompt_cache_hit_tokens },
|
|
53
|
+
...usage.prompt_cache_miss_tokens === void 0 ? {} : { prompt_cache_miss_tokens: usage.prompt_cache_miss_tokens }
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
var OpenAICompatible = class extends Component {
|
|
57
|
+
client;
|
|
58
|
+
model;
|
|
59
|
+
temperature;
|
|
60
|
+
maxTokens;
|
|
61
|
+
topP;
|
|
62
|
+
systemPrompt;
|
|
63
|
+
tools;
|
|
64
|
+
verbose;
|
|
65
|
+
name;
|
|
5
66
|
constructor(config) {
|
|
6
67
|
super({});
|
|
7
68
|
this.client = new OpenAI({
|
|
8
69
|
apiKey: config.apiKey,
|
|
9
|
-
baseURL: config.baseURL
|
|
70
|
+
baseURL: config.baseURL ?? DEFAULT_BASE_URL,
|
|
10
71
|
dangerouslyAllowBrowser: config.dangerouslyAllowBrowser ?? false
|
|
11
72
|
});
|
|
12
|
-
this.model = config.model
|
|
13
|
-
this.
|
|
73
|
+
this.model = config.model;
|
|
74
|
+
this.name = config.name ?? DEFAULT_NAME;
|
|
75
|
+
this.temperature = config.temperature ?? DEFAULT_TEMPERATURE;
|
|
14
76
|
this.maxTokens = config.maxTokens;
|
|
15
77
|
this.topP = config.topP;
|
|
16
78
|
this.systemPrompt = config.systemPrompt;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
type: "function",
|
|
20
|
-
function: {
|
|
21
|
-
name: tool.name,
|
|
22
|
-
description: tool.description,
|
|
23
|
-
parameters: tool.parameters || {}
|
|
24
|
-
}
|
|
25
|
-
}));
|
|
26
|
-
} else {
|
|
27
|
-
this.tools = config.tools;
|
|
28
|
-
}
|
|
79
|
+
this.verbose = config.verbose ?? false;
|
|
80
|
+
this.tools = config.rawTools !== void 0 && config.rawTools.length > 0 ? config.rawTools.map(toApiTool) : config.tools;
|
|
29
81
|
Component.Port.I("prompt").attach(this);
|
|
30
82
|
Component.Port.I("messages").attach(this);
|
|
31
83
|
Component.Port.O("completion").attach(this);
|
|
32
84
|
Component.Port.O("message").attach(this);
|
|
33
85
|
}
|
|
34
86
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* @returns
|
|
87
|
+
* Generates a completion for a single prompt.
|
|
88
|
+
*
|
|
89
|
+
* @returns The text answer, or the JSON-encoded assistant message when it contains tool calls.
|
|
38
90
|
*/
|
|
39
91
|
async generateCompletion(prompt) {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
messages.
|
|
43
|
-
|
|
44
|
-
content: this.systemPrompt
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
messages.push({
|
|
48
|
-
role: "user",
|
|
49
|
-
content: prompt
|
|
92
|
+
const response = await this.client.chat.completions.create({
|
|
93
|
+
...this.baseRequest(),
|
|
94
|
+
messages: [...this.systemMessages(), { role: "user", content: prompt }],
|
|
95
|
+
...this.toolsParam(this.tools)
|
|
50
96
|
});
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
temperature: this.temperature,
|
|
55
|
-
max_tokens: this.maxTokens,
|
|
56
|
-
top_p: this.topP
|
|
57
|
-
};
|
|
58
|
-
if (this.tools && this.tools.length > 0) {
|
|
59
|
-
requestParams.tools = this.tools;
|
|
60
|
-
}
|
|
61
|
-
const response = await this.client.chat.completions.create(requestParams);
|
|
62
|
-
if (response.choices[0].message.tool_calls && response.choices[0].message.tool_calls.length > 0) {
|
|
63
|
-
return JSON.stringify(response.choices[0].message);
|
|
97
|
+
const message = this.firstMessage(response);
|
|
98
|
+
if (message.tool_calls !== void 0 && message.tool_calls.length > 0) {
|
|
99
|
+
return JSON.stringify(message);
|
|
64
100
|
}
|
|
65
|
-
return
|
|
101
|
+
return message.content ?? "";
|
|
66
102
|
}
|
|
67
103
|
/**
|
|
68
|
-
*
|
|
69
|
-
* @param messages 对话消息数组
|
|
70
|
-
* @param options 可选的调用选项,包含临时工具列表
|
|
71
|
-
* @returns 生成的流式响应消息异步生成器
|
|
104
|
+
* Sends a conversation and returns the assistant reply.
|
|
72
105
|
*/
|
|
73
|
-
async
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
106
|
+
async chatCompletion(messages, options) {
|
|
107
|
+
const response = await this.client.chat.completions.create({
|
|
108
|
+
...this.baseRequest(),
|
|
109
|
+
messages: this.formatMessages(messages),
|
|
110
|
+
...this.toolsParam(options?.temporaryTools ?? this.tools)
|
|
111
|
+
});
|
|
112
|
+
const message = this.firstMessage(response);
|
|
113
|
+
const result = { role: "assistant", content: message.content ?? "" };
|
|
114
|
+
if (response.usage !== void 0) {
|
|
115
|
+
result.usage = mapUsage(response.usage);
|
|
80
116
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
content: msg.content
|
|
86
|
-
};
|
|
87
|
-
if (msg.role === "tool" && msg.tool_call_id) {
|
|
88
|
-
formattedMsg.tool_call_id = msg.tool_call_id;
|
|
89
|
-
}
|
|
90
|
-
return formattedMsg;
|
|
91
|
-
})
|
|
92
|
-
);
|
|
93
|
-
const requestParams = {
|
|
94
|
-
model: this.model,
|
|
95
|
-
messages: formattedMessages,
|
|
96
|
-
temperature: this.temperature,
|
|
97
|
-
max_tokens: this.maxTokens,
|
|
98
|
-
top_p: this.topP,
|
|
99
|
-
stream: true
|
|
100
|
-
// 开启流式模式
|
|
101
|
-
};
|
|
102
|
-
const toolsToUse = options?.temporaryTools || this.tools;
|
|
103
|
-
if (toolsToUse && toolsToUse.length > 0) {
|
|
104
|
-
const formattedTools = toolsToUse.map((tool) => {
|
|
105
|
-
const typedTool = tool;
|
|
106
|
-
if (typedTool.type === "function") {
|
|
107
|
-
return tool;
|
|
117
|
+
if (message.tool_calls !== void 0 && message.tool_calls.length > 0) {
|
|
118
|
+
result.tool_calls = message.tool_calls.map((toolCall) => {
|
|
119
|
+
if (toolCall.type !== "function") {
|
|
120
|
+
throw new Error(`Unsupported tool call type: ${toolCall.type}`);
|
|
108
121
|
}
|
|
122
|
+
const rawArguments = toolCall.function.arguments;
|
|
109
123
|
return {
|
|
124
|
+
id: toolCall.id,
|
|
110
125
|
type: "function",
|
|
111
126
|
function: {
|
|
112
|
-
name:
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
127
|
+
name: toolCall.function.name,
|
|
128
|
+
arguments: rawArguments.length > 0 ? rawArguments : "{}"
|
|
129
|
+
},
|
|
130
|
+
tool_name: toolCall.function.name,
|
|
131
|
+
arguments: parseArguments(rawArguments)
|
|
116
132
|
};
|
|
117
133
|
});
|
|
118
|
-
requestParams.tools = formattedTools;
|
|
119
134
|
}
|
|
120
|
-
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Streams the assistant reply. Each chunk holds a text delta, tool-call deltas, or usage.
|
|
139
|
+
*/
|
|
140
|
+
async *streamChatCompletion(messages, options) {
|
|
141
|
+
const stream = await this.client.chat.completions.create({
|
|
142
|
+
...this.baseRequest(),
|
|
143
|
+
messages: this.formatMessages(messages),
|
|
144
|
+
...this.toolsParam(options?.temporaryTools ?? this.tools),
|
|
145
|
+
stream: true
|
|
146
|
+
});
|
|
121
147
|
for await (const chunk of stream) {
|
|
122
148
|
const delta = chunk.choices[0]?.delta;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
content: delta.content
|
|
127
|
-
};
|
|
149
|
+
const text = delta?.content ?? "";
|
|
150
|
+
if (text !== "") {
|
|
151
|
+
yield { role: "assistant", content: text };
|
|
128
152
|
}
|
|
129
153
|
if (delta?.tool_calls) {
|
|
130
154
|
yield {
|
|
131
155
|
role: "assistant",
|
|
132
156
|
content: "",
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
})
|
|
157
|
+
tool_calls: delta.tool_calls.map((toolCall) => {
|
|
158
|
+
const name = toolCall.function?.name ?? "";
|
|
159
|
+
const args = toolCall.function?.arguments ?? "";
|
|
160
|
+
return {
|
|
161
|
+
id: toolCall.id ?? "",
|
|
162
|
+
type: "function",
|
|
163
|
+
function: { name, arguments: args },
|
|
164
|
+
tool_name: name,
|
|
165
|
+
arguments: args
|
|
166
|
+
};
|
|
167
|
+
})
|
|
144
168
|
};
|
|
145
169
|
}
|
|
146
170
|
if (chunk.usage) {
|
|
147
|
-
yield {
|
|
148
|
-
role: "assistant",
|
|
149
|
-
content: "",
|
|
150
|
-
usage: {
|
|
151
|
-
completion_tokens: chunk.usage.completion_tokens || 0,
|
|
152
|
-
prompt_tokens: chunk.usage.prompt_tokens || 0,
|
|
153
|
-
prompt_cache_hit_tokens: chunk.usage.prompt_cache_hit_tokens,
|
|
154
|
-
prompt_cache_miss_tokens: chunk.usage.prompt_cache_miss_tokens,
|
|
155
|
-
total_tokens: chunk.usage.total_tokens || 0
|
|
156
|
-
}
|
|
157
|
-
};
|
|
171
|
+
yield { role: "assistant", content: "", usage: mapUsage(chunk.usage) };
|
|
158
172
|
}
|
|
159
173
|
}
|
|
160
174
|
}
|
|
161
175
|
/**
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
* @param
|
|
165
|
-
* @returns 生成的响应消息
|
|
176
|
+
* Runs the model outside a pipeline.
|
|
177
|
+
*
|
|
178
|
+
* @param input - A prompt string or a list of messages.
|
|
166
179
|
*/
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
run(input) {
|
|
181
|
+
return typeof input === "string" ? this.generateCompletion(input) : this.chatCompletion(input);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Connects the `prompt` and `messages` input ports to the model.
|
|
185
|
+
* API errors produce a fallback value so the pipeline keeps flowing.
|
|
186
|
+
*/
|
|
187
|
+
_transform($i, $o) {
|
|
188
|
+
$i("prompt").receive((prompt) => {
|
|
189
|
+
this.generateCompletion(prompt).then(
|
|
190
|
+
(completion) => {
|
|
191
|
+
$o("completion").send(completion);
|
|
192
|
+
},
|
|
193
|
+
(error) => {
|
|
194
|
+
this.logError(error);
|
|
195
|
+
$o("completion").send(FALLBACK_TEXT);
|
|
196
|
+
}
|
|
197
|
+
);
|
|
198
|
+
});
|
|
199
|
+
$i("messages").receive((messages) => {
|
|
200
|
+
this.chatCompletion(messages).then(
|
|
201
|
+
(message) => {
|
|
202
|
+
$o("message").send(message);
|
|
203
|
+
},
|
|
204
|
+
(error) => {
|
|
205
|
+
this.logError(error);
|
|
206
|
+
$o("message").send({ role: "assistant", content: FALLBACK_TEXT });
|
|
183
207
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
208
|
+
);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
baseRequest() {
|
|
212
|
+
return {
|
|
188
213
|
model: this.model,
|
|
189
|
-
messages: formattedMessages,
|
|
190
214
|
temperature: this.temperature,
|
|
191
|
-
max_tokens: this.maxTokens,
|
|
192
|
-
top_p: this.topP
|
|
193
|
-
};
|
|
194
|
-
const toolsToUse = options?.temporaryTools || this.tools;
|
|
195
|
-
if (toolsToUse && toolsToUse.length > 0) {
|
|
196
|
-
const formattedTools = toolsToUse.map((tool) => {
|
|
197
|
-
const typedTool = tool;
|
|
198
|
-
if (typedTool.type === "function") {
|
|
199
|
-
return tool;
|
|
200
|
-
}
|
|
201
|
-
return {
|
|
202
|
-
type: "function",
|
|
203
|
-
function: {
|
|
204
|
-
name: typedTool.name,
|
|
205
|
-
description: typedTool.description,
|
|
206
|
-
parameters: typedTool.parameters || {}
|
|
207
|
-
}
|
|
208
|
-
};
|
|
209
|
-
});
|
|
210
|
-
requestParams.tools = formattedTools;
|
|
211
|
-
}
|
|
212
|
-
const response = await this.client.chat.completions.create(requestParams);
|
|
213
|
-
const responseMessage = response.choices[0].message;
|
|
214
|
-
const result = {
|
|
215
|
-
role: "assistant",
|
|
216
|
-
content: responseMessage.content || ""
|
|
215
|
+
...this.maxTokens === void 0 ? {} : { max_tokens: this.maxTokens },
|
|
216
|
+
...this.topP === void 0 ? {} : { top_p: this.topP }
|
|
217
217
|
};
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
prompt_cache_miss_tokens: usage.prompt_cache_miss_tokens,
|
|
225
|
-
total_tokens: usage.total_tokens || 0
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
if (responseMessage.tool_calls && responseMessage.tool_calls.length > 0) {
|
|
229
|
-
result.tool_calls = responseMessage.tool_calls.map((toolCall) => {
|
|
230
|
-
let args;
|
|
231
|
-
const rawArgs = toolCall.function.arguments;
|
|
232
|
-
if (typeof rawArgs === "string") {
|
|
233
|
-
const raw = rawArgs;
|
|
234
|
-
try {
|
|
235
|
-
args = raw && raw.trim().length > 0 ? JSON.parse(raw) : {};
|
|
236
|
-
} catch {
|
|
237
|
-
args = {};
|
|
238
|
-
}
|
|
239
|
-
} else if (rawArgs && typeof rawArgs === "object") {
|
|
240
|
-
args = rawArgs;
|
|
241
|
-
} else {
|
|
242
|
-
args = {};
|
|
243
|
-
}
|
|
244
|
-
return {
|
|
245
|
-
id: toolCall.id,
|
|
246
|
-
// 满足 Agent 组件期望的格式
|
|
247
|
-
function: {
|
|
248
|
-
name: toolCall.function.name,
|
|
249
|
-
arguments: toolCall.function.arguments || "{}"
|
|
250
|
-
},
|
|
251
|
-
type: "function",
|
|
252
|
-
// 满足内部 ToolCall 接口
|
|
253
|
-
tool_name: toolCall.function.name,
|
|
254
|
-
arguments: args
|
|
255
|
-
};
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
return result;
|
|
218
|
+
}
|
|
219
|
+
toolsParam(tools) {
|
|
220
|
+
return tools !== void 0 && tools.length > 0 ? { tools: tools.map(toApiTool) } : {};
|
|
221
|
+
}
|
|
222
|
+
systemMessages() {
|
|
223
|
+
return this.systemPrompt === void 0 || this.systemPrompt === "" ? [] : [{ role: "system", content: this.systemPrompt }];
|
|
259
224
|
}
|
|
260
225
|
/**
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
*
|
|
226
|
+
* Converts input messages to API messages. Assistant `tool_calls` are not forwarded:
|
|
227
|
+
* agents send tool results back as user messages, and the API rejects assistant tool
|
|
228
|
+
* calls that are not followed by tool messages.
|
|
264
229
|
*/
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
return this.generateCompletion(input);
|
|
268
|
-
} else {
|
|
269
|
-
return this.chatCompletion(input);
|
|
270
|
-
}
|
|
230
|
+
formatMessages(messages) {
|
|
231
|
+
return [...this.systemMessages(), ...messages.map((message) => this.toApiMessage(message))];
|
|
271
232
|
}
|
|
272
233
|
/**
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
* @
|
|
234
|
+
* Converts one input message to its API shape.
|
|
235
|
+
*
|
|
236
|
+
* @throws Error when the role is not one of `MessageRole`, or a `tool` message has no
|
|
237
|
+
* `tool_call_id`. The API would reject both.
|
|
276
238
|
*/
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
239
|
+
toApiMessage(message) {
|
|
240
|
+
const content = message.content ?? "";
|
|
241
|
+
switch (message.role) {
|
|
242
|
+
case "system":
|
|
243
|
+
return { role: "system", content };
|
|
244
|
+
case "user":
|
|
245
|
+
return { role: "user", content };
|
|
246
|
+
case "assistant":
|
|
247
|
+
return message.content === void 0 ? { role: "assistant" } : { role: "assistant", content: message.content };
|
|
248
|
+
case "tool":
|
|
249
|
+
if (message.tool_call_id === void 0 || message.tool_call_id === "") {
|
|
250
|
+
throw new Error(
|
|
251
|
+
`${this.name}: a tool message needs the tool_call_id of the call it answers.`
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
return { role: "tool", content, tool_call_id: message.tool_call_id };
|
|
255
|
+
default:
|
|
256
|
+
throw new Error(
|
|
257
|
+
`${this.name}: unsupported message role '${message.role}'. Use system, user, assistant or tool.`
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
firstMessage(response) {
|
|
262
|
+
const choice = response.choices[0];
|
|
263
|
+
if (choice === void 0) {
|
|
264
|
+
throw new Error(`${this.name} returned no choices.`);
|
|
265
|
+
}
|
|
266
|
+
return choice.message;
|
|
267
|
+
}
|
|
268
|
+
logError(error) {
|
|
269
|
+
if (this.verbose) {
|
|
270
|
+
console.error(`[${this.name}] API call failed:`, error);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
var openai_compatible_default = OpenAICompatible;
|
|
275
|
+
|
|
276
|
+
// src/model-provider/deepseek/index.ts
|
|
277
|
+
var DEFAULT_BASE_URL2 = "https://api.deepseek.com/v1";
|
|
278
|
+
var DEFAULT_MODEL = "deepseek-chat";
|
|
279
|
+
var Deepseek = class extends openai_compatible_default {
|
|
280
|
+
constructor(config) {
|
|
281
|
+
super({
|
|
282
|
+
...config,
|
|
283
|
+
model: config.model ?? DEFAULT_MODEL,
|
|
284
|
+
baseURL: config.baseURL ?? DEFAULT_BASE_URL2,
|
|
285
|
+
name: "DeepSeek"
|
|
299
286
|
});
|
|
300
287
|
}
|
|
301
288
|
};
|
|
302
289
|
var deepseek_default = Deepseek;
|
|
303
290
|
export {
|
|
304
|
-
deepseek_default as Deepseek
|
|
291
|
+
deepseek_default as Deepseek,
|
|
292
|
+
openai_compatible_default as OpenAICompatible
|
|
305
293
|
};
|
|
306
294
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/model-provider/deepseek/index.ts"],"sourcesContent":["import { Component } from '@astack-tech/core';\nimport OpenAI from 'openai';\n\n/**\n * Deepseek 模型提供者配置\n */\nexport interface DeepseekConfig {\n /**\n * API 密钥\n */\n apiKey: string;\n\n /**\n * 使用的模型名称\n * 默认为 'deepseek-chat'\n */\n model?: string;\n\n /**\n * 自定义 API 基础 URL\n * 默认为 Deepseek 官方 API 地址\n */\n baseURL?: string;\n\n /**\n * 温度参数,控制输出的随机性\n */\n temperature?: number;\n\n /**\n * 最大生成的 token 数\n */\n maxTokens?: number;\n\n /**\n * 采样概率\n */\n topP?: number;\n\n /**\n * 系统提示消息\n */\n systemPrompt?: string;\n\n /**\n * 工具实例数组,直接传递工具实例\n * 每个工具应具有 name、description 和 parameters 属性\n */\n rawTools?: Array<{\n name: string;\n description: string;\n parameters?: Record<string, unknown>;\n }>;\n\n /**\n * API 格式的工具定义数组,与 rawTools 二选一\n * 使用 OpenAI 兼容的工具定义格式\n */\n tools?: unknown[];\n\n /**\n * dangerouslyAllowBrowser\n * 是否允许在浏览器等非安全环境内运行\n */\n dangerouslyAllowBrowser?: boolean;\n}\n\n/**\n * 消息角色类型\n */\nexport type MessageRole = 'system' | 'user' | 'assistant' | 'tool';\n\n/**\n * 工具调用\n */\nexport interface ToolCall {\n /**\n * 工具调用 ID\n */\n id?: string;\n\n /**\n * 工具名称\n */\n tool_name: string;\n\n /**\n * 工具调用参数\n */\n arguments: Record<string, unknown>;\n}\n\n/**\n * Token 使用统计\n */\nexport interface TokenUsage {\n /**\n * 完成部分的 token 数量\n */\n completion_tokens: number;\n\n /**\n * 提示部分的 token 数量\n */\n prompt_tokens: number;\n\n /**\n * 提示缓存命中的 token 数量(可选)\n */\n prompt_cache_hit_tokens?: number;\n\n /**\n * 提示缓存未命中的 token 数量(可选)\n */\n prompt_cache_miss_tokens?: number;\n\n /**\n * 总 token 数量\n */\n total_tokens: number;\n}\n\n/**\n * 对话消息类型\n */\nexport interface Message {\n /**\n * 消息角色\n */\n role: MessageRole;\n\n /**\n * 消息内容\n */\n content?: string;\n\n /**\n * 工具调用\n */\n tool_calls?: ToolCall[];\n\n /**\n * 工具调用 ID,用于工具响应消息\n */\n tool_call_id?: string;\n\n /**\n * Token 使用统计(可选)\n */\n usage?: TokenUsage;\n}\n\n/**\n * Deepseek 组件\n *\n * 使用 OpenAI 兼容接口调用 Deepseek 模型\n *\n * 输入:\n * - prompt: 文本提示\n * - messages: 对话消息数组\n *\n * 输出:\n * - completion: 生成的文本完成\n * - message: 生成的响应消息\n */\nclass Deepseek extends Component {\n // OpenAI 客户端实例\n private client: OpenAI;\n\n // 配置选项\n private model: string;\n private temperature: number;\n private maxTokens?: number;\n private topP?: number;\n private systemPrompt?: string;\n private tools?: unknown[];\n\n constructor(config: DeepseekConfig) {\n super({});\n\n // 配置客户端\n this.client = new OpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseURL || 'https://api.deepseek.com/v1',\n dangerouslyAllowBrowser: config.dangerouslyAllowBrowser ?? false,\n });\n\n // 保存基本配置\n this.model = config.model || 'deepseek-chat';\n this.temperature = config.temperature ?? 0.7;\n this.maxTokens = config.maxTokens;\n this.topP = config.topP;\n this.systemPrompt = config.systemPrompt;\n\n // 处理工具配置,优先使用 rawTools\n if (config.rawTools && config.rawTools.length > 0) {\n // 将工具实例转换为 API 格式\n this.tools = config.rawTools.map(tool => ({\n type: 'function',\n function: {\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters || {},\n },\n }));\n } else {\n // 使用直接提供的 API 格式工具\n this.tools = config.tools;\n }\n\n // 重命名端口\n Component.Port.I('prompt').attach(this);\n Component.Port.I('messages').attach(this);\n Component.Port.O('completion').attach(this);\n Component.Port.O('message').attach(this);\n }\n\n /**\n * 生成文本完成\n * @param prompt 提示文本\n * @returns 生成的文本\n */\n async generateCompletion(prompt: string): Promise<string> {\n const messages: Array<OpenAI.Chat.ChatCompletionMessageParam> = [];\n\n // 添加系统提示\n if (this.systemPrompt) {\n messages.push({\n role: 'system',\n content: this.systemPrompt,\n });\n }\n\n // 添加用户提示\n messages.push({\n role: 'user',\n content: prompt,\n });\n\n // 创建请求参数\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const requestParams: any = {\n model: this.model,\n messages,\n temperature: this.temperature,\n max_tokens: this.maxTokens,\n top_p: this.topP,\n };\n\n // 如果有工具定义,添加到请求中\n if (this.tools && this.tools.length > 0) {\n requestParams.tools = this.tools;\n }\n\n // 调用 API\n const response = await this.client.chat.completions.create(requestParams);\n\n // 处理工具调用结果\n if (\n response.choices[0].message.tool_calls &&\n response.choices[0].message.tool_calls.length > 0\n ) {\n return JSON.stringify(response.choices[0].message);\n }\n\n return response.choices[0].message.content || '';\n }\n\n /**\n * 流式处理对话消息\n * @param messages 对话消息数组\n * @param options 可选的调用选项,包含临时工具列表\n * @returns 生成的流式响应消息异步生成器\n */\n async *streamChatCompletion(\n messages: Message[],\n options?: { temporaryTools?: unknown[] }\n ): AsyncGenerator<Partial<Message>> {\n // 转换消息格式 (复用现有逻辑)\n const formattedMessages: Array<OpenAI.Chat.ChatCompletionMessageParam> = [];\n\n // 添加系统提示\n if (this.systemPrompt) {\n formattedMessages.push({\n role: 'system',\n content: this.systemPrompt,\n });\n }\n\n // 添加用户提供的消息\n formattedMessages.push(\n ...messages.map(msg => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const formattedMsg: any = {\n role: msg.role,\n content: msg.content,\n };\n\n if (msg.role === 'tool' && msg.tool_call_id) {\n formattedMsg.tool_call_id = msg.tool_call_id;\n }\n\n return formattedMsg;\n })\n );\n\n // 创建请求参数\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const requestParams: any = {\n model: this.model,\n messages: formattedMessages,\n temperature: this.temperature,\n max_tokens: this.maxTokens,\n top_p: this.topP,\n stream: true, // 开启流式模式\n };\n\n // 决定使用哪些工具\n const toolsToUse = options?.temporaryTools || this.tools;\n\n // 如果有工具定义,添加到请求中\n if (toolsToUse && toolsToUse.length > 0) {\n const formattedTools = toolsToUse.map(tool => {\n type ToolType = {\n type?: string;\n name?: string;\n description?: string;\n parameters?: Record<string, unknown>;\n };\n\n const typedTool = tool as ToolType;\n\n if (typedTool.type === 'function') {\n return tool;\n }\n\n return {\n type: 'function',\n function: {\n name: typedTool.name,\n description: typedTool.description,\n parameters: typedTool.parameters || {},\n },\n };\n });\n\n requestParams.tools = formattedTools;\n }\n\n // 调用流式 API\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const stream = (await this.client.chat.completions.create(requestParams)) as any;\n\n // 处理流式响应\n for await (const chunk of stream) {\n const delta = chunk.choices[0]?.delta;\n\n if (delta?.content) {\n // 流式文本内容\n yield {\n role: 'assistant',\n content: delta.content,\n };\n }\n\n if (delta?.tool_calls) {\n // 流式工具调用(如果需要)\n yield {\n role: 'assistant',\n content: '',\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n tool_calls: delta.tool_calls.map((toolCall: any) => ({\n id: toolCall.id || '',\n function: {\n name: toolCall.function?.name || '',\n arguments: toolCall.function?.arguments || '',\n },\n type: 'function',\n tool_name: toolCall.function?.name || '',\n arguments: toolCall.function?.arguments || '',\n })),\n };\n }\n\n // 提取并返回 token 使用统计信息\n if (chunk.usage) {\n yield {\n role: 'assistant',\n content: '',\n usage: {\n completion_tokens: chunk.usage.completion_tokens || 0,\n prompt_tokens: chunk.usage.prompt_tokens || 0,\n prompt_cache_hit_tokens: chunk.usage.prompt_cache_hit_tokens,\n prompt_cache_miss_tokens: chunk.usage.prompt_cache_miss_tokens,\n total_tokens: chunk.usage.total_tokens || 0,\n },\n };\n }\n }\n }\n\n /**\n * 处理对话消息\n * @param messages 对话消息数组\n * @param options 可选的调用选项,包含临时工具列表\n * @returns 生成的响应消息\n */\n async chatCompletion(\n messages: Message[],\n options?: { temporaryTools?: unknown[] }\n ): Promise<Message> {\n // 转换消息格式\n const formattedMessages: Array<OpenAI.Chat.ChatCompletionMessageParam> = [];\n\n // 添加系统提示\n if (this.systemPrompt) {\n formattedMessages.push({\n role: 'system',\n content: this.systemPrompt,\n });\n }\n\n // 添加用户提供的消息\n formattedMessages.push(\n ...messages.map(msg => {\n // 基本消息结构\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const formattedMsg: any = {\n role: msg.role,\n content: msg.content,\n };\n\n // 如果有工具调用 ID,添加到消息中\n if (msg.role === 'tool' && msg.tool_call_id) {\n formattedMsg.tool_call_id = msg.tool_call_id;\n }\n\n return formattedMsg;\n })\n );\n\n // 创建请求参数\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const requestParams: any = {\n model: this.model,\n messages: formattedMessages,\n temperature: this.temperature,\n max_tokens: this.maxTokens,\n top_p: this.topP,\n };\n\n // 决定使用哪些工具\n // 如果提供了临时工具,优先使用临时工具\n const toolsToUse = options?.temporaryTools || this.tools;\n\n // 如果有工具定义,添加到请求中\n if (toolsToUse && toolsToUse.length > 0) {\n // 检查工具格式并转换,确保符合 Deepseek API 要求\n const formattedTools = toolsToUse.map(tool => {\n // 使用类型断言来处理 unknown 类型\n type ToolType = {\n type?: string;\n name?: string;\n description?: string;\n parameters?: Record<string, unknown>;\n };\n\n const typedTool = tool as ToolType;\n\n // 如果工具已经是 API 格式,直接返回\n if (typedTool.type === 'function') {\n return tool;\n }\n\n // 如果是简单工具实例,转换为 API 格式\n return {\n type: 'function',\n function: {\n name: typedTool.name,\n description: typedTool.description,\n parameters: typedTool.parameters || {},\n },\n };\n });\n\n requestParams.tools = formattedTools;\n }\n\n // 调用 API\n const response = await this.client.chat.completions.create(requestParams);\n\n // 解析响应\n const responseMessage = response.choices[0].message;\n\n // 转换为内部消息格式\n const result: Message = {\n role: 'assistant',\n content: responseMessage.content || '',\n };\n\n // 提取并添加 token 使用统计信息\n if (response.usage) {\n const usage = response.usage as typeof response.usage & {\n prompt_cache_hit_tokens?: number;\n prompt_cache_miss_tokens?: number;\n };\n result.usage = {\n completion_tokens: usage.completion_tokens || 0,\n prompt_tokens: usage.prompt_tokens || 0,\n prompt_cache_hit_tokens: usage.prompt_cache_hit_tokens,\n prompt_cache_miss_tokens: usage.prompt_cache_miss_tokens,\n total_tokens: usage.total_tokens || 0,\n };\n }\n\n // 如果有工具调用,添加到结果中\n if (responseMessage.tool_calls && responseMessage.tool_calls.length > 0) {\n // 为了兼容 Agent 组件期望的格式,保留 function 和 type 字段\n // 同时为了满足内部 ToolCall 接口,也添加 tool_name 和 arguments 字段\n result.tool_calls = responseMessage.tool_calls.map(toolCall => {\n // 解析参数,确保是对象形式\n let args: Record<string, unknown>;\n\n const rawArgs = toolCall.function.arguments;\n\n if (typeof rawArgs === 'string') {\n const raw = rawArgs;\n try {\n args = raw && raw.trim().length > 0 ? (JSON.parse(raw) as Record<string, unknown>) : {};\n } catch {\n args = {};\n }\n } else if (rawArgs && typeof rawArgs === 'object') {\n args = rawArgs as Record<string, unknown>;\n } else {\n args = {};\n }\n\n return {\n id: toolCall.id,\n // 满足 Agent 组件期望的格式\n function: {\n name: toolCall.function.name,\n arguments: toolCall.function.arguments || '{}',\n },\n type: 'function',\n // 满足内部 ToolCall 接口\n tool_name: toolCall.function.name,\n arguments: args,\n };\n });\n }\n\n return result;\n }\n\n /**\n * 在独立模式下运行组件\n * @param input 输入参数,可以是提示文本或对话消息数组\n * @returns 生成的文本或响应消息\n */\n async run(input: string | Message[]): Promise<string | Message> {\n if (typeof input === 'string') {\n return this.generateCompletion(input);\n } else {\n return this.chatCompletion(input);\n }\n }\n\n /**\n * 在流水线中运行组件\n * @param $i 输入端口\n * @param $o 输出端口\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n _transform($i: any, $o: any) {\n // 处理文本提示输入\n $i('prompt').receive(async (prompt: string) => {\n try {\n const completion = await this.generateCompletion(prompt);\n $o('completion').send(completion);\n } catch (error) {\n console.error('Deepseek API 调用错误:', error);\n $o('completion').send('API 调用错误');\n }\n });\n\n // 处理对话消息输入\n $i('messages').receive(async (messages: Message[]) => {\n try {\n const responseMessage = await this.chatCompletion(messages);\n $o('message').send(responseMessage);\n } catch (error) {\n console.error('Deepseek API 调用错误:', error);\n $o('message').send({\n role: 'assistant',\n content: 'API 调用错误',\n });\n }\n });\n }\n}\n\n// 默认导出组件\nexport default Deepseek;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/model-provider/openai-compatible/index.ts","../../src/model-provider/deepseek/index.ts"],"sourcesContent":["import { Component } from '@astack-tech/core';\nimport type { Port } from '@astack-tech/core';\nimport OpenAI from 'openai';\n\n/**\n * Options for a provider that speaks the OpenAI chat completions API.\n */\nexport interface OpenAICompatibleConfig {\n /** API key of the provider. */\n apiKey: string;\n /** Model name, for example `gpt-4o-mini`, `qwen-plus` or `llama3.1`. */\n model: string;\n /** API base URL. Defaults to `https://api.openai.com/v1`. */\n baseURL?: string | undefined;\n /** Provider name used in errors and logs. Defaults to `The model API`. */\n name?: string | undefined;\n /** Sampling temperature. Defaults to `0.7`. */\n temperature?: number | undefined;\n /** Maximum number of generated tokens. */\n maxTokens?: number | undefined;\n /** Nucleus sampling probability. */\n topP?: number | undefined;\n /** System prompt added before every request. */\n systemPrompt?: string | undefined;\n /**\n * Tools given as `{ name, description, parameters }` objects.\n * When this list is not empty, it takes precedence over `tools`.\n */\n rawTools?: RawTool[] | undefined;\n /** Tools in the OpenAI-compatible `{ type: 'function', function }` format. */\n tools?: unknown[] | undefined;\n /** Allows the OpenAI client to run in a browser. Defaults to `false`. */\n dangerouslyAllowBrowser?: boolean | undefined;\n /** Logs API errors to the console. Defaults to `false`. */\n verbose?: boolean | undefined;\n}\n\n/**\n * Tool description accepted by `rawTools` and `temporaryTools`.\n */\nexport interface RawTool {\n /** Unique tool name. */\n name: string;\n /** Description that tells the model when to use the tool. */\n description: string;\n /** JSON Schema of the arguments. Defaults to `{}`. */\n parameters?: Record<string, unknown> | undefined;\n}\n\n/**\n * Role of a chat message.\n */\nexport type MessageRole = 'system' | 'user' | 'assistant' | 'tool';\n\n/**\n * Tool call in the internal format.\n */\nexport interface ToolCall {\n /** Identifier assigned by the API. */\n id?: string | undefined;\n /** Name of the tool. */\n tool_name: string;\n /** Parsed arguments. */\n arguments: Record<string, unknown>;\n}\n\n/**\n * Tool call returned by `chatCompletion`. It carries both the OpenAI shape\n * (`type`, `function`) and the internal shape (`tool_name`, `arguments`).\n */\nexport interface ResponseToolCall {\n /** Identifier assigned by the API. A `tool` message answers the call with it. */\n id: string;\n /** Always `function`. */\n type: 'function';\n /** The call in the OpenAI shape: function name and raw JSON arguments. An empty argument string is sent as `{}`. */\n function: {\n /** Name of the tool to call. */\n name: string;\n /** Arguments as JSON text. */\n arguments: string;\n };\n /** Name of the tool, same as `function.name`. */\n tool_name: string;\n /** Parsed arguments. JSON that is not an object becomes `{}`. */\n arguments: Record<string, unknown>;\n}\n\n/**\n * Partial tool call emitted while streaming. `arguments` holds the raw JSON fragment.\n */\nexport interface StreamToolCall {\n /** Identifier assigned by the API. Only the first delta of a call carries it; later deltas have `''`. */\n id: string;\n /** Always `function`. */\n type: 'function';\n /** The delta in the OpenAI shape. `arguments` holds only this delta's JSON fragment. */\n function: {\n /** Name of the tool to call. */\n name: string;\n /** Arguments as JSON text. */\n arguments: string;\n };\n /** Name of the tool when this delta carries it, otherwise `''`. */\n tool_name: string;\n /** Raw JSON fragment of this delta. Concatenate the fragments of a call to get its arguments. */\n arguments: string;\n}\n\n/**\n * Token usage reported by the API.\n */\nexport interface TokenUsage {\n /** Tokens in the generated reply. */\n completion_tokens: number;\n /** Tokens in the request. */\n prompt_tokens: number;\n /** Prompt tokens served from the provider's context cache (reported by DeepSeek). */\n prompt_cache_hit_tokens?: number | undefined;\n /** Prompt tokens not served from the cache. */\n prompt_cache_miss_tokens?: number | undefined;\n /** Sum of prompt and completion tokens. */\n total_tokens: number;\n}\n\n/**\n * Chat message accepted as input. It matches the agent message contract in\n * `@astack-tech/components`, so agent histories can be passed directly.\n */\nexport interface Message {\n /** One of `system`, `user`, `assistant` or `tool` (see `MessageRole`). */\n role: string;\n /** Text content. Omitted content is sent as no content. */\n content?: string | undefined;\n /** Accepted for compatibility. Assistant tool calls are not forwarded to the API. */\n tool_calls?: readonly unknown[] | undefined;\n /** Identifier of the call that a `tool` message answers. */\n tool_call_id?: string | undefined;\n /** Ignored on input. Present so agent histories can be passed unchanged. */\n usage?: TokenUsage | undefined;\n}\n\n/**\n * Assistant message returned by `chatCompletion`.\n */\nexport interface AssistantMessage {\n /** Always `assistant`. */\n role: 'assistant';\n /** Reply text. Empty when the model only calls tools. */\n content: string;\n /** Tool calls requested by the model, if any. */\n tool_calls?: ResponseToolCall[] | undefined;\n /** Token usage of this request, when the API reports it. */\n usage?: TokenUsage | undefined;\n}\n\n/**\n * Chunk yielded by `streamChatCompletion`.\n */\nexport interface StreamChunk {\n /** Always `assistant`. */\n role: 'assistant';\n /** Text delta. Empty in chunks that carry tool calls or usage. */\n content: string;\n /** Tool-call deltas in this chunk. */\n tool_calls?: StreamToolCall[] | undefined;\n /** Token usage. Sent once, in the final chunk, when the API reports it. */\n usage?: TokenUsage | undefined;\n}\n\n/**\n * Per-call options.\n */\nexport interface ChatCompletionOptions {\n /** Tools for this call only. They replace the configured tools. */\n temporaryTools?: unknown[] | undefined;\n}\n\ntype ChatMessageParam = OpenAI.Chat.ChatCompletionMessageParam;\ntype ChatTool = OpenAI.Chat.ChatCompletionTool;\n\ninterface ApiUsage {\n completion_tokens?: number;\n prompt_tokens?: number;\n total_tokens?: number;\n prompt_cache_hit_tokens?: number;\n prompt_cache_miss_tokens?: number;\n}\n\nconst DEFAULT_BASE_URL = 'https://api.openai.com/v1';\nconst DEFAULT_NAME = 'The model API';\nconst DEFAULT_TEMPERATURE = 0.7;\nconst FALLBACK_TEXT = 'API call failed';\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Converts a `{ name, description, parameters }` object to the OpenAI tool format.\n * Objects already in the OpenAI format are returned unchanged.\n */\nfunction toApiTool(tool: unknown): ChatTool {\n const raw = isRecord(tool) ? tool : {};\n const definition = raw['function'];\n if (raw['type'] === 'function' && isRecord(definition)) {\n const { name, description, parameters, strict } = definition;\n return {\n type: 'function',\n function: {\n name: typeof name === 'string' ? name : '',\n ...(typeof description === 'string' ? { description } : {}),\n ...(isRecord(parameters) ? { parameters } : {}),\n ...(typeof strict === 'boolean' ? { strict } : {}),\n },\n };\n }\n const { name, description, parameters } = raw;\n return {\n type: 'function',\n function: {\n name: typeof name === 'string' ? name : '',\n description: typeof description === 'string' ? description : '',\n parameters: isRecord(parameters) ? parameters : {},\n },\n };\n}\n\n/**\n * Parses tool-call arguments. Anything that is not a JSON object becomes `{}`.\n */\nfunction parseArguments(raw: string): Record<string, unknown> {\n if (raw.trim().length === 0) {\n return {};\n }\n try {\n const parsed: unknown = JSON.parse(raw);\n return isRecord(parsed) ? parsed : {};\n } catch {\n return {};\n }\n}\n\nfunction mapUsage(usage: ApiUsage): TokenUsage {\n return {\n completion_tokens: usage.completion_tokens ?? 0,\n prompt_tokens: usage.prompt_tokens ?? 0,\n total_tokens: usage.total_tokens ?? 0,\n ...(usage.prompt_cache_hit_tokens === undefined\n ? {}\n : { prompt_cache_hit_tokens: usage.prompt_cache_hit_tokens }),\n ...(usage.prompt_cache_miss_tokens === undefined\n ? {}\n : { prompt_cache_miss_tokens: usage.prompt_cache_miss_tokens }),\n };\n}\n\n/**\n * Model provider for any API that speaks the OpenAI chat completions protocol:\n * OpenAI itself, and the compatible endpoints of DeepSeek, Qwen, Moonshot, Ollama,\n * vLLM and others. Set `baseURL` and `model` for the provider you use.\n *\n * Ports:\n * - `prompt` (in): a text prompt. The answer is sent on `completion`.\n * - `messages` (in): a list of chat messages. The reply is sent on `message`.\n */\nclass OpenAICompatible extends Component {\n private readonly client: OpenAI;\n private readonly model: string;\n private readonly temperature: number;\n private readonly maxTokens: number | undefined;\n private readonly topP: number | undefined;\n private readonly systemPrompt: string | undefined;\n private readonly tools: unknown[] | undefined;\n private readonly verbose: boolean;\n private readonly name: string;\n\n constructor(config: OpenAICompatibleConfig) {\n super({});\n\n this.client = new OpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseURL ?? DEFAULT_BASE_URL,\n dangerouslyAllowBrowser: config.dangerouslyAllowBrowser ?? false,\n });\n\n this.model = config.model;\n this.name = config.name ?? DEFAULT_NAME;\n this.temperature = config.temperature ?? DEFAULT_TEMPERATURE;\n this.maxTokens = config.maxTokens;\n this.topP = config.topP;\n this.systemPrompt = config.systemPrompt;\n this.verbose = config.verbose ?? false;\n this.tools =\n config.rawTools !== undefined && config.rawTools.length > 0\n ? config.rawTools.map(toApiTool)\n : config.tools;\n\n Component.Port.I('prompt').attach(this);\n Component.Port.I('messages').attach(this);\n Component.Port.O('completion').attach(this);\n Component.Port.O('message').attach(this);\n }\n\n /**\n * Generates a completion for a single prompt.\n *\n * @returns The text answer, or the JSON-encoded assistant message when it contains tool calls.\n */\n async generateCompletion(prompt: string): Promise<string> {\n const response = await this.client.chat.completions.create({\n ...this.baseRequest(),\n messages: [...this.systemMessages(), { role: 'user', content: prompt }],\n ...this.toolsParam(this.tools),\n });\n\n const message = this.firstMessage(response);\n if (message.tool_calls !== undefined && message.tool_calls.length > 0) {\n return JSON.stringify(message);\n }\n return message.content ?? '';\n }\n\n /**\n * Sends a conversation and returns the assistant reply.\n */\n async chatCompletion(\n messages: Message[],\n options?: ChatCompletionOptions\n ): Promise<AssistantMessage> {\n const response = await this.client.chat.completions.create({\n ...this.baseRequest(),\n messages: this.formatMessages(messages),\n ...this.toolsParam(options?.temporaryTools ?? this.tools),\n });\n\n const message = this.firstMessage(response);\n const result: AssistantMessage = { role: 'assistant', content: message.content ?? '' };\n\n if (response.usage !== undefined) {\n result.usage = mapUsage(response.usage);\n }\n\n if (message.tool_calls !== undefined && message.tool_calls.length > 0) {\n result.tool_calls = message.tool_calls.map(toolCall => {\n if (toolCall.type !== 'function') {\n throw new Error(`Unsupported tool call type: ${toolCall.type}`);\n }\n const rawArguments = toolCall.function.arguments;\n return {\n id: toolCall.id,\n type: 'function',\n function: {\n name: toolCall.function.name,\n arguments: rawArguments.length > 0 ? rawArguments : '{}',\n },\n tool_name: toolCall.function.name,\n arguments: parseArguments(rawArguments),\n };\n });\n }\n\n return result;\n }\n\n /**\n * Streams the assistant reply. Each chunk holds a text delta, tool-call deltas, or usage.\n */\n async *streamChatCompletion(\n messages: Message[],\n options?: ChatCompletionOptions\n ): AsyncGenerator<StreamChunk> {\n const stream = await this.client.chat.completions.create({\n ...this.baseRequest(),\n messages: this.formatMessages(messages),\n ...this.toolsParam(options?.temporaryTools ?? this.tools),\n stream: true,\n });\n\n for await (const chunk of stream) {\n const delta = chunk.choices[0]?.delta;\n\n const text = delta?.content ?? '';\n if (text !== '') {\n yield { role: 'assistant', content: text };\n }\n\n if (delta?.tool_calls) {\n yield {\n role: 'assistant',\n content: '',\n tool_calls: delta.tool_calls.map(toolCall => {\n const name = toolCall.function?.name ?? '';\n const args = toolCall.function?.arguments ?? '';\n return {\n id: toolCall.id ?? '',\n type: 'function',\n function: { name, arguments: args },\n tool_name: name,\n arguments: args,\n };\n }),\n };\n }\n\n if (chunk.usage) {\n yield { role: 'assistant', content: '', usage: mapUsage(chunk.usage) };\n }\n }\n }\n\n /**\n * Runs the model outside a pipeline.\n *\n * @param input - A prompt string or a list of messages.\n */\n override run(input: string | Message[]): Promise<string | AssistantMessage> {\n return typeof input === 'string' ? this.generateCompletion(input) : this.chatCompletion(input);\n }\n\n /**\n * Connects the `prompt` and `messages` input ports to the model.\n * API errors produce a fallback value so the pipeline keeps flowing.\n */\n override _transform($i: Port, $o: Port): void {\n $i('prompt').receive((prompt: string) => {\n this.generateCompletion(prompt).then(\n completion => {\n $o('completion').send(completion);\n },\n (error: unknown) => {\n this.logError(error);\n $o('completion').send(FALLBACK_TEXT);\n }\n );\n });\n\n $i('messages').receive((messages: Message[]) => {\n this.chatCompletion(messages).then(\n message => {\n $o('message').send(message);\n },\n (error: unknown) => {\n this.logError(error);\n $o('message').send({ role: 'assistant', content: FALLBACK_TEXT });\n }\n );\n });\n }\n\n private baseRequest(): {\n model: string;\n temperature: number;\n max_tokens?: number;\n top_p?: number;\n } {\n return {\n model: this.model,\n temperature: this.temperature,\n ...(this.maxTokens === undefined ? {} : { max_tokens: this.maxTokens }),\n ...(this.topP === undefined ? {} : { top_p: this.topP }),\n };\n }\n\n private toolsParam(tools: unknown[] | undefined): { tools?: ChatTool[] } {\n return tools !== undefined && tools.length > 0 ? { tools: tools.map(toApiTool) } : {};\n }\n\n private systemMessages(): ChatMessageParam[] {\n return this.systemPrompt === undefined || this.systemPrompt === ''\n ? []\n : [{ role: 'system', content: this.systemPrompt }];\n }\n\n /**\n * Converts input messages to API messages. Assistant `tool_calls` are not forwarded:\n * agents send tool results back as user messages, and the API rejects assistant tool\n * calls that are not followed by tool messages.\n */\n private formatMessages(messages: Message[]): ChatMessageParam[] {\n return [...this.systemMessages(), ...messages.map(message => this.toApiMessage(message))];\n }\n\n /**\n * Converts one input message to its API shape.\n *\n * @throws Error when the role is not one of `MessageRole`, or a `tool` message has no\n * `tool_call_id`. The API would reject both.\n */\n private toApiMessage(message: Message): ChatMessageParam {\n const content = message.content ?? '';\n switch (message.role) {\n case 'system':\n return { role: 'system', content };\n case 'user':\n return { role: 'user', content };\n case 'assistant':\n return message.content === undefined\n ? { role: 'assistant' }\n : { role: 'assistant', content: message.content };\n case 'tool':\n if (message.tool_call_id === undefined || message.tool_call_id === '') {\n throw new Error(\n `${this.name}: a tool message needs the tool_call_id of the call it answers.`\n );\n }\n return { role: 'tool', content, tool_call_id: message.tool_call_id };\n default:\n throw new Error(\n `${this.name}: unsupported message role '${message.role}'. Use system, user, assistant or tool.`\n );\n }\n }\n\n private firstMessage(response: OpenAI.Chat.ChatCompletion): OpenAI.Chat.ChatCompletionMessage {\n const choice = response.choices[0];\n if (choice === undefined) {\n throw new Error(`${this.name} returned no choices.`);\n }\n return choice.message;\n }\n\n private logError(error: unknown): void {\n if (this.verbose) {\n // eslint-disable-next-line no-console -- opt-in diagnostics controlled by `verbose`.\n console.error(`[${this.name}] API call failed:`, error);\n }\n }\n}\n\nexport default OpenAICompatible;\n","import OpenAICompatible from '../openai-compatible';\nimport type { OpenAICompatibleConfig } from '../openai-compatible';\n\nexport type {\n AssistantMessage,\n ChatCompletionOptions,\n Message,\n MessageRole,\n RawTool,\n ResponseToolCall,\n StreamChunk,\n StreamToolCall,\n TokenUsage,\n ToolCall,\n} from '../openai-compatible';\n\nconst DEFAULT_BASE_URL = 'https://api.deepseek.com/v1';\nconst DEFAULT_MODEL = 'deepseek-chat';\n\n/**\n * Options for the DeepSeek model provider. They are the options of\n * `OpenAICompatible`, with DeepSeek's endpoint and model as defaults.\n */\nexport interface DeepseekConfig extends Omit<OpenAICompatibleConfig, 'model' | 'name'> {\n /** Model name. Defaults to `deepseek-chat`. */\n model?: string | undefined;\n /** API base URL. Defaults to `https://api.deepseek.com/v1`. */\n baseURL?: string | undefined;\n}\n\n/**\n * DeepSeek model provider: `OpenAICompatible` set up for the DeepSeek API.\n *\n * Ports:\n * - `prompt` (in): a text prompt. The answer is sent on `completion`.\n * - `messages` (in): a list of chat messages. The reply is sent on `message`.\n */\nclass Deepseek extends OpenAICompatible {\n constructor(config: DeepseekConfig) {\n super({\n ...config,\n model: config.model ?? DEFAULT_MODEL,\n baseURL: config.baseURL ?? DEFAULT_BASE_URL,\n name: 'DeepSeek',\n });\n }\n}\n\nexport default Deepseek;\n"],"mappings":"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","names":["name","description","parameters","DEFAULT_BASE_URL"]}
|