diff --git a/agent/escort-admin/agent.js b/agent/escort-admin/agent.js index 7a95456..2607066 100644 --- a/agent/escort-admin/agent.js +++ b/agent/escort-admin/agent.js @@ -5,6 +5,10 @@ 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'; + +// 密钥由 conf.json 统一提供;百度地图 skill 通过 env_get 读环境变量,此处桥接 +process.env.TAVILY_API_KEY ??= config.agent.tavily?.apiKey; +process.env.BAIDU_MAP_AUTH_TOKEN ??= config.agent.baiduMap?.authToken; import EscortAdminPrompts from "./prompts.js"; import { getEnvTool, webFetchTool, webSearchTool, getCalendarInfoTool, @@ -20,8 +24,7 @@ export default class EscortAdminAgent { } clearMessages(userInfo) { - const userId = userInfo?._id ?? 'default-session'; - this.sessions.delete(userId); + this.sessions.delete(userInfo._id); } // msg: { agent: 'escort-admin', type: 'chat', ts: "2023-08-01 10:00:00", content: "你好" } @@ -30,7 +33,7 @@ export default class EscortAdminAgent { return; } - const userId = userInfo?._id ?? 'default-session'; + const userId = userInfo._id; // LRU:按用户取会话,并更新使用顺序 let session = this.sessions.get(userId); @@ -76,27 +79,27 @@ export default class EscortAdminAgent { 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") { - logger.info(`Subagent complete: ${msg.name}, Result: ${String(msg.content).slice(0, 200)}`); - } + // Main agent updates (empty namespace) + if (namespace.length === 0) { + for (const [nodeName, data_] of Object.entries(data)) { + if (!INTERESTING_NODES.has(nodeName)) continue; + if (nodeName === "tools") { + // 工具结果必须并入历史,否则下一轮会出现 tool_calls 缺少对应 tool 结果的断链 + for (const msg of data_.messages ?? []) { + if (msg.type === "tool") { + session.messages.push(msg); + logger.info(`Tool complete: ${msg.name}, Result: ${String(msg.content).slice(0, 200)}`); } - } else if (nodeName === "model_request") { - session.messages.push(...data_.messages); } + } else if (nodeName === "model_request") { + session.messages.push(...data_.messages); } - } else { - // Subagent updates (non-empty namespace) - for (const [nodeName, data_] of Object.entries(data)) { - logger.info(`[${namespace[0]}] step: ${nodeName}`); - } + } + } else { + // Subagent updates (non-empty namespace) + for (const nodeName of Object.keys(data)) { + if (!INTERESTING_NODES.has(nodeName)) continue; + logger.info(`[${namespace[0]}] step: ${nodeName}`); } } } else if (mode === "messages") { @@ -105,10 +108,10 @@ export default class EscortAdminAgent { continue; } if (AIMessageChunk.isInstance(message)) { - if (message.text && !message.tool_call_chunks?.length) { + if (message.text) { callback(source, "ai", message.text, message.id); } - if (message.additional_kwargs.reasoning_content && !message.tool_call_chunks?.length) { + if (message.additional_kwargs.reasoning_content) { callback(source, "reasoning", message.additional_kwargs.reasoning_content, message.id); } } diff --git a/agent/escort-admin/prompts.js b/agent/escort-admin/prompts.js index 8c664bc..e824f2d 100644 --- a/agent/escort-admin/prompts.js +++ b/agent/escort-admin/prompts.js @@ -1,4 +1,3 @@ -import moment from "moment"; import services from "../../resource/services.js"; import agreement from "../../resource/agreement.js"; diff --git a/agent/escort-admin/tools/calendar/lunar_calendar_info.js b/agent/escort-admin/tools/calendar/lunar_calendar_info.js index d37a5ab..efa9271 100644 --- a/agent/escort-admin/tools/calendar/lunar_calendar_info.js +++ b/agent/escort-admin/tools/calendar/lunar_calendar_info.js @@ -1,24 +1,33 @@ import { tool } from "langchain" +import lunarLib from "lunar-javascript" +const { Solar } = lunarLib /** * 特定日期日历工具 - * 提供指定日期的日历信息 + * 基于 lunar-javascript 提供指定日期的完整农历信息 */ export const getLunarCalendarInfoTool = tool( async ({ year, month, day }) => { try { - const date = new Date(year, month - 1, day) - - if (isNaN(date.getTime())) { - return JSON.stringify({ error: '无效的日期' }, null, 2) + const solar = Solar.fromYmd(year, month, day) + const lunar = solar.getLunar() + + const result = { + solar: solar.toString(), + weekday: `星期${solar.getWeekInChinese()}`, + lunar: lunar.toString(), + ganzhiYear: lunar.getYearInGanZhi(), + zodiac: lunar.getYearShengXiao(), + solarTerms: lunar.getJieQi() || null, + festivals: [...solar.getFestivals(), ...lunar.getFestivals()], + yi: lunar.getDayYi(), + ji: lunar.getDayJi(), + xiShen: lunar.getDayPositionXiDesc(), + caiShen: lunar.getDayPositionCaiDesc() } - - // 获取农历信息 - const lunarInfo = {} - - return JSON.stringify(lunarInfo, null, 2) + + return JSON.stringify(result, null, 2) } catch (error) { - console.error('Error in date calendar tool:', error) return JSON.stringify({ error: error.message }, null, 2) } }, @@ -50,4 +59,4 @@ export const getLunarCalendarInfoTool = tool( required: ["year", "month", "day"] } } -) \ No newline at end of file +) diff --git a/agent/escort-admin/tools/calendar/utils.js b/agent/escort-admin/tools/calendar/utils.js index 971a5f0..cda776f 100644 --- a/agent/escort-admin/tools/calendar/utils.js +++ b/agent/escort-admin/tools/calendar/utils.js @@ -40,7 +40,8 @@ export async function getAccurateTime() { for (const source of timeSources) { try { const startTime = Date.now() - const res = await fetch(source.url) + // 每个时间源限时 3 秒,防止单个源 TCP 挂起长时间阻塞 + const res = await fetch(source.url, { signal: AbortSignal.timeout(3000) }) const latency = Date.now() - startTime let timestamp = null diff --git a/agent/escort-admin/tools/calendar/year_holidays.js b/agent/escort-admin/tools/calendar/year_holidays.js index 4954f31..5546e3c 100644 --- a/agent/escort-admin/tools/calendar/year_holidays.js +++ b/agent/escort-admin/tools/calendar/year_holidays.js @@ -1,30 +1,41 @@ import { tool } from "langchain" +import lunarLib from "lunar-javascript" +const { Solar, HolidayUtil } = lunarLib /** * 年份节日列表工具 - * 查询给定年份节日所在日期列表 + * 基于 lunar-javascript 计算全年节日(公历节日 + 农历传统节日)与法定节假日安排 */ export const getYearHolidaysTool = tool( async ({ year }) => { try { - // 简化实现,返回基本节日信息 - const holidays = [ - { date: `${year}-01-01`, name: '元旦' }, - { date: `${year}-02-14`, name: '情人节' }, - { date: `${year}-05-01`, name: '劳动节' }, - { date: `${year}-06-01`, name: '儿童节' }, - { date: `${year}-10-01`, name: '国庆节' } - ] - - return JSON.stringify({ year, holidays }, null, 2) + // 法定节假日安排(含调休补班) + const legal = HolidayUtil.getHolidays(year).map(h => ({ + date: h.getTarget().toString(), + name: h.getName(), + type: h.isWork() ? "调休上班" : "放假" + })) + + // 遍历全年日期,收集公历节日与农历传统节日(春节、中秋、端午等) + const festivals = [] + const start = Solar.fromYmd(year, 1, 1) + const days = Solar.fromYmd(year + 1, 1, 1).subtract(start) + for (let i = 0; i < days; i++) { + const d = start.next(i) + const names = [...d.getFestivals(), ...d.getLunar().getFestivals()] + if (names.length) { + festivals.push({ date: d.toString(), name: names.join("、") }) + } + } + + return JSON.stringify({ year, legal, festivals }, null, 2) } catch (error) { - console.error('Error in year holidays tool:', error) return JSON.stringify({ error: error.message }, null, 2) } }, { name: "get_year_holidays", - description: "查询给定年份节日所在日期列表", + description: "查询给定年份节日所在日期列表,包括法定节假日安排(含调休)与传统节日", schema: { type: "object", properties: { @@ -38,4 +49,4 @@ export const getYearHolidaysTool = tool( required: ["year"] } } -) \ No newline at end of file +) diff --git a/agent/escort-admin/tools/calendar/year_terms.js b/agent/escort-admin/tools/calendar/year_terms.js index da7a38b..4b3b22b 100644 --- a/agent/escort-admin/tools/calendar/year_terms.js +++ b/agent/escort-admin/tools/calendar/year_terms.js @@ -1,43 +1,29 @@ import { tool } from "langchain" +import lunarLib from "lunar-javascript" +const { Lunar } = lunarLib + +// 当年冬至在节气表中的 key 为英文(上一年冬至占用中文 key) +const EN_TERM_NAMES = { DONG_ZHI: "冬至" } /** * 年份节气列表工具 - * 查询给定年份节气所在日期列表 + * 基于 lunar-javascript 计算给定年份的 24 节气精确日期 */ export const getYearTermsTool = tool( async ({ year }) => { try { - // 简化实现,返回24节气信息 - const terms = [ - { date: `${year}-02-04`, name: '立春' }, - { date: `${year}-02-19`, name: '雨水' }, - { date: `${year}-03-05`, name: '惊蛰' }, - { date: `${year}-03-20`, name: '春分' }, - { date: `${year}-04-04`, name: '清明' }, - { date: `${year}-04-19`, name: '谷雨' }, - { date: `${year}-05-05`, name: '立夏' }, - { date: `${year}-05-20`, name: '小满' }, - { date: `${year}-06-05`, name: '芒种' }, - { date: `${year}-06-21`, name: '夏至' }, - { date: `${year}-07-07`, name: '小暑' }, - { date: `${year}-07-22`, name: '大暑' }, - { date: `${year}-08-07`, name: '立秋' }, - { date: `${year}-08-23`, name: '处暑' }, - { date: `${year}-09-07`, name: '白露' }, - { date: `${year}-09-23`, name: '秋分' }, - { date: `${year}-10-08`, name: '寒露' }, - { date: `${year}-10-23`, name: '霜降' }, - { date: `${year}-11-07`, name: '立冬' }, - { date: `${year}-11-22`, name: '小雪' }, - { date: `${year}-12-07`, name: '大雪' }, - { date: `${year}-12-21`, name: '冬至' }, - { date: `${year + 1}-01-05`, name: '小寒' }, - { date: `${year + 1}-01-20`, name: '大寒' } - ] - + const table = Lunar.fromYmd(year, 1, 1).getJieQiTable() + const terms = [] + for (const [key, solar] of Object.entries(table)) { + // 只保留属于目标年份的节气(表首含上一年边界节气) + if (solar.getYear() !== year) continue + const name = EN_TERM_NAMES[key] ?? key + terms.push({ date: solar.toString(), name }) + } + terms.sort((a, b) => a.date.localeCompare(b.date)) + return JSON.stringify({ year, terms }, null, 2) } catch (error) { - console.error('Error in year terms tool:', error) return JSON.stringify({ error: error.message }, null, 2) } }, @@ -57,4 +43,4 @@ export const getYearTermsTool = tool( required: ["year"] } } -) \ No newline at end of file +) diff --git a/agent/escort-admin/tools/db/escort_record_set.js b/agent/escort-admin/tools/db/escort_record_set.js index e86fe08..a0dd2f8 100644 --- a/agent/escort-admin/tools/db/escort_record_set.js +++ b/agent/escort-admin/tools/db/escort_record_set.js @@ -1,5 +1,6 @@ import { tool } from "@langchain/core/tools"; import z from "zod"; +import mongoose from "mongoose"; import { DBModel } from "../../../../models/index.js"; const escortRecordSetTool = tool( @@ -8,18 +9,18 @@ const escortRecordSetTool = tool( if (!orderId) { return { success: false, - error: "Order ID (_id or orderNo) is required as the lookup key", + error: "Record ID (_id) is required as the lookup key", }; } - const query = { - $or: [ - { _id: orderId }, - { orderNo: orderId } - ] - }; + if (!mongoose.Types.ObjectId.isValid(orderId)) { + return { + success: false, + error: `Invalid record ID: ${orderId}. A valid record _id is required.`, + }; + } - const record = await DBModel.EscortRecord.findOne(query); + const record = await DBModel.EscortRecord.findById(orderId); if (!record) { return { success: false, @@ -79,11 +80,11 @@ const escortRecordSetTool = tool( { name: "escort_record_set", description: - "Update escort record fields by order ID (_id or orderNo). Supports updating status, notes (patientNote, escortNote, medicalSummary), and payment (totalFee, paidFee, status). Only provided fields will be updated.", + "Update escort record fields by record ID (_id). Supports updating status, notes (patientNote, escortNote, medicalSummary), and payment (totalFee, paidFee, status). Only provided fields will be updated.", schema: z.object({ orderId: z .string() - .describe("Order ID (_id or orderNo) used as the lookup key"), + .describe("Record ID (_id) used as the lookup key"), status: z .enum(["pending", "confirmed", "in_progress", "completed", "cancelled"]) .optional() diff --git a/agent/escort-admin/tools/web/fetch.js b/agent/escort-admin/tools/web/fetch.js index 58fc031..e8297d7 100644 --- a/agent/escort-admin/tools/web/fetch.js +++ b/agent/escort-admin/tools/web/fetch.js @@ -1,6 +1,7 @@ import { TavilyExtract } from "@langchain/tavily"; import { tool } from "@langchain/core/tools"; import * as z from "zod" +import config from "../../../../conf.json" with { type: "json" }; const webFetchTool = tool( async ({ @@ -10,7 +11,7 @@ const webFetchTool = tool( urls = [], }) => { const tavilyExtract = new TavilyExtract({ - tavilyApiKey: process.env.TAVILY_API_KEY, + tavilyApiKey: config.agent.tavily.apiKey, extractDepth, includeImages, format diff --git a/agent/escort-admin/tools/web/search.js b/agent/escort-admin/tools/web/search.js index 729d8c4..7d2d309 100644 --- a/agent/escort-admin/tools/web/search.js +++ b/agent/escort-admin/tools/web/search.js @@ -1,6 +1,7 @@ import { TavilySearch } from "@langchain/tavily"; import { tool } from "@langchain/core/tools"; import * as z from "zod" +import config from "../../../../conf.json" with { type: "json" }; const webSearchTool = tool( async ({ @@ -11,7 +12,7 @@ const webSearchTool = tool( }) => { const tavilySearch = new TavilySearch({ maxResults, - tavilyApiKey: process.env.TAVILY_API_KEY, + tavilyApiKey: config.agent.tavily.apiKey, includeRawContent, topic, }); diff --git a/agent/escort/agent.js b/agent/escort/agent.js index 7f338b7..1e3bc83 100644 --- a/agent/escort/agent.js +++ b/agent/escort/agent.js @@ -1,4 +1,5 @@ import 'dotenv/config'; +import fs from 'fs'; import path from 'path'; import { createDeepAgent, FilesystemBackend, CompositeBackend } from "deepagents"; import { ChatOpenAI } from "@langchain/openai"; @@ -7,6 +8,10 @@ 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'; + +// 密钥由 conf.json 统一提供;百度地图 skill 通过 env_get 读环境变量,此处桥接 +process.env.TAVILY_API_KEY ??= config.agent.tavily?.apiKey; +process.env.BAIDU_MAP_AUTH_TOKEN ??= config.agent.baiduMap?.authToken; import Prompts from "./prompts.js"; import { getEnvTool, webFetchTool, webSearchTool, getCalendarInfoTool, @@ -19,6 +24,7 @@ export default class EscortAgent { static MAX_HISTORY_CHARS = config.agent.maxHistoryChars || 40000; constructor() { + this.messages = []; } clearMessages() { @@ -137,12 +143,19 @@ export default class EscortAgent { } _genAgent(userInfo) { + const rootDir = process.cwd(); + const memoryFile = userInfo + ? path.join(rootDir, "data", userInfo._id, "memories", "user_memory.txt") + : null; + + // 会话中记忆文件被更新后重建 agent,使 systemPrompt 中的用户记忆保持最新 + if (this.agent && this._memoryMtime !== this._statMemory(memoryFile)) { + this.agent = null; + } if (this.agent) { return this.agent; } - const rootDir = process.cwd(); - this.messages = []; let backend = new FilesystemBackend({ rootDir }); if (userInfo) { @@ -164,6 +177,8 @@ export default class EscortAgent { temperature: 0.0 }); + this._memoryMtime = this._statMemory(memoryFile); + this.agent = createDeepAgent({ name: "deep-agent", model: this.flashModel, @@ -178,4 +193,14 @@ export default class EscortAgent { return this.agent; } + + // 返回记忆文件 mtime,文件不存在时返回 null + _statMemory(memoryFile) { + if (!memoryFile) return null; + try { + return fs.statSync(memoryFile).mtimeMs; + } catch { + return null; + } + } } diff --git a/agent/escort/prompts.js b/agent/escort/prompts.js index e229f44..2d6b304 100644 --- a/agent/escort/prompts.js +++ b/agent/escort/prompts.js @@ -1,8 +1,8 @@ -import moment from "moment"; import fs from "fs"; import path from "path"; import services from "../../resource/services.js"; import agreement from "../../resource/agreement.js"; +import logger from "../../utils/logger.js"; class Prompts { static buildSystemPrompt(userInfo) { @@ -24,7 +24,7 @@ class Prompts { try { usermem_str = fs.readFileSync(userMemoryPath, 'utf8'); } catch (err) { - console.log('读取用户记忆失败', err); + logger.error('读取用户记忆失败', err); } } diff --git a/agent/escort/tools/calendar/lunar_calendar_info.js b/agent/escort/tools/calendar/lunar_calendar_info.js index d37a5ab..efa9271 100644 --- a/agent/escort/tools/calendar/lunar_calendar_info.js +++ b/agent/escort/tools/calendar/lunar_calendar_info.js @@ -1,24 +1,33 @@ import { tool } from "langchain" +import lunarLib from "lunar-javascript" +const { Solar } = lunarLib /** * 特定日期日历工具 - * 提供指定日期的日历信息 + * 基于 lunar-javascript 提供指定日期的完整农历信息 */ export const getLunarCalendarInfoTool = tool( async ({ year, month, day }) => { try { - const date = new Date(year, month - 1, day) - - if (isNaN(date.getTime())) { - return JSON.stringify({ error: '无效的日期' }, null, 2) + const solar = Solar.fromYmd(year, month, day) + const lunar = solar.getLunar() + + const result = { + solar: solar.toString(), + weekday: `星期${solar.getWeekInChinese()}`, + lunar: lunar.toString(), + ganzhiYear: lunar.getYearInGanZhi(), + zodiac: lunar.getYearShengXiao(), + solarTerms: lunar.getJieQi() || null, + festivals: [...solar.getFestivals(), ...lunar.getFestivals()], + yi: lunar.getDayYi(), + ji: lunar.getDayJi(), + xiShen: lunar.getDayPositionXiDesc(), + caiShen: lunar.getDayPositionCaiDesc() } - - // 获取农历信息 - const lunarInfo = {} - - return JSON.stringify(lunarInfo, null, 2) + + return JSON.stringify(result, null, 2) } catch (error) { - console.error('Error in date calendar tool:', error) return JSON.stringify({ error: error.message }, null, 2) } }, @@ -50,4 +59,4 @@ export const getLunarCalendarInfoTool = tool( required: ["year", "month", "day"] } } -) \ No newline at end of file +) diff --git a/agent/escort/tools/calendar/utils.js b/agent/escort/tools/calendar/utils.js index 971a5f0..cda776f 100644 --- a/agent/escort/tools/calendar/utils.js +++ b/agent/escort/tools/calendar/utils.js @@ -40,7 +40,8 @@ export async function getAccurateTime() { for (const source of timeSources) { try { const startTime = Date.now() - const res = await fetch(source.url) + // 每个时间源限时 3 秒,防止单个源 TCP 挂起长时间阻塞 + const res = await fetch(source.url, { signal: AbortSignal.timeout(3000) }) const latency = Date.now() - startTime let timestamp = null diff --git a/agent/escort/tools/calendar/year_holidays.js b/agent/escort/tools/calendar/year_holidays.js index 4954f31..5546e3c 100644 --- a/agent/escort/tools/calendar/year_holidays.js +++ b/agent/escort/tools/calendar/year_holidays.js @@ -1,30 +1,41 @@ import { tool } from "langchain" +import lunarLib from "lunar-javascript" +const { Solar, HolidayUtil } = lunarLib /** * 年份节日列表工具 - * 查询给定年份节日所在日期列表 + * 基于 lunar-javascript 计算全年节日(公历节日 + 农历传统节日)与法定节假日安排 */ export const getYearHolidaysTool = tool( async ({ year }) => { try { - // 简化实现,返回基本节日信息 - const holidays = [ - { date: `${year}-01-01`, name: '元旦' }, - { date: `${year}-02-14`, name: '情人节' }, - { date: `${year}-05-01`, name: '劳动节' }, - { date: `${year}-06-01`, name: '儿童节' }, - { date: `${year}-10-01`, name: '国庆节' } - ] - - return JSON.stringify({ year, holidays }, null, 2) + // 法定节假日安排(含调休补班) + const legal = HolidayUtil.getHolidays(year).map(h => ({ + date: h.getTarget().toString(), + name: h.getName(), + type: h.isWork() ? "调休上班" : "放假" + })) + + // 遍历全年日期,收集公历节日与农历传统节日(春节、中秋、端午等) + const festivals = [] + const start = Solar.fromYmd(year, 1, 1) + const days = Solar.fromYmd(year + 1, 1, 1).subtract(start) + for (let i = 0; i < days; i++) { + const d = start.next(i) + const names = [...d.getFestivals(), ...d.getLunar().getFestivals()] + if (names.length) { + festivals.push({ date: d.toString(), name: names.join("、") }) + } + } + + return JSON.stringify({ year, legal, festivals }, null, 2) } catch (error) { - console.error('Error in year holidays tool:', error) return JSON.stringify({ error: error.message }, null, 2) } }, { name: "get_year_holidays", - description: "查询给定年份节日所在日期列表", + description: "查询给定年份节日所在日期列表,包括法定节假日安排(含调休)与传统节日", schema: { type: "object", properties: { @@ -38,4 +49,4 @@ export const getYearHolidaysTool = tool( required: ["year"] } } -) \ No newline at end of file +) diff --git a/agent/escort/tools/calendar/year_terms.js b/agent/escort/tools/calendar/year_terms.js index da7a38b..4b3b22b 100644 --- a/agent/escort/tools/calendar/year_terms.js +++ b/agent/escort/tools/calendar/year_terms.js @@ -1,43 +1,29 @@ import { tool } from "langchain" +import lunarLib from "lunar-javascript" +const { Lunar } = lunarLib + +// 当年冬至在节气表中的 key 为英文(上一年冬至占用中文 key) +const EN_TERM_NAMES = { DONG_ZHI: "冬至" } /** * 年份节气列表工具 - * 查询给定年份节气所在日期列表 + * 基于 lunar-javascript 计算给定年份的 24 节气精确日期 */ export const getYearTermsTool = tool( async ({ year }) => { try { - // 简化实现,返回24节气信息 - const terms = [ - { date: `${year}-02-04`, name: '立春' }, - { date: `${year}-02-19`, name: '雨水' }, - { date: `${year}-03-05`, name: '惊蛰' }, - { date: `${year}-03-20`, name: '春分' }, - { date: `${year}-04-04`, name: '清明' }, - { date: `${year}-04-19`, name: '谷雨' }, - { date: `${year}-05-05`, name: '立夏' }, - { date: `${year}-05-20`, name: '小满' }, - { date: `${year}-06-05`, name: '芒种' }, - { date: `${year}-06-21`, name: '夏至' }, - { date: `${year}-07-07`, name: '小暑' }, - { date: `${year}-07-22`, name: '大暑' }, - { date: `${year}-08-07`, name: '立秋' }, - { date: `${year}-08-23`, name: '处暑' }, - { date: `${year}-09-07`, name: '白露' }, - { date: `${year}-09-23`, name: '秋分' }, - { date: `${year}-10-08`, name: '寒露' }, - { date: `${year}-10-23`, name: '霜降' }, - { date: `${year}-11-07`, name: '立冬' }, - { date: `${year}-11-22`, name: '小雪' }, - { date: `${year}-12-07`, name: '大雪' }, - { date: `${year}-12-21`, name: '冬至' }, - { date: `${year + 1}-01-05`, name: '小寒' }, - { date: `${year + 1}-01-20`, name: '大寒' } - ] - + const table = Lunar.fromYmd(year, 1, 1).getJieQiTable() + const terms = [] + for (const [key, solar] of Object.entries(table)) { + // 只保留属于目标年份的节气(表首含上一年边界节气) + if (solar.getYear() !== year) continue + const name = EN_TERM_NAMES[key] ?? key + terms.push({ date: solar.toString(), name }) + } + terms.sort((a, b) => a.date.localeCompare(b.date)) + return JSON.stringify({ year, terms }, null, 2) } catch (error) { - console.error('Error in year terms tool:', error) return JSON.stringify({ error: error.message }, null, 2) } }, @@ -57,4 +43,4 @@ export const getYearTermsTool = tool( required: ["year"] } } -) \ No newline at end of file +) diff --git a/agent/escort/tools/db/escort_record_set.js b/agent/escort/tools/db/escort_record_set.js index e86fe08..a0dd2f8 100644 --- a/agent/escort/tools/db/escort_record_set.js +++ b/agent/escort/tools/db/escort_record_set.js @@ -1,5 +1,6 @@ import { tool } from "@langchain/core/tools"; import z from "zod"; +import mongoose from "mongoose"; import { DBModel } from "../../../../models/index.js"; const escortRecordSetTool = tool( @@ -8,18 +9,18 @@ const escortRecordSetTool = tool( if (!orderId) { return { success: false, - error: "Order ID (_id or orderNo) is required as the lookup key", + error: "Record ID (_id) is required as the lookup key", }; } - const query = { - $or: [ - { _id: orderId }, - { orderNo: orderId } - ] - }; + if (!mongoose.Types.ObjectId.isValid(orderId)) { + return { + success: false, + error: `Invalid record ID: ${orderId}. A valid record _id is required.`, + }; + } - const record = await DBModel.EscortRecord.findOne(query); + const record = await DBModel.EscortRecord.findById(orderId); if (!record) { return { success: false, @@ -79,11 +80,11 @@ const escortRecordSetTool = tool( { name: "escort_record_set", description: - "Update escort record fields by order ID (_id or orderNo). Supports updating status, notes (patientNote, escortNote, medicalSummary), and payment (totalFee, paidFee, status). Only provided fields will be updated.", + "Update escort record fields by record ID (_id). Supports updating status, notes (patientNote, escortNote, medicalSummary), and payment (totalFee, paidFee, status). Only provided fields will be updated.", schema: z.object({ orderId: z .string() - .describe("Order ID (_id or orderNo) used as the lookup key"), + .describe("Record ID (_id) used as the lookup key"), status: z .enum(["pending", "confirmed", "in_progress", "completed", "cancelled"]) .optional() diff --git a/agent/escort/tools/web/fetch.js b/agent/escort/tools/web/fetch.js index 58fc031..e8297d7 100644 --- a/agent/escort/tools/web/fetch.js +++ b/agent/escort/tools/web/fetch.js @@ -1,6 +1,7 @@ import { TavilyExtract } from "@langchain/tavily"; import { tool } from "@langchain/core/tools"; import * as z from "zod" +import config from "../../../../conf.json" with { type: "json" }; const webFetchTool = tool( async ({ @@ -10,7 +11,7 @@ const webFetchTool = tool( urls = [], }) => { const tavilyExtract = new TavilyExtract({ - tavilyApiKey: process.env.TAVILY_API_KEY, + tavilyApiKey: config.agent.tavily.apiKey, extractDepth, includeImages, format diff --git a/agent/escort/tools/web/search.js b/agent/escort/tools/web/search.js index 729d8c4..7d2d309 100644 --- a/agent/escort/tools/web/search.js +++ b/agent/escort/tools/web/search.js @@ -1,6 +1,7 @@ import { TavilySearch } from "@langchain/tavily"; import { tool } from "@langchain/core/tools"; import * as z from "zod" +import config from "../../../../conf.json" with { type: "json" }; const webSearchTool = tool( async ({ @@ -11,7 +12,7 @@ const webSearchTool = tool( }) => { const tavilySearch = new TavilySearch({ maxResults, - tavilyApiKey: process.env.TAVILY_API_KEY, + tavilyApiKey: config.agent.tavily.apiKey, includeRawContent, topic, }); diff --git a/conf.json b/conf.json index d8aeaa5..b79ca95 100644 --- a/conf.json +++ b/conf.json @@ -17,6 +17,12 @@ "apiKey": "ed5f2ec42cb9413f87402d38321553f8.u0FalmfLdXxmst69", "flashModel": "glm-5.3-flash", "proModel": "glm-5.3" + }, + "tavily": { + "apiKey": "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" + }, + "baiduMap": { + "authToken": "sk-ap-9xcqwNJ3FyJGUoAoQoCgWLqPd5o2tJKCA1xaSMRaZT0zDo0PCFm7rczL4anUuXf5" } }, "mongodb": { diff --git a/handler/health_profile.js b/handler/health_profile.js index 48ae11d..1fef5b7 100644 --- a/handler/health_profile.js +++ b/handler/health_profile.js @@ -6,7 +6,7 @@ class HandlerHealthProfile { } // 白名单:只允许写入 schema 定义的顶层字段(兼容 'profile.name' 等点号路径) - static PROFILE_FIELDS = ["userId", "profile", "health"]; + static PROFILE_FIELDS = ["userId", "profile", "location", "health"]; static pickFields(body) { const picked = {}; diff --git a/models/schema/health_profile.js b/models/schema/health_profile.js index bd9dd3a..1f9ca92 100644 --- a/models/schema/health_profile.js +++ b/models/schema/health_profile.js @@ -22,7 +22,16 @@ const HealthProfileSchema = mongoose.Schema( mobile: { type: String, default: "", index: true, comment: "患者电话" }, sex: { type: String, enum: ["male", "female", ""], default: "", comment: "性别" }, birth: { type: String, default: "", comment: "出生年月(YYYY-MM-DD)" }, - idnumber: { type: String, default: "", comment: "身份证号" }, + idnumber: { type: String, default: "", comment: "证件号(身份证/护照等)" }, + }, + + // 所在地(国外用户填国家;国内用户填省市区 + 详细地址) + location: { + country: { type: String, default: "中国", comment: "国家" }, + province: { type: String, default: "", comment: "省" }, + city: { type: String, default: "", comment: "市" }, + district: { type: String, default: "", comment: "区/县" }, + address: { type: String, default: "", comment: "详细地址" }, }, // 健康信息 @@ -68,27 +77,27 @@ HealthProfileSchema.statics.findByUserId = async function (userId) { * @param {string} [options.sortBy="createtime"] - 排序字段:createtime | updatetime(可选) * @returns {Promise} 返回 `{ list, total, page, pageSize }` */ - HealthProfileSchema.statics.findProfiles = async function (options = {}) { - const { page = 1, pageSize = 20, userId, name, mobile, sortBy = "createtime" } = options; - const filter = {}; +HealthProfileSchema.statics.findProfiles = async function (options = {}) { + const { page = 1, pageSize = 20, userId, name, mobile, sortBy = "createtime" } = options; + const filter = {}; - if (userId) { - filter.userId = userId; - } - if (name) { - // 转义正则特殊字符,避免查询报错或 ReDoS - const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); - filter["profile.name"] = { $regex: escaped, $options: "i" }; - } - if (mobile) { - filter["profile.mobile"] = mobile; - } + if (userId) { + filter.userId = userId; + } + if (name) { + // 转义正则特殊字符,避免查询报错或 ReDoS + const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + filter["profile.name"] = { $regex: escaped, $options: "i" }; + } + if (mobile) { + filter["profile.mobile"] = mobile; + } - const sortField = sortBy === "updatetime" ? "meta.updatetime" : "meta.createtime"; - const skip = (page - 1) * pageSize; - const [list, total] = await Promise.all([ - this.find(filter) - .sort({ [sortField]: -1 }) + const sortField = sortBy === "updatetime" ? "meta.updatetime" : "meta.createtime"; + const skip = (page - 1) * pageSize; + const [list, total] = await Promise.all([ + this.find(filter) + .sort({ [sortField]: -1 }) .skip(skip) .limit(pageSize) .exec(), diff --git a/package-lock.json b/package-lock.json index 1d0eef8..563e13c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,21 +8,20 @@ "name": "attendant-api", "version": "1.0.0", "dependencies": { - "@langchain/anthropic": "^1.4.0", - "@langchain/community": "^1.1.28", - "@langchain/core": "^1.1.48", - "@langchain/deepseek": "^1.0.27", - "@langchain/langgraph": "^1.3.2", - "@langchain/openai": "^1.4.7", + "@langchain/anthropic": "^1.5.9", + "@langchain/core": "^1.2.9", + "@langchain/deepseek": "^1.1.11", + "@langchain/langgraph": "^1.4.13", + "@langchain/openai": "^1.5.11", "@langchain/tavily": "^1.2.0", "bcrypt": "^5.1.1", - "deepagents": "^1.10.2", + "deepagents": "^1.13.2", "dotenv": "^17.4.2", "koa": "^2.16.4", "koa-bodyparser": "^4.4.1", "koa-cors": "^0.0.16", "koa-router": "^12.0.1", - "langchain": "^1.4.2", + "langchain": "^1.5.10", "lodash": "^4.18.1", "lunar-javascript": "^1.7.7", "moment": "^2.30.1", @@ -30,7 +29,7 @@ "node-fetch": "^3.3.2", "winston": "^3.19.0", "ws": "^8.21.0", - "zod": "^4.4.3" + "zod": "^4.5.4" }, "devDependencies": { "nodemon": "^3.0.2" @@ -41,9 +40,9 @@ } }, "node_modules/@anthropic-ai/sdk": { - "version": "0.95.2", - "resolved": "https://registry.npmmirror.com/@anthropic-ai/sdk/-/sdk-0.95.2.tgz", - "integrity": "sha512-Egddwo3sheo1PzUrMkZnH6VkQYwS0h/b/i8vSK8Ta9M45UQipAMeDFH57dYuDAfXMEUUGeKw6CMlremgMZgrSQ==", + "version": "0.120.0", + "resolved": "https://registry.npmmirror.com/@anthropic-ai/sdk/-/sdk-0.120.0.tgz", + "integrity": "sha512-ZlvmNFT/iIF6JD13rxbbMWD8nvGR0RaUp6yMQnoc+4Af0YjVVe/bIdW1XSQQsoxXAtg1NaT6Vak0LKFlJ4d37Q==", "license": "MIT", "dependencies": { "json-schema-to-ts": "^3.1.1", @@ -62,9 +61,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.29.2", - "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.29.2.tgz", - "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -103,574 +102,25 @@ "license": "BSD-3-Clause" }, "node_modules/@langchain/anthropic": { - "version": "1.4.0", - "resolved": "https://registry.npmmirror.com/@langchain/anthropic/-/anthropic-1.4.0.tgz", - "integrity": "sha512-rs1yVydrHjyiD31uChdCnKZpmDuKa0Bpz8Raiy9GvqnqmfXPMe0oOrap/2paE+NRSinDbtax8mMpP/yv8EbO1A==", + "version": "1.5.9", + "resolved": "https://registry.npmmirror.com/@langchain/anthropic/-/anthropic-1.5.9.tgz", + "integrity": "sha512-KENFWcb4f+vlbE49wDm/DV6CLX+BaL/8aAMWwkINwc/2ZW79HSY2nwFpFdmV10CPGBwfpiWFUZRBqvX+xw2idg==", "license": "MIT", "dependencies": { - "@anthropic-ai/sdk": "^0.95.1", + "@anthropic-ai/sdk": "^0.120.0", "zod": "^3.25.76 || ^4" }, "engines": { "node": ">=20" }, "peerDependencies": { - "@langchain/core": "^1.1.47" - } - }, - "node_modules/@langchain/classic": { - "version": "1.0.33", - "resolved": "https://registry.npmmirror.com/@langchain/classic/-/classic-1.0.33.tgz", - "integrity": "sha512-EffyMp4GhcRR3a/re+E/SQlBlsToE6kun266tYzKXbc6lEHeerXAkNsZChgP8kCVBhCYhYhdTbn68ZyldrE7JA==", - "license": "MIT", - "dependencies": { - "@langchain/openai": "1.4.6", - "@langchain/textsplitters": "1.0.1", - "handlebars": "^4.7.9", - "js-yaml": "^4.1.1", - "jsonpointer": "^5.0.1", - "openapi-types": "^12.1.3", - "yaml": "^2.8.3", - "zod": "^3.25.76 || ^4" - }, - "engines": { - "node": ">=20" - }, - "optionalDependencies": { - "langsmith": ">=0.4.0 <1.0.0" - }, - "peerDependencies": { - "@langchain/core": "^1.1.47", - "cheerio": "*", - "peggy": "^5.1.0", - "typeorm": "*" - }, - "peerDependenciesMeta": { - "cheerio": { - "optional": true - }, - "peggy": { - "optional": true - }, - "typeorm": { - "optional": true - } - } - }, - "node_modules/@langchain/classic/node_modules/@langchain/openai": { - "version": "1.4.6", - "resolved": "https://registry.npmmirror.com/@langchain/openai/-/openai-1.4.6.tgz", - "integrity": "sha512-R92/hW1aFlL9YNWLDEy1ePBnsn83kPOINNsVD+asjTJKB/00Dwf6s0VBpgZLRJiSWOW/RvbLJ/V4Djayh5boyQ==", - "license": "MIT", - "dependencies": { - "js-tiktoken": "^1.0.12", - "openai": "^6.37.0", - "zod": "^3.25.76 || ^4" - }, - "engines": { - "node": ">=20" - }, - "peerDependencies": { - "@langchain/core": "^1.1.47" - } - }, - "node_modules/@langchain/community": { - "version": "1.1.28", - "resolved": "https://registry.npmmirror.com/@langchain/community/-/community-1.1.28.tgz", - "integrity": "sha512-Mb6vmLE4a7LLkH/flxNJgzNXCbrLH/osAvuplXTRqfsysfL8/EjtN7B98kuj/4HwLtBpn8pUQ5HbJIRXLrhP8Q==", - "license": "MIT", - "dependencies": { - "@langchain/classic": "^1.0.27", - "@langchain/openai": "^1.4.1", - "binary-extensions": "^2.2.0", - "flat": "^5.0.2", - "js-yaml": "^4.1.1", - "langsmith": ">=0.4.0 <1.0.0", - "math-expression-evaluator": "^2.0.0", - "uuid": "^14.0.0", - "zod": "^3.25.76 || ^4" - }, - "engines": { - "node": ">=20" - }, - "peerDependencies": { - "@arcjet/redact": "^v1.2.0", - "@aws-crypto/sha256-js": "^5.0.0", - "@aws-sdk/client-dynamodb": "^3.1001.0", - "@aws-sdk/client-lambda": "^3.1001.0", - "@aws-sdk/client-s3": "^3.1001.0", - "@aws-sdk/client-sagemaker-runtime": "^3.1001.0", - "@aws-sdk/client-sfn": "^3.1001.0", - "@aws-sdk/credential-provider-node": "^3.388.0", - "@azure/search-documents": "^12.2.0", - "@azure/storage-blob": "^12.31.0", - "@browserbasehq/sdk": "*", - "@browserbasehq/stagehand": "^1.0.0", - "@clickhouse/client": "^0.2.5", - "@datastax/astra-db-ts": "^1.0.0", - "@elastic/elasticsearch": "^8.4.0", - "@getmetal/metal-sdk": "*", - "@getzep/zep-cloud": "^1.0.6", - "@getzep/zep-js": "^2.0.2", - "@gomomento/sdk-core": "^1.117.2", - "@google-cloud/storage": "^6.10.1 || ^7.7.0", - "@gradientai/nodejs-sdk": "^1.2.0", - "@huggingface/inference": "^4.13.14", - "@huggingface/transformers": "^3.8.1", - "@ibm-cloud/watsonx-ai": "*", - "@lancedb/lancedb": "^0.19.1", - "@langchain/core": "^1.1.38", - "@layerup/layerup-security": "^1.5.12", - "@libsql/client": "^0.17.0", - "@mendable/firecrawl-js": "^4.15.2", - "@mlc-ai/web-llm": "*", - "@mozilla/readability": "*", - "@neondatabase/serverless": "*", - "@notionhq/client": "^5.11.1", - "@opensearch-project/opensearch": "*", - "@planetscale/database": "^1.8.0", - "@premai/prem-sdk": "^0.3.25", - "@raycast/api": "^1.55.2", - "@rockset/client": "^0.9.1", - "@smithy/eventstream-codec": "^4.2.10", - "@smithy/protocol-http": "^5.3.10", - "@smithy/signature-v4": "^5.3.10", - "@smithy/util-utf8": "^4.2.2", - "@spider-cloud/spider-client": "^0.2.0", - "@supabase/supabase-js": "^2.45.0", - "@tensorflow-models/universal-sentence-encoder": "*", - "@tensorflow/tfjs-core": "*", - "@upstash/ratelimit": "^1.1.3 || ^2.0.3", - "@upstash/redis": "^1.20.6", - "@upstash/vector": "^1.1.1", - "@vercel/kv": "*", - "@vercel/postgres": "*", - "@writerai/writer-sdk": "^3.6.0", - "@xata.io/client": "^0.30.1", - "@zilliz/milvus2-sdk-node": ">=2.3.5", - "apify-client": "^2.22.2", - "assemblyai": "^4.25.1", - "azion": "^3.1.2", - "better-sqlite3": ">=9.4.0 <13.0.0", - "cassandra-driver": "^4.7.2", - "cborg": "^4.5.8", - "cheerio": "^1.2.0", - "chromadb": "*", - "closevector-common": "0.1.3", - "closevector-node": "0.1.6", - "closevector-web": "0.1.6", - "convex": "^1.32.0", - "couchbase": "^4.6.1", - "crypto-js": "^4.2.0", - "d3-dsv": "^3.0.1", - "discord.js": "^14.25.1", - "duck-duck-scrape": "^2.2.5", - "epub2": "^3.0.1", - "faiss-node": "*", - "fast-xml-parser": "*", - "firebase-admin": "^13.6.1", - "google-auth-library": "*", - "googleapis": "*", - "hnswlib-node": "^3.0.0", - "html-to-text": "^9.0.5", - "ibm-cloud-sdk-core": "*", - "ignore": "^7.0.5", - "interface-datastore": "^9.0.2", - "ioredis": "^5.3.2", - "it-all": "^3.0.4", - "jsdom": "*", - "jsonwebtoken": "^9.0.3", - "lodash": "^4.17.23", - "lunary": "^0.7.10", - "mammoth": "^1.11.0", - "mariadb": "^3.5.1", - "mem0ai": "^2.2.4", - "mysql2": "^3.19.1", - "neo4j-driver": "*", - "node-llama-cpp": ">=3.0.0", - "notion-to-md": "^3.1.0", - "officeparser": "^6.0.4", - "openai": "*", - "pdf-parse": "^1.0.0 || ^2.0.0", - "pg": "^8.11.0", - "pg-copy-streams": "^7.0.0", - "pickleparser": "^0.2.1", - "playwright": "^1.58.2", - "portkey-ai": "^3.0.3", - "puppeteer": "*", - "pyodide": ">=0.24.1 <0.27.0", - "replicate": "*", - "sonix-speech-recognition": "^2.1.1", - "srt-parser-2": "^1.2.3", - "typeorm": "^0.3.28", - "typesense": "^3.0.1", - "usearch": "^1.1.1", - "voy-search": "0.6.3", - "word-extractor": "*", - "ws": "^8.14.2", - "youtubei.js": "*" - }, - "peerDependenciesMeta": { - "@arcjet/redact": { - "optional": true - }, - "@aws-crypto/sha256-js": { - "optional": true - }, - "@aws-sdk/client-dynamodb": { - "optional": true - }, - "@aws-sdk/client-lambda": { - "optional": true - }, - "@aws-sdk/client-s3": { - "optional": true - }, - "@aws-sdk/client-sagemaker-runtime": { - "optional": true - }, - "@aws-sdk/client-sfn": { - "optional": true - }, - "@aws-sdk/credential-provider-node": { - "optional": true - }, - "@aws-sdk/dsql-signer": { - "optional": true - }, - "@azure/search-documents": { - "optional": true - }, - "@azure/storage-blob": { - "optional": true - }, - "@browserbasehq/sdk": { - "optional": true - }, - "@clickhouse/client": { - "optional": true - }, - "@datastax/astra-db-ts": { - "optional": true - }, - "@elastic/elasticsearch": { - "optional": true - }, - "@getmetal/metal-sdk": { - "optional": true - }, - "@getzep/zep-cloud": { - "optional": true - }, - "@getzep/zep-js": { - "optional": true - }, - "@gomomento/sdk-core": { - "optional": true - }, - "@google-cloud/storage": { - "optional": true - }, - "@gradientai/nodejs-sdk": { - "optional": true - }, - "@huggingface/inference": { - "optional": true - }, - "@huggingface/transformers": { - "optional": true - }, - "@lancedb/lancedb": { - "optional": true - }, - "@layerup/layerup-security": { - "optional": true - }, - "@libsql/client": { - "optional": true - }, - "@mendable/firecrawl-js": { - "optional": true - }, - "@mlc-ai/web-llm": { - "optional": true - }, - "@mozilla/readability": { - "optional": true - }, - "@neondatabase/serverless": { - "optional": true - }, - "@notionhq/client": { - "optional": true - }, - "@opensearch-project/opensearch": { - "optional": true - }, - "@pinecone-database/pinecone": { - "optional": true - }, - "@planetscale/database": { - "optional": true - }, - "@premai/prem-sdk": { - "optional": true - }, - "@qdrant/js-client-rest": { - "optional": true - }, - "@raycast/api": { - "optional": true - }, - "@rockset/client": { - "optional": true - }, - "@smithy/eventstream-codec": { - "optional": true - }, - "@smithy/protocol-http": { - "optional": true - }, - "@smithy/signature-v4": { - "optional": true - }, - "@smithy/util-utf8": { - "optional": true - }, - "@spider-cloud/spider-client": { - "optional": true - }, - "@supabase/supabase-js": { - "optional": true - }, - "@tensorflow-models/universal-sentence-encoder": { - "optional": true - }, - "@tensorflow/tfjs-core": { - "optional": true - }, - "@upstash/ratelimit": { - "optional": true - }, - "@upstash/redis": { - "optional": true - }, - "@upstash/vector": { - "optional": true - }, - "@vercel/kv": { - "optional": true - }, - "@vercel/postgres": { - "optional": true - }, - "@writerai/writer-sdk": { - "optional": true - }, - "@xata.io/client": { - "optional": true - }, - "@xenova/transformers": { - "optional": true - }, - "@zilliz/milvus2-sdk-node": { - "optional": true - }, - "apify-client": { - "optional": true - }, - "assemblyai": { - "optional": true - }, - "azion": { - "optional": true - }, - "better-sqlite3": { - "optional": true - }, - "cassandra-driver": { - "optional": true - }, - "cborg": { - "optional": true - }, - "cheerio": { - "optional": true - }, - "chromadb": { - "optional": true - }, - "closevector-common": { - "optional": true - }, - "closevector-node": { - "optional": true - }, - "closevector-web": { - "optional": true - }, - "cohere-ai": { - "optional": true - }, - "convex": { - "optional": true - }, - "couchbase": { - "optional": true - }, - "crypto-js": { - "optional": true - }, - "d3-dsv": { - "optional": true - }, - "discord.js": { - "optional": true - }, - "duck-duck-scrape": { - "optional": true - }, - "epub2": { - "optional": true - }, - "faiss-node": { - "optional": true - }, - "fast-xml-parser": { - "optional": true - }, - "firebase-admin": { - "optional": true - }, - "google-auth-library": { - "optional": true - }, - "googleapis": { - "optional": true - }, - "hnswlib-node": { - "optional": true - }, - "html-to-text": { - "optional": true - }, - "ignore": { - "optional": true - }, - "interface-datastore": { - "optional": true - }, - "ioredis": { - "optional": true - }, - "it-all": { - "optional": true - }, - "jsdom": { - "optional": true - }, - "jsonwebtoken": { - "optional": true - }, - "lodash": { - "optional": true - }, - "lunary": { - "optional": true - }, - "mammoth": { - "optional": true - }, - "mariadb": { - "optional": true - }, - "mem0ai": { - "optional": true - }, - "mongodb": { - "optional": true - }, - "mysql2": { - "optional": true - }, - "neo4j-driver": { - "optional": true - }, - "node-llama-cpp": { - "optional": true - }, - "notion-to-md": { - "optional": true - }, - "officeparser": { - "optional": true - }, - "pdf-parse": { - "optional": true - }, - "pg": { - "optional": true - }, - "pg-copy-streams": { - "optional": true - }, - "pickleparser": { - "optional": true - }, - "playwright": { - "optional": true - }, - "portkey-ai": { - "optional": true - }, - "puppeteer": { - "optional": true - }, - "pyodide": { - "optional": true - }, - "redis": { - "optional": true - }, - "replicate": { - "optional": true - }, - "sonix-speech-recognition": { - "optional": true - }, - "srt-parser-2": { - "optional": true - }, - "typeorm": { - "optional": true - }, - "typesense": { - "optional": true - }, - "usearch": { - "optional": true - }, - "voy-search": { - "optional": true - }, - "weaviate-client": { - "optional": true - }, - "word-extractor": { - "optional": true - }, - "ws": { - "optional": true - }, - "youtubei.js": { - "optional": true - } + "@langchain/core": "^1.2.9" } }, "node_modules/@langchain/core": { - "version": "1.1.48", - "resolved": "https://registry.npmmirror.com/@langchain/core/-/core-1.1.48.tgz", - "integrity": "sha512-fQU6Guyb1pwc2fEplmA8FPbKfOMAofjnyJzExevro0FxEiuGHE18Ov/ZHmT9trWCDTZRI9eW1VIc6aChxV8pAQ==", + "version": "1.2.9", + "resolved": "https://registry.npmmirror.com/@langchain/core/-/core-1.2.9.tgz", + "integrity": "sha512-conzSEj9Zu1AyXJLXsSbgrtxtxinmI1yGqQ5CIJZSoV5rvv+yvQE/vgBnoySpBQ/bl3YPgj2FL/gbDjWykLSfg==", "license": "MIT", "dependencies": { "@cfworker/json-schema": "^4.0.2", @@ -686,12 +136,12 @@ } }, "node_modules/@langchain/deepseek": { - "version": "1.0.27", - "resolved": "https://registry.npmmirror.com/@langchain/deepseek/-/deepseek-1.0.27.tgz", - "integrity": "sha512-lmj1yPy+noA0ceIzH5jNxJU/uNMGSYlWVwztvkTYC0GExja9sY+21Y9Fpn9WLld5g/AL9/1+3i2aWIQoXOaeGQ==", + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/@langchain/deepseek/-/deepseek-1.1.11.tgz", + "integrity": "sha512-M7+mXNbf7FUp9wHk+nwii9Wy7r+3cUATRS0hjUgJ4rZegV04gUWZPuCTGYrC0vncea40dhQAOGETseUFg8YmJg==", "license": "MIT", "dependencies": { - "@langchain/openai": "1.4.7" + "@langchain/openai": "1.5.11" }, "engines": { "node": ">=20" @@ -701,77 +151,51 @@ } }, "node_modules/@langchain/langgraph": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@langchain/langgraph/-/langgraph-1.3.2.tgz", - "integrity": "sha512-SL7Ktsr681R7da+1b2MVOWEbaCoFJOXEJPTGOjg4JIG4C7quWbTYC8DzxhcCxte6D/8cGp0rYDBnbKLXEpNqlA==", + "version": "1.4.13", + "resolved": "https://registry.npmmirror.com/@langchain/langgraph/-/langgraph-1.4.13.tgz", + "integrity": "sha512-LO1ak6jNQ9jR13tm7Ay4Yh2/otrH7LNVUwWTAI7WJigVdW5Fb6LuYSZUzVn4S7sVSiyVFfnrUcDTd8c7eAzPrQ==", "license": "MIT", "dependencies": { - "@langchain/langgraph-checkpoint": "^1.0.2", - "@langchain/langgraph-sdk": "~1.9.4", - "@langchain/protocol": "^0.0.15", - "@standard-schema/spec": "1.1.0", - "uuid": "^10.0.0" + "@langchain/langgraph-checkpoint": "^1.1.5", + "@langchain/langgraph-sdk": "~1.10.0", + "@langchain/protocol": "^0.0.18", + "@standard-schema/spec": "1.1.0" }, "engines": { "node": ">=18" }, "peerDependencies": { - "@langchain/core": "^1.1.44", - "zod": "^3.25.32 || ^4.2.0", - "zod-to-json-schema": "^3.x" - }, - "peerDependenciesMeta": { - "zod-to-json-schema": { - "optional": true - } + "@langchain/core": "^1.1.48", + "zod": "^3.25.32 || ^4.2.0" } }, "node_modules/@langchain/langgraph-checkpoint": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/@langchain/langgraph-checkpoint/-/langgraph-checkpoint-1.0.2.tgz", - "integrity": "sha512-F4E5Tr0nt8FGghgdscJtHw+ABzChOHeI80R7Y1pjIHdiJom6c2ieo76vL+FWiny80JmoGqhrVAEIWrw0cXKPxg==", + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/@langchain/langgraph-checkpoint/-/langgraph-checkpoint-1.1.5.tgz", + "integrity": "sha512-BwDwl5VeTOh6CVuiIPgsUgfK51vTJDMSbFcSCUfjJWsl8/DPdK/mbv+ejxJstkSk/BlSPMP4JfXWcN6jD2ea2Q==", "license": "MIT", - "dependencies": { - "uuid": "^10.0.0" - }, "engines": { "node": ">=18" }, "peerDependencies": { - "@langchain/core": "^1.1.44" - } - }, - "node_modules/@langchain/langgraph-checkpoint/node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmmirror.com/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" + "@langchain/core": "^1.1.48" } }, "node_modules/@langchain/langgraph-sdk": { - "version": "1.9.4", - "resolved": "https://registry.npmmirror.com/@langchain/langgraph-sdk/-/langgraph-sdk-1.9.4.tgz", - "integrity": "sha512-hhASJGKa2MDJDtDkuIFdWGysMTog/HkYe0r6B6Gn1XqsURWnF7FIFl9diITAPOv1tB8YpyjnbpsBj/NkT5d+jQ==", + "version": "1.10.0", + "resolved": "https://registry.npmmirror.com/@langchain/langgraph-sdk/-/langgraph-sdk-1.10.0.tgz", + "integrity": "sha512-cPPkh+hMNgeOaGtJRrqs1AjZde45cG2+Ma9Sc10wz2RyvT8SKToCKS+VvkS18SsLajnmq6/FKVmthq6rnUVYOw==", "license": "MIT", "dependencies": { - "@langchain/protocol": "^0.0.15", + "@langchain/protocol": "^0.0.19", "@types/json-schema": "^7.0.15", "p-queue": "^9.0.1", - "p-retry": "^7.1.1", - "uuid": "^13.0.0" + "p-retry": "^7.1.1" }, "peerDependencies": { - "@langchain/core": "^1.1.44", + "@langchain/core": "^1.1.48", "react": "^18 || ^19", - "react-dom": "^18 || ^19", - "svelte": "^4.0.0 || ^5.0.0", - "vue": "^3.0.0" + "react-dom": "^18 || ^19" }, "peerDependenciesMeta": { "react": { @@ -779,15 +203,15 @@ }, "react-dom": { "optional": true - }, - "svelte": { - "optional": true - }, - "vue": { - "optional": true } } }, + "node_modules/@langchain/langgraph-sdk/node_modules/@langchain/protocol": { + "version": "0.0.19", + "resolved": "https://registry.npmmirror.com/@langchain/protocol/-/protocol-0.0.19.tgz", + "integrity": "sha512-9hKcRrH7cBX6gfutdfXPoft1OCchHe4FEpALoDJMl5Qu+n/YG5ynZmyu8+8cxORlPwHBoKTxggvXz+76M1yX1Q==", + "license": "MIT" + }, "node_modules/@langchain/langgraph-sdk/node_modules/eventemitter3": { "version": "5.0.4", "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.4.tgz", @@ -795,9 +219,9 @@ "license": "MIT" }, "node_modules/@langchain/langgraph-sdk/node_modules/p-queue": { - "version": "9.3.0", - "resolved": "https://registry.npmmirror.com/p-queue/-/p-queue-9.3.0.tgz", - "integrity": "sha512-7NED7xhQ74Ngp4JP/2e0VZHp7vSWfJfqeiR92jPgxsz6m0Se4P03YoTKa9dDXyZ3r6P616gUXttrB6nnHYKang==", + "version": "9.3.3", + "resolved": "https://registry.npmmirror.com/p-queue/-/p-queue-9.3.3.tgz", + "integrity": "sha512-NXAOdnEe5FsZJfT4oK84lE1Y5cFFdWlRuOo5tww8DyNMxyRXwn39fIkUtNLKppcPC+UYU/bXujNCUGDv01y7CA==", "license": "MIT", "dependencies": { "eventemitter3": "^5.0.4", @@ -822,53 +246,64 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@langchain/langgraph-sdk/node_modules/uuid": { - "version": "13.0.2", - "resolved": "https://registry.npmmirror.com/uuid/-/uuid-13.0.2.tgz", - "integrity": "sha512-vzi9uRZ926x4XV73S/4qQaTwPXM2JBj6/6lI/byHH1jOpCzb0zDbfytgA9LcN/hzb2l7WQSQnxITOVx5un/wGw==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist-node/bin/uuid" - } - }, - "node_modules/@langchain/langgraph/node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmmirror.com/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/@langchain/openai": { - "version": "1.4.7", - "resolved": "https://registry.npmmirror.com/@langchain/openai/-/openai-1.4.7.tgz", - "integrity": "sha512-i1YLV4pWbGC6W8m0ZNpLObJuf1nyU4o8aWyX4AF9fHn7eM67HfIJWQ5n5XzcCpuSa41otrxA9jvH5XRKwI1qDA==", + "version": "1.5.11", + "resolved": "https://registry.npmmirror.com/@langchain/openai/-/openai-1.5.11.tgz", + "integrity": "sha512-BvGp5lQk5//0WVwTIepscazFpneT9I9+mc+kp+cLuhGHFb7mc9zGNrusZOXoa3p73SN0i3XqTo8lyIndpVx3Hw==", "license": "MIT", "dependencies": { "js-tiktoken": "^1.0.12", - "openai": "^6.37.0", + "openai": "^7.5.0", "zod": "^3.25.76 || ^4" }, "engines": { - "node": ">=20" + "node": ">=22" }, "peerDependencies": { - "@langchain/core": "^1.1.48" + "@langchain/core": "^1.2.9" + } + }, + "node_modules/@langchain/openai/node_modules/openai": { + "version": "7.8.0", + "resolved": "https://registry.npmmirror.com/openai/-/openai-7.8.0.tgz", + "integrity": "sha512-/2g9JzdnXNcjX1W/UlSNu+OdSFDAaAVt0n9Onom0kPenH54o59G2WrX/xjTnr26UHNSh6hxcAf58doGYRme2rw==", + "license": "Apache-2.0", + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "@aws-sdk/credential-provider-node": ">=3.972.0 <4", + "@smithy/hash-node": ">=4.3.0 <5", + "@smithy/signature-v4": ">=5.4.0 <6", + "undici": ">=5 <9", + "ws": "^8.21.0", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-provider-node": { + "optional": true + }, + "@smithy/hash-node": { + "optional": true + }, + "@smithy/signature-v4": { + "optional": true + }, + "undici": { + "optional": true + }, + "ws": { + "optional": true + }, + "zod": { + "optional": true + } } }, "node_modules/@langchain/protocol": { - "version": "0.0.15", - "resolved": "https://registry.npmmirror.com/@langchain/protocol/-/protocol-0.0.15.tgz", - "integrity": "sha512-MllvbpMjqHevUm+v94M422mH7XKN+wGCvJRBVROTWBotEDOATYB4Ktk2UheYP859y9o2LlhtPek5t1T9eyfAbQ==", + "version": "0.0.18", + "resolved": "https://registry.npmmirror.com/@langchain/protocol/-/protocol-0.0.18.tgz", + "integrity": "sha512-XW1egQtPfsGI41w2AMZNFZrUIwFSQHTjVMZs0OaTpCAvht/QLoaPN8FQcsysMVypOhupG28J29yOorrc70otBQ==", "license": "MIT" }, "node_modules/@langchain/tavily": { @@ -886,21 +321,6 @@ "@langchain/core": "^1.0.0" } }, - "node_modules/@langchain/textsplitters": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/@langchain/textsplitters/-/textsplitters-1.0.1.tgz", - "integrity": "sha512-rheJlB01iVtrOUzttscutRgLybPH9qR79EyzBEbf1u97ljWyuxQfCwIWK+SjoQTM9O8M7GGLLRBSYE26Jmcoww==", - "license": "MIT", - "dependencies": { - "js-tiktoken": "^1.0.12" - }, - "engines": { - "node": ">=20" - }, - "peerDependencies": { - "@langchain/core": "^1.0.0" - } - }, "node_modules/@mapbox/node-pre-gyp": { "version": "1.0.11", "resolved": "https://registry.npmmirror.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", @@ -1130,12 +550,6 @@ "node": ">=10" } }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "license": "Python-2.0" - }, "node_modules/async": { "version": "3.2.6", "resolved": "https://registry.npmmirror.com/async/-/async-3.2.6.tgz", @@ -1190,6 +604,7 @@ "version": "2.3.0", "resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -1497,22 +912,23 @@ "license": "MIT" }, "node_modules/deepagents": { - "version": "1.10.2", - "resolved": "https://registry.npmmirror.com/deepagents/-/deepagents-1.10.2.tgz", - "integrity": "sha512-Ptp+t/FgIvMhDbVK0ml3IHcNx3gog3Cbqx+s88H4Hz8ieHG7svuR+/4Mawc/g14FY7mCls7Y8gCcrGb0i3Mi4w==", + "version": "1.13.2", + "resolved": "https://registry.npmmirror.com/deepagents/-/deepagents-1.13.2.tgz", + "integrity": "sha512-OMm+Ark4yaICZhGqC9kYkIx5vw5eH+GqIhzX1PAMmYhdxK5XeBTyn4pdfo1fKrBj2X/8GEg6TPnKS2jORLqJAQ==", "license": "MIT", "dependencies": { - "@langchain/core": "^1.1.44", - "@langchain/langgraph": "^1.3.0", - "@langchain/langgraph-sdk": "^1.9.1", "fast-glob": "^3.3.3", - "langchain": "^1.4.0", "micromatch": "^4.0.8", "yaml": "^2.8.2", "zod": "^4.3.6" }, "peerDependencies": { - "langsmith": ">=0.6.0 <1.0.0" + "@langchain/core": "^1.2.9", + "@langchain/langgraph": "^1.4.10", + "@langchain/langgraph-checkpoint": "^1.1.5", + "@langchain/langgraph-sdk": "^1.9.23", + "langchain": "^1.5.10", + "langsmith": ">=0.7.1 <0.10.0" } }, "node_modules/delegates": { @@ -1716,15 +1132,6 @@ "node": ">=8" } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmmirror.com/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } - }, "node_modules/fn.name": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/fn.name/-/fn.name-1.1.0.tgz", @@ -1946,27 +1353,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/handlebars": { - "version": "4.7.9", - "resolved": "https://registry.npmmirror.com/handlebars/-/handlebars-4.7.9.tgz", - "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", - "license": "MIT", - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz", @@ -2240,18 +1626,6 @@ "base64-js": "^1.5.1" } }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/json-schema-to-ts": { "version": "3.1.1", "resolved": "https://registry.npmmirror.com/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", @@ -2265,15 +1639,6 @@ "node": ">=16" } }, - "node_modules/jsonpointer": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/jsonpointer/-/jsonpointer-5.0.1.tgz", - "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/kareem": { "version": "2.6.3", "resolved": "https://registry.npmmirror.com/kareem/-/kareem-2.6.3.tgz", @@ -2421,13 +1786,13 @@ "license": "MIT" }, "node_modules/langchain": { - "version": "1.4.2", - "resolved": "https://registry.npmmirror.com/langchain/-/langchain-1.4.2.tgz", - "integrity": "sha512-SLGipy0r4nqQD0aiUOBYLMeGFfB/QiYnMndfZ8sGN89vXDCIXbYqcE7G/4QDDX3nZsM7/emQpoScmlxEX6sDnQ==", + "version": "1.5.10", + "resolved": "https://registry.npmmirror.com/langchain/-/langchain-1.5.10.tgz", + "integrity": "sha512-JaC12C1qyGn985vvjttr4hr8lfFzWhrXp2M1byZJGmNJ2RiIgqnhiYDuLlG/xHDxhKD3onJ5pCuUif/cbdqPhA==", "license": "MIT", "dependencies": { - "@langchain/langgraph": "^1.3.2", - "@langchain/langgraph-checkpoint": "^1.0.1", + "@langchain/langgraph": "^1.4.10", + "@langchain/langgraph-checkpoint": "^1.1.5", "langsmith": ">=0.5.0 <1.0.0", "zod": "^3.25.76 || ^4" }, @@ -2435,7 +1800,7 @@ "node": ">=20" }, "peerDependencies": { - "@langchain/core": "^1.1.48" + "@langchain/core": "^1.2.9" } }, "node_modules/langsmith": { @@ -2524,12 +1889,6 @@ "semver": "bin/semver.js" } }, - "node_modules/math-expression-evaluator": { - "version": "2.0.7", - "resolved": "https://registry.npmmirror.com/math-expression-evaluator/-/math-expression-evaluator-2.0.7.tgz", - "integrity": "sha512-uwliJZ6BPHRq4eiqNWxZBDzKUiS5RIynFFcgchqhBOloVLVBpZpNG8jRYkedLcBvhph8TnRyWEuxPqiQcwIdog==", - "license": "MIT" - }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -2622,15 +1981,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/minipass": { "version": "5.0.0", "resolved": "https://registry.npmmirror.com/minipass/-/minipass-5.0.0.tgz", @@ -2809,12 +2159,6 @@ "node": ">= 0.6" } }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmmirror.com/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "license": "MIT" - }, "node_modules/node-addon-api": { "version": "5.1.0", "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-5.1.0.tgz", @@ -2999,6 +2343,8 @@ "resolved": "https://registry.npmmirror.com/openai/-/openai-6.38.0.tgz", "integrity": "sha512-AoMplt2UalrpgUDMh3L09QWjNRlgJPipclQvA6sYAaeF6nHNBMgmikAZGmcYLn8on4d9sQY9Q8bOLfrBS7Lc8g==", "license": "Apache-2.0", + "optional": true, + "peer": true, "bin": { "openai": "bin/cli" }, @@ -3015,12 +2361,6 @@ } } }, - "node_modules/openapi-types": { - "version": "12.1.3", - "resolved": "https://registry.npmmirror.com/openapi-types/-/openapi-types-12.1.3.tgz", - "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", - "license": "MIT" - }, "node_modules/p-finally": { "version": "1.0.0", "resolved": "https://registry.npmmirror.com/p-finally/-/p-finally-1.0.0.tgz", @@ -3453,15 +2793,6 @@ "node": ">=10" } }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmmirror.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", @@ -3481,9 +2812,9 @@ } }, "node_modules/standardwebhooks": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/standardwebhooks/-/standardwebhooks-1.0.0.tgz", - "integrity": "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==", + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/standardwebhooks/-/standardwebhooks-1.1.1.tgz", + "integrity": "sha512-bCbX9ZEyFkWPsRz7Bl3NuQUJohmwGSev/yhr7vhaGPlc4AfIrspIRa6cPTBuI1ItmrTDJ4d/S2hCsfe4+vQGnQ==", "license": "MIT", "dependencies": { "@stablelib/base64": "^1.0.0", @@ -3650,19 +2981,6 @@ "node": ">= 0.6" } }, - "node_modules/uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmmirror.com/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "license": "BSD-2-Clause", - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmmirror.com/undefsafe/-/undefsafe-2.0.5.tgz", @@ -3699,19 +3017,6 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, - "node_modules/uuid": { - "version": "14.0.0", - "resolved": "https://registry.npmmirror.com/uuid/-/uuid-14.0.0.tgz", - "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist-node/bin/uuid" - } - }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz", @@ -3797,12 +3102,6 @@ "node": ">= 12.0.0" } }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "license": "MIT" - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", @@ -3861,9 +3160,9 @@ } }, "node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmmirror.com/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "version": "4.5.4", + "resolved": "https://registry.npmmirror.com/zod/-/zod-4.5.4.tgz", + "integrity": "sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index de72f7d..030a207 100644 --- a/package.json +++ b/package.json @@ -9,21 +9,20 @@ "dev": "nodemon index.js" }, "dependencies": { - "@langchain/anthropic": "^1.4.0", - "@langchain/community": "^1.1.28", - "@langchain/core": "^1.1.48", - "@langchain/deepseek": "^1.0.27", - "@langchain/langgraph": "^1.3.2", - "@langchain/openai": "^1.4.7", + "@langchain/anthropic": "^1.5.9", + "@langchain/core": "^1.2.9", + "@langchain/deepseek": "^1.1.11", + "@langchain/langgraph": "^1.4.13", + "@langchain/openai": "^1.5.11", "@langchain/tavily": "^1.2.0", "bcrypt": "^5.1.1", - "deepagents": "^1.10.2", + "deepagents": "^1.13.2", "dotenv": "^17.4.2", "koa": "^2.16.4", "koa-bodyparser": "^4.4.1", "koa-cors": "^0.0.16", "koa-router": "^12.0.1", - "langchain": "^1.4.2", + "langchain": "^1.5.10", "lodash": "^4.18.1", "lunar-javascript": "^1.7.7", "moment": "^2.30.1", @@ -31,7 +30,7 @@ "node-fetch": "^3.3.2", "winston": "^3.19.0", "ws": "^8.21.0", - "zod": "^4.4.3" + "zod": "^4.5.4" }, "devDependencies": { "nodemon": "^3.0.2" diff --git a/websocket.js b/websocket.js index 9a976c4..5f63e0d 100644 --- a/websocket.js +++ b/websocket.js @@ -97,6 +97,11 @@ export default class WebSocketServerManager { return; } if (msg.agent === 'escort-admin') { + // 管理端 agent 含写库/环境变量等高危工具,必须校验管理员角色,防止普通用户越权 + if (!userInfo.app || !("wxapp-escort-admin" in userInfo.app)) { + ws.send(JSON.stringify({ type: 'error', content: '无管理员权限' })); + return; + } await adminAgent.streamChat(userInfo, [msg], (source, type, content, id) => { send(source, type, content, id); });