@saber2pr/ai-agent 0.0.19 → 0.0.21

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.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const agent_graph_1 = __importDefault(require("./core/agent-graph"));
8
+ const agent = new agent_graph_1.default();
9
+ agent.start();
@@ -0,0 +1,52 @@
1
+ import { BaseMessage } from "@langchain/core/messages";
2
+ import { AgentOptions } from "../types/type";
3
+ export declare const CONFIG_FILE: string;
4
+ declare const AgentState: import("@langchain/langgraph").AnnotationRoot<{
5
+ messages: import("@langchain/langgraph").BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
6
+ auditedFiles: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
7
+ targetCount: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
8
+ mode: import("@langchain/langgraph").BinaryOperatorAggregate<"chat" | "auto", "chat" | "auto">;
9
+ }>;
10
+ export default class McpGraphAgent {
11
+ private model;
12
+ private toolNode;
13
+ private targetDir;
14
+ private options;
15
+ private checkpointer;
16
+ private langchainTools;
17
+ private spinner;
18
+ constructor(options?: AgentOptions);
19
+ private askForConfig;
20
+ private getModel;
21
+ chat(query?: string): Promise<void>;
22
+ start(): Promise<void>;
23
+ private renderOutput;
24
+ callModel(state: typeof AgentState.State): Promise<{
25
+ messages: unknown[];
26
+ }>;
27
+ trackProgress(state: typeof AgentState.State): Promise<{
28
+ auditedFiles: string[];
29
+ }>;
30
+ createGraph(): Promise<import("@langchain/langgraph").CompiledStateGraph<import("@langchain/langgraph").StateType<{
31
+ messages: import("@langchain/langgraph").BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
32
+ auditedFiles: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
33
+ targetCount: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
34
+ mode: import("@langchain/langgraph").BinaryOperatorAggregate<"chat" | "auto", "chat" | "auto">;
35
+ }>, import("@langchain/langgraph").UpdateType<{
36
+ messages: import("@langchain/langgraph").BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
37
+ auditedFiles: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
38
+ targetCount: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
39
+ mode: import("@langchain/langgraph").BinaryOperatorAggregate<"chat" | "auto", "chat" | "auto">;
40
+ }>, "tools" | "agent" | "__start__" | "progress", {
41
+ messages: import("@langchain/langgraph").BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
42
+ auditedFiles: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
43
+ targetCount: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
44
+ mode: import("@langchain/langgraph").BinaryOperatorAggregate<"chat" | "auto", "chat" | "auto">;
45
+ }, {
46
+ messages: import("@langchain/langgraph").BinaryOperatorAggregate<BaseMessage[], BaseMessage[]>;
47
+ auditedFiles: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
48
+ targetCount: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
49
+ mode: import("@langchain/langgraph").BinaryOperatorAggregate<"chat" | "auto", "chat" | "auto">;
50
+ }, import("@langchain/langgraph").StateDefinition>>;
51
+ }
52
+ export {};
@@ -0,0 +1,245 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.CONFIG_FILE = void 0;
7
+ const openai_1 = require("@langchain/openai");
8
+ const messages_1 = require("@langchain/core/messages");
9
+ const langgraph_1 = require("@langchain/langgraph");
10
+ const prebuilt_1 = require("@langchain/langgraph/prebuilt");
11
+ const prompts_1 = require("@langchain/core/prompts");
12
+ const readline_1 = __importDefault(require("readline"));
13
+ const fs_1 = __importDefault(require("fs"));
14
+ const path_1 = __importDefault(require("path"));
15
+ const os_1 = __importDefault(require("os"));
16
+ const ora_1 = __importDefault(require("ora")); // 用于显示 Loading 动画
17
+ const builtin_1 = require("../tools/builtin");
18
+ const convertToLangChainTool_1 = require("../utils/convertToLangChainTool");
19
+ exports.CONFIG_FILE = path_1.default.join(os_1.default.homedir(), ".saber2pr-agent.json");
20
+ // --- 1. 定义状态 (State) ---
21
+ const AgentState = langgraph_1.Annotation.Root({
22
+ messages: (0, langgraph_1.Annotation)({
23
+ reducer: (x, y) => x.concat(y),
24
+ default: () => [],
25
+ }),
26
+ auditedFiles: (0, langgraph_1.Annotation)({
27
+ reducer: (x, y) => Array.from(new Set([...x, ...y])),
28
+ default: () => [],
29
+ }),
30
+ targetCount: (0, langgraph_1.Annotation)({
31
+ reducer: (x, y) => y !== null && y !== void 0 ? y : x,
32
+ default: () => 4,
33
+ }),
34
+ mode: (0, langgraph_1.Annotation)({
35
+ reducer: (x, y) => y !== null && y !== void 0 ? y : x,
36
+ default: () => "chat",
37
+ }),
38
+ });
39
+ class McpGraphAgent {
40
+ constructor(options = {}) {
41
+ this.checkpointer = new langgraph_1.MemorySaver();
42
+ this.langchainTools = [];
43
+ this.spinner = (0, ora_1.default)({ color: "cyan" });
44
+ this.options = options;
45
+ this.targetDir = options.targetDir || process.cwd();
46
+ process.setMaxListeners(50); // 防止 AbortSignal 监听器过多的警告
47
+ const builtinToolInfos = (0, builtin_1.createDefaultBuiltinTools)({ options });
48
+ const externalToolInfos = options.tools || [];
49
+ this.langchainTools = [...builtinToolInfos, ...externalToolInfos].map((t) => (0, convertToLangChainTool_1.convertToLangChainTool)(t));
50
+ this.toolNode = new prebuilt_1.ToolNode(this.langchainTools);
51
+ }
52
+ async askForConfig() {
53
+ let config = {};
54
+ if (fs_1.default.existsSync(exports.CONFIG_FILE)) {
55
+ try {
56
+ config = JSON.parse(fs_1.default.readFileSync(exports.CONFIG_FILE, "utf-8"));
57
+ }
58
+ catch (e) { }
59
+ }
60
+ if (!config.baseURL || !config.apiKey) {
61
+ const rl = readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
62
+ const question = (q) => new Promise((res) => rl.question(q, res));
63
+ console.log(`💡 首次运行请配置信息:`);
64
+ config.baseURL = config.baseURL || await question(`? API Base URL: `);
65
+ config.apiKey = config.apiKey || await question(`? API Key: `);
66
+ config.model = config.model || await question(`? Model Name: `) || "gpt-4o";
67
+ fs_1.default.writeFileSync(exports.CONFIG_FILE, JSON.stringify(config, null, 2));
68
+ rl.close();
69
+ }
70
+ return config;
71
+ }
72
+ async getModel() {
73
+ if (this.model)
74
+ return this.model;
75
+ let modelInstance = this.options.apiModel;
76
+ if (!modelInstance) {
77
+ const config = await this.askForConfig();
78
+ modelInstance = new openai_1.ChatOpenAI({
79
+ openAIApiKey: config.apiKey,
80
+ configuration: { baseURL: config.baseURL },
81
+ modelName: config.model,
82
+ temperature: 0,
83
+ });
84
+ }
85
+ this.model = modelInstance.bindTools(this.langchainTools);
86
+ return this.model;
87
+ }
88
+ async chat(query = "开始代码审计") {
89
+ await this.getModel();
90
+ const app = await this.createGraph();
91
+ const stream = await app.stream({
92
+ messages: [new messages_1.HumanMessage(query)],
93
+ mode: "auto",
94
+ targetCount: 4
95
+ }, { configurable: { thread_id: "auto_worker" }, recursionLimit: 100 });
96
+ for await (const output of stream)
97
+ this.renderOutput(output);
98
+ console.log("✅ 任务执行完毕。");
99
+ }
100
+ async start() {
101
+ await this.getModel();
102
+ const app = await this.createGraph();
103
+ const rl = readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
104
+ const threadId = `session_${Date.now()}`;
105
+ console.log(`\n💬 已进入交互审计模式 (Thread: ${threadId})`);
106
+ const ask = () => {
107
+ rl.question("> ", async (input) => {
108
+ if (input.toLowerCase() === "exit") {
109
+ rl.close();
110
+ return;
111
+ }
112
+ const stream = await app.stream({ messages: [new messages_1.HumanMessage(input)], mode: "chat" }, { configurable: { thread_id: threadId }, recursionLimit: 50 });
113
+ for await (const output of stream)
114
+ this.renderOutput(output);
115
+ ask();
116
+ });
117
+ };
118
+ ask();
119
+ }
120
+ renderOutput(output) {
121
+ var _a, _b;
122
+ // 每次渲染输出前,确保停止 Spinner
123
+ if (this.spinner.isSpinning)
124
+ this.spinner.stop();
125
+ const agentNode = output.agent;
126
+ if (agentNode) {
127
+ const msg = agentNode.messages[0];
128
+ // 1. 打印思考过程
129
+ const reasoning = (_a = msg.additional_kwargs) === null || _a === void 0 ? void 0 : _a.reasoning;
130
+ if (reasoning) {
131
+ console.log("\n🧠 [思考过程]:\n" + "─".repeat(50) + "\n" + reasoning + "\n" + "─".repeat(50) + "\n");
132
+ }
133
+ // 2. 打印正式回答
134
+ if (msg.content)
135
+ console.log("🤖 [AI]:", msg.content);
136
+ // 3. 打印工具调用
137
+ if ((_b = msg.tool_calls) === null || _b === void 0 ? void 0 : _b.length) {
138
+ msg.tool_calls.forEach((call) => {
139
+ console.log(`🛠️ [调用工具]: ${call.name} 📦 参数: ${JSON.stringify(call.args)}`);
140
+ });
141
+ }
142
+ }
143
+ }
144
+ // --- 节点逻辑 ---
145
+ async callModel(state) {
146
+ // 处理变量序列化,防止 [object Object]
147
+ const auditedListStr = state.auditedFiles.length > 0
148
+ ? state.auditedFiles.map(f => `\n - ${f}`).join("")
149
+ : "暂无";
150
+ const extraPromptStr = typeof this.options.extraSystemPrompt === 'object'
151
+ ? JSON.stringify(this.options.extraSystemPrompt, null, 2)
152
+ : (this.options.extraSystemPrompt || "");
153
+ // 使用变量占位符 {extraPrompt} 避免内容中的 {} 引发模板解析错误
154
+ const prompt = prompts_1.ChatPromptTemplate.fromMessages([
155
+ ["system", `你是一个代码专家。工作目录:${this.targetDir}。
156
+
157
+ # 当前进度状态
158
+ - 审计模式: {mode}
159
+ - 目标任务数: {targetCount}
160
+ - 已完成数量: {doneCount}
161
+ - 已审计文件列表: {auditedList}
162
+
163
+ # 核心任务准则
164
+ 1. 目标导向:如果 {doneCount} >= {targetCount},说明任务已达标。请直接输出总结,不要再调用任何工具。
165
+ 2. 避免死循环:不要反复尝试审计同一个文件或调用同样的工具。如果你发现某个文件修复失败,请尝试审计其他文件。
166
+ 3. 严格格式:
167
+ - 必须先在 <think> 标签内进行推理。
168
+ - 工具调用必须严格按照 Action: 名称 和 Arguments: {{JSON}} 的格式。
169
+ - 【重要】Arguments 中的 JSON 字符串,所有的换行符必须转义为 \\n,严禁出现物理换行符。
170
+
171
+ # 附加指令
172
+ {extraPrompt}`],
173
+ new prompts_1.MessagesPlaceholder("messages"),
174
+ ]);
175
+ // ✅ 显示 Loading
176
+ this.spinner.start("AI 正在思考并分析代码...");
177
+ try {
178
+ const chain = prompt.pipe(this.model);
179
+ const response = await chain.invoke({
180
+ messages: state.messages,
181
+ mode: state.mode,
182
+ targetCount: state.targetCount,
183
+ doneCount: state.auditedFiles.length,
184
+ auditedList: auditedListStr,
185
+ extraPrompt: extraPromptStr, // 变量方式传入更安全
186
+ });
187
+ this.spinner.stop(); // 得到响应即停止
188
+ return { messages: [response] };
189
+ }
190
+ catch (error) {
191
+ this.spinner.fail("AI 响应异常");
192
+ throw error;
193
+ }
194
+ }
195
+ // agent-graph.ts 中的 trackProgress 节点
196
+ async trackProgress(state) {
197
+ var _a;
198
+ // 获取最后一条 AI 消息(即发起工具调用的那条)
199
+ const lastAiMsg = state.messages[state.messages.length - 1];
200
+ const newFiles = [];
201
+ if ((_a = lastAiMsg === null || lastAiMsg === void 0 ? void 0 : lastAiMsg.tool_calls) === null || _a === void 0 ? void 0 : _a.length) {
202
+ for (const tc of lastAiMsg.tool_calls) {
203
+ // 这里的逻辑要宽容:只要 AI 尝试处理了这些文件,就计入进度
204
+ const file = tc.args.path || tc.args.filePath || tc.args.file;
205
+ if (file && typeof file === 'string') {
206
+ newFiles.push(file);
207
+ }
208
+ }
209
+ }
210
+ // 如果这一轮没有任何新文件被处理,且 AI 也没给最终回复,
211
+ // 我们需要防止它在下一轮条件判断中陷入死循环
212
+ return { auditedFiles: newFiles };
213
+ }
214
+ async createGraph() {
215
+ const workflow = new langgraph_1.StateGraph(AgentState)
216
+ .addNode("agent", (state) => this.callModel(state))
217
+ .addNode("tools", this.toolNode)
218
+ .addNode("progress", (state) => this.trackProgress(state))
219
+ .addEdge(langgraph_1.START, "agent")
220
+ .addConditionalEdges("agent", (state) => {
221
+ var _a;
222
+ const lastMsg = state.messages[state.messages.length - 1];
223
+ // 1. 如果 AI 想要调用工具,去 tools 节点
224
+ if ((_a = lastMsg.tool_calls) === null || _a === void 0 ? void 0 : _a.length)
225
+ return "tools";
226
+ // 2. 如果是自动模式且未达标
227
+ if (state.mode === "auto") {
228
+ const isDone = state.auditedFiles.length >= state.targetCount;
229
+ // 如果还没达标,继续让 agent 思考下一步
230
+ if (!isDone)
231
+ return "agent";
232
+ }
233
+ // 3. 其他情况(达标了,或者对话模式 AI 给出了回复)一律结束
234
+ return langgraph_1.END;
235
+ }, {
236
+ tools: "tools",
237
+ agent: "agent",
238
+ [langgraph_1.END]: langgraph_1.END,
239
+ })
240
+ .addEdge("tools", "progress")
241
+ .addEdge("progress", "agent");
242
+ return workflow.compile({ checkpointer: this.checkpointer });
243
+ }
244
+ }
245
+ exports.default = McpGraphAgent;
package/lib/index.d.ts CHANGED
@@ -3,3 +3,5 @@ export { default as McpChainAgent } from './core/agent-chain';
3
3
  export { default } from './core/agent';
