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 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
- constructor() {
103
- this.function_call = null;
104
- // 工具函数的说明文档, 供模型调用时参考
105
- this.function_call_doc = "";
106
- // 模型的聊天能力
107
- this.llm_chat_func = null;
108
- // 预置提示词
109
- this.preset_prompt = this.get_preset_prompt();
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
- register_function_call(function_call) {
115
- const tools_list = function_call.get_tools_list();
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
- * 注册LLM模型图片能力
129
- */
130
- register_llm_image_ability() {
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
- let dispose_user_input;
138
- if (typeof user_input === "string") {
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
- if (this.function_call_doc) {
151
- dispose_user_input.unshift({
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
- { type: "text", text: this.preset_prompt }
163
- ]
164
- });
165
- let max_loop = 20;
166
- let loop_count = 0;
167
- while (loop_count < max_loop) {
168
- const llm_res_str = await this.llm_chat_func(dispose_user_input);
169
- const llm_res = LLM_Utils.extract_json(llm_res_str);
170
- if (!llm_res.command) throw "\u5F02\u5E38\u6307\u4EE4, \u672A\u5305\u542Bcommand\u5B57\u6BB5";
171
- if (llm_res.command === "end") {
172
- return llm_res.result;
173
- } else if (llm_res.command === "get_tool_doc") {
174
- const tool_name = llm_res.tool_name;
175
- const tool_doc = this.function_call.gen_tool_doc(tool_name);
176
- dispose_user_input.push({
177
- role: "user",
178
- content: [
179
- { type: "text", text: `\u5DE5\u5177\u51FD\u6570${tool_name}\u7684\u8BF4\u660E\u6587\u6863:
180
- ${tool_doc}` }
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
- } else if (llm_res.command === "use_tool") {
184
- const tool_name = llm_res.tool_name;
185
- const tool_params = LLM_Utils.parse_json(llm_res.params);
186
- const tool_result = await this.function_call.exec_function(tool_name, tool_params);
187
- dispose_user_input.push({
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
- { type: "text", text: `\u5DE5\u5177\u51FD\u6570${tool_name}\u7684\u8C03\u7528\u7ED3\u679C:
191
- ${JSON.stringify(tool_result)}` }
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
- * agent预置提示词
224
+ * 构建系统提示词。
225
+ * 将所有工具的完整 schema(含参数类型、必填项、示例值)
226
+ * 直接注入系统提示词,让 LLM 在单次调用中就能做出准确的工具选择和参数填写。
200
227
  */
201
- get_preset_prompt() {
202
- const prompt = import_fs.default.readFileSync(import_path.default.join(__dirname, "./preset_prompt.md"), "utf-8");
203
- return prompt;
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.tools = {};
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 UserChatInput = string | {
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
- preset_prompt: string;
59
- constructor();
60
- /**
61
- * 注册工具函数
62
- */
63
- register_function_call(function_call: FunctionCall): boolean;
64
- /**
65
- * 注册LLM模型文字能力
66
- */
67
- register_llm_text_ability(func: (user_input: UserChatInput) => Promise<string>): void;
68
- /**
69
- * 注册LLM模型图片能力
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<any>;
113
+ create_chat(user_input: string | UserChatInput): Promise<CreateChatResult>;
76
114
  /**
77
- * agent预置提示词
115
+ * 构建系统提示词。
116
+ * 将所有工具的完整 schema(含参数类型、必填项、示例值)
117
+ * 直接注入系统提示词,让 LLM 在单次调用中就能做出准确的工具选择和参数填写。
78
118
  */
79
- get_preset_prompt(): string;
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 UserChatInput = string | {
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
- preset_prompt: string;
59
- constructor();
60
- /**
61
- * 注册工具函数
62
- */
63
- register_function_call(function_call: FunctionCall): boolean;
64
- /**
65
- * 注册LLM模型文字能力
66
- */
67
- register_llm_text_ability(func: (user_input: UserChatInput) => Promise<string>): void;
68
- /**
69
- * 注册LLM模型图片能力
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<any>;
113
+ create_chat(user_input: string | UserChatInput): Promise<CreateChatResult>;
76
114
  /**
77
- * agent预置提示词
115
+ * 构建系统提示词。
116
+ * 将所有工具的完整 schema(含参数类型、必填项、示例值)
117
+ * 直接注入系统提示词,让 LLM 在单次调用中就能做出准确的工具选择和参数填写。
78
118
  */
79
- get_preset_prompt(): string;
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
- constructor() {
72
- this.function_call = null;
73
- // 工具函数的说明文档, 供模型调用时参考
74
- this.function_call_doc = "";
75
- // 模型的聊天能力
76
- this.llm_chat_func = null;
77
- // 预置提示词
78
- this.preset_prompt = this.get_preset_prompt();
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
- register_function_call(function_call) {
84
- const tools_list = function_call.get_tools_list();
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
- * 注册LLM模型图片能力
98
- */
99
- register_llm_image_ability() {
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
- let dispose_user_input;
107
- if (typeof user_input === "string") {
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
- if (this.function_call_doc) {
120
- dispose_user_input.unshift({
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
- { type: "text", text: this.preset_prompt }
132
- ]
133
- });
134
- let max_loop = 20;
135
- let loop_count = 0;
136
- while (loop_count < max_loop) {
137
- const llm_res_str = await this.llm_chat_func(dispose_user_input);
138
- const llm_res = LLM_Utils.extract_json(llm_res_str);
139
- if (!llm_res.command) throw "\u5F02\u5E38\u6307\u4EE4, \u672A\u5305\u542Bcommand\u5B57\u6BB5";
140
- if (llm_res.command === "end") {
141
- return llm_res.result;
142
- } else if (llm_res.command === "get_tool_doc") {
143
- const tool_name = llm_res.tool_name;
144
- const tool_doc = this.function_call.gen_tool_doc(tool_name);
145
- dispose_user_input.push({
146
- role: "user",
147
- content: [
148
- { type: "text", text: `\u5DE5\u5177\u51FD\u6570${tool_name}\u7684\u8BF4\u660E\u6587\u6863:
149
- ${tool_doc}` }
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
- } else if (llm_res.command === "use_tool") {
153
- const tool_name = llm_res.tool_name;
154
- const tool_params = LLM_Utils.parse_json(llm_res.params);
155
- const tool_result = await this.function_call.exec_function(tool_name, tool_params);
156
- dispose_user_input.push({
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
- { type: "text", text: `\u5DE5\u5177\u51FD\u6570${tool_name}\u7684\u8C03\u7528\u7ED3\u679C:
160
- ${JSON.stringify(tool_result)}` }
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
- * agent预置提示词
195
+ * 构建系统提示词。
196
+ * 将所有工具的完整 schema(含参数类型、必填项、示例值)
197
+ * 直接注入系统提示词,让 LLM 在单次调用中就能做出准确的工具选择和参数填写。
169
198
  */
170
- get_preset_prompt() {
171
- const prompt = fs.readFileSync(path.join(__dirname, "./preset_prompt.md"), "utf-8");
172
- return prompt;
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.tools = {};
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.1",
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
  }