tmp
This commit is contained in:
@@ -3,124 +3,149 @@ import { createDeepAgent, FilesystemBackend } from "deepagents";
|
|||||||
import { AIMessageChunk, ToolMessage } from "langchain";
|
import { AIMessageChunk, ToolMessage } from "langchain";
|
||||||
import { SystemMessage, HumanMessage, AIMessage } from "@langchain/core/messages";
|
import { SystemMessage, HumanMessage, AIMessage } from "@langchain/core/messages";
|
||||||
import { ChatDeepSeek } from "@langchain/deepseek";
|
import { ChatDeepSeek } from "@langchain/deepseek";
|
||||||
import Prompts from "./prompts.js";
|
import EscortAdminPrompts from "./prompts.js";
|
||||||
import { getEnvTool,webFetchTool, webSearchTool, getCalendarInfoTool,
|
import {
|
||||||
getLunarCalendarInfoTool, getYearHolidaysTool, getYearTermsTool, getLatLngTool,
|
getEnvTool, webFetchTool, webSearchTool, getCalendarInfoTool,
|
||||||
httpGetTool, httpPostTool
|
getLunarCalendarInfoTool, getYearHolidaysTool, getYearTermsTool, getLatLngTool,
|
||||||
} from "./tools/index.js";
|
httpGetTool, httpPostTool, escortRecordQueryTool
|
||||||
|
} from "./tools/index.js";
|
||||||
|
|
||||||
export default class EscortAdminAgent {
|
export default class EscortAdminAgent {
|
||||||
constructor() {
|
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);
|
clearMessages() {
|
||||||
msgs.forEach(msg => {
|
|
||||||
if (msg.type === "clear") {
|
|
||||||
this.messages = [];
|
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"]);
|
// msg: { agent: 'escort-admin', type: 'chat', ts: "2023-08-01 10:00:00", content: "你好" }
|
||||||
for await (const [namespace, mode, data] of await agent.stream(
|
async streamChat(userInfo, msgs, callback) {
|
||||||
{ messages: this.messages },
|
if (!msgs.length) {
|
||||||
{
|
return;
|
||||||
recursion_limit: 50,
|
|
||||||
streamMode: ["updates", "messages", "custom"], subgraphs: true,
|
|
||||||
configurable: {
|
|
||||||
thread_id: 'default-session'
|
|
||||||
}
|
}
|
||||||
})) {
|
|
||||||
const isSubagent = namespace.some(s => s.startsWith("tools:"));
|
const agent = this._genAgent(userInfo);
|
||||||
const source = isSubagent ? "subagent" : "main";
|
msgs.forEach(msg => {
|
||||||
if (mode === "updates") {
|
if (msg.type === "clear") {
|
||||||
for (const nodeName of Object.keys(data)) {
|
this.messages = [];
|
||||||
if (!INTERESTING_NODES.has(nodeName)) continue;
|
} else {
|
||||||
// Main agent updates (empty namespace)
|
this.messages.push(new HumanMessage(`${msg.ts} - ${msg.content}`));
|
||||||
if (namespace.length === 0) {
|
}
|
||||||
for (const [nodeName, data_] of Object.entries(data)) {
|
});
|
||||||
if (nodeName === "tools") {
|
|
||||||
// Subagent results returned to main agent
|
if (this.messages.length === 0) {
|
||||||
for (const msg of data_.messages ?? []) {
|
return;
|
||||||
if (msg.type === "tool") {
|
}
|
||||||
console.log(`\nSubagent complete: ${msg.name}`);
|
|
||||||
console.log(` Result: ${String(msg.content).slice(0, 200)}...`);
|
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'
|
||||||
}
|
}
|
||||||
} else if (nodeName === "model_request") {
|
})) {
|
||||||
this.messages.push(...data_.messages);
|
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);
|
||||||
}
|
}
|
||||||
} 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 = [];
|
_genAgent(userInfo) {
|
||||||
|
if (this.agent) {
|
||||||
|
return this.agent;
|
||||||
|
}
|
||||||
|
|
||||||
const rootDir = process.cwd();
|
this.messages = [];
|
||||||
const backend = new FilesystemBackend({ rootDir });
|
|
||||||
|
|
||||||
this.model = new ChatDeepSeek({
|
const rootDir = process.cwd();
|
||||||
model: 'deepseek-v4-pro',
|
const backend = new FilesystemBackend({ rootDir });
|
||||||
apiKey: 'sk-a58ccd82b7ba4ce3ac176a88c9381095',
|
|
||||||
temperature: 0.3
|
|
||||||
});
|
|
||||||
|
|
||||||
this.agent = createDeepAgent({
|
this.flashModel = new ChatDeepSeek({
|
||||||
name: "deep-agent",
|
model: 'deepseek-v4-flash',
|
||||||
model: this.model,
|
apiKey: 'sk-a58ccd82b7ba4ce3ac176a88c9381095',
|
||||||
systemPrompt: Prompts.buildSystemPrompt(userInfo),
|
temperature: 0.0
|
||||||
backend,
|
});
|
||||||
tools: [getEnvTool, webFetchTool, webSearchTool, getLatLngTool, httpGetTool, httpPostTool,
|
this.proModel = new ChatDeepSeek({
|
||||||
getCalendarInfoTool, getLunarCalendarInfoTool, getYearHolidaysTool, getYearTermsTool],
|
model: 'deepseek-v4-pro',
|
||||||
skills: ["./agent/escort/skills/"]
|
apiKey: 'sk-a58ccd82b7ba4ce3ac176a88c9381095',
|
||||||
});
|
temperature: 0.3
|
||||||
|
});
|
||||||
|
|
||||||
return this.agent;
|
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 };
|
||||||
34
agent/escort-admin/prompts.js
Normal file
34
agent/escort-admin/prompts.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import moment from "moment";
|
||||||
|
import services from "../../resource/services.js";
|
||||||
|
import agreement from "../../resource/agreement.js";
|
||||||
|
|
||||||
|
class EscortAdminPrompts {
|
||||||
|
static buildSystemPrompt(userInfo) {
|
||||||
|
let userInfo_str = "用户未登录,提示用户先登录,并在'我的'中完善个人信息";
|
||||||
|
if (userInfo) {
|
||||||
|
userInfo_str = JSON.stringify({
|
||||||
|
name: userInfo.profile.name,
|
||||||
|
mobile: userInfo.profile.mobile,
|
||||||
|
role: userInfo.app
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return `
|
||||||
|
# 角色定义
|
||||||
|
你是小暖,暖橙陪诊平台的管理助手,直接、高效的解决平台问题。
|
||||||
|
|
||||||
|
# 核心能力
|
||||||
|
- 解答服务流程、价格、注意事项
|
||||||
|
- 提供就诊准备建议
|
||||||
|
- 通过tools和skills,为用户提供其他服务。如:查询天气、路线、查询医院信息、查询医生信息等。
|
||||||
|
|
||||||
|
# 铁律(必须遵守)
|
||||||
|
1. 思考和理解任务意图,专业、谨慎、高效、专注的完成任务。
|
||||||
|
|
||||||
|
## 参考信息
|
||||||
|
管理员信息:${userInfo_str};
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EscortAdminPrompts;
|
||||||
66
agent/escort-admin/tools/db/escort_record_query.js
Normal file
66
agent/escort-admin/tools/db/escort_record_query.js
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import { tool } from "@langchain/core/tools";
|
||||||
|
import z from "zod";
|
||||||
|
import { DBModel } from "../../../../models/index.js";
|
||||||
|
|
||||||
|
const escortRecordQueryTool = tool(
|
||||||
|
async ({ patientName, mobile, status, page = 1, pageSize = 20 }) => {
|
||||||
|
try {
|
||||||
|
const filter = {};
|
||||||
|
|
||||||
|
if (patientName) {
|
||||||
|
filter["patient.name"] = { $regex: patientName, $options: "i" };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mobile) {
|
||||||
|
filter["patient.mobile"] = mobile;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
filter.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
const skip = (page - 1) * pageSize;
|
||||||
|
|
||||||
|
const records = await DBModel.EscortRecord.find(filter)
|
||||||
|
.sort({ "schedule.date": -1 })
|
||||||
|
.skip(skip)
|
||||||
|
.limit(pageSize)
|
||||||
|
.lean();
|
||||||
|
|
||||||
|
const total = await DBModel.EscortRecord.countDocuments(filter);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: records,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: error.message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "escort_record_query",
|
||||||
|
description:
|
||||||
|
"Query escort records from database. Supports filtering by patient name, mobile phone number, and appointment status. Returns paginated results sorted by appointment date in descending order.",
|
||||||
|
schema: z.object({
|
||||||
|
patientName: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Patient name for fuzzy search"),
|
||||||
|
mobile: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Patient mobile phone number for exact match"),
|
||||||
|
status: z
|
||||||
|
.enum(["pending", "confirmed", "in_progress", "completed", "cancelled"])
|
||||||
|
.optional()
|
||||||
|
.describe(
|
||||||
|
"Appointment status: pending (待确认), confirmed (已确认), in_progress (进行中), completed (已完成), cancelled (已取消)"
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export { escortRecordQueryTool };
|
||||||
109
agent/escort-admin/tools/db/escort_record_set.js
Normal file
109
agent/escort-admin/tools/db/escort_record_set.js
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
import { tool } from "@langchain/core/tools";
|
||||||
|
import z from "zod";
|
||||||
|
import { DBModel } from "../../../../models/index.js";
|
||||||
|
|
||||||
|
const escortRecordSetTool = tool(
|
||||||
|
async ({ mobile, status, notes, payment }) => {
|
||||||
|
try {
|
||||||
|
if (!mobile) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: "Mobile phone number is required as the lookup key",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const record = await DBModel.EscortRecord.findOne({ "patient.mobile": mobile });
|
||||||
|
if (!record) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: `No escort record found for mobile: ${mobile}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const update = {};
|
||||||
|
|
||||||
|
if (status !== undefined) {
|
||||||
|
update.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notes !== undefined) {
|
||||||
|
if (notes.patientNote !== undefined) {
|
||||||
|
update["notes.patientNote"] = notes.patientNote;
|
||||||
|
}
|
||||||
|
if (notes.escortNote !== undefined) {
|
||||||
|
update["notes.escortNote"] = notes.escortNote;
|
||||||
|
}
|
||||||
|
if (notes.medicalSummary !== undefined) {
|
||||||
|
update["notes.medicalSummary"] = notes.medicalSummary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payment !== undefined) {
|
||||||
|
if (payment.totalFee !== undefined) {
|
||||||
|
update["payment.totalFee"] = payment.totalFee;
|
||||||
|
}
|
||||||
|
if (payment.paidFee !== undefined) {
|
||||||
|
update["payment.paidFee"] = payment.paidFee;
|
||||||
|
}
|
||||||
|
if (payment.status !== undefined) {
|
||||||
|
update["payment.status"] = payment.status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update["meta.updatetime"] = Date.now();
|
||||||
|
|
||||||
|
const updatedRecord = await DBModel.EscortRecord.findByIdAndUpdate(
|
||||||
|
record._id,
|
||||||
|
{ $set: update },
|
||||||
|
{ new: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: updatedRecord,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: error.message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "escort_record_set",
|
||||||
|
description:
|
||||||
|
"Update escort record fields by patient mobile phone number. Supports updating status, notes (patientNote, escortNote, medicalSummary), and payment (totalFee, paidFee, status). Only provided fields will be updated.",
|
||||||
|
schema: z.object({
|
||||||
|
mobile: z
|
||||||
|
.string()
|
||||||
|
.describe("Patient mobile phone number used as the lookup key"),
|
||||||
|
status: z
|
||||||
|
.enum(["pending", "confirmed", "in_progress", "completed", "cancelled"])
|
||||||
|
.optional()
|
||||||
|
.describe(
|
||||||
|
"Appointment status: pending (待确认), confirmed (已确认), in_progress (进行中), completed (已完成), cancelled (已取消)"
|
||||||
|
),
|
||||||
|
notes: z
|
||||||
|
.object({
|
||||||
|
patientNote: z.string().optional().describe("Patient remarks / special requirements"),
|
||||||
|
escortNote: z.string().optional().describe("Escort service notes"),
|
||||||
|
medicalSummary: z.string().optional().describe("Medical visit summary"),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.describe("Notes information to update"),
|
||||||
|
payment: z
|
||||||
|
.object({
|
||||||
|
totalFee: z.number().optional().describe("Total service fee (RMB)"),
|
||||||
|
paidFee: z.number().optional().describe("Amount already paid (RMB)"),
|
||||||
|
status: z
|
||||||
|
.enum(["unpaid", "partial", "paid", "refunded"])
|
||||||
|
.optional()
|
||||||
|
.describe("Payment status: unpaid, partial, paid, refunded"),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.describe("Payment information to update"),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export { escortRecordSetTool };
|
||||||
@@ -16,5 +16,10 @@ export { getYearTermsTool } from './calendar/year_terms.js';
|
|||||||
// 地理工具 (LangChain format)
|
// 地理工具 (LangChain format)
|
||||||
export { getLatLngTool } from './geo/latlon.js';
|
export { getLatLngTool } from './geo/latlon.js';
|
||||||
|
|
||||||
|
// 系统工具 (LangChain format)
|
||||||
export { getEnvTool } from './system/envs.js';
|
export { getEnvTool } from './system/envs.js';
|
||||||
|
|
||||||
|
// db
|
||||||
|
export { escortRecordQueryTool } from './db/escort_record_query.js';
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const EscortRecordSchema = mongoose.Schema(
|
|||||||
*/
|
*/
|
||||||
patient: {
|
patient: {
|
||||||
name: { type: String, default: "", comment: "患者姓名" },
|
name: { type: String, default: "", comment: "患者姓名" },
|
||||||
mobile: { type: String, default: "", comment: "患者联系电话" },
|
mobile: { type: String, default: "", unique: true, index: true, comment: "患者联系电话" },
|
||||||
sex: { type: String, enum: ["male", "female"], comment: "患者性别" },
|
sex: { type: String, enum: ["male", "female"], comment: "患者性别" },
|
||||||
age: { type: Number, default: 0, comment: "患者年龄" },
|
age: { type: Number, default: 0, comment: "患者年龄" },
|
||||||
idnumber: { type: String, default: "", comment: "患者身份证号" },
|
idnumber: { type: String, default: "", comment: "患者身份证号" },
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import WebSocket, { WebSocketServer } from 'ws';
|
|||||||
import http from 'http';
|
import http from 'http';
|
||||||
import { DBModel } from "./models/index.js";
|
import { DBModel } from "./models/index.js";
|
||||||
import { chatTask } from "./agent/escort/task.js";
|
import { chatTask } from "./agent/escort/task.js";
|
||||||
|
import { adminAgent } from "./agent/escort-admin/agent.js"
|
||||||
|
|
||||||
export default class WebSocketServerManager {
|
export default class WebSocketServerManager {
|
||||||
constructor(port = 8080) {
|
constructor(port = 8080) {
|
||||||
@@ -80,6 +81,10 @@ export default class WebSocketServerManager {
|
|||||||
|
|
||||||
if (msg.type === 'chat' || msg.type === 'clear') {
|
if (msg.type === 'chat' || msg.type === 'clear') {
|
||||||
if (msg.agent === 'escort-admin') {
|
if (msg.agent === 'escort-admin') {
|
||||||
|
const userInfo = await this.getUserInfo(msg.userId);
|
||||||
|
adminAgent.streamChat(userInfo, [msg], (source, type, content, id) => {
|
||||||
|
ws.send(JSON.stringify({ source, type, content, id }));
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
const userInfo = await this.getUserInfo(msg.userId);
|
const userInfo = await this.getUserInfo(msg.userId);
|
||||||
chatTask.streamChat(userInfo, msg, (source, type, content, id) => {
|
chatTask.streamChat(userInfo, msg, (source, type, content, id) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user