4
4
  export { createTool } from './utils/createTool';
5
5
  export { AgentChainModel } from './model/AgentChainModel';
6
+ export { AgentGraphModel, AgentGraphLLMResponse } from './model/AgentGraphModel';
7
+ export { default as McpGraphAgent } from './core/agent-graph';
package/lib/index.js CHANGED
@@ -17,7 +17,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.AgentChainModel = exports.createTool = exports.default = exports.McpChainAgent = void 0;
20
+ exports.McpGraphAgent = exports.AgentGraphModel = exports.AgentChainModel = exports.createTool = exports.default = exports.McpChainAgent = void 0;
21
21
  __exportStar(require("./core/agent"), exports);
22
22
  var agent_chain_1 = require("./core/agent-chain");
23
23
  Object.defineProperty(exports, "McpChainAgent", { enumerable: true, get: function () { return __importDefault(agent_chain_1).default; } });
@@ -27,3 +27,7 @@ var createTool_1 = require("./utils/createTool");
27
27
  Object.defineProperty(exports, "createTool", { enumerable: true, get: function () { return createTool_1.createTool; } });
28
28
  var AgentChainModel_1 = require("./model/AgentChainModel");
29
29
  Object.defineProperty(exports, "AgentChainModel", { enumerable: true, get: function () { return AgentChainModel_1.AgentChainModel; } });
