This commit is contained in:
lik
2026-09-01 22:34:36 +08:00
parent 98c9026485
commit 71aba287bf
14 changed files with 129 additions and 219 deletions
+11 -16
View File
@@ -1,10 +1,12 @@
import 'dotenv/config';
import path from 'path';
import { createDeepAgent, FilesystemBackend, CompositeBackend, StoreBackend } from "deepagents";
import { createDeepAgent, FilesystemBackend, CompositeBackend } from "deepagents";
import { ChatOpenAI } from "@langchain/openai";
import { AIMessageChunk, ToolMessage, summarizationMiddleware } from "langchain";
import { SystemMessage, HumanMessage, AIMessage } from "@langchain/core/messages";
import { AIMessageChunk, ToolMessage } from "langchain";
import { HumanMessage } from "@langchain/core/messages";
import { ChatDeepSeek } from "@langchain/deepseek";
import config from '../../conf.json' with { type: 'json' };
import logger from '../../utils/logger.js';
import Prompts from "./prompts.js";
import {
getEnvTool, webFetchTool, webSearchTool, getCalendarInfoTool,
@@ -62,8 +64,7 @@ export default class EscortAgent {
// 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)}...`);
logger.info(`Subagent complete: ${msg.name}, Result: ${String(msg.content).slice(0, 200)}`);
}
}
} else if (nodeName === "model_request") {
@@ -73,7 +74,7 @@ export default class EscortAgent {
} else {
// Subagent updates (non-empty namespace)
for (const [nodeName, data_] of Object.entries(data)) {
console.log(` [${namespace[0]}] step: ${nodeName}`);
logger.info(`[${namespace[0]}] step: ${nodeName}`);
}
}
}
@@ -97,7 +98,7 @@ export default class EscortAgent {
callback(source, "tool", message.text, message.id);
}
} else if (mode === "custom") {
this.logger.info("custom: ", data);
logger.info("custom: ", data);
}
}
}
@@ -113,7 +114,6 @@ export default class EscortAgent {
if (userInfo) {
const userMemoryPath = path.join(rootDir, "data", userInfo._id, "memories");
console.log(userMemoryPath);
backend = new CompositeBackend(
new FilesystemBackend({ rootDir }),
{
@@ -126,15 +126,10 @@ export default class EscortAgent {
}
this.flashModel = new ChatDeepSeek({
model: 'deepseek-v4-flash',
apiKey: 'sk-a58ccd82b7ba4ce3ac176a88c9381095',
model: config.agent.deepseek.flashModel,
apiKey: config.agent.deepseek.apiKey,
temperature: 0.0
});
this.proModel = new ChatDeepSeek({
model: 'deepseek-v4-pro',
apiKey: 'sk-a58ccd82b7ba4ce3ac176a88c9381095',
temperature: 0.3
});
this.agent = createDeepAgent({
name: "deep-agent",
@@ -150,4 +145,4 @@ export default class EscortAgent {
return this.agent;
}
}
}
+19 -6
View File
@@ -61,12 +61,25 @@ function createEscortRecordQueryTool(userInfo) {
.optional()
.describe("Patient name for fuzzy search"),
status: z
.enum(["pending", "confirmed", "in_progress", "completed", "cancelled"])
.optional()
.describe(
"Appointment status: pending (待确认), confirmed (已确认), in_progress (进行中), completed (已完成), cancelled (已取消)"
),
}),
.enum(["pending", "confirmed", "in_progress", "completed", "cancelled"])
.optional()
.describe(
"Appointment status: pending (待确认), confirmed (已确认), in_progress (进行中), completed (已完成), cancelled (已取消)"
),
page: z
.number()
.int()
.min(1)
.optional()
.describe("Page number, starting from 1"),
pageSize: z
.number()
.int()
.min(1)
.max(50)
.optional()
.describe("Records per page (1-50), default 20"),
}),
}
);
}
+6 -5
View File
@@ -13,21 +13,22 @@ export const getEnvTool = tool(
async (input) => {
const { name } = input || {};
const sensitiveKeys = ['API_KEY', 'SECRET', 'PASSWORD', 'TOKEN', 'CREDENTIAL'];
const isSensitive = (key) => sensitiveKeys.some(s => key.toUpperCase().includes(s));
if (name) {
const value = process.env[name];
if (value === undefined) {
return JSON.stringify({ error: `Environment variable '${name}' not found` });
}
return JSON.stringify({ name, value });
// 按名查询同样脱敏,防止 LLM 绕过读取密钥
return JSON.stringify({ name, value: isSensitive(name) ? '***REDACTED***' : value });
}
// 返回所有环境变量(过滤敏感信息)
const env = { ...process.env };
const sensitiveKeys = ['API_KEY', 'SECRET', 'PASSWORD', 'TOKEN', 'CREDENTIAL'];
for (const key of Object.keys(env)) {
const upperKey = key.toUpperCase();
if (sensitiveKeys.some(s => upperKey.includes(s))) {
if (isSensitive(key)) {
env[key] = '***REDACTED***';
}
}
-74
View File
@@ -1,74 +0,0 @@
import * as z from 'zod';
import { tool } from 'langchain';
import { spawn } from 'child_process';
export const winCmdTool = tool(
async ({ command, cwd, timeout = 30000 }) => {
const workingDir = cwd || process.cwd();
return new Promise((resolve) => {
let stdout = '';
let stderr = '';
let killed = false;
const proc = spawn('cmd.exe', ['/c', command], {
cwd: workingDir,
shell: false,
windowsHide: true
});
const timer = setTimeout(() => {
killed = true;
proc.kill('SIGKILL');
}, timeout);
proc.stdout.on('data', (data) => {
stdout += data.toString();
});
proc.stderr.on('data', (data) => {
stderr += data.toString();
});
proc.on('close', (code) => {
clearTimeout(timer);
if (killed) {
resolve(JSON.stringify({
success: false,
error: `Command timed out after ${timeout}ms`,
command,
cwd: workingDir
}));
return;
}
resolve(JSON.stringify({
success: code === 0,
exitCode: code,
stdout: stdout.trim(),
stderr: stderr.trim(),
command,
cwd: workingDir
}));
});
proc.on('error', (error) => {
clearTimeout(timer);
resolve(JSON.stringify({
success: false,
error: error.message,
command,
cwd: workingDir
}));
});
});
},
{
name: 'win_cmd',
description: '在 Windows 系统上执行 cmd.exe 命令行命令。适用于运行 Windows 批处理命令、文件系统操作命令(如 dir、copy、del、mkdir 等)。不支持 PowerShell 命令。',
schema: z.object({
command: z.string().describe('要执行的 cmd.exe 命令或命令组合,使用 && 连接多个命令,如 "dir /b" 或 "echo hello && dir"'),
cwd: z.string().optional().describe('执行命令的工作目录,默认为当前工作目录'),
timeout: z.number().optional().describe('命令执行超时时间(毫秒),默认30000')
})
}
);