@agentscope-ai/agentscope 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/index.d.mts +234 -0
- package/dist/agent/index.d.ts +234 -0
- package/dist/agent/index.js +1412 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/index.mjs +1375 -0
- package/dist/agent/index.mjs.map +1 -0
- package/dist/base-BOx3UzOl.d.mts +41 -0
- package/dist/base-BoIps2RL.d.ts +41 -0
- package/dist/base-C7jwyH4Z.d.mts +52 -0
- package/dist/base-Cwi4bjze.d.ts +127 -0
- package/dist/base-DYlBMCy_.d.mts +127 -0
- package/dist/base-NX-knWOv.d.ts +52 -0
- package/dist/block-VsnHrllL.d.mts +48 -0
- package/dist/block-VsnHrllL.d.ts +48 -0
- package/dist/event/index.d.mts +181 -0
- package/dist/event/index.d.ts +181 -0
- package/dist/event/index.js +58 -0
- package/dist/event/index.js.map +1 -0
- package/dist/event/index.mjs +33 -0
- package/dist/event/index.mjs.map +1 -0
- package/dist/formatter/index.d.mts +187 -0
- package/dist/formatter/index.d.ts +187 -0
- package/dist/formatter/index.js +647 -0
- package/dist/formatter/index.js.map +1 -0
- package/dist/formatter/index.mjs +616 -0
- package/dist/formatter/index.mjs.map +1 -0
- package/dist/index-BTJDlKvQ.d.mts +195 -0
- package/dist/index-BcatlwXQ.d.ts +195 -0
- package/dist/index-CAxQAkiP.d.mts +21 -0
- package/dist/index-CAxQAkiP.d.ts +21 -0
- package/dist/mcp/index.d.mts +9 -0
- package/dist/mcp/index.d.ts +9 -0
- package/dist/mcp/index.js +432 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/index.mjs +408 -0
- package/dist/mcp/index.mjs.map +1 -0
- package/dist/message/index.d.mts +10 -0
- package/dist/message/index.d.ts +10 -0
- package/dist/message/index.js +67 -0
- package/dist/message/index.js.map +1 -0
- package/dist/message/index.mjs +37 -0
- package/dist/message/index.mjs.map +1 -0
- package/dist/message-CkN21KaY.d.mts +99 -0
- package/dist/message-CzLeTlua.d.ts +99 -0
- package/dist/model/index.d.mts +377 -0
- package/dist/model/index.d.ts +377 -0
- package/dist/model/index.js +1880 -0
- package/dist/model/index.js.map +1 -0
- package/dist/model/index.mjs +1849 -0
- package/dist/model/index.mjs.map +1 -0
- package/dist/storage/index.d.mts +68 -0
- package/dist/storage/index.d.ts +68 -0
- package/dist/storage/index.js +250 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/index.mjs +212 -0
- package/dist/storage/index.mjs.map +1 -0
- package/dist/tool/index.d.mts +311 -0
- package/dist/tool/index.d.ts +311 -0
- package/dist/tool/index.js +1494 -0
- package/dist/tool/index.js.map +1 -0
- package/dist/tool/index.mjs +1447 -0
- package/dist/tool/index.mjs.map +1 -0
- package/dist/toolkit-CEpulFi0.d.ts +99 -0
- package/dist/toolkit-CGEZSZPa.d.mts +99 -0
- package/jest.config.js +11 -0
- package/package.json +92 -0
- package/src/_utils/common.ts +104 -0
- package/src/_utils/index.ts +1 -0
- package/src/agent/agent-base.ts +0 -0
- package/src/agent/agent.test.ts +1028 -0
- package/src/agent/agent.ts +1032 -0
- package/src/agent/index.ts +2 -0
- package/src/agent/interfaces.ts +23 -0
- package/src/agent/test-compression.ts +72 -0
- package/src/event/index.ts +250 -0
- package/src/formatter/base.ts +133 -0
- package/src/formatter/dashscope-chat-formatter.test.ts +372 -0
- package/src/formatter/dashscope-chat-formatter.ts +163 -0
- package/src/formatter/deepseek-chat-formatter.ts +130 -0
- package/src/formatter/index.ts +5 -0
- package/src/formatter/ollama-chat-formatter.ts +67 -0
- package/src/formatter/openai-chat-formatter.test.ts +263 -0
- package/src/formatter/openai-chat-formatter.ts +301 -0
- package/src/formatter/openai.md +767 -0
- package/src/mcp/base.ts +114 -0
- package/src/mcp/http.test.ts +303 -0
- package/src/mcp/http.ts +224 -0
- package/src/mcp/index.ts +2 -0
- package/src/mcp/stdio.test.ts +91 -0
- package/src/mcp/stdio.ts +119 -0
- package/src/message/block.ts +60 -0
- package/src/message/enums.ts +4 -0
- package/src/message/index.ts +12 -0
- package/src/message/message.test.ts +80 -0
- package/src/message/message.ts +131 -0
- package/src/model/base.ts +226 -0
- package/src/model/dashscope-model.test.ts +335 -0
- package/src/model/dashscope-model.ts +441 -0
- package/src/model/deepseek-model.test.ts +279 -0
- package/src/model/deepseek-model.ts +401 -0
- package/src/model/index.ts +7 -0
- package/src/model/ollama-model.test.ts +307 -0
- package/src/model/ollama-model.ts +356 -0
- package/src/model/openai-model.ts +327 -0
- package/src/model/response.ts +22 -0
- package/src/model/usage.ts +12 -0
- package/src/storage/base.ts +52 -0
- package/src/storage/file-system.test.ts +587 -0
- package/src/storage/file-system.ts +269 -0
- package/src/storage/index.ts +2 -0
- package/src/tool/base.ts +23 -0
- package/src/tool/bash.test.ts +174 -0
- package/src/tool/bash.ts +152 -0
- package/src/tool/edit.test.ts +83 -0
- package/src/tool/edit.ts +95 -0
- package/src/tool/glob.test.ts +63 -0
- package/src/tool/glob.ts +166 -0
- package/src/tool/grep.test.ts +74 -0
- package/src/tool/grep.ts +256 -0
- package/src/tool/index.ts +10 -0
- package/src/tool/read.test.ts +77 -0
- package/src/tool/read.ts +117 -0
- package/src/tool/response.ts +82 -0
- package/src/tool/task.test.ts +299 -0
- package/src/tool/task.ts +399 -0
- package/src/tool/toolkit.test.ts +636 -0
- package/src/tool/toolkit.ts +601 -0
- package/src/tool/write.test.ts +52 -0
- package/src/tool/write.ts +57 -0
- package/src/type/index.ts +52 -0
- package/tsconfig.build.json +4 -0
- package/tsconfig.cjs.json +11 -0
- package/tsconfig.esm.json +10 -0
- package/tsconfig.json +14 -0
- package/tsup.config.ts +20 -0
- package/typedoc.json +52 -0
|
@@ -0,0 +1,647 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/formatter/index.ts
|
|
21
|
+
var formatter_exports = {};
|
|
22
|
+
__export(formatter_exports, {
|
|
23
|
+
DashScopeChatFormatter: () => DashScopeChatFormatter,
|
|
24
|
+
DeepSeekChatFormatter: () => DeepSeekChatFormatter,
|
|
25
|
+
FormatterBase: () => FormatterBase,
|
|
26
|
+
OllamaChatFormatter: () => OllamaChatFormatter,
|
|
27
|
+
OpenAIChatFormatter: () => OpenAIChatFormatter
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(formatter_exports);
|
|
30
|
+
|
|
31
|
+
// src/message/message.ts
|
|
32
|
+
function createMsg({
|
|
33
|
+
name,
|
|
34
|
+
content,
|
|
35
|
+
role,
|
|
36
|
+
metadata = {},
|
|
37
|
+
id = crypto.randomUUID(),
|
|
38
|
+
timestamp = (/* @__PURE__ */ new Date()).toISOString(),
|
|
39
|
+
usage
|
|
40
|
+
}) {
|
|
41
|
+
return { id, name, role, content, metadata, timestamp, usage };
|
|
42
|
+
}
|
|
43
|
+
function getTextContent(msg, separator = "\n") {
|
|
44
|
+
const textBlocks = msg.content.filter((block) => block.type === "text");
|
|
45
|
+
if (textBlocks.length === 0) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
return textBlocks.map((block) => block.text).join(separator);
|
|
49
|
+
}
|
|
50
|
+
function getContentBlocks(msg, blockType) {
|
|
51
|
+
if (!blockType) return msg.content;
|
|
52
|
+
return msg.content.filter((block) => block.type === blockType);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/formatter/base.ts
|
|
56
|
+
var FormatterBase = class {
|
|
57
|
+
/**
|
|
58
|
+
* Convert the tool output to string format for the LLM APIs that only accept text input. If
|
|
59
|
+
* `promoteMultimodalToolResult` is true, the multimodal content will be promoted to be a user message with
|
|
60
|
+
* "<system-info></system-info>" tags. Otherwise, the multimodal content will be saved to a storage and a URL link
|
|
61
|
+
* will be provided in the text output.
|
|
62
|
+
*
|
|
63
|
+
* @param output - The tool output, which can be a string or an array of content blocks.
|
|
64
|
+
* @param promoteMultimodalToolResult - Whether to promote the multimodal content to the prompt messages.
|
|
65
|
+
* @returns An object containing the text output and an optional promoted message.
|
|
66
|
+
*/
|
|
67
|
+
convertToolOutputToString(output, promoteMultimodalToolResult) {
|
|
68
|
+
if (typeof output === "string") return { text: output, promotedMsg: null };
|
|
69
|
+
let textualOutput = [];
|
|
70
|
+
const promotedData = [];
|
|
71
|
+
for (const block of output) {
|
|
72
|
+
switch (block.type) {
|
|
73
|
+
case "text":
|
|
74
|
+
textualOutput.push(block.text);
|
|
75
|
+
break;
|
|
76
|
+
default:
|
|
77
|
+
const type = block.source.mediaType.split("/")[0];
|
|
78
|
+
if (type !== "image" && type !== "audio" && type !== "video") {
|
|
79
|
+
console.log(
|
|
80
|
+
`Unsupported media type '${block.source.mediaType}' in tool output. Only image, audio and video are supported.`
|
|
81
|
+
);
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
if (block.source.type === "url") {
|
|
85
|
+
textualOutput.push(
|
|
86
|
+
`<system-info>One returned ${type} can be found at: ${block.source.url}</system-info>`
|
|
87
|
+
);
|
|
88
|
+
} else {
|
|
89
|
+
const shouldPromote = promoteMultimodalToolResult === true || typeof promoteMultimodalToolResult === "object" && promoteMultimodalToolResult[type];
|
|
90
|
+
if (shouldPromote) {
|
|
91
|
+
const dataID = Math.random().toString(36).substring(2, 10);
|
|
92
|
+
textualOutput.push(
|
|
93
|
+
`<system-info>One returned ${type} is embedded with ID '${dataID}' and will be attached within '<system-info></system-info>' tags later.</system-info>`
|
|
94
|
+
);
|
|
95
|
+
promotedData.push({ id: dataID, block });
|
|
96
|
+
} else {
|
|
97
|
+
textualOutput.push(`The returned ${block.type} is stored locally.`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const promotedBlocks = [];
|
|
103
|
+
promotedData.forEach(({ id, block }) => {
|
|
104
|
+
const type = block.source.mediaType.split("/")[0];
|
|
105
|
+
promotedBlocks.push({
|
|
106
|
+
id: crypto.randomUUID(),
|
|
107
|
+
type: "text",
|
|
108
|
+
text: `<${type}_data id='${id}'>`
|
|
109
|
+
});
|
|
110
|
+
promotedBlocks.push(block);
|
|
111
|
+
promotedBlocks.push({
|
|
112
|
+
id: crypto.randomUUID(),
|
|
113
|
+
type: "text",
|
|
114
|
+
text: `</${type}_data>
|
|
115
|
+
`
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
if (promotedBlocks.length > 0) {
|
|
119
|
+
const prefix = "<system-info>The multimodal contents returned from the tool call are as follows:\n";
|
|
120
|
+
if (promotedBlocks[0].type === "text") {
|
|
121
|
+
promotedBlocks[0].text = `${prefix}${promotedBlocks[0].text}`;
|
|
122
|
+
} else {
|
|
123
|
+
promotedBlocks.unshift({
|
|
124
|
+
id: crypto.randomUUID(),
|
|
125
|
+
type: "text",
|
|
126
|
+
text: `${prefix}`
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
const lastBlock = promotedBlocks[promotedBlocks.length - 1];
|
|
130
|
+
if (lastBlock.type === "text") {
|
|
131
|
+
promotedBlocks[promotedBlocks.length - 1] = {
|
|
132
|
+
id: crypto.randomUUID(),
|
|
133
|
+
type: "text",
|
|
134
|
+
text: `${lastBlock.text}</system-info>`
|
|
135
|
+
};
|
|
136
|
+
} else {
|
|
137
|
+
promotedBlocks.push({
|
|
138
|
+
id: crypto.randomUUID(),
|
|
139
|
+
type: "text",
|
|
140
|
+
text: `</system-info>`
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
text: textualOutput.join("\n"),
|
|
146
|
+
promotedMsg: createMsg({ name: "user", content: promotedBlocks, role: "user" })
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// src/formatter/dashscope-chat-formatter.ts
|
|
152
|
+
var DashScopeChatFormatter = class extends FormatterBase {
|
|
153
|
+
promoteMultimodalToolResult;
|
|
154
|
+
/**
|
|
155
|
+
* Initialize a DashScopeChatFormatter instance.
|
|
156
|
+
*
|
|
157
|
+
* @param promoteMultimodalToolResult - Since DashScope API doesn't support multimodal tool outputs, this option
|
|
158
|
+
* indicates whether to promote the multimodal tool results to the prompt messages, so that LLMs can see them.
|
|
159
|
+
* Note you should ensure your model supports the corresponding modalities.
|
|
160
|
+
* @param promoteMultimodalToolResult.promoteMultimodalToolResult
|
|
161
|
+
*/
|
|
162
|
+
constructor({ promoteMultimodalToolResult = false } = {}) {
|
|
163
|
+
super();
|
|
164
|
+
this.promoteMultimodalToolResult = promoteMultimodalToolResult;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Format the input message objects into the required format by DashScope API.
|
|
168
|
+
*
|
|
169
|
+
* @param msgs - An array of Msg instances to be formatted.
|
|
170
|
+
* @param msgs.msgs
|
|
171
|
+
* @returns A promise that resolves to an array of formatted message objects.
|
|
172
|
+
*/
|
|
173
|
+
async format({ msgs }) {
|
|
174
|
+
const formattedMsgs = [];
|
|
175
|
+
let index = 0;
|
|
176
|
+
while (index < msgs.length) {
|
|
177
|
+
const msg = msgs[index];
|
|
178
|
+
const formattedMsg = {
|
|
179
|
+
role: msg.role,
|
|
180
|
+
content: []
|
|
181
|
+
};
|
|
182
|
+
const cachedMsgs = [];
|
|
183
|
+
for (const block of getContentBlocks(msg)) {
|
|
184
|
+
switch (block.type) {
|
|
185
|
+
case "text":
|
|
186
|
+
formattedMsg.content.push(this._formatTextBlock(block));
|
|
187
|
+
break;
|
|
188
|
+
case "thinking":
|
|
189
|
+
break;
|
|
190
|
+
case "tool_call":
|
|
191
|
+
if (!formattedMsg.tool_calls) {
|
|
192
|
+
formattedMsg.tool_calls = [];
|
|
193
|
+
}
|
|
194
|
+
formattedMsg.tool_calls.push({
|
|
195
|
+
id: block.id,
|
|
196
|
+
type: "function",
|
|
197
|
+
function: {
|
|
198
|
+
name: block.name,
|
|
199
|
+
arguments: block.input
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
break;
|
|
203
|
+
case "tool_result":
|
|
204
|
+
const formattedToolResult = this.convertToolOutputToString(
|
|
205
|
+
block.output,
|
|
206
|
+
this.promoteMultimodalToolResult
|
|
207
|
+
);
|
|
208
|
+
cachedMsgs.push({
|
|
209
|
+
role: "tool",
|
|
210
|
+
tool_call_id: block.id,
|
|
211
|
+
name: block.name,
|
|
212
|
+
content: formattedToolResult.text
|
|
213
|
+
});
|
|
214
|
+
if (formattedToolResult.promotedMsg) {
|
|
215
|
+
msgs.splice(index + 1, 0, formattedToolResult.promotedMsg);
|
|
216
|
+
}
|
|
217
|
+
break;
|
|
218
|
+
case "data":
|
|
219
|
+
formattedMsg.content.push(...this._formatMultimodalBlock(block));
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (formattedMsg.content.length > 0 || formattedMsg.tool_calls) {
|
|
224
|
+
formattedMsgs.push(formattedMsg);
|
|
225
|
+
}
|
|
226
|
+
if (cachedMsgs.length > 0) {
|
|
227
|
+
formattedMsgs.push(...cachedMsgs);
|
|
228
|
+
}
|
|
229
|
+
index++;
|
|
230
|
+
}
|
|
231
|
+
return formattedMsgs;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Format a text content block into the required format.
|
|
235
|
+
*
|
|
236
|
+
* @param block - The text content block to format.
|
|
237
|
+
* @returns An object representing the formatted text content.
|
|
238
|
+
*/
|
|
239
|
+
_formatTextBlock(block) {
|
|
240
|
+
return { text: block.text };
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Format a multimodal data block into the required format.
|
|
244
|
+
* In DashScope API, the local file paths should be prefixed with "file://". URLs are kept unchanged.
|
|
245
|
+
*
|
|
246
|
+
* @param block - The multimodal content block to format.
|
|
247
|
+
* @returns An object representing the formatted multimodal content.
|
|
248
|
+
*/
|
|
249
|
+
_formatMultimodalBlock(block) {
|
|
250
|
+
const type = block.source.mediaType.split("/")[0];
|
|
251
|
+
if (!["image", "audio", "video"].includes(type)) {
|
|
252
|
+
console.log(
|
|
253
|
+
`Skip unsupported media type ${block.source.mediaType} in DashScopeChatFormatter. Only image, audio and video are supported.`
|
|
254
|
+
);
|
|
255
|
+
return [];
|
|
256
|
+
}
|
|
257
|
+
if (block.source.type === "url") {
|
|
258
|
+
return [{ [type]: block.source.url }];
|
|
259
|
+
}
|
|
260
|
+
return [
|
|
261
|
+
{
|
|
262
|
+
[type]: `data:${block.source.mediaType};base64,${block.source.data}`
|
|
263
|
+
}
|
|
264
|
+
];
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
// src/formatter/deepseek-chat-formatter.ts
|
|
269
|
+
var DeepSeekChatFormatter = class extends FormatterBase {
|
|
270
|
+
promoteMultimodalToolResult;
|
|
271
|
+
/**
|
|
272
|
+
* Initializes a new instance of the DeepSeekChatFormatter class.
|
|
273
|
+
* @param root0
|
|
274
|
+
* @param root0.promoteMultimodalToolResult
|
|
275
|
+
*/
|
|
276
|
+
constructor({ promoteMultimodalToolResult = false } = {}) {
|
|
277
|
+
super();
|
|
278
|
+
this.promoteMultimodalToolResult = promoteMultimodalToolResult;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Format the input messages into the structure expected by DeepSeek Chat Completions API.
|
|
282
|
+
* @param root0
|
|
283
|
+
* @param root0.msgs
|
|
284
|
+
* @returns An array of formatted message objects ready to be sent to the DeepSeek API.
|
|
285
|
+
*/
|
|
286
|
+
async format({ msgs }) {
|
|
287
|
+
const formattedMsgs = [];
|
|
288
|
+
let index = 0;
|
|
289
|
+
while (index < msgs.length) {
|
|
290
|
+
const msg = msgs[index];
|
|
291
|
+
const formattedMsg = {
|
|
292
|
+
role: msg.role,
|
|
293
|
+
name: msg.name,
|
|
294
|
+
content: null
|
|
295
|
+
};
|
|
296
|
+
const content = [];
|
|
297
|
+
const cachedMsgs = [];
|
|
298
|
+
for (const block of getContentBlocks(msg)) {
|
|
299
|
+
switch (block.type) {
|
|
300
|
+
case "text":
|
|
301
|
+
content.push({
|
|
302
|
+
type: "text",
|
|
303
|
+
text: block.text
|
|
304
|
+
});
|
|
305
|
+
break;
|
|
306
|
+
case "thinking":
|
|
307
|
+
break;
|
|
308
|
+
case "tool_call":
|
|
309
|
+
if (!formattedMsg.tool_calls) {
|
|
310
|
+
formattedMsg.tool_calls = [];
|
|
311
|
+
}
|
|
312
|
+
formattedMsg.tool_calls.push({
|
|
313
|
+
id: block.id,
|
|
314
|
+
type: "function",
|
|
315
|
+
function: {
|
|
316
|
+
name: block.name,
|
|
317
|
+
arguments: block.input
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
break;
|
|
321
|
+
case "tool_result":
|
|
322
|
+
const formattedToolResult = this.convertToolOutputToString(
|
|
323
|
+
block.output,
|
|
324
|
+
this.promoteMultimodalToolResult
|
|
325
|
+
);
|
|
326
|
+
cachedMsgs.push({
|
|
327
|
+
role: "tool",
|
|
328
|
+
tool_call_id: block.id,
|
|
329
|
+
name: block.name,
|
|
330
|
+
content: formattedToolResult.text
|
|
331
|
+
});
|
|
332
|
+
if (formattedToolResult.promotedMsg?.content.length) {
|
|
333
|
+
msgs.splice(index + 1, 0, formattedToolResult.promotedMsg);
|
|
334
|
+
}
|
|
335
|
+
break;
|
|
336
|
+
case "data":
|
|
337
|
+
console.warn(
|
|
338
|
+
`DeepSeek models don't support multimodal data for now (2026-03), skip the data block in message content.`
|
|
339
|
+
);
|
|
340
|
+
break;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
if (content.length > 0) {
|
|
344
|
+
formattedMsg.content = content;
|
|
345
|
+
}
|
|
346
|
+
if (formattedMsg.content || formattedMsg.tool_calls) {
|
|
347
|
+
formattedMsgs.push(formattedMsg);
|
|
348
|
+
}
|
|
349
|
+
if (cachedMsgs.length > 0) {
|
|
350
|
+
formattedMsgs.push(...cachedMsgs);
|
|
351
|
+
}
|
|
352
|
+
index++;
|
|
353
|
+
}
|
|
354
|
+
return formattedMsgs;
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
// src/formatter/ollama-chat-formatter.ts
|
|
359
|
+
var OllamaChatFormatter = class extends FormatterBase {
|
|
360
|
+
// eslint-disable-next-line jsdoc/require-returns
|
|
361
|
+
/**
|
|
362
|
+
* Format messages for Ollama API
|
|
363
|
+
* @param root0
|
|
364
|
+
* @param root0.msgs
|
|
365
|
+
*/
|
|
366
|
+
async format({ msgs }) {
|
|
367
|
+
const formattedMsgs = [];
|
|
368
|
+
for (const msg of msgs) {
|
|
369
|
+
const formattedMsg = {
|
|
370
|
+
role: msg.role,
|
|
371
|
+
content: ""
|
|
372
|
+
};
|
|
373
|
+
const textContent = getTextContent(msg);
|
|
374
|
+
if (textContent) {
|
|
375
|
+
formattedMsg.content = textContent;
|
|
376
|
+
}
|
|
377
|
+
const toolCalls = getContentBlocks(msg, "tool_call");
|
|
378
|
+
if (toolCalls.length > 0) {
|
|
379
|
+
formattedMsg.tool_calls = toolCalls.map((toolCall) => ({
|
|
380
|
+
function: {
|
|
381
|
+
name: toolCall.name,
|
|
382
|
+
arguments: JSON.parse(toolCall.input)
|
|
383
|
+
}
|
|
384
|
+
}));
|
|
385
|
+
}
|
|
386
|
+
const toolResults = getContentBlocks(msg, "tool_result");
|
|
387
|
+
for (const toolResult of toolResults) {
|
|
388
|
+
const resultText = this.convertToolOutputToString(toolResult.output, false);
|
|
389
|
+
formattedMsgs.push({
|
|
390
|
+
role: "tool",
|
|
391
|
+
content: resultText.text
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
if (formattedMsg.content || formattedMsg.tool_calls) {
|
|
395
|
+
formattedMsgs.push(formattedMsg);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return formattedMsgs;
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
// src/formatter/openai-chat-formatter.ts
|
|
403
|
+
var import_fs = require("fs");
|
|
404
|
+
var import_promises = require("fs/promises");
|
|
405
|
+
var import_path = require("path");
|
|
406
|
+
var import_url = require("url");
|
|
407
|
+
var OpenAIChatFormatter = class extends FormatterBase {
|
|
408
|
+
promoteMultimodalToolResult;
|
|
409
|
+
/**
|
|
410
|
+
* Initializes a new instance of the OpenAIChatFormatter class.
|
|
411
|
+
* @param root0
|
|
412
|
+
* @param root0.promoteMultimodalToolResult
|
|
413
|
+
*/
|
|
414
|
+
constructor({ promoteMultimodalToolResult = false } = {}) {
|
|
415
|
+
super();
|
|
416
|
+
this.promoteMultimodalToolResult = promoteMultimodalToolResult;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Format the input messages into OpenAI Chat Completions message format.
|
|
420
|
+
* @param root0
|
|
421
|
+
* @param root0.msgs
|
|
422
|
+
* @returns An array of formatted messages compatible with OpenAI Chat Completions API.
|
|
423
|
+
*/
|
|
424
|
+
async format({ msgs }) {
|
|
425
|
+
const formattedMsgs = [];
|
|
426
|
+
let index = 0;
|
|
427
|
+
while (index < msgs.length) {
|
|
428
|
+
const msg = msgs[index];
|
|
429
|
+
const formattedMsg = {
|
|
430
|
+
role: msg.role,
|
|
431
|
+
name: msg.name,
|
|
432
|
+
content: null
|
|
433
|
+
};
|
|
434
|
+
const content = [];
|
|
435
|
+
const cachedMsgs = [];
|
|
436
|
+
for (const block of getContentBlocks(msg)) {
|
|
437
|
+
switch (block.type) {
|
|
438
|
+
case "text":
|
|
439
|
+
content.push(this._formatTextBlock(block));
|
|
440
|
+
break;
|
|
441
|
+
case "thinking":
|
|
442
|
+
break;
|
|
443
|
+
case "tool_call":
|
|
444
|
+
if (!formattedMsg.tool_calls) {
|
|
445
|
+
formattedMsg.tool_calls = [];
|
|
446
|
+
}
|
|
447
|
+
formattedMsg.tool_calls.push({
|
|
448
|
+
id: block.id,
|
|
449
|
+
type: "function",
|
|
450
|
+
function: {
|
|
451
|
+
name: block.name,
|
|
452
|
+
arguments: block.input
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
break;
|
|
456
|
+
case "tool_result":
|
|
457
|
+
const formattedToolResult = this.convertToolOutputToString(
|
|
458
|
+
block.output,
|
|
459
|
+
this.promoteMultimodalToolResult
|
|
460
|
+
);
|
|
461
|
+
cachedMsgs.push({
|
|
462
|
+
role: "tool",
|
|
463
|
+
tool_call_id: block.id,
|
|
464
|
+
name: block.name,
|
|
465
|
+
content: formattedToolResult.text
|
|
466
|
+
});
|
|
467
|
+
if (formattedToolResult.promotedMsg?.content.length) {
|
|
468
|
+
msgs.splice(index + 1, 0, formattedToolResult.promotedMsg);
|
|
469
|
+
}
|
|
470
|
+
break;
|
|
471
|
+
case "data":
|
|
472
|
+
content.push(
|
|
473
|
+
...await this._formatMultimodalBlock({ block, role: msg.role })
|
|
474
|
+
);
|
|
475
|
+
break;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if (content.length > 0) {
|
|
479
|
+
formattedMsg.content = content;
|
|
480
|
+
}
|
|
481
|
+
if (formattedMsg.content || formattedMsg.tool_calls) {
|
|
482
|
+
formattedMsgs.push(formattedMsg);
|
|
483
|
+
}
|
|
484
|
+
if (cachedMsgs.length > 0) {
|
|
485
|
+
formattedMsgs.push(...cachedMsgs);
|
|
486
|
+
}
|
|
487
|
+
index++;
|
|
488
|
+
}
|
|
489
|
+
return formattedMsgs;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Format a text block into OpenAI Chat Completions message content format.
|
|
493
|
+
* @param block
|
|
494
|
+
* @returns An object representing the formatted text block.
|
|
495
|
+
*/
|
|
496
|
+
_formatTextBlock(block) {
|
|
497
|
+
return {
|
|
498
|
+
type: "text",
|
|
499
|
+
text: block.text
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Format a multimodal data block into OpenAI Chat Completions message content format.
|
|
504
|
+
* @param root0
|
|
505
|
+
* @param root0.block
|
|
506
|
+
* @param root0.role
|
|
507
|
+
* @returns The formatted content blocks
|
|
508
|
+
*/
|
|
509
|
+
async _formatMultimodalBlock({
|
|
510
|
+
block,
|
|
511
|
+
role
|
|
512
|
+
}) {
|
|
513
|
+
const type = block.source.mediaType.split("/")[0];
|
|
514
|
+
if (type === "image") {
|
|
515
|
+
return [
|
|
516
|
+
{
|
|
517
|
+
type: "image_url",
|
|
518
|
+
image_url: {
|
|
519
|
+
url: await this._toOpenAIImageURL(block)
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
];
|
|
523
|
+
}
|
|
524
|
+
if (type === "audio") {
|
|
525
|
+
if (role === "assistant") {
|
|
526
|
+
return [];
|
|
527
|
+
}
|
|
528
|
+
return [
|
|
529
|
+
{
|
|
530
|
+
type: "input_audio",
|
|
531
|
+
input_audio: await this._toOpenAIAudioData(block)
|
|
532
|
+
}
|
|
533
|
+
];
|
|
534
|
+
}
|
|
535
|
+
console.log(
|
|
536
|
+
`Skip unsupported media type ${block.source.mediaType} in OpenAIChatFormatter. Only image and audio are supported.`
|
|
537
|
+
);
|
|
538
|
+
return [];
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Convert the data block to an OpenAI compatible image URL.
|
|
542
|
+
* @param block
|
|
543
|
+
* @returns A promise that resolves to a string representing the image URL in a format compatible with OpenAI Chat Completions API.
|
|
544
|
+
*/
|
|
545
|
+
async _toOpenAIImageURL(block) {
|
|
546
|
+
if (block.source.type === "base64") {
|
|
547
|
+
return `data:${block.source.mediaType};base64,${block.source.data}`;
|
|
548
|
+
}
|
|
549
|
+
const sourceUrl = block.source.url;
|
|
550
|
+
if (sourceUrl.startsWith("http://") || sourceUrl.startsWith("https://")) {
|
|
551
|
+
return sourceUrl;
|
|
552
|
+
}
|
|
553
|
+
if (sourceUrl.startsWith("data:")) {
|
|
554
|
+
return sourceUrl;
|
|
555
|
+
}
|
|
556
|
+
const localPath = this._toLocalPath(sourceUrl);
|
|
557
|
+
if (!localPath || !(0, import_fs.existsSync)(localPath)) {
|
|
558
|
+
throw new Error(`Image path not found: ${sourceUrl}`);
|
|
559
|
+
}
|
|
560
|
+
const ext = (0, import_path.extname)(localPath).toLowerCase();
|
|
561
|
+
const supportedImageExtensions = [".png", ".jpg", ".jpeg", ".gif", ".webp"];
|
|
562
|
+
if (!supportedImageExtensions.includes(ext)) {
|
|
563
|
+
throw new TypeError(
|
|
564
|
+
`Unsupported image extension: ${ext}. Supported: ${supportedImageExtensions.join(", ")}`
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
const file = await (0, import_promises.readFile)(localPath);
|
|
568
|
+
const mime = block.source.mediaType || `image/${ext.slice(1)}`;
|
|
569
|
+
return `data:${mime};base64,${file.toString("base64")}`;
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Converts a data block to OpenAI compatible audio data format.
|
|
573
|
+
*
|
|
574
|
+
* @param block - The data block containing audio information.
|
|
575
|
+
* @returns A promise that resolves to an object with audio data and format.
|
|
576
|
+
*/
|
|
577
|
+
async _toOpenAIAudioData(block) {
|
|
578
|
+
const supportedMediaTypes = /* @__PURE__ */ new Map([
|
|
579
|
+
["audio/wav", "wav"],
|
|
580
|
+
["audio/mp3", "mp3"],
|
|
581
|
+
["audio/mpeg", "mp3"]
|
|
582
|
+
]);
|
|
583
|
+
if (block.source.type === "base64") {
|
|
584
|
+
const format2 = supportedMediaTypes.get(block.source.mediaType);
|
|
585
|
+
if (!format2) {
|
|
586
|
+
throw new TypeError(
|
|
587
|
+
`Unsupported audio media type: ${block.source.mediaType}, only audio/wav and audio/mp3 are supported.`
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
return { data: block.source.data, format: format2 };
|
|
591
|
+
}
|
|
592
|
+
const sourceUrl = block.source.url;
|
|
593
|
+
const localPath = this._toLocalPath(sourceUrl);
|
|
594
|
+
let data;
|
|
595
|
+
if (localPath && (0, import_fs.existsSync)(localPath)) {
|
|
596
|
+
const file = await (0, import_promises.readFile)(localPath);
|
|
597
|
+
data = file.toString("base64");
|
|
598
|
+
} else if (sourceUrl.startsWith("http://") || sourceUrl.startsWith("https://")) {
|
|
599
|
+
const response = await fetch(sourceUrl);
|
|
600
|
+
if (!response.ok) {
|
|
601
|
+
throw new Error(
|
|
602
|
+
`Failed to fetch audio from URL: ${sourceUrl} (${response.status})`
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
const arr = await response.arrayBuffer();
|
|
606
|
+
data = Buffer.from(arr).toString("base64");
|
|
607
|
+
} else {
|
|
608
|
+
throw new Error(
|
|
609
|
+
`Unsupported audio source: ${sourceUrl}, it should be a local file path, file URL, or an HTTP URL.`
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
const ext = (0, import_path.extname)(localPath || sourceUrl).toLowerCase();
|
|
613
|
+
const extToFormat = /* @__PURE__ */ new Map([
|
|
614
|
+
[".wav", "wav"],
|
|
615
|
+
[".mp3", "mp3"]
|
|
616
|
+
]);
|
|
617
|
+
const format = extToFormat.get(ext);
|
|
618
|
+
if (!format) {
|
|
619
|
+
throw new TypeError(`Unsupported audio extension: ${ext}, wav and mp3 are supported.`);
|
|
620
|
+
}
|
|
621
|
+
return { data, format };
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Converts a URL or path to a local file path.
|
|
625
|
+
*
|
|
626
|
+
* @param urlOrPath - The URL or path to convert.
|
|
627
|
+
* @returns The local file path, or null if not a local path.
|
|
628
|
+
*/
|
|
629
|
+
_toLocalPath(urlOrPath) {
|
|
630
|
+
if (urlOrPath.startsWith("file://")) {
|
|
631
|
+
return (0, import_url.fileURLToPath)(urlOrPath);
|
|
632
|
+
}
|
|
633
|
+
if (!urlOrPath.includes("://")) {
|
|
634
|
+
return urlOrPath;
|
|
635
|
+
}
|
|
636
|
+
return null;
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
640
|
+
0 && (module.exports = {
|
|
641
|
+
DashScopeChatFormatter,
|
|
642
|
+
DeepSeekChatFormatter,
|
|
643
|
+
FormatterBase,
|
|
644
|
+
OllamaChatFormatter,
|
|
645
|
+
OpenAIChatFormatter
|
|
646
|
+
});
|
|
647
|
+
//# sourceMappingURL=index.js.map
|