p-api-agent 0.0.1 → 0.0.3
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/index.cjs +186 -87
- package/dist/index.d.cts +68 -23
- package/dist/index.d.ts +68 -23
- package/dist/index.js +187 -86
- package/package.json +6 -3
package/dist/index.cjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
5
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
8
|
var __export = (target, all) => {
|
|
9
9
|
for (var name in all)
|
|
10
10
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -26,6 +26,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
mod
|
|
27
27
|
));
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
29
30
|
|
|
30
31
|
// src/index.ts
|
|
31
32
|
var index_exports = {};
|
|
@@ -98,109 +99,191 @@ var LLM_Utils = new _LLM_Utils();
|
|
|
98
99
|
// src/agent/index.ts
|
|
99
100
|
var import_path = __toESM(require("path"), 1);
|
|
100
101
|
var Agent = class {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
this
|
|
104
|
-
|
|
105
|
-
this
|
|
106
|
-
|
|
107
|
-
this.
|
|
108
|
-
|
|
109
|
-
|
|
102
|
+
constructor(options = {}) {
|
|
103
|
+
__publicField(this, "function_call", null);
|
|
104
|
+
__publicField(this, "llm_chat_func", null);
|
|
105
|
+
__publicField(this, "max_loop");
|
|
106
|
+
__publicField(this, "retry_times");
|
|
107
|
+
__publicField(this, "custom_system_prompt", null);
|
|
108
|
+
this.max_loop = options.maxLoop ?? 20;
|
|
109
|
+
this.retry_times = options.retryTimes ?? 2;
|
|
110
|
+
if (options.customSystemPrompt) {
|
|
111
|
+
this.custom_system_prompt = options.customSystemPrompt;
|
|
112
|
+
}
|
|
110
113
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
this.function_call_doc = tools_list.map((val) => `\u5DE5\u5177\u51FD\u6570:${val.name}
|
|
117
|
-
\u5DE5\u5177\u63CF\u8FF0:${val.description}`).join("\n\n");
|
|
118
|
-
this.function_call = function_call;
|
|
119
|
-
return true;
|
|
114
|
+
// ─────────── Registration ───────────
|
|
115
|
+
/** 注册工具函数集合,支持链式调用 */
|
|
116
|
+
register_function_call(fc) {
|
|
117
|
+
this.function_call = fc;
|
|
118
|
+
return this;
|
|
120
119
|
}
|
|
121
|
-
/**
|
|
122
|
-
* 注册LLM模型文字能力
|
|
123
|
-
*/
|
|
120
|
+
/** 注册 LLM 文字能力,支持链式调用 */
|
|
124
121
|
register_llm_text_ability(func) {
|
|
125
122
|
this.llm_chat_func = func;
|
|
123
|
+
return this;
|
|
126
124
|
}
|
|
127
|
-
/**
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
return true;
|
|
125
|
+
/** 覆盖系统提示词 */
|
|
126
|
+
set_system_prompt(prompt) {
|
|
127
|
+
this.custom_system_prompt = prompt;
|
|
128
|
+
return this;
|
|
132
129
|
}
|
|
130
|
+
/** 动态修改最大循环次数 */
|
|
131
|
+
set_max_loop(n) {
|
|
132
|
+
this.max_loop = n;
|
|
133
|
+
return this;
|
|
134
|
+
}
|
|
135
|
+
// ─────────── Main ReAct Loop ───────────
|
|
133
136
|
/**
|
|
134
|
-
*
|
|
137
|
+
* 发起对话。
|
|
138
|
+
*
|
|
139
|
+
* 架构:ReAct 单调用循环
|
|
140
|
+
* 每轮只调用一次 LLM,LLM 在拥有完整工具 schema 的系统提示词下
|
|
141
|
+
* 直接输出 end / use_tool / no_ability 三种指令,
|
|
142
|
+
* 彻底消除了旧版 "判断→查文档→生成参数→再生成答案" 的多次调用开销。
|
|
135
143
|
*/
|
|
136
144
|
async create_chat(user_input) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
dispose_user_input = [
|
|
140
|
-
{
|
|
141
|
-
role: "user",
|
|
142
|
-
content: [
|
|
143
|
-
{ type: "text", text: user_input }
|
|
144
|
-
]
|
|
145
|
-
}
|
|
146
|
-
];
|
|
147
|
-
} else {
|
|
148
|
-
dispose_user_input = JSON.parse(JSON.stringify(user_input));
|
|
145
|
+
if (!this.llm_chat_func) {
|
|
146
|
+
return { result: "\u672A\u6CE8\u518CLLM\u80FD\u529B", use_tools: [] };
|
|
149
147
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
role: "system",
|
|
153
|
-
content: [
|
|
154
|
-
{ type: "text", text: `# \u5DE5\u5177\u51FD\u6570\u8BF4\u660E\u6587\u6863:
|
|
155
|
-
${this.function_call_doc}` }
|
|
156
|
-
]
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
dispose_user_input.unshift({
|
|
148
|
+
const history = this.normalize_input(user_input);
|
|
149
|
+
const system_msg = {
|
|
160
150
|
role: "system",
|
|
161
|
-
content: [
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
let
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
151
|
+
content: [{ type: "text", text: this.build_system_prompt() }]
|
|
152
|
+
};
|
|
153
|
+
const result = { result: "", use_tools: [] };
|
|
154
|
+
const tool_fail_count = {};
|
|
155
|
+
for (let turn = 0; turn < this.max_loop; turn++) {
|
|
156
|
+
let raw;
|
|
157
|
+
try {
|
|
158
|
+
raw = await this.call_llm_with_retry([system_msg, ...history]);
|
|
159
|
+
} catch (err) {
|
|
160
|
+
result.result = `LLM\u8C03\u7528\u5931\u8D25: ${err?.message ?? String(err)}`;
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
const cmd = this.parse_command(raw);
|
|
164
|
+
if (!cmd) {
|
|
165
|
+
result.result = raw;
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
if (cmd.command === "end") {
|
|
169
|
+
result.result = cmd.result;
|
|
170
|
+
return result;
|
|
171
|
+
}
|
|
172
|
+
if (cmd.command === "no_ability") {
|
|
173
|
+
result.result = cmd.result || "\u65E0\u6CD5\u6267\u884C\u6B64\u64CD\u4F5C";
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
if (cmd.command === "use_tool") {
|
|
177
|
+
const { tool_name, params } = cmd;
|
|
178
|
+
if (!this.function_call) {
|
|
179
|
+
result.result = "\u672A\u6CE8\u518C\u5DE5\u5177\u51FD\u6570\u96C6\u5408\uFF0C\u65E0\u6CD5\u6267\u884C\u5DE5\u5177\u8C03\u7528";
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
182
|
+
history.push({
|
|
183
|
+
role: "assistant",
|
|
184
|
+
content: [{ type: "text", text: raw }]
|
|
182
185
|
});
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
186
|
+
let tool_result;
|
|
187
|
+
try {
|
|
188
|
+
tool_result = await this.function_call.exec_function(tool_name, params);
|
|
189
|
+
} catch (err) {
|
|
190
|
+
const err_msg = err?.message ?? String(err);
|
|
191
|
+
tool_fail_count[tool_name] = (tool_fail_count[tool_name] ?? 0) + 1;
|
|
192
|
+
history.push({
|
|
193
|
+
role: "user",
|
|
194
|
+
content: [{
|
|
195
|
+
type: "text",
|
|
196
|
+
text: `[\u5DE5\u5177\u6267\u884C\u5931\u8D25] ${tool_name}
|
|
197
|
+
\u9519\u8BEF\u4FE1\u606F: ${err_msg}
|
|
198
|
+
\u8BF7\u6839\u636E\u9519\u8BEF\u8C03\u6574\u7B56\u7565\u540E\u7EE7\u7EED`
|
|
199
|
+
}]
|
|
200
|
+
});
|
|
201
|
+
if (tool_fail_count[tool_name] >= 2) {
|
|
202
|
+
result.result = `\u5DE5\u5177 "${tool_name}" \u8FDE\u7EED\u8C03\u7528\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`;
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
history.push({
|
|
188
208
|
role: "user",
|
|
189
|
-
content: [
|
|
190
|
-
|
|
191
|
-
${
|
|
192
|
-
|
|
209
|
+
content: [{
|
|
210
|
+
type: "text",
|
|
211
|
+
text: `[\u5DE5\u5177\u8C03\u7528\u7ED3\u679C] ${tool_name}
|
|
212
|
+
${JSON.stringify(tool_result, null, 2)}`
|
|
213
|
+
}]
|
|
193
214
|
});
|
|
215
|
+
result.use_tools.push({ tool_name, params, exec_result: tool_result });
|
|
216
|
+
continue;
|
|
194
217
|
}
|
|
195
|
-
loop_count++;
|
|
196
218
|
}
|
|
219
|
+
result.result = "\u8D85\u51FA\u6700\u5927\u63A8\u7406\u8F6E\u6B21\uFF0C\u8BF7\u7CBE\u7B80\u95EE\u9898\u540E\u91CD\u8BD5";
|
|
220
|
+
return result;
|
|
197
221
|
}
|
|
222
|
+
// ─────────── System Prompt ───────────
|
|
198
223
|
/**
|
|
199
|
-
*
|
|
224
|
+
* 构建系统提示词。
|
|
225
|
+
* 将所有工具的完整 schema(含参数类型、必填项、示例值)
|
|
226
|
+
* 直接注入系统提示词,让 LLM 在单次调用中就能做出准确的工具选择和参数填写。
|
|
200
227
|
*/
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
228
|
+
build_system_prompt() {
|
|
229
|
+
if (this.custom_system_prompt) return this.custom_system_prompt;
|
|
230
|
+
const base = this.load_preset_prompt();
|
|
231
|
+
if (!this.function_call) return base;
|
|
232
|
+
const tool_schemas = this.function_call.get_tools_with_schema().map((t) => {
|
|
233
|
+
const props = Object.entries(t.input_schema.properties).map(([k, v]) => {
|
|
234
|
+
const req = t.input_schema.required?.includes(k) ? "\u5FC5\u586B" : "\u53EF\u9009";
|
|
235
|
+
const ex = v.examples?.length ? `\uFF0C\u793A\u4F8B: ${v.examples.join(" / ")}` : "";
|
|
236
|
+
return ` - ${k} (${v.type}, ${req}): ${v.description}${ex}`;
|
|
237
|
+
}).join("\n");
|
|
238
|
+
return `### ${t.name}
|
|
239
|
+
\u63CF\u8FF0: ${t.description}
|
|
240
|
+
\u53C2\u6570:
|
|
241
|
+
${props}`;
|
|
242
|
+
}).join("\n\n");
|
|
243
|
+
return `${base}
|
|
244
|
+
|
|
245
|
+
## \u53EF\u7528\u5DE5\u5177\u5217\u8868
|
|
246
|
+
|
|
247
|
+
${tool_schemas}`;
|
|
248
|
+
}
|
|
249
|
+
load_preset_prompt() {
|
|
250
|
+
try {
|
|
251
|
+
return import_fs.default.readFileSync(import_path.default.join(__dirname, "./preset_prompt.md"), "utf-8");
|
|
252
|
+
} catch {
|
|
253
|
+
return "";
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
// ─────────── Helpers ───────────
|
|
257
|
+
normalize_input(input) {
|
|
258
|
+
if (typeof input === "string") {
|
|
259
|
+
return [{ role: "user", content: [{ type: "text", text: input }] }];
|
|
260
|
+
}
|
|
261
|
+
return [...input];
|
|
262
|
+
}
|
|
263
|
+
parse_command(raw) {
|
|
264
|
+
const json = this.safe_extract_json(raw);
|
|
265
|
+
if (!json || typeof json.command !== "string") return null;
|
|
266
|
+
return json;
|
|
267
|
+
}
|
|
268
|
+
safe_extract_json(content) {
|
|
269
|
+
try {
|
|
270
|
+
return LLM_Utils.extract_json(content);
|
|
271
|
+
} catch {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
async call_llm_with_retry(input) {
|
|
276
|
+
let last_error;
|
|
277
|
+
for (let i = 0; i <= this.retry_times; i++) {
|
|
278
|
+
try {
|
|
279
|
+
const res = await this.llm_chat_func(input);
|
|
280
|
+
if (typeof res === "string" && res.trim()) return res;
|
|
281
|
+
throw new Error("\u7A7A\u54CD\u5E94");
|
|
282
|
+
} catch (err) {
|
|
283
|
+
last_error = err;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
throw last_error ?? new Error("LLM\u8C03\u7528\u5931\u8D25");
|
|
204
287
|
}
|
|
205
288
|
};
|
|
206
289
|
|
|
@@ -210,7 +293,7 @@ var import_fs2 = __toESM(require("fs"), 1);
|
|
|
210
293
|
var FunctionCall = class {
|
|
211
294
|
constructor(tool_path) {
|
|
212
295
|
this.tool_path = tool_path;
|
|
213
|
-
this
|
|
296
|
+
__publicField(this, "tools", {});
|
|
214
297
|
this.init();
|
|
215
298
|
}
|
|
216
299
|
init() {
|
|
@@ -226,6 +309,9 @@ var FunctionCall = class {
|
|
|
226
309
|
*/
|
|
227
310
|
gen_tool_doc(name) {
|
|
228
311
|
const info = this.tools[name];
|
|
312
|
+
if (!info) {
|
|
313
|
+
throw `${name}\u5DE5\u5177\u51FD\u6570\u4E0D\u5B58\u5728`;
|
|
314
|
+
}
|
|
229
315
|
const schema = info.input_schema;
|
|
230
316
|
const schemaDesc = `\u7C7B\u578B: ${schema.type}`;
|
|
231
317
|
const params = Object.keys(schema.properties).map((key) => {
|
|
@@ -243,7 +329,7 @@ var FunctionCall = class {
|
|
|
243
329
|
${params}`;
|
|
244
330
|
}
|
|
245
331
|
/**
|
|
246
|
-
*
|
|
332
|
+
* 获取工具函数列表(仅名称 + 描述)
|
|
247
333
|
*/
|
|
248
334
|
get_tools_list() {
|
|
249
335
|
return Object.keys(this.tools).map((key) => {
|
|
@@ -254,6 +340,19 @@ ${params}`;
|
|
|
254
340
|
};
|
|
255
341
|
});
|
|
256
342
|
}
|
|
343
|
+
/**
|
|
344
|
+
* 获取工具函数列表(含完整 input_schema),供 Agent 注入系统提示词
|
|
345
|
+
*/
|
|
346
|
+
get_tools_with_schema() {
|
|
347
|
+
return Object.keys(this.tools).map((key) => {
|
|
348
|
+
const info = this.tools[key];
|
|
349
|
+
return {
|
|
350
|
+
name: info.name,
|
|
351
|
+
description: info.description,
|
|
352
|
+
input_schema: info.input_schema
|
|
353
|
+
};
|
|
354
|
+
});
|
|
355
|
+
}
|
|
257
356
|
/**
|
|
258
357
|
* 执行工具函数
|
|
259
358
|
*/
|
package/dist/index.d.cts
CHANGED
|
@@ -24,12 +24,30 @@ declare class FunctionCall {
|
|
|
24
24
|
*/
|
|
25
25
|
gen_tool_doc(name: string): string;
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* 获取工具函数列表(仅名称 + 描述)
|
|
28
28
|
*/
|
|
29
29
|
get_tools_list(): {
|
|
30
30
|
name: string;
|
|
31
31
|
description: string;
|
|
32
32
|
}[];
|
|
33
|
+
/**
|
|
34
|
+
* 获取工具函数列表(含完整 input_schema),供 Agent 注入系统提示词
|
|
35
|
+
*/
|
|
36
|
+
get_tools_with_schema(): {
|
|
37
|
+
name: string;
|
|
38
|
+
description: string;
|
|
39
|
+
input_schema: {
|
|
40
|
+
type: string;
|
|
41
|
+
properties: {
|
|
42
|
+
[key: string]: {
|
|
43
|
+
type: string;
|
|
44
|
+
description: string;
|
|
45
|
+
examples?: string[];
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
required?: string[];
|
|
49
|
+
};
|
|
50
|
+
}[];
|
|
33
51
|
/**
|
|
34
52
|
* 执行工具函数
|
|
35
53
|
*/
|
|
@@ -47,36 +65,63 @@ interface ImageContent {
|
|
|
47
65
|
};
|
|
48
66
|
}
|
|
49
67
|
type Content = TextContent | ImageContent;
|
|
50
|
-
type
|
|
68
|
+
type Message = {
|
|
51
69
|
role: 'system' | 'user' | 'assistant';
|
|
52
70
|
content: Content[];
|
|
53
|
-
}
|
|
71
|
+
};
|
|
72
|
+
type UserChatInput = Message[];
|
|
73
|
+
interface ToolRecord {
|
|
74
|
+
tool_name: string;
|
|
75
|
+
params: any;
|
|
76
|
+
exec_result: any;
|
|
77
|
+
}
|
|
78
|
+
interface CreateChatResult {
|
|
79
|
+
result: string;
|
|
80
|
+
use_tools: ToolRecord[];
|
|
81
|
+
}
|
|
82
|
+
interface AgentOptions {
|
|
83
|
+
/** 最大推理循环次数,默认 20 */
|
|
84
|
+
maxLoop?: number;
|
|
85
|
+
/** LLM 失败重试次数,默认 2 */
|
|
86
|
+
retryTimes?: number;
|
|
87
|
+
/** 完全覆盖系统提示词 */
|
|
88
|
+
customSystemPrompt?: string;
|
|
89
|
+
}
|
|
54
90
|
declare class Agent {
|
|
55
91
|
private function_call;
|
|
56
|
-
private function_call_doc;
|
|
57
92
|
private llm_chat_func;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
register_function_call(
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
|
|
70
|
-
*/
|
|
71
|
-
register_llm_image_ability(): boolean;
|
|
93
|
+
private max_loop;
|
|
94
|
+
private retry_times;
|
|
95
|
+
private custom_system_prompt;
|
|
96
|
+
constructor(options?: AgentOptions);
|
|
97
|
+
/** 注册工具函数集合,支持链式调用 */
|
|
98
|
+
register_function_call(fc: FunctionCall): this;
|
|
99
|
+
/** 注册 LLM 文字能力,支持链式调用 */
|
|
100
|
+
register_llm_text_ability(func: (input: UserChatInput) => Promise<string>): this;
|
|
101
|
+
/** 覆盖系统提示词 */
|
|
102
|
+
set_system_prompt(prompt: string): this;
|
|
103
|
+
/** 动态修改最大循环次数 */
|
|
104
|
+
set_max_loop(n: number): this;
|
|
72
105
|
/**
|
|
73
|
-
*
|
|
106
|
+
* 发起对话。
|
|
107
|
+
*
|
|
108
|
+
* 架构:ReAct 单调用循环
|
|
109
|
+
* 每轮只调用一次 LLM,LLM 在拥有完整工具 schema 的系统提示词下
|
|
110
|
+
* 直接输出 end / use_tool / no_ability 三种指令,
|
|
111
|
+
* 彻底消除了旧版 "判断→查文档→生成参数→再生成答案" 的多次调用开销。
|
|
74
112
|
*/
|
|
75
|
-
create_chat(user_input: UserChatInput): Promise<
|
|
113
|
+
create_chat(user_input: string | UserChatInput): Promise<CreateChatResult>;
|
|
76
114
|
/**
|
|
77
|
-
*
|
|
115
|
+
* 构建系统提示词。
|
|
116
|
+
* 将所有工具的完整 schema(含参数类型、必填项、示例值)
|
|
117
|
+
* 直接注入系统提示词,让 LLM 在单次调用中就能做出准确的工具选择和参数填写。
|
|
78
118
|
*/
|
|
79
|
-
|
|
119
|
+
private build_system_prompt;
|
|
120
|
+
private load_preset_prompt;
|
|
121
|
+
private normalize_input;
|
|
122
|
+
private parse_command;
|
|
123
|
+
private safe_extract_json;
|
|
124
|
+
private call_llm_with_retry;
|
|
80
125
|
}
|
|
81
126
|
|
|
82
127
|
declare class _LLM_Utils {
|
|
@@ -100,4 +145,4 @@ declare class _LLM_Utils {
|
|
|
100
145
|
}
|
|
101
146
|
declare const LLM_Utils: _LLM_Utils;
|
|
102
147
|
|
|
103
|
-
export { Agent, FunctionCall, LLM_Utils, type RegisterInfo };
|
|
148
|
+
export { Agent, type AgentOptions, type CreateChatResult, FunctionCall, LLM_Utils, type Message, type RegisterInfo, type ToolRecord, type UserChatInput };
|
package/dist/index.d.ts
CHANGED
|
@@ -24,12 +24,30 @@ declare class FunctionCall {
|
|
|
24
24
|
*/
|
|
25
25
|
gen_tool_doc(name: string): string;
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* 获取工具函数列表(仅名称 + 描述)
|
|
28
28
|
*/
|
|
29
29
|
get_tools_list(): {
|
|
30
30
|
name: string;
|
|
31
31
|
description: string;
|
|
32
32
|
}[];
|
|
33
|
+
/**
|
|
34
|
+
* 获取工具函数列表(含完整 input_schema),供 Agent 注入系统提示词
|
|
35
|
+
*/
|
|
36
|
+
get_tools_with_schema(): {
|
|
37
|
+
name: string;
|
|
38
|
+
description: string;
|
|
39
|
+
input_schema: {
|
|
40
|
+
type: string;
|
|
41
|
+
properties: {
|
|
42
|
+
[key: string]: {
|
|
43
|
+
type: string;
|
|
44
|
+
description: string;
|
|
45
|
+
examples?: string[];
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
required?: string[];
|
|
49
|
+
};
|
|
50
|
+
}[];
|
|
33
51
|
/**
|
|
34
52
|
* 执行工具函数
|
|
35
53
|
*/
|
|
@@ -47,36 +65,63 @@ interface ImageContent {
|
|
|
47
65
|
};
|
|
48
66
|
}
|
|
49
67
|
type Content = TextContent | ImageContent;
|
|
50
|
-
type
|
|
68
|
+
type Message = {
|
|
51
69
|
role: 'system' | 'user' | 'assistant';
|
|
52
70
|
content: Content[];
|
|
53
|
-
}
|
|
71
|
+
};
|
|
72
|
+
type UserChatInput = Message[];
|
|
73
|
+
interface ToolRecord {
|
|
74
|
+
tool_name: string;
|
|
75
|
+
params: any;
|
|
76
|
+
exec_result: any;
|
|
77
|
+
}
|
|
78
|
+
interface CreateChatResult {
|
|
79
|
+
result: string;
|
|
80
|
+
use_tools: ToolRecord[];
|
|
81
|
+
}
|
|
82
|
+
interface AgentOptions {
|
|
83
|
+
/** 最大推理循环次数,默认 20 */
|
|
84
|
+
maxLoop?: number;
|
|
85
|
+
/** LLM 失败重试次数,默认 2 */
|
|
86
|
+
retryTimes?: number;
|
|
87
|
+
/** 完全覆盖系统提示词 */
|
|
88
|
+
customSystemPrompt?: string;
|
|
89
|
+
}
|
|
54
90
|
declare class Agent {
|
|
55
91
|
private function_call;
|
|
56
|
-
private function_call_doc;
|
|
57
92
|
private llm_chat_func;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
register_function_call(
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
|
|
70
|
-
*/
|
|
71
|
-
register_llm_image_ability(): boolean;
|
|
93
|
+
private max_loop;
|
|
94
|
+
private retry_times;
|
|
95
|
+
private custom_system_prompt;
|
|
96
|
+
constructor(options?: AgentOptions);
|
|
97
|
+
/** 注册工具函数集合,支持链式调用 */
|
|
98
|
+
register_function_call(fc: FunctionCall): this;
|
|
99
|
+
/** 注册 LLM 文字能力,支持链式调用 */
|
|
100
|
+
register_llm_text_ability(func: (input: UserChatInput) => Promise<string>): this;
|
|
101
|
+
/** 覆盖系统提示词 */
|
|
102
|
+
set_system_prompt(prompt: string): this;
|
|
103
|
+
/** 动态修改最大循环次数 */
|
|
104
|
+
set_max_loop(n: number): this;
|
|
72
105
|
/**
|
|
73
|
-
*
|
|
106
|
+
* 发起对话。
|
|
107
|
+
*
|
|
108
|
+
* 架构:ReAct 单调用循环
|
|
109
|
+
* 每轮只调用一次 LLM,LLM 在拥有完整工具 schema 的系统提示词下
|
|
110
|
+
* 直接输出 end / use_tool / no_ability 三种指令,
|
|
111
|
+
* 彻底消除了旧版 "判断→查文档→生成参数→再生成答案" 的多次调用开销。
|
|
74
112
|
*/
|
|
75
|
-
create_chat(user_input: UserChatInput): Promise<
|
|
113
|
+
create_chat(user_input: string | UserChatInput): Promise<CreateChatResult>;
|
|
76
114
|
/**
|
|
77
|
-
*
|
|
115
|
+
* 构建系统提示词。
|
|
116
|
+
* 将所有工具的完整 schema(含参数类型、必填项、示例值)
|
|
117
|
+
* 直接注入系统提示词,让 LLM 在单次调用中就能做出准确的工具选择和参数填写。
|
|
78
118
|
*/
|
|
79
|
-
|
|
119
|
+
private build_system_prompt;
|
|
120
|
+
private load_preset_prompt;
|
|
121
|
+
private normalize_input;
|
|
122
|
+
private parse_command;
|
|
123
|
+
private safe_extract_json;
|
|
124
|
+
private call_llm_with_retry;
|
|
80
125
|
}
|
|
81
126
|
|
|
82
127
|
declare class _LLM_Utils {
|
|
@@ -100,4 +145,4 @@ declare class _LLM_Utils {
|
|
|
100
145
|
}
|
|
101
146
|
declare const LLM_Utils: _LLM_Utils;
|
|
102
147
|
|
|
103
|
-
export { Agent, FunctionCall, LLM_Utils, type RegisterInfo };
|
|
148
|
+
export { Agent, type AgentOptions, type CreateChatResult, FunctionCall, LLM_Utils, type Message, type RegisterInfo, type ToolRecord, type UserChatInput };
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1
3
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
4
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
5
|
}) : x)(function(x) {
|
|
4
6
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
7
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
8
|
});
|
|
9
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
7
10
|
|
|
8
11
|
// src/agent/index.ts
|
|
9
12
|
import fs from "fs";
|
|
@@ -67,109 +70,191 @@ var LLM_Utils = new _LLM_Utils();
|
|
|
67
70
|
// src/agent/index.ts
|
|
68
71
|
import path from "path";
|
|
69
72
|
var Agent = class {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
this
|
|
73
|
-
|
|
74
|
-
this
|
|
75
|
-
|
|
76
|
-
this.
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
constructor(options = {}) {
|
|
74
|
+
__publicField(this, "function_call", null);
|
|
75
|
+
__publicField(this, "llm_chat_func", null);
|
|
76
|
+
__publicField(this, "max_loop");
|
|
77
|
+
__publicField(this, "retry_times");
|
|
78
|
+
__publicField(this, "custom_system_prompt", null);
|
|
79
|
+
this.max_loop = options.maxLoop ?? 20;
|
|
80
|
+
this.retry_times = options.retryTimes ?? 2;
|
|
81
|
+
if (options.customSystemPrompt) {
|
|
82
|
+
this.custom_system_prompt = options.customSystemPrompt;
|
|
83
|
+
}
|
|
79
84
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
this.function_call_doc = tools_list.map((val) => `\u5DE5\u5177\u51FD\u6570:${val.name}
|
|
86
|
-
\u5DE5\u5177\u63CF\u8FF0:${val.description}`).join("\n\n");
|
|
87
|
-
this.function_call = function_call;
|
|
88
|
-
return true;
|
|
85
|
+
// ─────────── Registration ───────────
|
|
86
|
+
/** 注册工具函数集合,支持链式调用 */
|
|
87
|
+
register_function_call(fc) {
|
|
88
|
+
this.function_call = fc;
|
|
89
|
+
return this;
|
|
89
90
|
}
|
|
90
|
-
/**
|
|
91
|
-
* 注册LLM模型文字能力
|
|
92
|
-
*/
|
|
91
|
+
/** 注册 LLM 文字能力,支持链式调用 */
|
|
93
92
|
register_llm_text_ability(func) {
|
|
94
93
|
this.llm_chat_func = func;
|
|
94
|
+
return this;
|
|
95
95
|
}
|
|
96
|
-
/**
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return true;
|
|
96
|
+
/** 覆盖系统提示词 */
|
|
97
|
+
set_system_prompt(prompt) {
|
|
98
|
+
this.custom_system_prompt = prompt;
|
|
99
|
+
return this;
|
|
101
100
|
}
|
|
101
|
+
/** 动态修改最大循环次数 */
|
|
102
|
+
set_max_loop(n) {
|
|
103
|
+
this.max_loop = n;
|
|
104
|
+
return this;
|
|
105
|
+
}
|
|
106
|
+
// ─────────── Main ReAct Loop ───────────
|
|
102
107
|
/**
|
|
103
|
-
*
|
|
108
|
+
* 发起对话。
|
|
109
|
+
*
|
|
110
|
+
* 架构:ReAct 单调用循环
|
|
111
|
+
* 每轮只调用一次 LLM,LLM 在拥有完整工具 schema 的系统提示词下
|
|
112
|
+
* 直接输出 end / use_tool / no_ability 三种指令,
|
|
113
|
+
* 彻底消除了旧版 "判断→查文档→生成参数→再生成答案" 的多次调用开销。
|
|
104
114
|
*/
|
|
105
115
|
async create_chat(user_input) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
dispose_user_input = [
|
|
109
|
-
{
|
|
110
|
-
role: "user",
|
|
111
|
-
content: [
|
|
112
|
-
{ type: "text", text: user_input }
|
|
113
|
-
]
|
|
114
|
-
}
|
|
115
|
-
];
|
|
116
|
-
} else {
|
|
117
|
-
dispose_user_input = JSON.parse(JSON.stringify(user_input));
|
|
116
|
+
if (!this.llm_chat_func) {
|
|
117
|
+
return { result: "\u672A\u6CE8\u518CLLM\u80FD\u529B", use_tools: [] };
|
|
118
118
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
role: "system",
|
|
122
|
-
content: [
|
|
123
|
-
{ type: "text", text: `# \u5DE5\u5177\u51FD\u6570\u8BF4\u660E\u6587\u6863:
|
|
124
|
-
${this.function_call_doc}` }
|
|
125
|
-
]
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
dispose_user_input.unshift({
|
|
119
|
+
const history = this.normalize_input(user_input);
|
|
120
|
+
const system_msg = {
|
|
129
121
|
role: "system",
|
|
130
|
-
content: [
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
let
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
122
|
+
content: [{ type: "text", text: this.build_system_prompt() }]
|
|
123
|
+
};
|
|
124
|
+
const result = { result: "", use_tools: [] };
|
|
125
|
+
const tool_fail_count = {};
|
|
126
|
+
for (let turn = 0; turn < this.max_loop; turn++) {
|
|
127
|
+
let raw;
|
|
128
|
+
try {
|
|
129
|
+
raw = await this.call_llm_with_retry([system_msg, ...history]);
|
|
130
|
+
} catch (err) {
|
|
131
|
+
result.result = `LLM\u8C03\u7528\u5931\u8D25: ${err?.message ?? String(err)}`;
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
const cmd = this.parse_command(raw);
|
|
135
|
+
if (!cmd) {
|
|
136
|
+
result.result = raw;
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
if (cmd.command === "end") {
|
|
140
|
+
result.result = cmd.result;
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
if (cmd.command === "no_ability") {
|
|
144
|
+
result.result = cmd.result || "\u65E0\u6CD5\u6267\u884C\u6B64\u64CD\u4F5C";
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
if (cmd.command === "use_tool") {
|
|
148
|
+
const { tool_name, params } = cmd;
|
|
149
|
+
if (!this.function_call) {
|
|
150
|
+
result.result = "\u672A\u6CE8\u518C\u5DE5\u5177\u51FD\u6570\u96C6\u5408\uFF0C\u65E0\u6CD5\u6267\u884C\u5DE5\u5177\u8C03\u7528";
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
history.push({
|
|
154
|
+
role: "assistant",
|
|
155
|
+
content: [{ type: "text", text: raw }]
|
|
151
156
|
});
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
+
let tool_result;
|
|
158
|
+
try {
|
|
159
|
+
tool_result = await this.function_call.exec_function(tool_name, params);
|
|
160
|
+
} catch (err) {
|
|
161
|
+
const err_msg = err?.message ?? String(err);
|
|
162
|
+
tool_fail_count[tool_name] = (tool_fail_count[tool_name] ?? 0) + 1;
|
|
163
|
+
history.push({
|
|
164
|
+
role: "user",
|
|
165
|
+
content: [{
|
|
166
|
+
type: "text",
|
|
167
|
+
text: `[\u5DE5\u5177\u6267\u884C\u5931\u8D25] ${tool_name}
|
|
168
|
+
\u9519\u8BEF\u4FE1\u606F: ${err_msg}
|
|
169
|
+
\u8BF7\u6839\u636E\u9519\u8BEF\u8C03\u6574\u7B56\u7565\u540E\u7EE7\u7EED`
|
|
170
|
+
}]
|
|
171
|
+
});
|
|
172
|
+
if (tool_fail_count[tool_name] >= 2) {
|
|
173
|
+
result.result = `\u5DE5\u5177 "${tool_name}" \u8FDE\u7EED\u8C03\u7528\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`;
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
history.push({
|
|
157
179
|
role: "user",
|
|
158
|
-
content: [
|
|
159
|
-
|
|
160
|
-
${
|
|
161
|
-
|
|
180
|
+
content: [{
|
|
181
|
+
type: "text",
|
|
182
|
+
text: `[\u5DE5\u5177\u8C03\u7528\u7ED3\u679C] ${tool_name}
|
|
183
|
+
${JSON.stringify(tool_result, null, 2)}`
|
|
184
|
+
}]
|
|
162
185
|
});
|
|
186
|
+
result.use_tools.push({ tool_name, params, exec_result: tool_result });
|
|
187
|
+
continue;
|
|
163
188
|
}
|
|
164
|
-
loop_count++;
|
|
165
189
|
}
|
|
190
|
+
result.result = "\u8D85\u51FA\u6700\u5927\u63A8\u7406\u8F6E\u6B21\uFF0C\u8BF7\u7CBE\u7B80\u95EE\u9898\u540E\u91CD\u8BD5";
|
|
191
|
+
return result;
|
|
166
192
|
}
|
|
193
|
+
// ─────────── System Prompt ───────────
|
|
167
194
|
/**
|
|
168
|
-
*
|
|
195
|
+
* 构建系统提示词。
|
|
196
|
+
* 将所有工具的完整 schema(含参数类型、必填项、示例值)
|
|
197
|
+
* 直接注入系统提示词,让 LLM 在单次调用中就能做出准确的工具选择和参数填写。
|
|
169
198
|
*/
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
199
|
+
build_system_prompt() {
|
|
200
|
+
if (this.custom_system_prompt) return this.custom_system_prompt;
|
|
201
|
+
const base = this.load_preset_prompt();
|
|
202
|
+
if (!this.function_call) return base;
|
|
203
|
+
const tool_schemas = this.function_call.get_tools_with_schema().map((t) => {
|
|
204
|
+
const props = Object.entries(t.input_schema.properties).map(([k, v]) => {
|
|
205
|
+
const req = t.input_schema.required?.includes(k) ? "\u5FC5\u586B" : "\u53EF\u9009";
|
|
206
|
+
const ex = v.examples?.length ? `\uFF0C\u793A\u4F8B: ${v.examples.join(" / ")}` : "";
|
|
207
|
+
return ` - ${k} (${v.type}, ${req}): ${v.description}${ex}`;
|
|
208
|
+
}).join("\n");
|
|
209
|
+
return `### ${t.name}
|
|
210
|
+
\u63CF\u8FF0: ${t.description}
|
|
211
|
+
\u53C2\u6570:
|
|
212
|
+
${props}`;
|
|
213
|
+
}).join("\n\n");
|
|
214
|
+
return `${base}
|
|
215
|
+
|
|
216
|
+
## \u53EF\u7528\u5DE5\u5177\u5217\u8868
|
|
217
|
+
|
|
218
|
+
${tool_schemas}`;
|
|
219
|
+
}
|
|
220
|
+
load_preset_prompt() {
|
|
221
|
+
try {
|
|
222
|
+
return fs.readFileSync(path.join(__dirname, "./preset_prompt.md"), "utf-8");
|
|
223
|
+
} catch {
|
|
224
|
+
return "";
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// ─────────── Helpers ───────────
|
|
228
|
+
normalize_input(input) {
|
|
229
|
+
if (typeof input === "string") {
|
|
230
|
+
return [{ role: "user", content: [{ type: "text", text: input }] }];
|
|
231
|
+
}
|
|
232
|
+
return [...input];
|
|
233
|
+
}
|
|
234
|
+
parse_command(raw) {
|
|
235
|
+
const json = this.safe_extract_json(raw);
|
|
236
|
+
if (!json || typeof json.command !== "string") return null;
|
|
237
|
+
return json;
|
|
238
|
+
}
|
|
239
|
+
safe_extract_json(content) {
|
|
240
|
+
try {
|
|
241
|
+
return LLM_Utils.extract_json(content);
|
|
242
|
+
} catch {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
async call_llm_with_retry(input) {
|
|
247
|
+
let last_error;
|
|
248
|
+
for (let i = 0; i <= this.retry_times; i++) {
|
|
249
|
+
try {
|
|
250
|
+
const res = await this.llm_chat_func(input);
|
|
251
|
+
if (typeof res === "string" && res.trim()) return res;
|
|
252
|
+
throw new Error("\u7A7A\u54CD\u5E94");
|
|
253
|
+
} catch (err) {
|
|
254
|
+
last_error = err;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
throw last_error ?? new Error("LLM\u8C03\u7528\u5931\u8D25");
|
|
173
258
|
}
|
|
174
259
|
};
|
|
175
260
|
|
|
@@ -179,7 +264,7 @@ import fs2 from "fs";
|
|
|
179
264
|
var FunctionCall = class {
|
|
180
265
|
constructor(tool_path) {
|
|
181
266
|
this.tool_path = tool_path;
|
|
182
|
-
this
|
|
267
|
+
__publicField(this, "tools", {});
|
|
183
268
|
this.init();
|
|
184
269
|
}
|
|
185
270
|
init() {
|
|
@@ -195,6 +280,9 @@ var FunctionCall = class {
|
|
|
195
280
|
*/
|
|
196
281
|
gen_tool_doc(name) {
|
|
197
282
|
const info = this.tools[name];
|
|
283
|
+
if (!info) {
|
|
284
|
+
throw `${name}\u5DE5\u5177\u51FD\u6570\u4E0D\u5B58\u5728`;
|
|
285
|
+
}
|
|
198
286
|
const schema = info.input_schema;
|
|
199
287
|
const schemaDesc = `\u7C7B\u578B: ${schema.type}`;
|
|
200
288
|
const params = Object.keys(schema.properties).map((key) => {
|
|
@@ -212,7 +300,7 @@ var FunctionCall = class {
|
|
|
212
300
|
${params}`;
|
|
213
301
|
}
|
|
214
302
|
/**
|
|
215
|
-
*
|
|
303
|
+
* 获取工具函数列表(仅名称 + 描述)
|
|
216
304
|
*/
|
|
217
305
|
get_tools_list() {
|
|
218
306
|
return Object.keys(this.tools).map((key) => {
|
|
@@ -223,6 +311,19 @@ ${params}`;
|
|
|
223
311
|
};
|
|
224
312
|
});
|
|
225
313
|
}
|
|
314
|
+
/**
|
|
315
|
+
* 获取工具函数列表(含完整 input_schema),供 Agent 注入系统提示词
|
|
316
|
+
*/
|
|
317
|
+
get_tools_with_schema() {
|
|
318
|
+
return Object.keys(this.tools).map((key) => {
|
|
319
|
+
const info = this.tools[key];
|
|
320
|
+
return {
|
|
321
|
+
name: info.name,
|
|
322
|
+
description: info.description,
|
|
323
|
+
input_schema: info.input_schema
|
|
324
|
+
};
|
|
325
|
+
});
|
|
326
|
+
}
|
|
226
327
|
/**
|
|
227
328
|
* 执行工具函数
|
|
228
329
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"type": "module",
|
|
3
2
|
"name": "p-api-agent",
|
|
4
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
5
4
|
"main": "./dist/index.cjs",
|
|
6
5
|
"module": "./dist/index.mjs",
|
|
7
6
|
"files": [
|
|
@@ -24,11 +23,15 @@
|
|
|
24
23
|
"@types/lodash": "4.17.16",
|
|
25
24
|
"@types/node": "^25.3.5",
|
|
26
25
|
"javascript-obfuscator": "^4.1.1",
|
|
26
|
+
"lodash": "^4.17.23",
|
|
27
|
+
"ts-node": "^10.9.2",
|
|
27
28
|
"tsup": "^8.4.0",
|
|
29
|
+
"tsx": "^4.21.0",
|
|
28
30
|
"typescript": "5.8.3"
|
|
29
31
|
},
|
|
30
32
|
"dependencies": {
|
|
31
33
|
"axios": "^1.13.6",
|
|
32
34
|
"jsonrepair": "^3.13.2"
|
|
33
|
-
}
|
|
35
|
+
},
|
|
36
|
+
"type": "module"
|
|
34
37
|
}
|