@zhin.js/core 1.0.37 → 1.0.38
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.
- package/CHANGELOG.md +9 -0
- package/README.md +57 -3
- package/lib/adapter.d.ts +11 -0
- package/lib/adapter.d.ts.map +1 -1
- package/lib/adapter.js +61 -0
- package/lib/adapter.js.map +1 -1
- package/lib/ai/index.d.ts +3 -39
- package/lib/ai/index.d.ts.map +1 -1
- package/lib/ai/index.js +2 -44
- package/lib/ai/index.js.map +1 -1
- package/lib/ai/types.d.ts +4 -3
- package/lib/ai/types.d.ts.map +1 -1
- package/lib/built/ai-trigger.js.map +1 -1
- package/lib/built/common-adapter-tools.d.ts +55 -0
- package/lib/built/common-adapter-tools.d.ts.map +1 -0
- package/lib/built/common-adapter-tools.js +158 -0
- package/lib/built/common-adapter-tools.js.map +1 -0
- package/lib/built/dispatcher.d.ts.map +1 -1
- package/lib/built/dispatcher.js +50 -46
- package/lib/built/dispatcher.js.map +1 -1
- package/lib/built/skill.d.ts.map +1 -1
- package/lib/built/skill.js +0 -1
- package/lib/built/skill.js.map +1 -1
- package/lib/built/tool.d.ts +3 -3
- package/lib/built/tool.d.ts.map +1 -1
- package/lib/built/tool.js.map +1 -1
- package/lib/feature.d.ts +16 -1
- package/lib/feature.d.ts.map +1 -1
- package/lib/feature.js +41 -2
- package/lib/feature.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/plugin.d.ts +38 -1
- package/lib/plugin.d.ts.map +1 -1
- package/lib/plugin.js +73 -22
- package/lib/plugin.js.map +1 -1
- package/lib/scheduler/scheduler.js +1 -1
- package/lib/scheduler/scheduler.js.map +1 -1
- package/lib/types.d.ts +43 -28
- package/lib/types.d.ts.map +1 -1
- package/lib/utils.d.ts +12 -3
- package/lib/utils.d.ts.map +1 -1
- package/lib/utils.js +64 -54
- package/lib/utils.js.map +1 -1
- package/package.json +5 -5
- package/src/adapter.ts +85 -5
- package/src/ai/index.ts +8 -186
- package/src/ai/types.ts +5 -4
- package/src/built/ai-trigger.ts +2 -2
- package/src/built/common-adapter-tools.ts +207 -0
- package/src/built/dispatcher.ts +51 -52
- package/src/built/skill.ts +3 -4
- package/src/built/tool.ts +3 -3
- package/src/feature.ts +45 -2
- package/src/index.ts +2 -0
- package/src/plugin.ts +92 -31
- package/src/scheduler/scheduler.ts +1 -1
- package/src/types.ts +39 -28
- package/src/utils.ts +63 -52
- package/tests/ai/setup.ts +2 -2
- package/tests/utils.test.ts +1 -3
- package/lib/ai/agent.d.ts +0 -130
- package/lib/ai/agent.d.ts.map +0 -1
- package/lib/ai/agent.js +0 -702
- package/lib/ai/agent.js.map +0 -1
- package/lib/ai/bootstrap.d.ts +0 -91
- package/lib/ai/bootstrap.d.ts.map +0 -1
- package/lib/ai/bootstrap.js +0 -243
- package/lib/ai/bootstrap.js.map +0 -1
- package/lib/ai/builtin-tools.d.ts +0 -59
- package/lib/ai/builtin-tools.d.ts.map +0 -1
- package/lib/ai/builtin-tools.js +0 -777
- package/lib/ai/builtin-tools.js.map +0 -1
- package/lib/ai/compaction.d.ts +0 -132
- package/lib/ai/compaction.d.ts.map +0 -1
- package/lib/ai/compaction.js +0 -370
- package/lib/ai/compaction.js.map +0 -1
- package/lib/ai/context-manager.d.ts +0 -213
- package/lib/ai/context-manager.d.ts.map +0 -1
- package/lib/ai/context-manager.js +0 -313
- package/lib/ai/context-manager.js.map +0 -1
- package/lib/ai/conversation-memory.d.ts +0 -181
- package/lib/ai/conversation-memory.d.ts.map +0 -1
- package/lib/ai/conversation-memory.js +0 -581
- package/lib/ai/conversation-memory.js.map +0 -1
- package/lib/ai/cron-engine.d.ts +0 -92
- package/lib/ai/cron-engine.d.ts.map +0 -1
- package/lib/ai/cron-engine.js +0 -278
- package/lib/ai/cron-engine.js.map +0 -1
- package/lib/ai/follow-up.d.ts +0 -131
- package/lib/ai/follow-up.d.ts.map +0 -1
- package/lib/ai/follow-up.js +0 -265
- package/lib/ai/follow-up.js.map +0 -1
- package/lib/ai/hooks.d.ts +0 -143
- package/lib/ai/hooks.d.ts.map +0 -1
- package/lib/ai/hooks.js +0 -108
- package/lib/ai/hooks.js.map +0 -1
- package/lib/ai/init.d.ts +0 -30
- package/lib/ai/init.d.ts.map +0 -1
- package/lib/ai/init.js +0 -686
- package/lib/ai/init.js.map +0 -1
- package/lib/ai/output.d.ts +0 -93
- package/lib/ai/output.d.ts.map +0 -1
- package/lib/ai/output.js +0 -176
- package/lib/ai/output.js.map +0 -1
- package/lib/ai/rate-limiter.d.ts +0 -38
- package/lib/ai/rate-limiter.d.ts.map +0 -1
- package/lib/ai/rate-limiter.js +0 -86
- package/lib/ai/rate-limiter.js.map +0 -1
- package/lib/ai/service.d.ts +0 -88
- package/lib/ai/service.d.ts.map +0 -1
- package/lib/ai/service.js +0 -285
- package/lib/ai/service.js.map +0 -1
- package/lib/ai/session.d.ts +0 -186
- package/lib/ai/session.d.ts.map +0 -1
- package/lib/ai/session.js +0 -443
- package/lib/ai/session.js.map +0 -1
- package/lib/ai/subagent.d.ts +0 -50
- package/lib/ai/subagent.d.ts.map +0 -1
- package/lib/ai/subagent.js +0 -144
- package/lib/ai/subagent.js.map +0 -1
- package/lib/ai/tone-detector.d.ts +0 -19
- package/lib/ai/tone-detector.d.ts.map +0 -1
- package/lib/ai/tone-detector.js +0 -72
- package/lib/ai/tone-detector.js.map +0 -1
- package/lib/ai/tools.d.ts +0 -45
- package/lib/ai/tools.d.ts.map +0 -1
- package/lib/ai/tools.js +0 -206
- package/lib/ai/tools.js.map +0 -1
- package/lib/ai/user-profile.d.ts +0 -56
- package/lib/ai/user-profile.d.ts.map +0 -1
- package/lib/ai/user-profile.js +0 -130
- package/lib/ai/user-profile.js.map +0 -1
- package/lib/ai/zhin-agent/builtin-tools.d.ts +0 -17
- package/lib/ai/zhin-agent/builtin-tools.d.ts.map +0 -1
- package/lib/ai/zhin-agent/builtin-tools.js +0 -220
- package/lib/ai/zhin-agent/builtin-tools.js.map +0 -1
- package/lib/ai/zhin-agent/config.d.ts +0 -54
- package/lib/ai/zhin-agent/config.d.ts.map +0 -1
- package/lib/ai/zhin-agent/config.js +0 -76
- package/lib/ai/zhin-agent/config.js.map +0 -1
- package/lib/ai/zhin-agent/exec-policy.d.ts +0 -20
- package/lib/ai/zhin-agent/exec-policy.d.ts.map +0 -1
- package/lib/ai/zhin-agent/exec-policy.js +0 -71
- package/lib/ai/zhin-agent/exec-policy.js.map +0 -1
- package/lib/ai/zhin-agent/index.d.ts +0 -70
- package/lib/ai/zhin-agent/index.d.ts.map +0 -1
- package/lib/ai/zhin-agent/index.js +0 -404
- package/lib/ai/zhin-agent/index.js.map +0 -1
- package/lib/ai/zhin-agent/prompt.d.ts +0 -21
- package/lib/ai/zhin-agent/prompt.d.ts.map +0 -1
- package/lib/ai/zhin-agent/prompt.js +0 -111
- package/lib/ai/zhin-agent/prompt.js.map +0 -1
- package/lib/ai/zhin-agent/tool-collector.d.ts +0 -22
- package/lib/ai/zhin-agent/tool-collector.d.ts.map +0 -1
- package/lib/ai/zhin-agent/tool-collector.js +0 -218
- package/lib/ai/zhin-agent/tool-collector.js.map +0 -1
- package/src/ai/agent.ts +0 -831
- package/src/ai/bootstrap.ts +0 -309
- package/src/ai/builtin-tools.ts +0 -849
- package/src/ai/compaction.ts +0 -529
- package/src/ai/context-manager.ts +0 -440
- package/src/ai/conversation-memory.ts +0 -774
- package/src/ai/cron-engine.ts +0 -337
- package/src/ai/follow-up.ts +0 -357
- package/src/ai/hooks.ts +0 -223
- package/src/ai/init.ts +0 -762
- package/src/ai/output.ts +0 -261
- package/src/ai/rate-limiter.ts +0 -129
- package/src/ai/service.ts +0 -331
- package/src/ai/session.ts +0 -544
- package/src/ai/subagent.ts +0 -209
- package/src/ai/tone-detector.ts +0 -89
- package/src/ai/tools.ts +0 -218
- package/src/ai/user-profile.ts +0 -181
- package/src/ai/zhin-agent/builtin-tools.ts +0 -247
- package/src/ai/zhin-agent/config.ts +0 -113
- package/src/ai/zhin-agent/exec-policy.ts +0 -78
- package/src/ai/zhin-agent/index.ts +0 -512
- package/src/ai/zhin-agent/prompt.ts +0 -131
- package/src/ai/zhin-agent/tool-collector.ts +0 -243
- package/tests/ai/agent.test.ts +0 -614
- package/tests/ai/context-manager.test.ts +0 -413
- package/tests/ai/conversation-memory.test.ts +0 -128
- package/tests/ai/follow-up.test.ts +0 -175
- package/tests/ai/integration.test.ts +0 -584
- package/tests/ai/output.test.ts +0 -128
- package/tests/ai/rate-limiter.test.ts +0 -108
- package/tests/ai/session.test.ts +0 -375
- package/tests/ai/subagent.test.ts +0 -270
- package/tests/ai/tone-detector.test.ts +0 -80
- package/tests/ai/tools-builtin.test.ts +0 -346
- package/tests/ai/user-profile.test.ts +0 -73
- package/tests/ai/zhin-agent.test.ts +0 -177
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ZhinAgent 内置上下文工具工厂
|
|
3
|
-
*
|
|
4
|
-
* 这些工具依赖运行时上下文(sessionId / userId / context),
|
|
5
|
-
* 由 ZhinAgent.process() 按需创建并注入到工具列表中。
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { ToolContext } from '../../types.js';
|
|
9
|
-
import type { AgentTool } from '../types.js';
|
|
10
|
-
import type { ConversationMemory } from '../conversation-memory.js';
|
|
11
|
-
import type { UserProfileStore } from '../user-profile.js';
|
|
12
|
-
import type { FollowUpManager } from '../follow-up.js';
|
|
13
|
-
import type { SubagentManager, SubagentOrigin } from '../subagent.js';
|
|
14
|
-
|
|
15
|
-
export function createChatHistoryTool(sessionId: string, memory: ConversationMemory): AgentTool {
|
|
16
|
-
return {
|
|
17
|
-
name: 'chat_history',
|
|
18
|
-
description: '搜索与用户的历史聊天记录。可以按关键词搜索,也可以按对话轮次范围查询。当用户问到"之前聊过什么""我们讨论过什么"等回忆类问题时使用。',
|
|
19
|
-
parameters: {
|
|
20
|
-
type: 'object',
|
|
21
|
-
properties: {
|
|
22
|
-
keyword: {
|
|
23
|
-
type: 'string',
|
|
24
|
-
description: '搜索关键词(模糊匹配消息内容和摘要)。留空则返回最近几轮记录',
|
|
25
|
-
},
|
|
26
|
-
from_round: {
|
|
27
|
-
type: 'number',
|
|
28
|
-
description: '起始轮次(与 to_round 配合使用,精确查询某段对话)',
|
|
29
|
-
},
|
|
30
|
-
to_round: {
|
|
31
|
-
type: 'number',
|
|
32
|
-
description: '结束轮次',
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
required: ['keyword'],
|
|
36
|
-
},
|
|
37
|
-
tags: ['memory', 'history', '聊天记录', '回忆', '之前'],
|
|
38
|
-
keywords: ['之前', '历史', '聊过', '讨论过', '记得', '上次', '以前', '回忆'],
|
|
39
|
-
async execute(args: Record<string, any>) {
|
|
40
|
-
const { keyword, from_round, to_round } = args;
|
|
41
|
-
const currentRound = await memory.getCurrentRound(sessionId);
|
|
42
|
-
|
|
43
|
-
if (keyword) {
|
|
44
|
-
const result = await memory.traceByKeyword(sessionId, keyword);
|
|
45
|
-
const msgs = result.messages.map(m => {
|
|
46
|
-
const role = m.role === 'user' ? '用户' : '助手';
|
|
47
|
-
const time = new Date(m.time).toLocaleString('zh-CN');
|
|
48
|
-
return `[第${m.round}轮 ${time}] ${role}: ${m.content}`;
|
|
49
|
-
}).join('\n');
|
|
50
|
-
|
|
51
|
-
let output = `当前是第 ${currentRound} 轮对话。\n\n`;
|
|
52
|
-
if (result.summary) {
|
|
53
|
-
output += `📋 找到相关摘要(覆盖第${result.summary.fromRound}-${result.summary.toRound}轮):\n${result.summary.summary}\n\n`;
|
|
54
|
-
}
|
|
55
|
-
output += msgs ? `💬 相关聊天记录:\n${msgs}` : '未找到包含该关键词的聊天记录。';
|
|
56
|
-
return output;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (from_round != null && to_round != null) {
|
|
60
|
-
const messages = await memory.getMessagesByRound(sessionId, from_round, to_round);
|
|
61
|
-
if (messages.length === 0) {
|
|
62
|
-
return `第 ${from_round}-${to_round} 轮没有聊天记录。当前是第 ${currentRound} 轮。`;
|
|
63
|
-
}
|
|
64
|
-
const msgs = messages.map(m => {
|
|
65
|
-
const role = m.role === 'user' ? '用户' : '助手';
|
|
66
|
-
const time = new Date(m.time).toLocaleString('zh-CN');
|
|
67
|
-
return `[第${m.round}轮 ${time}] ${role}: ${m.content}`;
|
|
68
|
-
}).join('\n');
|
|
69
|
-
return `第 ${from_round}-${to_round} 轮聊天记录(当前第 ${currentRound} 轮):\n${msgs}`;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const messages = await memory.getMessagesByRound(
|
|
73
|
-
sessionId,
|
|
74
|
-
Math.max(1, currentRound - 4),
|
|
75
|
-
currentRound,
|
|
76
|
-
);
|
|
77
|
-
if (messages.length === 0) {
|
|
78
|
-
return '暂无聊天记录。';
|
|
79
|
-
}
|
|
80
|
-
const msgs = messages.map(m => {
|
|
81
|
-
const role = m.role === 'user' ? '用户' : '助手';
|
|
82
|
-
return `[第${m.round}轮] ${role}: ${m.content}`;
|
|
83
|
-
}).join('\n');
|
|
84
|
-
return `最近的聊天记录(当前第 ${currentRound} 轮):\n${msgs}`;
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export function createUserProfileTool(userId: string, profiles: UserProfileStore): AgentTool {
|
|
90
|
-
return {
|
|
91
|
-
name: 'user_profile',
|
|
92
|
-
description: '读取或保存用户的个人偏好和信息。当用户告诉你他的名字、偏好、兴趣、习惯等个人信息时,用 set 操作保存。当需要了解用户偏好时,用 get 操作读取。',
|
|
93
|
-
parameters: {
|
|
94
|
-
type: 'object',
|
|
95
|
-
properties: {
|
|
96
|
-
action: {
|
|
97
|
-
type: 'string',
|
|
98
|
-
description: '操作类型: get(读取所有偏好), set(保存偏好), delete(删除偏好)',
|
|
99
|
-
enum: ['get', 'set', 'delete'],
|
|
100
|
-
},
|
|
101
|
-
key: {
|
|
102
|
-
type: 'string',
|
|
103
|
-
description: '偏好名称,如: name, style, interests, timezone, language 等',
|
|
104
|
-
},
|
|
105
|
-
value: {
|
|
106
|
-
type: 'string',
|
|
107
|
-
description: '偏好值(仅 set 操作需要)',
|
|
108
|
-
},
|
|
109
|
-
},
|
|
110
|
-
required: ['action'],
|
|
111
|
-
},
|
|
112
|
-
tags: ['profile', '偏好', '用户', '个性化', '记住'],
|
|
113
|
-
keywords: ['我叫', '我的名字', '记住我', '我喜欢', '我偏好', '我习惯', '叫我', '我是'],
|
|
114
|
-
async execute(args: Record<string, any>) {
|
|
115
|
-
const { action, key, value } = args;
|
|
116
|
-
|
|
117
|
-
switch (action) {
|
|
118
|
-
case 'get': {
|
|
119
|
-
const all = await profiles.getAll(userId);
|
|
120
|
-
const entries = Object.entries(all);
|
|
121
|
-
if (entries.length === 0) return '暂无保存的用户偏好。';
|
|
122
|
-
return '用户偏好:\n' + entries.map(([k, v]) => ` ${k}: ${v}`).join('\n');
|
|
123
|
-
}
|
|
124
|
-
case 'set': {
|
|
125
|
-
if (!key || !value) return '需要提供 key 和 value';
|
|
126
|
-
await profiles.set(userId, key, value);
|
|
127
|
-
return `已保存: ${key} = ${value}`;
|
|
128
|
-
}
|
|
129
|
-
case 'delete': {
|
|
130
|
-
if (!key) return '需要提供 key';
|
|
131
|
-
const deleted = await profiles.delete(userId, key);
|
|
132
|
-
return deleted ? `已删除: ${key}` : `未找到偏好: ${key}`;
|
|
133
|
-
}
|
|
134
|
-
default:
|
|
135
|
-
return '不支持的操作,请使用 get/set/delete';
|
|
136
|
-
}
|
|
137
|
-
},
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export function createScheduleFollowUpTool(
|
|
142
|
-
sessionId: string,
|
|
143
|
-
context: ToolContext,
|
|
144
|
-
followUps: FollowUpManager,
|
|
145
|
-
): AgentTool {
|
|
146
|
-
const platform = context.platform || '';
|
|
147
|
-
const botId = context.botId || '';
|
|
148
|
-
const senderId = context.senderId || '';
|
|
149
|
-
const sceneId = context.sceneId || '';
|
|
150
|
-
const sceneType = (context.message as any)?.$channel?.type || 'private';
|
|
151
|
-
|
|
152
|
-
return {
|
|
153
|
-
name: 'schedule_followup',
|
|
154
|
-
description: '安排或取消定时跟进提醒。创建新提醒会自动取消之前的提醒。提醒持久保存,重启不丢失。',
|
|
155
|
-
parameters: {
|
|
156
|
-
type: 'object',
|
|
157
|
-
properties: {
|
|
158
|
-
action: {
|
|
159
|
-
type: 'string',
|
|
160
|
-
description: '操作类型: create(创建提醒,默认)或 cancel(取消当前会话所有提醒)',
|
|
161
|
-
enum: ['create', 'cancel'],
|
|
162
|
-
},
|
|
163
|
-
delay_minutes: {
|
|
164
|
-
type: 'number',
|
|
165
|
-
description: '延迟时间,单位是分钟。注意:3 就是 3 分钟,不是 3 小时。举例: 3 = 3分钟后, 60 = 1小时后, 1440 = 1天后',
|
|
166
|
-
},
|
|
167
|
-
message: {
|
|
168
|
-
type: 'string',
|
|
169
|
-
description: '提醒消息内容',
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
required: ['action'],
|
|
173
|
-
},
|
|
174
|
-
tags: ['reminder', '提醒', '跟进', '定时'],
|
|
175
|
-
keywords: ['提醒', '提醒我', '过一会', '过一小时', '明天', '跟进', '别忘了', '记得提醒', '取消提醒'],
|
|
176
|
-
async execute(args: Record<string, any>) {
|
|
177
|
-
const { action = 'create', delay_minutes, message: msg } = args;
|
|
178
|
-
|
|
179
|
-
if (action === 'cancel') {
|
|
180
|
-
const count = await followUps.cancelBySession(sessionId);
|
|
181
|
-
return count > 0
|
|
182
|
-
? `✅ 已取消 ${count} 个待执行的提醒`
|
|
183
|
-
: '当前没有待执行的提醒';
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (!delay_minutes || delay_minutes <= 0) return '延迟时间必须大于 0 分钟';
|
|
187
|
-
if (!msg) return '请提供提醒内容';
|
|
188
|
-
|
|
189
|
-
return followUps.schedule({
|
|
190
|
-
sessionId,
|
|
191
|
-
platform,
|
|
192
|
-
botId,
|
|
193
|
-
senderId,
|
|
194
|
-
sceneId,
|
|
195
|
-
sceneType,
|
|
196
|
-
message: msg,
|
|
197
|
-
delayMinutes: delay_minutes,
|
|
198
|
-
});
|
|
199
|
-
},
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
export function createSpawnTaskTool(
|
|
204
|
-
context: ToolContext,
|
|
205
|
-
manager: SubagentManager,
|
|
206
|
-
): AgentTool {
|
|
207
|
-
const platform = context.platform || '';
|
|
208
|
-
const botId = context.botId || '';
|
|
209
|
-
const senderId = context.senderId || '';
|
|
210
|
-
const sceneId = context.sceneId || '';
|
|
211
|
-
const sceneType = (context.message as any)?.$channel?.type || 'private';
|
|
212
|
-
|
|
213
|
-
return {
|
|
214
|
-
name: 'spawn_task',
|
|
215
|
-
description: '将复杂或耗时的任务交给后台子 agent 异步处理。子 agent 拥有文件读写、Shell、网络搜索等能力,完成后会自动通知用户。适用于需要多步操作的文件处理、代码分析、数据收集等任务。',
|
|
216
|
-
parameters: {
|
|
217
|
-
type: 'object',
|
|
218
|
-
properties: {
|
|
219
|
-
task: {
|
|
220
|
-
type: 'string',
|
|
221
|
-
description: '要交给子 agent 完成的任务描述(尽量详细,包含目标、范围、期望输出)',
|
|
222
|
-
},
|
|
223
|
-
label: {
|
|
224
|
-
type: 'string',
|
|
225
|
-
description: '任务的简短标签(用于显示,可选)',
|
|
226
|
-
},
|
|
227
|
-
},
|
|
228
|
-
required: ['task'],
|
|
229
|
-
},
|
|
230
|
-
tags: ['agent', 'async', 'task', '后台', '子任务'],
|
|
231
|
-
keywords: ['后台', '异步', '子任务', 'spawn', 'background', '并行', '独立处理'],
|
|
232
|
-
async execute(args: Record<string, any>) {
|
|
233
|
-
const { task, label } = args;
|
|
234
|
-
if (!task) return '请提供任务描述';
|
|
235
|
-
|
|
236
|
-
const origin: SubagentOrigin = {
|
|
237
|
-
platform,
|
|
238
|
-
botId,
|
|
239
|
-
sceneId,
|
|
240
|
-
senderId,
|
|
241
|
-
sceneType,
|
|
242
|
-
};
|
|
243
|
-
|
|
244
|
-
return manager.spawn({ task, label, origin });
|
|
245
|
-
},
|
|
246
|
-
};
|
|
247
|
-
}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ZhinAgent 配置、常量、类型定义
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { RateLimitConfig } from '../rate-limiter.js';
|
|
6
|
-
import { DEFAULT_CONTEXT_TOKENS } from '../compaction.js';
|
|
7
|
-
|
|
8
|
-
export type ModelSizeHint = 'small' | 'medium' | 'large';
|
|
9
|
-
|
|
10
|
-
const SMALL_MODEL_RE = /[:\-_](0\.5|1\.?[58]?|[3-8])b\b/i;
|
|
11
|
-
const MEDIUM_MODEL_RE = /[:\-_](14|[12][0-9]|32)b\b/i;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Infer model size from model name string.
|
|
15
|
-
* Pattern: `:8b` → small, `:14b` → medium, else large.
|
|
16
|
-
*/
|
|
17
|
-
export function inferModelSize(modelName: string): ModelSizeHint {
|
|
18
|
-
if (SMALL_MODEL_RE.test(modelName)) return 'small';
|
|
19
|
-
if (MEDIUM_MODEL_RE.test(modelName)) return 'medium';
|
|
20
|
-
return 'large';
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Resolve the effective model size hint.
|
|
25
|
-
* Priority: explicit config > model name inference.
|
|
26
|
-
*/
|
|
27
|
-
export function resolveModelSize(config: Required<ZhinAgentConfig>, modelName: string): ModelSizeHint {
|
|
28
|
-
if (config.modelSizeHint && config.modelSizeHint !== ('' as any)) return config.modelSizeHint;
|
|
29
|
-
return inferModelSize(modelName);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Resolve the effective skill instruction max chars based on model size.
|
|
34
|
-
*/
|
|
35
|
-
export function resolveSkillInstructionMaxChars(config: Required<ZhinAgentConfig>, modelName: string): number {
|
|
36
|
-
if (config.skillInstructionMaxChars && config.skillInstructionMaxChars > 0) return config.skillInstructionMaxChars;
|
|
37
|
-
const size = resolveModelSize(config, modelName);
|
|
38
|
-
switch (size) {
|
|
39
|
-
case 'small': return 1500;
|
|
40
|
-
case 'medium': return 4000;
|
|
41
|
-
case 'large': return 8000;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export const SECTION_SEP = '\n\n---\n\n';
|
|
46
|
-
export const HISTORY_CONTEXT_MARKER = '[Chat messages since your last reply - for context]';
|
|
47
|
-
export const CURRENT_MESSAGE_MARKER = '[Current message - respond to this]';
|
|
48
|
-
|
|
49
|
-
export const PERM_MAP: Record<string, number> = {
|
|
50
|
-
user: 0,
|
|
51
|
-
group_admin: 1,
|
|
52
|
-
group_owner: 2,
|
|
53
|
-
bot_admin: 3,
|
|
54
|
-
owner: 4,
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export type OnChunkCallback = (chunk: string, full: string) => void;
|
|
58
|
-
|
|
59
|
-
export interface ZhinAgentConfig {
|
|
60
|
-
persona?: string;
|
|
61
|
-
maxIterations?: number;
|
|
62
|
-
timeout?: number;
|
|
63
|
-
preExecTimeout?: number;
|
|
64
|
-
maxSkills?: number;
|
|
65
|
-
maxTools?: number;
|
|
66
|
-
minTopicRounds?: number;
|
|
67
|
-
slidingWindowSize?: number;
|
|
68
|
-
topicChangeThreshold?: number;
|
|
69
|
-
rateLimit?: RateLimitConfig;
|
|
70
|
-
toneAwareness?: boolean;
|
|
71
|
-
visionModel?: string;
|
|
72
|
-
contextTokens?: number;
|
|
73
|
-
maxHistoryShare?: number;
|
|
74
|
-
disabledTools?: string[];
|
|
75
|
-
allowedTools?: string[];
|
|
76
|
-
execSecurity?: 'deny' | 'allowlist' | 'full';
|
|
77
|
-
execPreset?: 'readonly' | 'network' | 'development' | 'custom';
|
|
78
|
-
execAllowlist?: string[];
|
|
79
|
-
execAsk?: boolean;
|
|
80
|
-
maxSubagentIterations?: number;
|
|
81
|
-
subagentTools?: string[];
|
|
82
|
-
/** 模型大小提示,影响技能指令截断长度。留空则根据模型名自动推断 */
|
|
83
|
-
modelSizeHint?: 'small' | 'medium' | 'large';
|
|
84
|
-
/** 技能指令最大字符数(覆盖 modelSizeHint 推断值) */
|
|
85
|
-
skillInstructionMaxChars?: number;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export const DEFAULT_CONFIG: Required<ZhinAgentConfig> = {
|
|
89
|
-
persona: '你是一个友好的中文 AI 助手,擅长使用工具帮助用户解决问题。',
|
|
90
|
-
maxIterations: 5,
|
|
91
|
-
timeout: 60_000,
|
|
92
|
-
preExecTimeout: 10_000,
|
|
93
|
-
maxSkills: 3,
|
|
94
|
-
maxTools: 8,
|
|
95
|
-
minTopicRounds: 5,
|
|
96
|
-
slidingWindowSize: 5,
|
|
97
|
-
topicChangeThreshold: 0.15,
|
|
98
|
-
rateLimit: {},
|
|
99
|
-
toneAwareness: true,
|
|
100
|
-
visionModel: '',
|
|
101
|
-
contextTokens: DEFAULT_CONTEXT_TOKENS,
|
|
102
|
-
maxHistoryShare: 0.5,
|
|
103
|
-
disabledTools: [],
|
|
104
|
-
allowedTools: [],
|
|
105
|
-
execSecurity: 'deny',
|
|
106
|
-
execPreset: 'custom',
|
|
107
|
-
execAllowlist: [],
|
|
108
|
-
execAsk: false,
|
|
109
|
-
maxSubagentIterations: 15,
|
|
110
|
-
subagentTools: [],
|
|
111
|
-
modelSizeHint: '' as any,
|
|
112
|
-
skillInstructionMaxChars: 0,
|
|
113
|
-
};
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ZhinAgent 执行策略 — bash 命令的安全检查与工具包装
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { AgentTool } from '../types.js';
|
|
6
|
-
import type { ZhinAgentConfig } from './config.js';
|
|
7
|
-
|
|
8
|
-
// ── 预设命令白名单 ──────────────────────────────────────────────────
|
|
9
|
-
|
|
10
|
-
const PRESET_READONLY = ['ls', 'cat', 'pwd', 'date', 'whoami', 'grep', 'find', 'head', 'tail', 'wc'];
|
|
11
|
-
const PRESET_NETWORK = [...PRESET_READONLY, 'curl', 'wget', 'ping', 'dig'];
|
|
12
|
-
const PRESET_DEVELOPMENT = [...PRESET_NETWORK, 'npm', 'npx', 'node', 'git', 'gh', 'python', 'python3', 'pip', 'pnpm', 'yarn'];
|
|
13
|
-
|
|
14
|
-
export const EXEC_PRESETS: Record<string, string[]> = {
|
|
15
|
-
readonly: PRESET_READONLY,
|
|
16
|
-
network: PRESET_NETWORK,
|
|
17
|
-
development: PRESET_DEVELOPMENT,
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Resolves the effective allowlist by merging preset commands with custom allowlist.
|
|
22
|
-
*/
|
|
23
|
-
export function resolveExecAllowlist(config: Required<ZhinAgentConfig>): string[] {
|
|
24
|
-
const preset = config.execPreset;
|
|
25
|
-
const presetList = (preset && preset !== 'custom') ? (EXEC_PRESETS[preset] ?? []) : [];
|
|
26
|
-
const custom = config.execAllowlist ?? [];
|
|
27
|
-
const merged = [...new Set([...presetList, ...custom])];
|
|
28
|
-
return merged;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Check if a bash command is allowed under the current exec policy.
|
|
33
|
-
* Throws an Error when the command is denied.
|
|
34
|
-
*/
|
|
35
|
-
export function checkExecPolicy(config: Required<ZhinAgentConfig>, command: string): void {
|
|
36
|
-
const security = config.execSecurity ?? 'deny';
|
|
37
|
-
if (security === 'full') return;
|
|
38
|
-
if (security === 'deny') {
|
|
39
|
-
throw new Error('当前配置禁止执行 Shell 命令(execSecurity=deny)。如需开放请在配置中设置 ai.agent.execSecurity。');
|
|
40
|
-
}
|
|
41
|
-
// allowlist
|
|
42
|
-
const list = resolveExecAllowlist(config);
|
|
43
|
-
const cmd = (command || '').trim();
|
|
44
|
-
const allowed = list.some(pattern => {
|
|
45
|
-
try {
|
|
46
|
-
const re = new RegExp(pattern);
|
|
47
|
-
return re.test(cmd);
|
|
48
|
-
} catch {
|
|
49
|
-
return cmd === pattern || cmd.startsWith(pattern);
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
if (!allowed) {
|
|
53
|
-
const ask = config.execAsk;
|
|
54
|
-
throw new Error(
|
|
55
|
-
ask
|
|
56
|
-
? '该命令不在允许列表中,需要审批后执行。当前版本请将命令加入 ai.agent.execAllowlist 或联系管理员。'
|
|
57
|
-
: '该命令不在允许列表中,已被拒绝执行。可将允许的命令模式加入 ai.agent.execAllowlist。',
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Wrap `bash` tools with exec policy enforcement.
|
|
64
|
-
*/
|
|
65
|
-
export function applyExecPolicyToTools(config: Required<ZhinAgentConfig>, tools: AgentTool[]): AgentTool[] {
|
|
66
|
-
return tools.map(t => {
|
|
67
|
-
if (t.name !== 'bash') return t;
|
|
68
|
-
const original = t.execute;
|
|
69
|
-
return {
|
|
70
|
-
...t,
|
|
71
|
-
execute: async (args: Record<string, any>) => {
|
|
72
|
-
const cmd = args?.command != null ? String(args.command) : '';
|
|
73
|
-
checkExecPolicy(config, cmd);
|
|
74
|
-
return original(args);
|
|
75
|
-
},
|
|
76
|
-
};
|
|
77
|
-
});
|
|
78
|
-
}
|