import 'dotenv/config'; import { createDeepAgent, FilesystemBackend } from "deepagents"; import { AIMessageChunk, ToolMessage } from "langchain"; import { SystemMessage, HumanMessage, AIMessage } from "@langchain/core/messages"; import { ChatDeepSeek } from "@langchain/deepseek"; import EscortAdminPrompts from "./prompts.js"; import { getEnvTool, webFetchTool, webSearchTool, getCalendarInfoTool, getLunarCalendarInfoTool, getYearHolidaysTool, getYearTermsTool, getLatLngTool, httpGetTool, httpPostTool, escortRecordQueryTool } from "./tools/index.js"; export default class EscortAdminAgent { constructor() { } clearMessages() { this.messages = []; } // msg: { agent: 'escort-admin', type: 'chat', ts: "2023-08-01 10:00:00", content: "你好" } async streamChat(userInfo, msgs, callback) { if (!msgs.length) { return; } const agent = this._genAgent(userInfo); msgs.forEach(msg => { if (msg.type === "clear") { this.messages = []; } else { this.messages.push(new HumanMessage(`${msg.ts} - ${msg.content}`)); } }); if (this.messages.length === 0) { return; } const INTERESTING_NODES = new Set(["model_request", "tools"]); for await (const [namespace, mode, data] of await agent.stream( { messages: this.messages }, { recursion_limit: 50, streamMode: ["updates", "messages", "custom"], subgraphs: true, configurable: { thread_id: 'default-session' } })) { const isSubagent = namespace.some(s => s.startsWith("tools:")); const source = isSubagent ? "subagent" : "main"; if (mode === "updates") { for (const nodeName of Object.keys(data)) { if (!INTERESTING_NODES.has(nodeName)) continue; // Main agent updates (empty namespace) if (namespace.length === 0) { for (const [nodeName, data_] of Object.entries(data)) { if (nodeName === "tools") { // Subagent results returned to main agent for (const msg of data_.messages ?? []) { if (msg.type === "tool") { console.log(`\nSubagent complete: ${msg.name}`); console.log(` Result: ${String(msg.content).slice(0, 200)}...`); } } } else if (nodeName === "model_request") { this.messages.push(...data_.messages); } } } else { // Subagent updates (non-empty namespace) for (const [nodeName, data_] of Object.entries(data)) { console.log(` [${namespace[0]}] step: ${nodeName}`); } } } } else if (mode === "messages") { const [message] = data; if (message.tool_call_chunks?.length) { continue; } if (AIMessageChunk.isInstance(message)) { if (message.text && !message.tool_call_chunks?.length) { callback(source, "ai", message.text, message.id); } if (message.additional_kwargs.reasoning_content && !message.tool_call_chunks?.length) { callback(source, "reasoning", message.additional_kwargs.reasoning_content, message.id); } } if (ToolMessage.isInstance(message) && message.text) { callback(source, "tool", message.text, message.id); } } else if (mode === "custom") { this.logger.info("custom: ", data); } } } _genAgent(userInfo) { if (this.agent) { return this.agent; } this.messages = []; const rootDir = process.cwd(); const backend = new FilesystemBackend({ rootDir }); this.flashModel = new ChatDeepSeek({ model: 'deepseek-v4-flash', apiKey: 'sk-a58ccd82b7ba4ce3ac176a88c9381095', temperature: 0.0 }); this.proModel = new ChatDeepSeek({ model: 'deepseek-v4-pro', apiKey: 'sk-a58ccd82b7ba4ce3ac176a88c9381095', temperature: 0.3 }); const escortRecordOperSubagent = { name: "escort-record-oper-subagent", description: "查询和设置陪诊预约记录", systemPrompt: "根据用户指令,调用工具完成查询和设置陪诊记录。", model: this.flashModel, tools: [escortRecordQueryTool], }; const escortResearchSubagent = { name: "escort-research-subagent", description: "陪诊(陪同就医)行业问题研究和解答", systemPrompt: "你是陪诊(陪同就医)行业政策、发展趋势、行业知识研究和解答专家。", model: this.proModel, tools: [webFetchTool, webSearchTool], }; this.agent = createDeepAgent({ name: "deep-agent", model: this.flashModel, systemPrompt: EscortAdminPrompts.buildSystemPrompt(userInfo), backend, tools: [getEnvTool, webFetchTool, webSearchTool, getLatLngTool, httpGetTool, httpPostTool, getCalendarInfoTool, getLunarCalendarInfoTool, getYearHolidaysTool, getYearTermsTool, escortRecordQueryTool] }); return this.agent; } } const adminAgent = new EscortAdminAgent(); export { adminAgent };