xiaozuoassistant 0.2.44 → 0.2.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -15,9 +15,9 @@ export class BaseChannel {
|
|
|
15
15
|
onMessage(handler) {
|
|
16
16
|
this.messageHandler = handler;
|
|
17
17
|
}
|
|
18
|
-
emitMessage(sessionId, message) {
|
|
18
|
+
emitMessage(sessionId, message, botName) {
|
|
19
19
|
if (this.messageHandler) {
|
|
20
|
-
this.messageHandler(sessionId, message);
|
|
20
|
+
this.messageHandler(sessionId, message, botName);
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
}
|
|
@@ -83,35 +83,22 @@ export class FeishuChannel extends BaseChannel {
|
|
|
83
83
|
// 在群聊中,只有当机器人被 @ 时才响应
|
|
84
84
|
if (event.chat_type === 'group') {
|
|
85
85
|
const mentions = event.mentions || [];
|
|
86
|
-
//
|
|
87
|
-
// 飞书 SDK 会将消息文本中的 @ 解析到 mentions 数组
|
|
88
|
-
// 对于机器人自己,如果没有被 @,则直接忽略
|
|
89
|
-
const isMentioned = mentions.some((m) => !m.id || m.id.open_id === undefined);
|
|
90
|
-
// 注意:在飞书事件中,如果 @ 的是机器人自己,通常没有具体的 user_id,或者带有特定的标识。
|
|
91
|
-
// 更严谨的做法是:如果 message 内容中包含 "@_user_1" 并且 mentions 里有机器人的标识。
|
|
92
|
-
// 简单且通用的判定是:群聊中如果不包含 mentions,肯定没被@
|
|
86
|
+
// 1. 如果群聊中没有任何人被 @,则忽略(防止机器人被动读取群消息时刷屏)
|
|
93
87
|
if (mentions.length === 0) {
|
|
94
|
-
return;
|
|
88
|
+
return;
|
|
95
89
|
}
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
// 更精确:飞书给机器人的事件回调,只有在机器人被@或者在单聊时,才会触发!
|
|
103
|
-
// !!!等一下!!!
|
|
104
|
-
// 实际上,飞书开放平台规则:机器人如果在群里,只有被 @ 时,飞书服务器才会把消息推送给长连接!
|
|
105
|
-
// 如果没被 @,飞书根本不会发事件过来!
|
|
106
|
-
// 但是,如果机器人在后台申请了“获取群内所有消息”的高级权限,那么每条消息都会推过来。
|
|
107
|
-
// 为了防止刷屏,我们检查 event.mentions 是否包含机器人。
|
|
108
|
-
// 我们通过检查 mentions 数组里是否包含一个 name 为本机器人的项,或者 id.open_id 为空的项
|
|
90
|
+
// 2. 检查被 @ 的列表中是否包含自己
|
|
91
|
+
// 由于飞书返回的 mentions 对象里,如果被 @ 的是当前收到事件的机器人自己,
|
|
92
|
+
// 通常其 is_self 属性为 true,或者 name 匹配,或者 id 为空/不完整。
|
|
93
|
+
// 最稳妥的方法是依靠飞书 SDK 在下发事件时设置的 m.name === botName,
|
|
94
|
+
// 或者直接看是否有一个 `m.id.open_id` 未定义(因为机器人本身没有用户 open_id),
|
|
95
|
+
// 或者检查 is_self === true
|
|
109
96
|
const isMentionedSelf = mentions.some((m) => {
|
|
110
|
-
|
|
111
|
-
return m.name === botName || !m.id || Object.keys(m.id).length === 0 || m.is_self === true;
|
|
97
|
+
return m.name === botName || m.is_self === true || (!m.id || Object.keys(m.id).length === 0);
|
|
112
98
|
});
|
|
113
|
-
|
|
114
|
-
|
|
99
|
+
if (!isMentionedSelf) {
|
|
100
|
+
return; // 被 @ 的是别人,不是本机器人,忽略
|
|
101
|
+
}
|
|
115
102
|
}
|
|
116
103
|
try {
|
|
117
104
|
let content = JSON.parse(event.content).text;
|
|
@@ -156,7 +143,7 @@ export class FeishuChannel extends BaseChannel {
|
|
|
156
143
|
}
|
|
157
144
|
return;
|
|
158
145
|
}
|
|
159
|
-
this.emitMessage(sessionId, content);
|
|
146
|
+
this.emitMessage(sessionId, content, botName);
|
|
160
147
|
}
|
|
161
148
|
catch (e) {
|
|
162
149
|
console.error(`[Feishu-${botName}] Failed to parse message content:`, e);
|
|
@@ -20,9 +20,14 @@ export class AgentRuntime {
|
|
|
20
20
|
return this.skills.map(skill => skill.toJSON());
|
|
21
21
|
}
|
|
22
22
|
async process(history, newMessage, contextPrompt, context) {
|
|
23
|
+
// 如果上下文中包含 botName,将其注入到系统提示词中
|
|
24
|
+
let identityContext = '';
|
|
25
|
+
if (context?.metadata?.botName) {
|
|
26
|
+
identityContext = `\n\n[System Identity]: Your name is "${context.metadata.botName}". You are acting as this bot. You must refer to yourself strictly as "${context.metadata.botName}" when introducing yourself or when asked about your identity. Do not use the generic name "xiaozuoAssistant" unless explicitly necessary.`;
|
|
27
|
+
}
|
|
23
28
|
const finalSystemPrompt = contextPrompt
|
|
24
|
-
? `${this.systemPrompt}\n${contextPrompt}`
|
|
25
|
-
: this.systemPrompt
|
|
29
|
+
? `${this.systemPrompt}${identityContext}\n${contextPrompt}`
|
|
30
|
+
: `${this.systemPrompt}${identityContext}`;
|
|
26
31
|
const messages = [
|
|
27
32
|
{ role: 'system', content: finalSystemPrompt },
|
|
28
33
|
...history.map(m => ({ role: m.role, content: m.content, name: m.name, tool_call_id: m.tool_call_id, tool_calls: m.tool_calls })),
|
|
@@ -44,6 +44,11 @@ export class Brain {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
+
// 如果上下文中包含 botName,将其注入到系统提示词中
|
|
48
|
+
let identityContext = '';
|
|
49
|
+
if (context?.metadata?.botName) {
|
|
50
|
+
identityContext = `\n\n[System Identity]: Your name is "${context.metadata.botName}". You are acting as this bot. You must refer to yourself strictly as "${context.metadata.botName}" when introducing yourself or when asked about your identity. Do not use the generic name "xiaozuoAssistant" unless explicitly necessary.`;
|
|
51
|
+
}
|
|
47
52
|
// Convert history messages to the format expected by OpenAI
|
|
48
53
|
// Strategy: Keep last N messages to avoid context window overflow
|
|
49
54
|
// TODO: A better strategy would be token-based truncation.
|
|
@@ -60,7 +65,7 @@ export class Brain {
|
|
|
60
65
|
return msg;
|
|
61
66
|
});
|
|
62
67
|
const messages = [
|
|
63
|
-
{ role: 'system', content: defaultSystemPrompt + wakeupContext },
|
|
68
|
+
{ role: 'system', content: defaultSystemPrompt + identityContext + wakeupContext },
|
|
64
69
|
...messageHistory,
|
|
65
70
|
{ role: 'user', content: newMessage }
|
|
66
71
|
];
|
|
@@ -18,7 +18,7 @@ export class TaskQueue {
|
|
|
18
18
|
this.chains.set(key, next);
|
|
19
19
|
}
|
|
20
20
|
async process(task) {
|
|
21
|
-
const { run, channel } = task;
|
|
21
|
+
const { run, channel, botName } = task;
|
|
22
22
|
try {
|
|
23
23
|
const session = await memory.getSession(run.sessionId);
|
|
24
24
|
if (!session) {
|
|
@@ -56,7 +56,8 @@ ${context}`;
|
|
|
56
56
|
metadata: {
|
|
57
57
|
workspace: session.meta.workspace,
|
|
58
58
|
alias: session.meta.alias,
|
|
59
|
-
runId: run.id
|
|
59
|
+
runId: run.id,
|
|
60
|
+
botName: botName
|
|
60
61
|
}
|
|
61
62
|
};
|
|
62
63
|
const responseContent = await brain.processMessage(session.messages, run.userContent, enhancedSystemPrompt, ctx);
|
package/dist/server/index.js
CHANGED
|
@@ -376,13 +376,14 @@ app.post('/api/config', async (req, res) => {
|
|
|
376
376
|
const feishuChannel = new FeishuChannel();
|
|
377
377
|
channels.push(feishuChannel);
|
|
378
378
|
await feishuChannel.start();
|
|
379
|
-
feishuChannel.onMessage((sessionId, message) => {
|
|
379
|
+
feishuChannel.onMessage((sessionId, message, botName) => {
|
|
380
380
|
eventBus.emitEvent({
|
|
381
381
|
type: 'message',
|
|
382
382
|
payload: { content: message },
|
|
383
383
|
channel: feishuChannel.name,
|
|
384
384
|
sessionId: sessionId,
|
|
385
|
-
timestamp: Date.now()
|
|
385
|
+
timestamp: Date.now(),
|
|
386
|
+
botName: botName
|
|
386
387
|
});
|
|
387
388
|
});
|
|
388
389
|
}
|
|
@@ -775,13 +776,14 @@ for (const ch of channels) {
|
|
|
775
776
|
channels.forEach(channel => {
|
|
776
777
|
channel.start();
|
|
777
778
|
// 监听通道消息 -> 发送到 EventBus
|
|
778
|
-
channel.onMessage((sessionId, message) => {
|
|
779
|
+
channel.onMessage((sessionId, message, botName) => {
|
|
779
780
|
eventBus.emitEvent({
|
|
780
781
|
type: 'message',
|
|
781
782
|
payload: { content: message },
|
|
782
783
|
channel: channel.name,
|
|
783
784
|
sessionId: sessionId,
|
|
784
|
-
timestamp: Date.now()
|
|
785
|
+
timestamp: Date.now(),
|
|
786
|
+
botName: botName
|
|
785
787
|
});
|
|
786
788
|
});
|
|
787
789
|
});
|
|
@@ -837,16 +839,18 @@ eventBus.onEvent('message', async (event) => {
|
|
|
837
839
|
payload: { runId: run.id },
|
|
838
840
|
channel: channelName,
|
|
839
841
|
sessionId,
|
|
840
|
-
timestamp: Date.now()
|
|
842
|
+
timestamp: Date.now(),
|
|
843
|
+
botName: event.botName
|
|
841
844
|
});
|
|
842
845
|
eventBus.emitEvent({
|
|
843
846
|
type: 'run_status',
|
|
844
847
|
payload: { runId: run.id, status: 'queued' },
|
|
845
848
|
channel: channelName,
|
|
846
849
|
sessionId,
|
|
847
|
-
timestamp: Date.now()
|
|
850
|
+
timestamp: Date.now(),
|
|
851
|
+
botName: event.botName
|
|
848
852
|
});
|
|
849
|
-
taskQueue.enqueue({ run, channel: channelName });
|
|
853
|
+
taskQueue.enqueue({ run, channel: channelName, botName: event.botName });
|
|
850
854
|
}
|
|
851
855
|
catch (error) {
|
|
852
856
|
console.error('Error processing message:', error);
|