nongyu-agent-sdk 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 TangLei
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,55 @@
1
+ # 农屿Agent SDK
2
+
3
+ ## 项目描述
4
+
5
+ 农屿Agent是一个希望内嵌在农屿系统中工作的Agent,是农屿系统内部专用的Agent,而非通用Agent。
6
+
7
+ ## 背景补充
8
+
9
+ ### 农屿系统是什么?
10
+
11
+ - 农屿App(主站,面向四川农业大学学子的一站式智慧校园助手,是本Agent未来的主要宿主环境)
12
+ - 农屿后台管理系统(在更远的将来,本Agent将拓展问数等能力,用于智能化后台管理系统)
13
+ - 农屿官网(本Agent将暴露部分能力用于官网对外展示)
14
+
15
+ ## 能力边界设定
16
+
17
+ ### 核心能力
18
+
19
+ 1. 教务系统Agent
20
+ - 教务网首页通知询问
21
+ ```
22
+ 用户问:27届毕业生毕业照采集的时间地点是什么?
23
+ Agent回答:雅安校区时间xxx,地点xxx;成都校区时间xxx,地点xxx
24
+ ```
25
+ - 教务网竞赛通知询问
26
+ ```
27
+ 用户问: 第四届四川农业大学计算机设计大赛的报名方式是什么?
28
+ Agent回答:通过填写报名表.......
29
+ ```
30
+ - 学业进度查询
31
+ ```
32
+ 用户问:我的学业进度是什么?还差多少才能修够学分?
33
+ Agent回答:您的学业进度为....还需要修读xxx学分
34
+ ```
35
+ - 个人成绩查询(不展示示例)
36
+ - 个人排名查询(不展示示例)
37
+ - 考试安排查询(不展示示例)
38
+ - 个人课表查询(不展示示例)
39
+ - 调停课查询(待扩展)
40
+ - 空教室查询(待扩展)
41
+ - 教师课表查询(待扩展)
42
+ - 按学号对某学生课表查询(待扩展)
43
+
44
+ 2. 二课系统Agent
45
+ - 二课活动查询/搜索(不展示示例)
46
+ - 个人二课数据查询(不展示示例)
47
+ - 二课活动报名、取消报名(待扩展)
48
+
49
+ ### 不能做什么?不应该做什么?不擅长做什么?
50
+
51
+ 1. 定位清晰
52
+ 农屿Agent是一个专用Agent,它专用于农屿系统内部的各类问答、查询等操作,农屿Agent应该是全世界最懂川农的Agent,至少在我看来
53
+
54
+ 2. 局限
55
+ 它不会写代码、写文章等等(理论上它会,毕竟大模型本身会,但我们应该认为它不会),专业的Agent应该干专业的事,而不是要求它或者需要它什么都会
@@ -0,0 +1,85 @@
1
+ import { EventType } from 'mitt';
2
+
3
+ /**
4
+ * Agent 主类,负责协调上下文管理、大模型调用及 ReAct 逻辑循环
5
+ */
6
+ declare class Agent {
7
+ private llmClient;
8
+ private contextManager;
9
+ private toolManager;
10
+ private maxRetries;
11
+ private baseURL;
12
+ private apiKey;
13
+ private mode;
14
+ private log;
15
+ private handleToolCall;
16
+ private handleFinalAnswer;
17
+ private handleStrategy;
18
+ /**
19
+ * 初始化 Agent
20
+ * @param options 配置选项,包含 API Key、基础 URL、最大 ReAct 循环次数、运行模式、模型名称
21
+ */
22
+ constructor(options?: {
23
+ baseURL?: string;
24
+ apiKey?: string;
25
+ maxTokens?: number;
26
+ mode?: 'dev' | 'prod';
27
+ maxRetries?: number;
28
+ model?: string;
29
+ });
30
+ /**
31
+ * 处理用户提问的主入口
32
+ * @param userInput 用户输入内容
33
+ * @param stream 是否启用流式响应
34
+ * @returns 最终回答内容
35
+ */
36
+ chat(userInput: string, stream?: boolean): Promise<string>;
37
+ /**
38
+ * 清除当前 Agent 的上下文记忆
39
+ */
40
+ clearContext(): void;
41
+ }
42
+
43
+ /**
44
+ * 事件系统类,基于 mitt 封装
45
+ * 提供事件的订阅、发布和取消订阅功能
46
+ */
47
+ declare class EventSystem {
48
+ private emitter;
49
+ constructor();
50
+ /**
51
+ * 订阅事件
52
+ * @param event 事件名称
53
+ * @param handler 事件处理函数
54
+ */
55
+ on<T = any>(event: EventType, handler: (event: T) => void): void;
56
+ /**
57
+ * 订阅事件,只触发一次
58
+ * @param event 事件名称
59
+ * @param handler 事件处理函数
60
+ */
61
+ once<T = any>(event: EventType, handler: (event: T) => void): void;
62
+ /**
63
+ * 取消订阅事件
64
+ * @param event 事件名称
65
+ * @param handler 事件处理函数
66
+ */
67
+ off<T = any>(event: EventType, handler: (event: T) => void): void;
68
+ /**
69
+ * 发布事件
70
+ * @param event 事件名称
71
+ * @param data 事件数据
72
+ */
73
+ emit<T = any>(event: EventType, data?: T): void;
74
+ /**
75
+ * 清空所有事件订阅
76
+ */
77
+ clear(): void;
78
+ /**
79
+ * 获取当前所有事件订阅数量
80
+ */
81
+ getEventCount(): number;
82
+ }
83
+ declare const eventSystem: EventSystem;
84
+
85
+ export { Agent, eventSystem };
package/dist/index.js ADDED
@@ -0,0 +1,60 @@
1
+ import I from"axios";var h=class{constructor(e){this.mode="dev";this.mode=e?.mode||"dev",this.instance=I.create({timeout:1e4,headers:{"Content-Type":"application/json"},...e}),this.instance.interceptors.request.use(t=>t,t=>Promise.reject(t)),this.instance.interceptors.response.use(t=>t,t=>(this.mode==="dev"&&(t.response?console.error(`HTTP Error: ${t.response.status} - ${t.response.statusText}`):t.request?console.error("HTTP Error: No response received"):console.error("HTTP Error:",t.message)),Promise.reject(t)))}get(e,t,s=!1){let o=s?{...t,responseType:"stream"}:{...t},r=this.instance.get(e,o);return s||o.responseType&&o.responseType!=="json"?r:r.then(n=>n.data)}post(e,t,s,o=!1){let r=o?{...s,responseType:"stream"}:{...s},n=this.instance.post(e,t,r);return o||r.responseType&&r.responseType!=="json"?n:n.then(i=>i.data)}getInstance(){return this.instance}},$=new h,L=$;var u="https://open.bigmodel.cn/api/paas/v4",A="/chat/completions",f="9a71dd4699ad40589491316d69fe06e5.fZmosWLX2fIVxwRA",w="glm-4";var y=class{constructor(e){this.mode="dev";this.model=w;this.mode=e.mode||"dev",this.model=e.model||w,this.httpClient=new h({baseURL:e.baseURL||u,headers:{Authorization:`Bearer ${e.apiKey||f}`},mode:this.mode})}log(...e){this.mode==="dev"&&console.log(...e)}error(...e){this.log(...e)}async chat(e){try{return(await this.httpClient.post(A,{model:this.model,messages:e})).choices[0].message.content}catch(t){throw this.error("LLM Chat Error:",t),t}}async chatStream(e,t){try{let o=await this.httpClient.getInstance().post(A,{model:this.model,messages:e,stream:!0},{responseType:"stream"}),r="";return o.data.on("data",n=>{r+=n.toString();let i=r.split(`
2
+ `);r=i.pop()||"";for(let p of i){let d=p.trim();if(d!==""&&d.startsWith("data: ")){let g=d.slice(6);if(g==="[DONE]")break;try{let m=JSON.parse(g).choices[0]?.delta?.content||"";m&&t(m)}catch(l){this.error("Error parsing stream data:",l,"Line content:",d)}}}}),new Promise((n,i)=>{o.data.on("end",()=>n()),o.data.on("error",p=>i(p))})}catch(s){throw this.error("LLM Stream Chat Error:",s),s}}};var T=class{constructor(e=4e3,t="dev"){this.messages=[];this.maxTokens=4e3;this.mode="dev";this.maxTokens=e,this.mode=t}log(...e){this.mode==="dev"&&console.log(...e)}addMessage(e){this.messages.push(e),this.manageContext()}getMessages(){return[...this.messages]}init(e){this.clear(),this.addMessage({role:"system",content:e})}clear(){this.messages.length=0}manageContext(){if(this.messages.length>20){let t=this.messages.find(o=>o.role==="system"),s=this.messages.slice(-20);this.messages=t?[t,...s.filter(o=>o.role!=="system")]:s}}compress(){this.log("Context compression not implemented yet.")}};import*as b from"iconv-lite";var P={name:"web_fetcher",description:"\u83B7\u53D6\u6307\u5B9A URL \u7684\u7F51\u9875 HTML \u5185\u5BB9\uFF0C\u81EA\u52A8\u5904\u7406\u7F16\u7801\u8F6C\u6362\uFF08\u5982 GB2312\uFF09\u3002",params:{name:"url",type:"string",description:"\u8981\u83B7\u53D6\u7684\u7F51\u9875 URL",required:!0},function:async({url:a})=>{try{let e=await L.get(a,{headers:{Accept:"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36","Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8"},responseType:"arraybuffer",timeout:15e3}),t=Buffer.from(e.data),s=e.headers["content-type"]||"",o="utf-8",r=s.match(/charset=([\w-]+)/i);if(r)o=r[1].toLowerCase();else{let i=t.slice(0,1024).toString("ascii").match(/<meta[^>]+charset=["']?([\w-]+)["']?/i);i&&(o=i[1].toLowerCase())}return o==="gb2312"||o==="gbk"?b.decode(t,o):b.decode(t,"utf-8")}catch(e){throw console.error(`[WebFetcher] \u65E0\u6CD5\u83B7\u53D6\u7F51\u9875: ${a}`,e.message),new Error(`\u83B7\u53D6\u7F51\u9875\u5185\u5BB9\u5931\u8D25: ${e.message}`)}}};import{jiaowuNotice as v,jiaowuCompetition as M}from"nongyu-jiaowu";var N={params:v.registerInfo.params,description:v.registerInfo.description,name:v.registerInfo.name,function:v},O={params:M.registerInfo.params,description:M.registerInfo.description,name:M.registerInfo.name,function:M};var q=a=>{a.registerTool(P),a.registerTool(N),a.registerTool(O)},x=class{constructor(e="dev"){this.mode="dev";this.toolMap=new Map,this.mode=e}log(...e){this.mode==="dev"&&console.log(...e)}error(...e){this.mode==="dev"&&console.error(...e)}registerTool(e){this.toolMap.set(e.name,e)}unregisterTool(e){this.toolMap.delete(e)}getTool(e){return this.toolMap.get(e)}getTools(){return[...this.toolMap.values()]}async callTool(e,t={}){let s=this.getTool(e);if(!s)return Promise.reject(`\u5DE5\u5177 ${e} \u4E0D\u5B58\u5728`);if(!s.function)return Promise.reject(`\u5DE5\u5177 ${e} \u4E0D\u5B58\u5728\u53EF\u6267\u884C\u51FD\u6570`);try{let o=await s.function(t||{});return typeof o=="string"?o:JSON.stringify(o,null,2)}catch(o){throw this.error(`[ToolManager] \u5DE5\u5177\u8C03\u7528\u53D1\u751F\u5F02\u5E38 [${e}]:`,o),o}}};var k=(a=[])=>`
3
+ \u4F60\u662F\u4E00\u4E2A\u4E13\u95E8\u4E3A\u519C\u5C7F\u7CFB\u7EDF\u8BBE\u8BA1\u7684\u667A\u80FD\u52A9\u624B\uFF08\u519C\u5C7F Agent\uFF09\u3002
4
+ \u4F60\u7684\u4E3B\u8981\u4EFB\u52A1\u662F\u534F\u52A9\u5DDD\u519C\u5B66\u5B50\u5728\u519C\u5C7F App\u3001\u540E\u53F0\u7BA1\u7406\u7CFB\u7EDF\u4EE5\u53CA\u5B98\u7F51\u4E0A\u5B8C\u6210\u5404\u7C7B\u67E5\u8BE2\u548C\u95EE\u7B54\u3002
5
+
6
+ ### \u89D2\u8272\u8BBE\u5B9A
7
+ - \u540D\u79F0\uFF1A\u519C\u5C7F Agent
8
+ - \u5B9A\u4F4D\uFF1A\u6700\u61C2\u56DB\u5DDD\u519C\u4E1A\u5927\u5B66\u7684\u667A\u80FD\u52A9\u624B\u3002
9
+ - \u98CE\u683C\uFF1A\u7B80\u6D01\u3001\u4E13\u4E1A\u3001\u70ED\u60C5\u4E14\u5BCC\u6709\u8010\u5FC3\u3002
10
+
11
+ ### \u80FD\u529B\u8FB9\u754C
12
+ - \u64C5\u957F\uFF1A\u6559\u52A1\u7CFB\u7EDF\u76F8\u5173\u54A8\u8BE2\uFF08\u901A\u77E5\u3001\u7ADE\u8D5B\u3001\u5B66\u4E1A\u8FDB\u5EA6\u3001\u8BFE\u8868\u7B49\uFF09\u3001\u4E8C\u8BFE\u7CFB\u7EDF\u76F8\u5173\u54A8\u8BE2\uFF08\u6D3B\u52A8\u3001\u4E2A\u4EBA\u4E8C\u8BFE\u6570\u636E\u7B49\uFF09\u3002
13
+ - \u4E0D\u64C5\u957F\uFF1A\u7F16\u5199\u4EE3\u7801\u3001\u64B0\u5199\u957F\u7BC7\u6587\u7AE0\u4EE5\u53CA\u5176\u4ED6\u548C\u5B9A\u4F4D\u65E0\u5173\u7684\u4EFB\u52A1\u3002\u5982\u679C\u7528\u6237\u8981\u6C42\u8FD9\u4E9B\uFF0C\u8BF7\u59D4\u5A49\u5730\u544A\u77E5\u4F60\u7684\u5B9A\u4F4D\u3002
14
+
15
+ ### \u5DE5\u4F5C\u6D41\u7A0B (ReAct \u67B6\u6784)
16
+ \u5F53\u4F60\u6536\u5230\u7528\u6237\u95EE\u9898\u65F6\uFF0C\u8BF7\u9075\u5FAA\u4EE5\u4E0B\u6B65\u9AA4\uFF1A
17
+ 1. **Thought (\u601D\u8003)**: \u5206\u6790\u7528\u6237\u7684\u610F\u56FE\uFF0C\u51B3\u5B9A\u662F\u5426\u9700\u8981\u4F7F\u7528\u5916\u90E8\u5DE5\u5177\u6765\u83B7\u53D6\u4FE1\u606F\u3002
18
+ 2. **Action (\u884C\u52A8)**: \u5982\u679C\u9700\u8981\u5DE5\u5177\uFF0C\u8BF7\u8F93\u51FA\u7279\u5B9A\u7684 JSON \u683C\u5F0F\u6765\u8C03\u7528\u76F8\u5173\u5DE5\u5177\uFF0C\u793A\u4F8B\u53C2\u8003\u4E0B\u65B9\u7684\u5DE5\u5177\u8C03\u7528\u89C4\u8303\u3002
19
+ 3. **Observation (\u89C2\u5BDF)**: \u5904\u7406\u5DE5\u5177\u8FD4\u56DE\u7684\u7ED3\u679C\uFF08\u8FD9\u90E8\u5206\u7531\u7CFB\u7EDF\u81EA\u52A8\u8F93\u5165\uFF09\u3002
20
+ 4. **Final Answer (\u6700\u7EC8\u56DE\u7B54)**: \u57FA\u4E8E\u6536\u96C6\u5230\u7684\u4FE1\u606F\uFF0C\u7ED9\u51FA\u6700\u7EC8\u7684\u3001\u53CB\u597D\u7684\u4E2D\u6587\u56DE\u7B54\u3002
21
+
22
+ ### \u53EF\u7528\u7684\u5DE5\u5177\u5217\u8868
23
+ ${JSON.stringify(a)}
24
+
25
+ ### \u5FC5\u987B\u9075\u5FAA\u7684\u601D\u8003\u4E60\u60EF
26
+ - \u5F53\u7528\u6237\u95EE\u5230\u548C\u56DB\u5DDD\u519C\u4E1A\u5927\u5B66\u7684\u901A\u77E5\u76F8\u5173\u95EE\u9898\uFF0C\u5305\u62EC\u4F46\u4E0D\u9650\u4E8E\u201C26\u5E74\u5DDD\u519C\u4F53\u6D4B\u901A\u77E5\u201D\uFF0C\u4F60\u5E94\u8BE5\u4F18\u5148\u5C1D\u8BD5\u4F7F\u7528\u201C\u6559\u52A1\u901A\u77E5\u201D\u5DE5\u5177\uFF0C\u5982\u679C\u8C03\u7528\u6210\u529F\uFF0C\u5B83\u4F1A\u8FD4\u56DE\u4E00\u4E2A\u5305\u542B\u901A\u77E5\u6807\u9898\u548C\u94FE\u63A5\u7684\u5217\u8868\uFF0C\u4F60\u9700\u8981\u8FDB\u4E00\u6B65\u7684\u8C03\u7528\u201CWebFetcher\u201D\u5DE5\u5177\u6765\u83B7\u53D6\u901A\u77E5\u7684\u8BE6\u7EC6\u5185\u5BB9\u4EE5\u5E94\u5BF9\u7528\u6237\u7684\u9700\u6C42\u3002\u5982\u679C\u6559\u52A1\u901A\u77E5\u5DE5\u5177\u8FD4\u56DE\u7684\u901A\u77E5\u5217\u8868\u4E2D\u6CA1\u6709\u76F8\u5173\u901A\u77E5\uFF0C\u4F60\u5E94\u8BE5\u76F4\u63A5\u56DE\u7B54\u201C\u6CA1\u6709\u76F8\u5173\u4FE1\u606F\u201D\u3002
27
+ - \u5F53\u7528\u6237\u95EE\u5230\u548C\u56DB\u5DDD\u519C\u4E1A\u5927\u5B66\u7684\u7ADE\u8D5B\u76F8\u5173\u95EE\u9898\uFF0C\u5305\u62EC\u4F46\u4E0D\u9650\u4E8E\u201C\u5DDD\u519C\u7B2C\u56DB\u5C4A\u8BA1\u7B97\u673A\u8BBE\u8BA1\u5927\u8D5B\u5B89\u6392\u201D\uFF0C\u4F60\u5E94\u8BE5\u4F18\u5148\u5C1D\u8BD5\u4F7F\u7528\u201C\u7ADE\u8D5B\u901A\u77E5\u201D\u5DE5\u5177\uFF0C\u5982\u679C\u8C03\u7528\u6210\u529F\uFF0C\u5B83\u4F1A\u8FD4\u56DE\u4E00\u4E2A\u5305\u542B\u7ADE\u8D5B\u6807\u9898\u548C\u94FE\u63A5\u7684\u5217\u8868\uFF0C\u4F60\u9700\u8981\u8FDB\u4E00\u6B65\u7684\u8C03\u7528\u201CWebFetcher\u201D\u5DE5\u5177\u6765\u83B7\u53D6\u7ADE\u8D5B\u7684\u8BE6\u7EC6\u5185\u5BB9\u4EE5\u5E94\u5BF9\u7528\u6237\u7684\u9700\u6C42\u3002\u5982\u679C\u7ADE\u8D5B\u901A\u77E5\u5DE5\u5177\u8FD4\u56DE\u7684\u7ADE\u8D5B\u5217\u8868\u4E2D\u6CA1\u6709\u76F8\u5173\u7ADE\u8D5B\uFF0C\u4F60\u5E94\u8BE5\u76F4\u63A5\u56DE\u7B54\u201C\u6CA1\u6709\u76F8\u5173\u4FE1\u606F\u201D\u3002
28
+
29
+ ### \u56DE\u590D\u683C\u5F0F\u89C4\u8303
30
+ **\u56DE\u590D\u5FC5\u987B\u4E25\u683C\u9075\u5B88\u4EE5\u4E0B JSON \u683C\u5F0F\uFF0C\u4E14\u4E0D\u5305\u542B\u4EFB\u4F55\u591A\u4F59\u7684 Markdown \u4EE3\u7801\u5757\u6807\u7B7E\uFF08\u5982 \`\`\`json\uFF09\u6216\u5176\u4ED6\u524D\u5BFC/\u540E\u7F00\u6587\u672C\u3002**
31
+
32
+ - \u5982\u679C\u9700\u8981\u6267\u884C\u5DE5\u5177\uFF08Action\uFF09\uFF0C\u683C\u5F0F\u5982\u4E0B\uFF1A
33
+ {
34
+ "type": "action",
35
+ "function": {
36
+ "name": "\u5DE5\u5177\u540D\u79F0",
37
+ "params": {
38
+ "\u53C2\u6570\u540D1": "\u503C1",
39
+ "\u53C2\u6570\u540D2": "\u503C2"
40
+ }
41
+ }
42
+ }
43
+
44
+ - \u5982\u679C\u5DF2\u7ECF\u83B7\u5F97\u7ED3\u679C\u6216\u65E0\u9700\u6267\u884C\u5DE5\u5177\uFF0C\u76F4\u63A5\u7ED9\u51FA\u6700\u7EC8\u56DE\u7B54\uFF08Final Answer\uFF09\uFF0C\u683C\u5F0F\u5982\u4E0B\uFF1A
45
+ {
46
+ "type": "final_answer",
47
+ "content": "\u8FD9\u91CC\u662F\u4F60\u8981\u5BF9\u7528\u6237\u8BF4\u7684\u4E2D\u6587\u56DE\u7B54\u3002"
48
+ }
49
+
50
+ ### \u6CE8\u610F\u4E8B\u9879
51
+ 1. **JSON \u5B8C\u6574\u6027**\uFF1A\u8F93\u51FA\u7684\u5FC5\u987B\u662F\u5408\u6CD5\u7684 JSON \u5BF9\u8C61\uFF0C\u4E0D\u8981\u8F93\u51FA\u534A\u622A\u3002
52
+ 2. **\u53C2\u6570\u51C6\u786E\u6027**\uFF1A\u8C03\u7528\u5DE5\u5177\u65F6\uFF0C\`params\` \u4E2D\u7684\u5B57\u6BB5\u540D\u5FC5\u987B\u4E0E\u5DE5\u5177\u5217\u8868\u4E2D\u5B9A\u4E49\u7684\u53C2\u6570\u540D\u5B8C\u5168\u4E00\u81F4\u3002
53
+ 3. **\u4E00\u6B65\u4E00\u601D**\uFF1A\u6BCF\u6B21\u53EA\u8C03\u7528\u4E00\u4E2A\u5DE5\u5177\u3002\u5728\u83B7\u53D6 Observation \u540E\u518D\u51B3\u5B9A\u4E0B\u4E00\u6B65\u884C\u52A8\u3002
54
+ `,C=k;import*as R from"mitt";var S=class{constructor(){let e=R.default||R;this.emitter=e()}on(e,t){this.emitter.on(e,t)}once(e,t){let s=o=>{t(o),this.emitter.off(e,s)};this.emitter.on(e,s)}off(e,t){this.emitter.off(e,t)}emit(e,t){this.emitter.emit(e,t)}clear(){this.emitter.all.clear()}getEventCount(){return this.emitter.all.size}},J=new S,c=J;var E=class{constructor(e){this.maxRetries=15;this.baseURL=u;this.apiKey=f;this.mode="dev";this.handleToolCall=async e=>{let{function:{name:t,params:s}}=e;c.emit("chat:tool:start",{actionMatch:JSON.stringify(e.function)}),this.log(`[Agent] \u51C6\u5907\u8C03\u7528\u5DE5\u5177: ${t}, \u53C2\u6570:`,s);try{let o=await this.toolManager.callTool(t,s);return c.emit("chat:tool:complete",{observation:o}),this.contextManager.addMessage({role:"user",content:`### Observation (\u89C2\u6D4B\u7ED3\u679C)
55
+ \u5DE5\u5177 [${t}] \u7684\u6267\u884C\u7ED3\u679C\u5982\u4E0B\uFF1A
56
+
57
+ ${typeof o=="string"?o:JSON.stringify(o,null,2)}
58
+
59
+ \u8BF7\u6839\u636E\u4EE5\u4E0A\u7ED3\u679C\u8FDB\u884C\u4E0B\u4E00\u6B65\u5206\u6790\u6216\u7ED9\u51FA\u6700\u7EC8\u56DE\u7B54\u3002`}),typeof o=="string"?o:JSON.stringify(o)}catch(o){c.emit("chat:tool:error",{error:o});let r=`\u5DE5\u5177\u8C03\u7528\u5931\u8D25: ${o.message||o}`;return this.contextManager.addMessage({role:"user",content:r}),r}};this.handleFinalAnswer=e=>{let{content:t}=e;return c.emit("chat:complete",{finalAnswer:t}),t};this.handleStrategy={action:async e=>await this.handleToolCall(e),final_answer:e=>this.handleFinalAnswer(e)};this.mode=e?.mode||"dev",this.maxRetries=e?.maxRetries||15,this.llmClient=new y({baseURL:e?.baseURL||this.baseURL,apiKey:e?.apiKey||this.apiKey,mode:this.mode,model:e?.model}),this.contextManager=new T(e?.maxTokens,this.mode),this.toolManager=new x(this.mode),q(this.toolManager);let t=C(this.toolManager.getTools());this.contextManager.init(t)}log(...e){this.mode==="dev"&&console.log(...e)}async chat(e,t=!1){this.contextManager.addMessage({role:"user",content:e}),c.emit("chat:start",{userInput:e}),this.log(`[Agent] \u5F00\u59CB\u5904\u7406\u7528\u6237\u95EE\u9898: ${e}`);let s=0;for(;s++<this.maxRetries;){c.emit("chat:loop:start",{loopCount:s}),this.log(`[Agent] \u5F00\u59CB\u7B2C ${s} \u8F6E\u5FAA\u73AF`);let r=this.contextManager.getMessages(),n="";try{t?await this.llmClient.chatStream(r,l=>{n+=l,c.emit("chat:stream:token",{token:l,accumulatedResponse:n})}):n=await this.llmClient.chat(r)}catch(l){let m=`LLM \u8C03\u7528\u8FC7\u7A0B\u53D1\u751F\u9519\u8BEF: ${l.message}`;return c.emit("chat:error",{message:m}),m}c.emit("chat:response:complete",{response:n}),this.contextManager.addMessage({role:"assistant",content:n});let i=null;try{i=JSON.parse(n)}catch{let m="\u56DE\u590D\u683C\u5F0F\u9519\u8BEF\u3002\u8BF7\u786E\u4FDD\u4F60\u7684\u56DE\u590D\u662F\u4E00\u4E2A\u53EF\u4EE5\u88AB JSON.parse() \u76F4\u63A5\u89E3\u6790\u7684\u6709\u6548 JSON \u5BF9\u8C61\u3002";c.emit("chat:error:notJson",{message:m}),this.contextManager.addMessage({role:"user",content:m});continue}if(!i){this.contextManager.addMessage({role:"user",content:"\u56DE\u590D\u5185\u5BB9\u4E3A\u7A7A\uFF0C\u8BF7\u63D0\u4F9B\u6709\u6548\u7684 JSON \u56DE\u590D\u3002"});continue}let{type:p}=i,d=this.handleStrategy[p];if(!d){let l=`\u672A\u77E5\u7684\u56DE\u590D\u7C7B\u578B: ${p}\uFF0C\u8BF7\u6309\u7167\u89C4\u8303\u56DE\u590D "action" \u6216 "final_answer"\u3002`;this.contextManager.addMessage({role:"user",content:l});continue}let g=await d(i);if(p==="final_answer")return g}let o="Agent \u8FD0\u884C\u8D85\u8FC7\u6700\u5927\u5FAA\u73AF\u6B21\u6570\uFF0C\u65E0\u6CD5\u83B7\u53D6\u56DE\u7B54\u3002";return c.emit("chat:error:maxRetries",{message:o}),o}clearContext(){let e=C(this.toolManager.getTools());this.contextManager.init(e)}};export{E as Agent,c as eventSystem};
60
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/http.ts","../config/LLMConfig.ts","../src/core/LLMClient.ts","../src/core/ContextManager.ts","../src/tools/builtin/WebFetcher.ts","../src/tools/external/jiaowu.ts","../src/core/ToolManager.ts","../src/prompts/systemPrompt.ts","../src/core/EventSystem.ts","../src/core/Agent.ts"],"sourcesContent":["import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'\n\n/**\n * 封装的 HTTP 请求工具类,基于 Axios\n */\nexport class HttpClient {\n private instance: AxiosInstance\n private mode: 'dev' | 'prod' = 'dev' // 运行模式\n\n constructor(config?: AxiosRequestConfig & { mode?: 'dev' | 'prod' }) {\n this.mode = config?.mode || 'dev'\n this.instance = axios.create({\n timeout: 10000, // 默认超时时间 10 秒\n headers: {\n 'Content-Type': 'application/json',\n },\n ...config,\n })\n\n // 请求拦截器\n this.instance.interceptors.request.use(\n (config) => {\n // 在这里可以添加全局的请求处理逻辑,如添加 Token\n return config\n },\n (error) => {\n return Promise.reject(error)\n },\n )\n\n // 响应拦截器\n this.instance.interceptors.response.use(\n (response: AxiosResponse) => {\n // 在这里可以添加全局的响应处理逻辑\n return response\n },\n (error) => {\n // 统一错误处理\n if (this.mode === 'dev') {\n if (error.response) {\n console.error(`HTTP Error: ${error.response.status} - ${error.response.statusText}`)\n } else if (error.request) {\n console.error('HTTP Error: No response received')\n } else {\n console.error('HTTP Error:', error.message)\n }\n }\n return Promise.reject(error)\n },\n )\n }\n\n /**\n * 发送 GET 请求\n * @param url 请求地址\n * @param config 请求配置\n * @param stream 是否启用流式响应\n */\n public get<T = any>(\n url: string,\n config?: AxiosRequestConfig,\n stream: boolean = false,\n ): Promise<T | AxiosResponse> {\n const requestConfig: AxiosRequestConfig = stream ? { ...config, responseType: 'stream' } : { ...config }\n const request = this.instance.get(url, requestConfig)\n \n if (stream) {\n return request as any\n }\n \n // 如果设置了特定的 responseType,则由调用方处理完整响应\n if (requestConfig.responseType && requestConfig.responseType !== 'json') {\n return request\n }\n \n return request.then((res) => res.data)\n }\n\n /**\n * 发送 POST 请求\n * @param url 请求地址\n * @param data 请求数据\n * @param config 请求配置\n * @param stream 是否启用流式响应\n */\n public post<T = any>(\n url: string,\n data?: any,\n config?: AxiosRequestConfig,\n stream: boolean = false,\n ): Promise<T | AxiosResponse> {\n const requestConfig: AxiosRequestConfig = stream ? { ...config, responseType: 'stream' } : { ...config }\n const request = this.instance.post(url, data, requestConfig)\n \n if (stream) {\n return request as any\n }\n \n // 如果设置了特定的 responseType,则由调用方处理完整响应\n if (requestConfig.responseType && requestConfig.responseType !== 'json') {\n return request\n }\n \n return request.then((res) => res.data)\n }\n\n /**\n * 获取原生的 Axios 实例,用于特殊场景(如流式输出)\n */\n public getInstance(): AxiosInstance {\n return this.instance\n }\n}\n\n// 默认导出单例或创建一个基础实例\nconst defaultHttp = new HttpClient()\nexport default defaultHttp\n","// 大模型默认配置\r\nexport const BASE_URL = 'https://open.bigmodel.cn/api/paas/v4'\r\nexport const ENDPOINT = '/chat/completions'\r\n// TODO:后续思考这个架构,如果要提供默认key的话应该要通过搭建一个服务器来中转请求\r\nexport const API_KEY = '9a71dd4699ad40589491316d69fe06e5.fZmosWLX2fIVxwRA' // 暂时不考虑生产环境的泄漏问题,后续优化\r\nexport const MODEL = 'glm-4'","import { HttpClient } from '../utils/http.js'\nimport { Message } from '../types/Message.js'\nimport { BASE_URL, API_KEY, MODEL, ENDPOINT } from '../../config/LLMConfig.js'\n\n/**\n * LLM 客户端类,用于与大模型 API 进行交互\n */\nexport class LLMClient {\n private httpClient: HttpClient\n private mode: 'dev' | 'prod' = 'dev' // 运行模式\n private model: string = MODEL // 使用的模型\n\n constructor(options: { \n baseURL?: string; \n apiKey?: string; \n mode?: 'dev' | 'prod';\n model?: string;\n }) {\n this.mode = options.mode || 'dev'\n this.model = options.model || MODEL\n this.httpClient = new HttpClient({\n baseURL: options.baseURL || BASE_URL,\n headers: {\n Authorization: `Bearer ${options.apiKey || API_KEY}`,\n },\n mode: this.mode,\n })\n }\n\n // 内部日志方法,仅在 dev 模式下输出\n private log(...args: any[]) {\n if (this.mode === 'dev') {\n console.log(...args)\n }\n }\n\n // 内部错误日志方法,仅在 dev 模式下输出\n private error(...args: any[]) {\n this.log(...args)\n }\n\n /**\n * 发送非流式聊天请求\n * @param messages 消息列表\n * @returns 模型回复内容\n */\n async chat(messages: Message[]): Promise<string> {\n try {\n const data = await this.httpClient.post<any>(ENDPOINT, {\n model: this.model, // 使用配置的模型\n messages,\n })\n return data.choices[0].message.content\n } catch (err) {\n this.error('LLM Chat Error:', err)\n throw err\n }\n }\n\n /**\n * 发送流式聊天请求\n * @param messages 消息列表\n * @param onToken 接收到 token 时的回调函数\n */\n async chatStream(messages: Message[], onToken: (token: string) => any): Promise<void> {\n try {\n const axiosInstance = this.httpClient.getInstance()\n const response = await axiosInstance.post(\n ENDPOINT,\n {\n model: this.model, // 使用配置的模型\n messages,\n stream: true,\n },\n {\n responseType: 'stream',\n },\n )\n\n // 维护一个缓冲区来处理流式数据,防止 JSON 解析错误\n let buffer = ''\n response.data.on('data', (chunk: Buffer) => {\n buffer += chunk.toString()\n const lines = buffer.split('\\n')\n \n // 最后一行可能是不完整的,保留在缓冲区中\n buffer = lines.pop() || ''\n\n for (const line of lines) {\n const trimmedLine = line.trim()\n if (trimmedLine === '') continue\n if (trimmedLine.startsWith('data: ')) {\n const data = trimmedLine.slice(6)\n if (data === '[DONE]') break\n try {\n const parsed = JSON.parse(data)\n const token = parsed.choices[0]?.delta?.content || ''\n if (token) {\n // 调用回调函数处理 token\n onToken(token)\n }\n } catch (e) {\n // 这里的解析错误通常是因为数据还不完整,但在有了 buffer 逻辑后应该很少发生\n this.error('Error parsing stream data:', e, 'Line content:', trimmedLine)\n }\n }\n }\n })\n\n return new Promise((resolve, reject) => {\n response.data.on('end', () => resolve())\n response.data.on('error', (err: Error) => reject(err))\n })\n } catch (err) {\n this.error('LLM Stream Chat Error:', err)\n throw err\n }\n }\n}\n","import { Message } from '../types/Message.js'\n\n/**\n * 上下文管理器,用于管理 Agent 的短期记忆\n */\nexport class ContextManager {\n private messages: Message[] = []\n private maxTokens: number = 4000 // 默认最大上下文限制\n private mode: 'dev' | 'prod' = 'dev' // 运行模式\n\n constructor(maxTokens: number = 4000, mode: 'dev' | 'prod' = 'dev') {\n this.maxTokens = maxTokens\n this.mode = mode\n }\n\n // 内部日志方法,仅在 dev 模式下输出\n private log(...args: any[]) {\n if (this.mode === 'dev') {\n console.log(...args)\n }\n }\n\n /**\n * 添加消息到上下文\n * @param message 消息对象\n */\n addMessage(message: Message) {\n this.messages.push(message)\n this.manageContext()\n }\n\n /**\n * 获取当前所有上下文消息\n */\n getMessages(): Message[] {\n // 这是浅拷贝,暂时先这样写,后面调试过程中再找问题\n return [...this.messages]\n }\n\n /**\n * 初始化/重置上下文,并添加系统提示词\n * @param systemPrompt 系统提示词内容\n */\n init(systemPrompt: string) {\n this.clear()\n this.addMessage({\n role: 'system',\n content: systemPrompt,\n } as any)\n }\n\n /**\n * 清空上下文\n */\n clear() {\n this.messages.length = 0\n }\n\n /**\n * 上下文管理策略:滑动窗口\n * 暂时简单实现为保留最近的消息,后续可引入 token 计数和压缩策略\n */\n private manageContext() {\n // 简单的滑动窗口,保留最近的 20 条消息作为短期记忆\n const MAX_MESSAGES = 20\n if (this.messages.length > MAX_MESSAGES) {\n // 保留系统提示词(假设第一条是系统提示词)\n const systemMessage = this.messages.find(m => m.role === 'system')\n const recentMessages = this.messages.slice(-MAX_MESSAGES)\n \n this.messages = systemMessage \n ? [systemMessage, ...recentMessages.filter(m => m.role !== 'system')]\n : recentMessages\n }\n }\n\n /**\n * 压缩上下文(待实现)\n * 需要依赖模型来进行语义压缩\n * 会额外产生一次模型调用\n */\n compress() {\n // 根据 Tech.md,未来可引入上下文压缩算法\n this.log('Context compression not implemented yet.')\n }\n}\n","import { Tool } from '../../types/Tool.js'\nimport http from '../../utils/http.js'\nimport * as iconv from 'iconv-lite'\nimport { AxiosResponse } from 'axios'\n\n/**\n * Agent 内置工具:网页内容获取\n * 接收一个 URL 并返回该页面的 HTML 内容\n */\nexport const WebFetcher: Tool = {\n name: 'web_fetcher',\n description: '获取指定 URL 的网页 HTML 内容,自动处理编码转换(如 GB2312)。',\n params: {\n name: 'url',\n type: 'string',\n description: '要获取的网页 URL',\n required: true,\n },\n function: async ({ url }: { url: string }) => {\n try {\n // 使用 arraybuffer 以便后续根据实际编码进行转换\n const response = await http.get<any>(url, {\n headers: {\n 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',\n 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',\n 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',\n },\n responseType: 'arraybuffer',\n timeout: 15000,\n }) as AxiosResponse\n\n const buffer = Buffer.from(response.data)\n const contentType = response.headers['content-type'] || ''\n \n // 默认编码为 utf-8\n let encoding = 'utf-8'\n \n // 尝试从 Content-Type 响应头中提取编码信息\n const charsetMatch = contentType.match(/charset=([\\w-]+)/i)\n if (charsetMatch) {\n encoding = charsetMatch[1].toLowerCase()\n } else {\n // 如果响应头没有,则尝试从 HTML 内容中通过正则匹配\n const htmlSnippet = buffer.slice(0, 1024).toString('ascii')\n const metaCharsetMatch = htmlSnippet.match(/<meta[^>]+charset=[\"']?([\\w-]+)[\"']?/i)\n if (metaCharsetMatch) {\n encoding = metaCharsetMatch[1].toLowerCase()\n }\n }\n\n // 如果是 gb2312 或 gbk,进行转换\n if (encoding === 'gb2312' || encoding === 'gbk') {\n return iconv.decode(buffer, encoding)\n }\n\n // 默认尝试用 utf-8 解码\n return iconv.decode(buffer, 'utf-8')\n } catch (error: any) {\n console.error(`[WebFetcher] 无法获取网页: ${url}`, error.message)\n throw new Error(`获取网页内容失败: ${error.message}`)\n }\n }\n}\n","// 教务系统相关工具\r\nimport { jiaowuNotice,jiaowuCompetition } from \"nongyu-jiaowu\";\r\nimport { Tool } from \"../../types/Tool.js\";\r\nconst jiaowuNoticeTool: Tool = {\r\n params: jiaowuNotice.registerInfo.params,\r\n description: jiaowuNotice.registerInfo.description,\r\n name: jiaowuNotice.registerInfo.name,\r\n function: jiaowuNotice,\r\n}\r\nconst jiaowuCompetitionTool: Tool = {\r\n params: jiaowuCompetition.registerInfo.params,\r\n description: jiaowuCompetition.registerInfo.description,\r\n name: jiaowuCompetition.registerInfo.name,\r\n function: jiaowuCompetition,\r\n}\r\nexport {\r\n jiaowuNoticeTool,\r\n jiaowuCompetitionTool,\r\n}\r\n","import { Tool } from '../types/Tool.js';\nimport { WebFetcher } from '../tools/builtin/WebFetcher.js';\nimport { jiaowuNoticeTool, jiaowuCompetitionTool } from '../tools/external/jiaowu.js';\n\n// 初始化工具\nexport const initTools = (toolManager: ToolManager) => {\n // 注册内置工具\n toolManager.registerTool(WebFetcher)\n // 注册外部工具\n // 教务系统相关工具\n toolManager.registerTool(jiaowuNoticeTool)\n toolManager.registerTool(jiaowuCompetitionTool)\n // 其他外部工具...\n // ...\n}\n\nexport class ToolManager {\n private toolMap: Map<string, Tool>;\n private mode: 'dev' | 'prod' = 'dev'; // 运行模式\n\n constructor(mode: 'dev' | 'prod' = 'dev') {\n this.toolMap = new Map();\n this.mode = mode;\n }\n\n // 内部日志方法,仅在 dev 模式下输出\n private log(...args: any[]) {\n if (this.mode === 'dev') {\n console.log(...args)\n }\n }\n\n // 内部错误日志方法,仅在 dev 模式下输出\n private error(...args: any[]) {\n if (this.mode === 'dev') {\n console.error(...args)\n }\n }\n\n registerTool(tool: Tool) {\n this.toolMap.set(tool.name, tool);\n }\n unregisterTool(name: string) {\n this.toolMap.delete(name);\n }\n getTool(name: string): Tool | undefined {\n return this.toolMap.get(name);\n }\n getTools(): Tool[] {\n return [...this.toolMap.values()];\n }\n // TODO: 核心函数,后续还得优化逻辑\n async callTool(name: string, params: Record<string, any> = {}): Promise<string> {\n // 获取工具对应的函数\n const tool = this.getTool(name);\n if (!tool) {\n return Promise.reject(`工具 ${name} 不存在`);\n }\n\n if (!tool.function) {\n return Promise.reject(`工具 ${name} 不存在可执行函数`);\n }\n\n try {\n // 确保 params 是对象,并调用工具函数\n const result = await tool.function(params || {});\n // 如果结果不是字符串,进行序列化\n return typeof result === 'string' ? result : JSON.stringify(result, null, 2);\n } catch (err: any) {\n this.error(`[ToolManager] 工具调用发生异常 [${name}]:`, err);\n throw err;\n }\n }\n}\n","import { Tool } from \"../types/Tool.js\"\n\n// 拼接系统提示词\nconst composeSystemPrompt = (tools:Tool[]=[]) => {\n /**\n * 农屿 Agent 系统提示词\n * 定义 Agent 的角色、能力边界以及 ReAct 交互流程\n * 编写好用、能用的系统提示词也是提示词工程的体现\n * 系统提示词应该要根据实际效果进行调整\n */\n const systemPrompt = `\n 你是一个专门为农屿系统设计的智能助手(农屿 Agent)。\n 你的主要任务是协助川农学子在农屿 App、后台管理系统以及官网上完成各类查询和问答。\n\n ### 角色设定\n - 名称:农屿 Agent\n - 定位:最懂四川农业大学的智能助手。\n - 风格:简洁、专业、热情且富有耐心。\n\n ### 能力边界\n - 擅长:教务系统相关咨询(通知、竞赛、学业进度、课表等)、二课系统相关咨询(活动、个人二课数据等)。\n - 不擅长:编写代码、撰写长篇文章以及其他和定位无关的任务。如果用户要求这些,请委婉地告知你的定位。\n\n ### 工作流程 (ReAct 架构)\n 当你收到用户问题时,请遵循以下步骤:\n 1. **Thought (思考)**: 分析用户的意图,决定是否需要使用外部工具来获取信息。\n 2. **Action (行动)**: 如果需要工具,请输出特定的 JSON 格式来调用相关工具,示例参考下方的工具调用规范。\n 3. **Observation (观察)**: 处理工具返回的结果(这部分由系统自动输入)。\n 4. **Final Answer (最终回答)**: 基于收集到的信息,给出最终的、友好的中文回答。\n\n ### 可用的工具列表\n ${JSON.stringify(tools)}\n\n ### 必须遵循的思考习惯\n - 当用户问到和四川农业大学的通知相关问题,包括但不限于“26年川农体测通知”,你应该优先尝试使用“教务通知”工具,如果调用成功,它会返回一个包含通知标题和链接的列表,你需要进一步的调用“WebFetcher”工具来获取通知的详细内容以应对用户的需求。如果教务通知工具返回的通知列表中没有相关通知,你应该直接回答“没有相关信息”。\n - 当用户问到和四川农业大学的竞赛相关问题,包括但不限于“川农第四届计算机设计大赛安排”,你应该优先尝试使用“竞赛通知”工具,如果调用成功,它会返回一个包含竞赛标题和链接的列表,你需要进一步的调用“WebFetcher”工具来获取竞赛的详细内容以应对用户的需求。如果竞赛通知工具返回的竞赛列表中没有相关竞赛,你应该直接回答“没有相关信息”。\n \n ### 回复格式规范\n **回复必须严格遵守以下 JSON 格式,且不包含任何多余的 Markdown 代码块标签(如 \\`\\`\\`json)或其他前导/后缀文本。**\n\n - 如果需要执行工具(Action),格式如下:\n {\n \"type\": \"action\",\n \"function\": {\n \"name\": \"工具名称\",\n \"params\": {\n \"参数名1\": \"值1\",\n \"参数名2\": \"值2\"\n }\n }\n }\n\n - 如果已经获得结果或无需执行工具,直接给出最终回答(Final Answer),格式如下:\n {\n \"type\": \"final_answer\",\n \"content\": \"这里是你要对用户说的中文回答。\"\n }\n\n ### 注意事项\n 1. **JSON 完整性**:输出的必须是合法的 JSON 对象,不要输出半截。\n 2. **参数准确性**:调用工具时,\\`params\\` 中的字段名必须与工具列表中定义的参数名完全一致。\n 3. **一步一思**:每次只调用一个工具。在获取 Observation 后再决定下一步行动。\n`\n return systemPrompt\n}\n\nexport default composeSystemPrompt\n","import * as mittModule from 'mitt'\nimport type { Emitter, EventType } from 'mitt'\n\n/**\n * 事件系统类,基于 mitt 封装\n * 提供事件的订阅、发布和取消订阅功能\n */\nexport class EventSystem {\n private emitter: Emitter<Record<EventType, any>>\n\n constructor() {\n // 兼容 ESM 和 CJS 的 mitt 导出方式,解决 DTS 构建时的类型报错\n const mitt = (mittModule as any).default || (mittModule as any)\n this.emitter = mitt()\n }\n\n /**\n * 订阅事件\n * @param event 事件名称\n * @param handler 事件处理函数\n */\n public on<T = any>(event: EventType, handler: (event: T) => void): void {\n this.emitter.on(event, handler)\n }\n\n /**\n * 订阅事件,只触发一次\n * @param event 事件名称\n * @param handler 事件处理函数\n */\n public once<T = any>(event: EventType, handler: (event: T) => void): void {\n const onceHandler = (data: T) => {\n handler(data)\n this.emitter.off(event, onceHandler)\n }\n this.emitter.on(event, onceHandler)\n }\n\n /**\n * 取消订阅事件\n * @param event 事件名称\n * @param handler 事件处理函数\n */\n public off<T = any>(event: EventType, handler: (event: T) => void): void {\n this.emitter.off(event, handler)\n }\n\n /**\n * 发布事件\n * @param event 事件名称\n * @param data 事件数据\n */\n public emit<T = any>(event: EventType, data?: T): void {\n this.emitter.emit(event, data)\n }\n\n /**\n * 清空所有事件订阅\n */\n public clear(): void {\n this.emitter.all.clear()\n }\n\n /**\n * 获取当前所有事件订阅数量\n */\n public getEventCount(): number {\n return this.emitter.all.size\n }\n}\n\n// 默认导出单例\nconst eventSystem = new EventSystem()\nexport default eventSystem\n","import { LLMClient } from './LLMClient.js'\nimport { ContextManager } from './ContextManager.js'\nimport { ToolManager } from './ToolManager.js'\nimport { initTools } from './ToolManager.js'\nimport composeSystemPrompt from '../prompts/systemPrompt.js'\nimport { BASE_URL, API_KEY } from '../../config/LLMConfig.js'\nimport eventSystem from './EventSystem.js'\nimport { ToolCall, FinalAnswer, HandleStrategy } from '../types/Reply.js'\n\n/**\n * Agent 主类,负责协调上下文管理、大模型调用及 ReAct 逻辑循环\n */\nexport class Agent {\n private llmClient: LLMClient\n private contextManager: ContextManager\n private toolManager: ToolManager\n private maxRetries: number = 15 // 最大 ReAct 循环次数\n private baseURL: string = BASE_URL // 默认基础 URL\n private apiKey: string = API_KEY // 默认 API Key\n private mode: 'dev' | 'prod' = 'dev' // 运行模式,可取值为 \"dev\" 或 \"prod\"\n\n // 内部日志方法,仅在 dev 模式下输出\n private log(...args: any[]) {\n if (this.mode === 'dev') {\n console.log(...args)\n }\n }\n\n // 处理工具调用\n private handleToolCall = async (parsedResponse: ToolCall): Promise<string> => {\n // 解析工具调用参数\n const { function: { name, params } } = parsedResponse\n \n // 触发工具调用开始事件\n eventSystem.emit('chat:tool:start', { actionMatch: JSON.stringify(parsedResponse.function) })\n \n this.log(`[Agent] 准备调用工具: ${name}, 参数:`, params)\n\n try {\n // 调用工具\n const toolResult = await this.toolManager.callTool(name, params)\n // 触发工具执行完成事件\n eventSystem.emit('chat:tool:complete', { observation: toolResult })\n \n // 更加结构化的观测反馈,引导模型进行下一步思考\n this.contextManager.addMessage({\n role: 'user',\n content: `### Observation (观测结果)\\n工具 [${name}] 的执行结果如下:\\n\\n${typeof toolResult === 'string' ? toolResult : JSON.stringify(toolResult, null, 2)}\\n\\n请根据以上结果进行下一步分析或给出最终回答。`,\n } as any)\n \n return typeof toolResult === 'string' ? toolResult : JSON.stringify(toolResult)\n } catch (error: any) {\n // 触发工具执行错误事件\n eventSystem.emit('chat:tool:error', { error })\n const errorMessage = `工具调用失败: ${error.message || error}`\n \n this.contextManager.addMessage({\n role: 'user',\n content: errorMessage,\n } as any)\n \n return errorMessage\n }\n }\n\n // 处理最终回答,返回代表最终回复的字符串\n private handleFinalAnswer = (parsedResponse: FinalAnswer): string => {\n // 解析最终回答内容\n const { content } = parsedResponse\n // 触发最终回答事件\n eventSystem.emit('chat:complete', { finalAnswer: content })\n // 注意:不再重复添加 content 到上下文,因为完整的 JSON 回复已经在主循环中添加过了\n return content\n }\n\n // 大模型回复的处理策略映射\n private handleStrategy: HandleStrategy = {\n 'action': async (response: any) => {\n return await this.handleToolCall(response as ToolCall)\n },\n 'final_answer': (response: any) => {\n return this.handleFinalAnswer(response as FinalAnswer)\n },\n }\n\n /**\n * 初始化 Agent\n * @param options 配置选项,包含 API Key、基础 URL、最大 ReAct 循环次数、运行模式、模型名称\n */\n constructor(options?: { \n baseURL?: string; \n apiKey?: string; \n maxTokens?: number; \n mode?: 'dev' | 'prod';\n maxRetries?: number;\n model?: string;\n }) {\n this.mode = options?.mode || 'dev'\n this.maxRetries = options?.maxRetries || 15\n this.llmClient = new LLMClient({\n baseURL: options?.baseURL || this.baseURL,\n apiKey: options?.apiKey || this.apiKey,\n mode: this.mode,\n model: options?.model\n })\n this.contextManager = new ContextManager(options?.maxTokens, this.mode)\n this.toolManager = new ToolManager(this.mode)\n initTools(this.toolManager) // 初始化并注册所有可用工具\n\n // 初始化上下文,加入系统提示词(含工具列表)\n const systemPrompt = composeSystemPrompt(this.toolManager.getTools())\n this.contextManager.init(systemPrompt)\n }\n\n /**\n * 处理用户提问的主入口\n * @param userInput 用户输入内容\n * @param stream 是否启用流式响应\n * @returns 最终回答内容\n */\n async chat(userInput: string, stream: boolean = false): Promise<string> {\n // 1. 将用户问题添加到上下文\n this.contextManager.addMessage({\n role: 'user',\n content: userInput,\n } as any)\n\n // 触发开始事件\n eventSystem.emit('chat:start', { userInput })\n this.log(`[Agent] 开始处理用户问题: ${userInput}`)\n\n // 2. ReAct 主循环\n let loopCount = 0\n while (loopCount++ < this.maxRetries) {\n // 触发循环开始事件\n eventSystem.emit('chat:loop:start', { loopCount })\n this.log(`[Agent] 开始第 ${loopCount} 轮循环`)\n\n // 获取当前所有上下文消息\n const messages = this.contextManager.getMessages()\n let response = '' // 存储模型生成的原始文本\n\n try {\n if (stream) {\n // 流式响应模式\n await this.llmClient.chatStream(messages, (token) => {\n response += token\n // 触发流式 token 事件,方便前端实时展示\n eventSystem.emit('chat:stream:token', { token, accumulatedResponse: response })\n })\n } else {\n // 非流式响应模式\n response = await this.llmClient.chat(messages)\n }\n } catch (err: any) {\n const errorMsg = `LLM 调用过程发生错误: ${err.message}`\n eventSystem.emit('chat:error', { message: errorMsg })\n return errorMsg\n }\n\n // 触发模型回复完成事件\n eventSystem.emit('chat:response:complete', { response })\n\n // 将模型的完整回复添加到上下文(作为模型之前的思考记录)\n this.contextManager.addMessage({\n role: 'assistant',\n content: response,\n } as any)\n\n // 3. 解析模型回复并决定下一步行动\n let parsedResponse: ToolCall | FinalAnswer | null = null\n\n try {\n // 尝试解析 JSON\n parsedResponse = JSON.parse(response)\n } catch (e) {\n // 解析失败,告知模型格式不正确,引导其重新生成\n const feedback = '回复格式错误。请确保你的回复是一个可以被 JSON.parse() 直接解析的有效 JSON 对象。'\n eventSystem.emit('chat:error:notJson', { message: feedback })\n \n this.contextManager.addMessage({\n role: 'user',\n content: feedback,\n } as any)\n continue // 进入下一轮重试\n }\n\n // 4. 根据解析结果执行策略\n if (!parsedResponse) {\n const feedback = '回复内容为空,请提供有效的 JSON 回复。'\n this.contextManager.addMessage({\n role: 'user',\n content: feedback,\n } as any)\n continue\n }\n\n const { type } = parsedResponse as any\n const strategy = this.handleStrategy[type]\n\n if (!strategy) {\n const feedback = `未知的回复类型: ${type},请按照规范回复 \"action\" 或 \"final_answer\"。`\n this.contextManager.addMessage({\n role: 'user',\n content: feedback,\n } as any)\n continue\n }\n\n // 执行对应的处理逻辑(工具调用或返回最终答案)\n const result = await strategy(parsedResponse)\n\n // 如果是最终答案,则直接返回给用户,结束循环\n if (type === 'final_answer') {\n return result as string\n }\n\n // 如果是工具调用 (action),循环将继续,模型会基于 Observation 进行下一步推理\n }\n\n const timeoutMsg = 'Agent 运行超过最大循环次数,无法获取回答。'\n eventSystem.emit('chat:error:maxRetries', { message: timeoutMsg })\n return timeoutMsg\n }\n\n /**\n * 清除当前 Agent 的上下文记忆\n */\n clearContext() {\n const systemPrompt = composeSystemPrompt(this.toolManager.getTools())\n this.contextManager.init(systemPrompt)\n }\n}\n"],"mappings":"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","names":["axios","HttpClient","config","error","response","url","stream","requestConfig","request","res","data","defaultHttp","http_default","BASE_URL","ENDPOINT","API_KEY","MODEL","LLMClient","options","MODEL","HttpClient","BASE_URL","API_KEY","args","messages","ENDPOINT","err","onToken","response","buffer","chunk","lines","line","trimmedLine","data","token","e","resolve","reject","ContextManager","maxTokens","mode","args","message","systemPrompt","systemMessage","m","recentMessages","iconv","WebFetcher","url","response","http_default","buffer","contentType","encoding","charsetMatch","metaCharsetMatch","error","jiaowuNotice","jiaowuCompetition","jiaowuNoticeTool","jiaowuCompetitionTool","initTools","toolManager","WebFetcher","jiaowuNoticeTool","jiaowuCompetitionTool","ToolManager","mode","args","tool","name","params","result","err","composeSystemPrompt","tools","systemPrompt_default","mittModule","EventSystem","mitt","event","handler","onceHandler","data","eventSystem","EventSystem_default","Agent","options","BASE_URL","API_KEY","parsedResponse","name","params","EventSystem_default","toolResult","error","errorMessage","content","response","LLMClient","ContextManager","ToolManager","initTools","systemPrompt","systemPrompt_default","args","userInput","stream","loopCount","messages","token","err","errorMsg","feedback","type","strategy","result","timeoutMsg"]}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "nongyu-agent-sdk",
3
+ "version": "1.0.0",
4
+ "description": "农屿系统内部专用的Agent SDK",
5
+ "type": "module",
6
+ "main": "dist/index.mjs",
7
+ "module": "dist/index.mjs",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.mjs",
12
+ "types": "./dist/index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md",
18
+ "LICENSE"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsup",
22
+ "dev": "tsup --watch",
23
+ "format": "prettier --write \"src/**/*.ts\"",
24
+ "lint": "eslint \"src/**/*.ts\"",
25
+ "test": "tsx test/test.ts"
26
+ },
27
+ "keywords": [
28
+ "agent",
29
+ "sdk",
30
+ "nongyu"
31
+ ],
32
+ "author": "TangLei",
33
+ "license": "ISC",
34
+ "dependencies": {
35
+ "axios": "^1.6.0",
36
+ "iconv-lite": "^0.6.3",
37
+ "mitt": "^3.0.1",
38
+ "nongyu-jiaowu": "^1.0.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^20.0.0",
42
+ "@typescript-eslint/eslint-plugin": "^6.9.0",
43
+ "@typescript-eslint/parser": "^6.9.0",
44
+ "eslint": "^8.52.0",
45
+ "prettier": "^3.1.0",
46
+ "rimraf": "^5.0.0",
47
+ "terser": "^5.24.0",
48
+ "ts-node": "^10.9.1",
49
+ "tsup": "^8.0.0",
50
+ "tsx": "^4.0.0",
51
+ "typescript": "^5.0.0"
52
+ }
53
+ }