30
+ var AgentGraphModel_1 = require("./model/AgentGraphModel");
31
+ Object.defineProperty(exports, "AgentGraphModel", { enumerable: true, get: function () { return AgentGraphModel_1.AgentGraphModel; } });
32
+ var agent_graph_1 = require("./core/agent-graph");
33
+ Object.defineProperty(exports, "McpGraphAgent", { enumerable: true, get: function () { return __importDefault(agent_graph_1).default; } });
@@ -1,12 +1,12 @@
1
1
  import { BaseChatModel } from '@langchain/core/language_models/chat_models';
2
2
  import { AIMessage, MessageFieldWithRole } from '@langchain/core/messages';
3
3
  interface AgentChainModelImpl {
4
- generateAgentChainResponse: (messages: MessageFieldWithRole[]) => Promise<string>;
4
+ generateResponse: (messages: MessageFieldWithRole[]) => Promise<string>;
5
5
  }
6
6
  export declare abstract class AgentChainModel extends BaseChatModel implements AgentChainModelImpl {
7
7
  bind(args: any): any;
8
8
  constructor(fields?: any);
9
- generateAgentChainResponse(messages: MessageFieldWithRole[]): Promise<string>;
9
+ generateResponse(messages: MessageFieldWithRole[]): Promise<string>;
10
10
  _generate(messages: any): Promise<{
11
11
  generations: {
12
12
  text: string;
@@ -11,11 +11,11 @@ class AgentChainModel extends chat_models_1.BaseChatModel {
11
11
  return (super.bind ? super.bind(args) : this);
12
12
  }
13
13
  constructor(fields) { super(fields || {}); }
14
- async generateAgentChainResponse(messages) {
14
+ async generateResponse(messages) {
15
15
  return '';
16
16
  }
17
17
  async _generate(messages) {
18
- let text = await this.generateAgentChainResponse(messages);
18
+ let text = await this.generateResponse(messages);
19
19
  return { generations: [{ text, message: new messages_1.AIMessage(text) }] };
20
20
  }
21
21
  _llmType() { return "my_private_llm"; }
@@ -0,0 +1,21 @@
1
+ import { BaseChatModel, BaseChatModelParams } from '@langchain/core/language_models/chat_models';
2
+ import { BaseMessage } from '@langchain/core/messages';
3
+ import { ChatResult } from '@langchain/core/outputs';
4
+ export interface AgentGraphLLMResponse {
5
+ text: string;
6
+ reasoning?: string;
7
+ chatId?: string;
8
+ }
9
+ export declare abstract class AgentGraphModel extends BaseChatModel {
10
+ protected boundTools?: any[];
11
+ protected chatId?: string;
12
+ constructor(fields?: BaseChatModelParams & {
13
+ chatId?: string;
14
+ });
15
+ bindTools(tools: any[]): any;
16
+ abstract callApi(prompt: string, chatId?: string): Promise<AgentGraphLLMResponse>;
17
+ _generate(messages: BaseMessage[]): Promise<ChatResult>;
18
+ private serializeMessages;
19
+ private parseToolCalls;
20
+ _llmType(): string;
21
+ }
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AgentGraphModel = void 0;
4
+ const chat_models_1 = require("@langchain/core/language_models/chat_models");
5
+ const messages_1 = require("@langchain/core/messages");
6
+ const function_calling_1 = require("@langchain/core/utils/function_calling");
7
+ class AgentGraphModel extends chat_models_1.BaseChatModel {
8
+ constructor(fields) {
9
+ super(fields || {});
10
+ this.chatId = fields === null || fields === void 0 ? void 0 : fields.chatId;
11
+ }
12
+ bindTools(tools) {
13
+ this.boundTools = tools.map(t => (0, function_calling_1.convertToOpenAITool)(t));
14
+ return this;
15
+ }
16
+ async _generate(messages) {
17
+ const fullPrompt = this.serializeMessages(messages);
18
+ const response = await this.callApi(fullPrompt, this.chatId);
19
+ if (response.chatId)
20
+ this.chatId = response.chatId;
21
+ let { text, reasoning } = response;
22
+ // ✅ 通用逻辑:解析 <think> 标签
23
+ if (!reasoning && text.includes("<think>")) {
24
+ const match = text.match(/<think>([\s\S]*?)<\/think>/);
25
+ if (match) {
26
+ reasoning = match[1].trim();
27
+ text = text.replace(/<think>[\s\S]*?<\/think>/, "").trim();
28
+ }
29
+ }
30
+ const toolCalls = this.parseToolCalls(text);
31
+ return {
32
+ generations: [{
33
+ text,
34
+ message: new messages_1.AIMessage({
35
+ content: text,
36
+ tool_calls: toolCalls,
37
+ additional_kwargs: { reasoning: reasoning || "" }
38
+ })
39
+ }]
40
+ };
41
+ }
42
+ serializeMessages(messages) {
43
+ const systemMsg = messages.find(m => m._getType() === 'system');
44
+ const lastMsg = messages[messages.length - 1];
45
+ const format = (m) => {
46
+ const content = typeof m.content === 'string' ? m.content : JSON.stringify(m.content, null, 2);
47
+ return `${m._getType().toUpperCase()}: ${content}`;
48
+ };
49
+ const toolsContext = this.boundTools ? `\n[Tools]\n${JSON.stringify(this.boundTools, null, 2)}` : "";
50
+ return `
51
+ ${format(systemMsg)}
52
+ ${toolsContext}
53
+ # Current Progress
54
+ ${format(lastMsg)}
55
+ # Output Requirement
56
+ 1. Reasoning in <think> tags.
57
+ 2. Action: Name
58
+ 3. Arguments: {JSON}
59
+ `.trim();
60
+ }
61
+ parseToolCalls(text) {
62
+ const actionMatch = text.match(/Action:\s*(\w+)/);
63
+ const argsMatch = text.match(/Arguments:\s*({[\s\S]*})/);
64
+ if (!actionMatch)
65
+ return [];
66
+ let args = {};
67
+ if (argsMatch) {
68
+ try {
69
+ // 强力解析逻辑,处理物理换行
70
+ const rawArgs = argsMatch[1].trim().replace(/\n/g, "\\n");
71
+ args = JSON.parse(rawArgs);
72
+ // 参数映射
73
+ const anyArgs = args;
74
+ if (anyArgs.file_path && !anyArgs.path)
75
+ anyArgs.path = anyArgs.file_path;
76
+ if (anyArgs.filePath && !anyArgs.path)
77
+ anyArgs.path = anyArgs.filePath;
78
+ if (anyArgs.path && !anyArgs.filePath)
79
+ anyArgs.filePath = anyArgs.path;
80
+ if (anyArgs.file && !anyArgs.filePath)
81
+ anyArgs.filePath = anyArgs.file;
82
+ }
83
+ catch (e) {
84
+ console.warn("JSON Parse Error", e);
85
+ }
86
+ }
87
+ return [{
88
+ name: actionMatch[1],
89
+ args,
90
+ id: `call_${Date.now()}`,
91
+ type: "tool_call",
92
+ }];
93
+ }
94
+ _llmType() { return "agent_graph_model"; }
95
+ }
96
+ exports.AgentGraphModel = AgentGraphModel;
@@ -46,4 +46,16 @@ export interface AgentOptions {
46
46
  * only for chain agent
47
47
  */
48
48
  verbose?: boolean;
49
+ /**
50
+ * only for graph agent
51
+ */
52
+ baseURL?: string;
53
+ /**
54
+ * only for graph agent
55
+ */
56
+ apiKey?: string;
57
+ /**
58
+ * only for graph agent
59
+ */
60
+ modelName?: string;
49
61
  }
@@ -0,0 +1,3 @@
1
+ import { DynamicStructuredTool } from "@langchain/core/tools";
2
+ import { z } from "zod";
3
+ export declare function convertToLangChainTool(info: any): DynamicStructuredTool<z.ZodRecord<z.ZodString, z.ZodAny>>;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.convertToLangChainTool = convertToLangChainTool;
4
+ const tools_1 = require("@langchain/core/tools");
5
+ const zod_1 = require("zod");
6
+ function convertToLangChainTool(info) {
7
+ return new tools_1.DynamicStructuredTool({
8
+ name: info.function.name,
9
+ description: info.function.description || "",
10
+ schema: zod_1.z.record(zod_1.z.any()),
11
+ func: async (args) => {
12
+ if (info._handler)
13
+ return await info._handler(args);
14
+ if (info._client && info._originalName) {
15
+ const result = await info._client.callTool({
16
+ name: info._originalName,
17
+ arguments: args,
18
+ });
19
+ return JSON.stringify(result);
20
+ }
21
+ return "Error: No tool execution handler found.";
22
+ },
23
+ });
24
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saber2pr/ai-agent",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
4
4
  "description": "AI Assistant CLI.",
5
5
  "author": "saber2pr",
6
6
  "license": "ISC",
@@ -9,7 +9,8 @@
9
9
  ],
10
10
  "bin": {
11
11
  "sagent": "./lib/cli.js",
12
- "sagent-chain": "./lib/cli-chain.js"
12
+ "sagent-chain": "./lib/cli-chain.js",
13
+ "sagent-graph": "./lib/cli-graph.js"
13
14
  },
14
15
  "publishConfig": {
15
16
  "access": "public",
@@ -22,18 +23,20 @@
22
23
  "prepublishOnly": "tsc"
23
24
  },
24
25
  "dependencies": {
26
+ "@langchain/core": "0.3.39",
27
+ "@langchain/langgraph": "^0.2.39",
28
+ "@langchain/openai": "0.4.0",
25
29
  "@modelcontextprotocol/sdk": "^1.25.3",
26
30
  "@saber2pr/ts-context-mcp": "^0.0.8",
27
31
  "diff": "^8.0.3",
28
32
  "glob": "^10.5.0",
29
33
  "js-tiktoken": "^1.0.21",
34
+ "langchain": "0.3.15",
30
35
  "minimatch": "^10.0.1",
31
36
  "openai": "^6.16.0",
32
- "zod-to-json-schema": "3.23.2",
33
- "langchain": "0.3.15",
34
- "@langchain/core": "0.3.39",
35
- "@langchain/openai": "0.4.0",
36
- "zod": "3.23.8"
37
+ "ora": "^9.3.0",
38
+ "zod": "3.23.8",
39
+ "zod-to-json-schema": "3.23.2"
37
40
  },
38
41
  "resolutions": {
39
42
  "@langchain/core": "0.3.39"