@zhin.js/agent 0.0.19 → 0.1.0
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 +29 -0
- package/README.md +5 -2
- package/lib/builtin-tools.d.ts.map +1 -1
- package/lib/builtin-tools.js +136 -37
- package/lib/builtin-tools.js.map +1 -1
- package/lib/init/create-zhin-agent.d.ts.map +1 -1
- package/lib/init/create-zhin-agent.js +28 -2
- package/lib/init/create-zhin-agent.js.map +1 -1
- package/lib/init/register-ai-trigger.d.ts.map +1 -1
- package/lib/init/register-ai-trigger.js +10 -3
- package/lib/init/register-ai-trigger.js.map +1 -1
- package/lib/service.d.ts +4 -0
- package/lib/service.d.ts.map +1 -1
- package/lib/service.js +3 -0
- package/lib/service.js.map +1 -1
- package/lib/zhin-agent/config.d.ts +2 -0
- package/lib/zhin-agent/config.d.ts.map +1 -1
- package/lib/zhin-agent/config.js +1 -0
- package/lib/zhin-agent/config.js.map +1 -1
- package/lib/zhin-agent/exec-policy.js +2 -2
- package/lib/zhin-agent/exec-policy.js.map +1 -1
- package/lib/zhin-agent/index.d.ts +10 -0
- package/lib/zhin-agent/index.d.ts.map +1 -1
- package/lib/zhin-agent/index.js +122 -48
- package/lib/zhin-agent/index.js.map +1 -1
- package/lib/zhin-agent/prompt.js +2 -2
- package/lib/zhin-agent/prompt.js.map +1 -1
- package/package.json +3 -3
- package/src/builtin-tools.ts +143 -37
- package/src/init/create-zhin-agent.ts +27 -2
- package/src/init/register-ai-trigger.ts +15 -3
- package/src/service.ts +4 -0
- package/src/zhin-agent/config.ts +3 -0
- package/src/zhin-agent/exec-policy.ts +2 -2
- package/src/zhin-agent/index.ts +116 -42
- package/src/zhin-agent/prompt.ts +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/zhin-agent/prompt.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../src/zhin-agent/prompt.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/agent",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Zhin AI Agent — session, ZhinAgent, init; composes @zhin.js/core providers and tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"js-yaml": "^4.1.0",
|
|
17
|
-
"@zhin.js/ai": "1.0
|
|
18
|
-
"@zhin.js/core": "1.0
|
|
17
|
+
"@zhin.js/ai": "1.1.0",
|
|
18
|
+
"@zhin.js/core": "1.1.0"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/js-yaml": "^4.0.9",
|
package/src/builtin-tools.ts
CHANGED
|
@@ -16,7 +16,7 @@ import * as fs from 'fs';
|
|
|
16
16
|
import * as path from 'path';
|
|
17
17
|
import { exec } from 'child_process';
|
|
18
18
|
import { promisify } from 'util';
|
|
19
|
-
import { Logger, Prompt, type Plugin, type PropertySchema } from '@zhin.js/core';
|
|
19
|
+
import { Logger, Prompt, Adapter, type Plugin, type PropertySchema, type MessageMiddleware, type SendOptions } from '@zhin.js/core';
|
|
20
20
|
import { ZhinTool } from '@zhin.js/core';
|
|
21
21
|
import {
|
|
22
22
|
assertFileAccess, checkBashCommandSafety, shellEscape,
|
|
@@ -137,6 +137,76 @@ function isImageFile(filePath: string): boolean {
|
|
|
137
137
|
return IMAGE_EXTENSIONS.has(path.extname(filePath).toLowerCase());
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
// ============================================================================
|
|
141
|
+
// ask_user 辅助函数
|
|
142
|
+
// ============================================================================
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* 私聊 Owner 场景:使用 Prompt 类直接交互(原有行为)
|
|
146
|
+
*/
|
|
147
|
+
async function askViaPrompt(
|
|
148
|
+
plugin: Plugin,
|
|
149
|
+
message: any,
|
|
150
|
+
args: Record<string, any>,
|
|
151
|
+
questionType: string,
|
|
152
|
+
timeoutMs: number,
|
|
153
|
+
): Promise<string> {
|
|
154
|
+
const prompt = new Prompt(plugin, message);
|
|
155
|
+
try {
|
|
156
|
+
switch (questionType) {
|
|
157
|
+
case 'number': {
|
|
158
|
+
const defaultNum = args.default_value != null ? Number(args.default_value) : undefined;
|
|
159
|
+
const result = await prompt.number(args.question, timeoutMs, defaultNum, '输入超时,已取消');
|
|
160
|
+
return String(result);
|
|
161
|
+
}
|
|
162
|
+
case 'confirm': {
|
|
163
|
+
const result = await prompt.confirm(args.question, 'yes', timeoutMs, false, '确认超时,已取消');
|
|
164
|
+
return result ? 'yes' : 'no';
|
|
165
|
+
}
|
|
166
|
+
case 'pick': {
|
|
167
|
+
if (!args.options?.length) {
|
|
168
|
+
return 'Error: type=pick 时必须提供 options 选项列表';
|
|
169
|
+
}
|
|
170
|
+
const pickOptions = (args.options as string[]).map((o: string) => ({ label: o, value: o }));
|
|
171
|
+
const result = await prompt.pick(args.question, {
|
|
172
|
+
type: 'text' as const,
|
|
173
|
+
options: pickOptions,
|
|
174
|
+
timeout: timeoutMs,
|
|
175
|
+
}, '选择超时,已取消');
|
|
176
|
+
return String(result);
|
|
177
|
+
}
|
|
178
|
+
case 'text':
|
|
179
|
+
default: {
|
|
180
|
+
const result = await prompt.text(args.question, timeoutMs, args.default_value || '', '输入超时,已取消');
|
|
181
|
+
return result;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
} catch (e: unknown) {
|
|
185
|
+
return `Owner 未响应或输入错误: ${errMsg(e)}`;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* 将 Owner 私聊回复格式化为对应类型的结果
|
|
191
|
+
*/
|
|
192
|
+
function formatOwnerResponse(raw: string, questionType: string, args: Record<string, any>): string {
|
|
193
|
+
switch (questionType) {
|
|
194
|
+
case 'confirm':
|
|
195
|
+
return raw.trim().toLowerCase() === 'yes' ? 'yes' : 'no';
|
|
196
|
+
case 'number':
|
|
197
|
+
return String(Number(raw) || 0);
|
|
198
|
+
case 'pick': {
|
|
199
|
+
const idx = Number(raw.trim());
|
|
200
|
+
const options = (args.options as string[]) || [];
|
|
201
|
+
if (idx >= 1 && idx <= options.length) return options[idx - 1];
|
|
202
|
+
return raw;
|
|
203
|
+
}
|
|
204
|
+
case 'text':
|
|
205
|
+
default:
|
|
206
|
+
return raw;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
140
210
|
// ============================================================================
|
|
141
211
|
// 工具工厂函数
|
|
142
212
|
// ============================================================================
|
|
@@ -789,62 +859,98 @@ export function createBuiltinTools(options?: BuiltinToolsOptions): ZhinTool[] {
|
|
|
789
859
|
);
|
|
790
860
|
|
|
791
861
|
// ── ask_user(基于 Prompt 类的用户确认/提问工具) ──
|
|
862
|
+
// 安全策略:在群聊中 ask_user 只向 owner 私聊确认,防止非 owner 用户操控安全敏感决策
|
|
792
863
|
tools.push(
|
|
793
864
|
new ZhinTool('ask_user')
|
|
794
|
-
.desc('
|
|
865
|
+
.desc('向 Bot Owner 发送问题并等待回复。用于需要确认、补充信息或做出选择时。在群聊中始终通过私聊向 Owner 确认,确保安全性。')
|
|
795
866
|
.keyword('询问', '确认', '提问', '用户输入', 'ask', 'confirm', 'prompt', '选择', '请问')
|
|
796
867
|
.tag('interaction', 'prompt')
|
|
797
868
|
.kind('interaction')
|
|
798
|
-
.param('question', { type: 'string', description: '
|
|
869
|
+
.param('question', { type: 'string', description: '要向 Owner 提出的问题文本' }, true)
|
|
799
870
|
.param('type', { type: 'string', description: '问题类型: text(文本输入)、number(数字输入)、confirm(是/否确认)、pick(选项选择)。默认 text' })
|
|
800
871
|
.param('options', { type: 'array', description: '选项列表(type=pick 时必填),每项为字符串,如 ["选项A","选项B","选项C"]' })
|
|
801
|
-
.param('default_value', { type: 'string', description: '
|
|
802
|
-
.param('timeout', { type: 'number', description: '
|
|
872
|
+
.param('default_value', { type: 'string', description: 'Owner 超时未回复时使用的默认值' })
|
|
873
|
+
.param('timeout', { type: 'number', description: '等待 Owner 回复的超时时间(秒),默认 120' })
|
|
803
874
|
.execute(async (args, context) => {
|
|
804
|
-
// 无消息上下文时无法使用(如子任务场景)
|
|
805
875
|
if (!context?.message) {
|
|
806
|
-
return 'Error:
|
|
876
|
+
return 'Error: 当前上下文没有消息来源,无法向 Owner 提问。请改为在回复中直接询问。';
|
|
807
877
|
}
|
|
808
878
|
if (!pluginRef) {
|
|
809
879
|
return 'Error: 插件实例不可用,无法创建交互式提问。请改为在回复中直接询问。';
|
|
810
880
|
}
|
|
811
881
|
|
|
812
|
-
const prompt = new Prompt(pluginRef, context.message);
|
|
813
882
|
const timeoutMs = (args.timeout ?? 120) * 1000;
|
|
814
883
|
const questionType = args.type || 'text';
|
|
815
884
|
|
|
885
|
+
// 从 adapter 的 bot 配置中查找 owner
|
|
886
|
+
const platform = context.platform!;
|
|
887
|
+
const botId = context.botId!;
|
|
888
|
+
const adapter = pluginRef.inject(platform) as Adapter | undefined;
|
|
889
|
+
const bot = adapter?.bots?.get(botId);
|
|
890
|
+
const botOwner: string | undefined = (bot?.$config as any)?.owner;
|
|
891
|
+
const isPrivateOwner = context.scope === 'private'
|
|
892
|
+
&& botOwner != null && String(context.senderId) === String(botOwner);
|
|
893
|
+
|
|
894
|
+
// ── 私聊 + 发送者是 Owner → 直接用 Prompt(原有行为) ──
|
|
895
|
+
if (isPrivateOwner) {
|
|
896
|
+
return askViaPrompt(pluginRef, context.message, args, questionType, timeoutMs);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
// ── 非私聊 Owner → 必须通过私聊向 Owner 确认 ──
|
|
900
|
+
if (!botOwner) {
|
|
901
|
+
return 'Error: 当前 Bot 未配置 owner,无法进行安全确认。请在 bots 配置中设置 owner 字段。';
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
if (!adapter || typeof adapter.sendMessage !== 'function') {
|
|
905
|
+
return `Error: 无法获取适配器 ${platform},无法向 Owner 发送私聊确认。`;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
// 构建发送给 Owner 的问题文本(包含来源上下文)
|
|
909
|
+
const sourceInfo = context.scope !== 'private'
|
|
910
|
+
? `来源: ${context.scope}(${context.sceneId}) 用户: ${context.senderId}`
|
|
911
|
+
: `来源: 私聊 用户: ${context.senderId}`;
|
|
912
|
+
let questionText = `🔐 AI 安全确认\n${sourceInfo}\n\n${args.question}`;
|
|
913
|
+
if (questionType === 'confirm') {
|
|
914
|
+
questionText += '\n输入"yes"以确认';
|
|
915
|
+
} else if (questionType === 'pick' && args.options?.length) {
|
|
916
|
+
questionText += '\n' + (args.options as string[]).map((o, i) => `${i + 1}.${o}`).join('\n');
|
|
917
|
+
} else if (questionType === 'number') {
|
|
918
|
+
questionText += '\n(请输入数字)';
|
|
919
|
+
}
|
|
920
|
+
|
|
816
921
|
try {
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
const result = await prompt.confirm(args.question, 'yes', timeoutMs, false, '确认超时,已取消');
|
|
825
|
-
return result ? 'yes' : 'no';
|
|
826
|
-
}
|
|
827
|
-
case 'pick': {
|
|
828
|
-
if (!args.options?.length) {
|
|
829
|
-
return 'Error: type=pick 时必须提供 options 选项列表';
|
|
830
|
-
}
|
|
831
|
-
const pickOptions = (args.options as string[]).map((o: string) => ({ label: o, value: o }));
|
|
832
|
-
const result = await prompt.pick(args.question, {
|
|
833
|
-
type: 'text' as const,
|
|
834
|
-
options: pickOptions,
|
|
835
|
-
timeout: timeoutMs,
|
|
836
|
-
}, '选择超时,已取消');
|
|
837
|
-
return String(result);
|
|
838
|
-
}
|
|
839
|
-
case 'text':
|
|
840
|
-
default: {
|
|
841
|
-
const result = await prompt.text(args.question, timeoutMs, args.default_value || '', '输入超时,已取消');
|
|
842
|
-
return result;
|
|
843
|
-
}
|
|
844
|
-
}
|
|
922
|
+
await adapter.sendMessage({
|
|
923
|
+
context: platform,
|
|
924
|
+
bot: botId,
|
|
925
|
+
id: botOwner,
|
|
926
|
+
type: 'private',
|
|
927
|
+
content: questionText,
|
|
928
|
+
} satisfies SendOptions);
|
|
845
929
|
} catch (e: unknown) {
|
|
846
|
-
return
|
|
930
|
+
return `Error: 无法向 Owner 发送私聊消息: ${errMsg(e)}`;
|
|
847
931
|
}
|
|
932
|
+
|
|
933
|
+
// 注册一次性中间件等待 Owner 私聊回复
|
|
934
|
+
return new Promise<string>((resolve) => {
|
|
935
|
+
const middleware: MessageMiddleware = async (message, next) => {
|
|
936
|
+
if (message.$channel?.type !== 'private') return next();
|
|
937
|
+
if (String(message.$sender.id) !== String(botOwner)) return next();
|
|
938
|
+
if (String(message.$bot) !== String(botId)) return next();
|
|
939
|
+
dispose();
|
|
940
|
+
clearTimeout(timer);
|
|
941
|
+
const raw = message.$raw;
|
|
942
|
+
resolve(formatOwnerResponse(raw, questionType, args));
|
|
943
|
+
};
|
|
944
|
+
const dispose = pluginRef!.addMiddleware(middleware);
|
|
945
|
+
const timer = setTimeout(() => {
|
|
946
|
+
dispose();
|
|
947
|
+
if (args.default_value != null) {
|
|
948
|
+
resolve(String(args.default_value));
|
|
949
|
+
} else {
|
|
950
|
+
resolve('Owner 未在规定时间内响应,操作已取消。');
|
|
951
|
+
}
|
|
952
|
+
}, timeoutMs);
|
|
953
|
+
});
|
|
848
954
|
}),
|
|
849
955
|
);
|
|
850
956
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import { getPlugin, Scheduler, getScheduler, setScheduler, type MessageType, type SendOptions } from '@zhin.js/core';
|
|
7
|
+
import { ModelRegistry, computeTierScore } from '@zhin.js/ai';
|
|
7
8
|
import { ZhinAgent } from '../zhin-agent/index.js';
|
|
8
9
|
import { createBuiltinTools } from '../builtin-tools.js';
|
|
9
10
|
import { collectPluginSkillSearchRoots } from '../discovery-utils.js';
|
|
@@ -29,6 +30,32 @@ export function createZhinAgentContext(refs: AIServiceRefs): void {
|
|
|
29
30
|
const skillRegistry = root.inject('skill');
|
|
30
31
|
if (skillRegistry) agent.setSkillRegistry(skillRegistry);
|
|
31
32
|
|
|
33
|
+
// Model Registry: discover models and wire to agent
|
|
34
|
+
const dataDir = path.join(process.cwd(), 'data');
|
|
35
|
+
const modelRegistry = new ModelRegistry(dataDir);
|
|
36
|
+
const hadCache = modelRegistry.loadCache();
|
|
37
|
+
agent.setModelRegistry(modelRegistry);
|
|
38
|
+
ai.setModelRegistry(modelRegistry);
|
|
39
|
+
// Discover models in background (don't block startup)
|
|
40
|
+
(async () => {
|
|
41
|
+
try {
|
|
42
|
+
const discovered = await modelRegistry.discover(provider);
|
|
43
|
+
modelRegistry.saveCache();
|
|
44
|
+
if (discovered.length > 0) {
|
|
45
|
+
provider.models = discovered
|
|
46
|
+
.sort((a, b) => computeTierScore(b.id) - computeTierScore(a.id))
|
|
47
|
+
.map(m => m.id);
|
|
48
|
+
}
|
|
49
|
+
if (hadCache) {
|
|
50
|
+
logger.debug(`ModelRegistry: refreshed ${discovered.length} models from ${provider.name}`);
|
|
51
|
+
} else {
|
|
52
|
+
logger.info(`ModelRegistry: discovered ${discovered.length} models from ${provider.name}`);
|
|
53
|
+
}
|
|
54
|
+
} catch (e) {
|
|
55
|
+
logger.warn(`ModelRegistry: discovery failed for ${provider.name}: ${(e as Error).message}`);
|
|
56
|
+
}
|
|
57
|
+
})();
|
|
58
|
+
|
|
32
59
|
// Follow-up reminder sender
|
|
33
60
|
agent.setFollowUpSender(async (record) => {
|
|
34
61
|
const adapter = root.inject(record.platform) as { sendMessage?: (opts: SendOptions) => Promise<string> } | undefined;
|
|
@@ -85,7 +112,6 @@ export function createZhinAgentContext(refs: AIServiceRefs): void {
|
|
|
85
112
|
let cronEngine: PersistentCronEngine | null = null;
|
|
86
113
|
const cronFeature = root.inject('cron') as import('@zhin.js/core').CronFeature | undefined;
|
|
87
114
|
if (cronFeature && typeof cronFeature.add === 'function') {
|
|
88
|
-
const dataDir = path.join(process.cwd(), 'data');
|
|
89
115
|
const addCron: import('../cron-engine.js').AddCronFn = (c) => cronFeature.add(c, 'cron-engine');
|
|
90
116
|
const runner = async (prompt: string) => {
|
|
91
117
|
if (!refs.zhinAgent) return;
|
|
@@ -101,7 +127,6 @@ export function createZhinAgentContext(refs: AIServiceRefs): void {
|
|
|
101
127
|
}
|
|
102
128
|
|
|
103
129
|
// Unified scheduler (at/every/cron)
|
|
104
|
-
const dataDir = path.join(process.cwd(), 'data');
|
|
105
130
|
const scheduler = new Scheduler({
|
|
106
131
|
storePath: path.join(dataDir, 'scheduler-jobs.json'),
|
|
107
132
|
workspace: process.cwd(),
|
|
@@ -150,6 +150,18 @@ export function registerAITrigger(refs: AIServiceRefs): void {
|
|
|
150
150
|
await replyOutbound(triggerConfig.thinkingMessage);
|
|
151
151
|
|
|
152
152
|
const permissions = inferSenderPermissions(message, triggerConfig);
|
|
153
|
+
|
|
154
|
+
// 从 bot 配置中查找 owner(bots[].owner)
|
|
155
|
+
const adapterInstance = root.inject(message.$adapter) as
|
|
156
|
+
| { bots?: Map<string, { $config?: Record<string, any> }> }
|
|
157
|
+
| undefined;
|
|
158
|
+
const botConfig = adapterInstance?.bots?.get(message.$bot)?.$config as Record<string, any> | undefined;
|
|
159
|
+
const botOwner: string | undefined = botConfig?.owner;
|
|
160
|
+
|
|
161
|
+
// 用 bot 级别 owner 覆盖权限判断
|
|
162
|
+
const isOwner = botOwner ? String(message.$sender.id) === String(botOwner) : permissions.isOwner;
|
|
163
|
+
const permissionLevel = isOwner ? 'owner' as const : permissions.permissionLevel;
|
|
164
|
+
|
|
153
165
|
const toolContext: ToolContext = {
|
|
154
166
|
platform: message.$adapter,
|
|
155
167
|
botId: message.$bot,
|
|
@@ -157,11 +169,11 @@ export function registerAITrigger(refs: AIServiceRefs): void {
|
|
|
157
169
|
senderId: message.$sender.id,
|
|
158
170
|
message,
|
|
159
171
|
scope: permissions.scope,
|
|
160
|
-
senderPermissionLevel:
|
|
172
|
+
senderPermissionLevel: permissionLevel,
|
|
161
173
|
isGroupAdmin: permissions.isGroupAdmin,
|
|
162
174
|
isGroupOwner: permissions.isGroupOwner,
|
|
163
|
-
isBotAdmin: permissions.isBotAdmin,
|
|
164
|
-
isOwner
|
|
175
|
+
isBotAdmin: isOwner || permissions.isBotAdmin,
|
|
176
|
+
isOwner,
|
|
165
177
|
};
|
|
166
178
|
|
|
167
179
|
const tCollect = performance.now();
|
package/src/service.ts
CHANGED
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
createMemorySessionManager,
|
|
28
28
|
} from '@zhin.js/ai';
|
|
29
29
|
import { Agent, createAgent } from '@zhin.js/ai';
|
|
30
|
+
import type { ModelRegistry } from '@zhin.js/ai';
|
|
30
31
|
import { getBuiltinTools } from './tools.js';
|
|
31
32
|
import type { ContextManager, ContextConfig } from '@zhin.js/ai';
|
|
32
33
|
import { PERM_MAP } from './zhin-agent/config.js';
|
|
@@ -59,6 +60,7 @@ export class AIService {
|
|
|
59
60
|
private agentConfig: AIConfig['agent'];
|
|
60
61
|
private plugin?: Plugin;
|
|
61
62
|
private customTools: Map<string, AgentTool> = new Map();
|
|
63
|
+
private _modelRegistry: ModelRegistry | null = null;
|
|
62
64
|
|
|
63
65
|
constructor(config: AIConfig = {}) {
|
|
64
66
|
this.defaultProvider = config.defaultProvider || 'openai';
|
|
@@ -135,6 +137,8 @@ export class AIService {
|
|
|
135
137
|
if (defaultProvider) manager.setAIProvider(defaultProvider);
|
|
136
138
|
}
|
|
137
139
|
setPlugin(plugin: Plugin): void { this.plugin = plugin; }
|
|
140
|
+
setModelRegistry(registry: ModelRegistry): void { this._modelRegistry = registry; }
|
|
141
|
+
getModelRegistry(): ModelRegistry | null { return this._modelRegistry; }
|
|
138
142
|
registerTool(tool: AgentTool): () => void { this.customTools.set(tool.name, tool); return () => { this.customTools.delete(tool.name); }; }
|
|
139
143
|
|
|
140
144
|
collectAllTools(): AgentTool[] {
|
package/src/zhin-agent/config.ts
CHANGED
|
@@ -76,6 +76,8 @@ export interface ZhinAgentConfig {
|
|
|
76
76
|
topicChangeThreshold?: number;
|
|
77
77
|
rateLimit?: RateLimitConfig;
|
|
78
78
|
toneAwareness?: boolean;
|
|
79
|
+
/** 聊天任务使用的模型(覆盖自动选择) */
|
|
80
|
+
chatModel?: string;
|
|
79
81
|
visionModel?: string;
|
|
80
82
|
contextTokens?: number;
|
|
81
83
|
maxHistoryShare?: number;
|
|
@@ -105,6 +107,7 @@ export const DEFAULT_CONFIG: Required<ZhinAgentConfig> = {
|
|
|
105
107
|
topicChangeThreshold: 0.15,
|
|
106
108
|
rateLimit: {},
|
|
107
109
|
toneAwareness: true,
|
|
110
|
+
chatModel: '',
|
|
108
111
|
visionModel: '',
|
|
109
112
|
contextTokens: DEFAULT_CONTEXT_TOKENS,
|
|
110
113
|
maxHistoryShare: 0.5,
|
|
@@ -273,8 +273,8 @@ export function applyExecPolicyToTools(config: Required<ZhinAgentConfig>, tools:
|
|
|
273
273
|
const result = checkExecPolicy(config, cmd);
|
|
274
274
|
if (!result.allowed) {
|
|
275
275
|
if (result.needsApproval) {
|
|
276
|
-
// 返回可读消息让 AI 用 ask_user
|
|
277
|
-
return `⚠️ ${result.reason}\n请使用 ask_user
|
|
276
|
+
// 返回可读消息让 AI 用 ask_user 向 Owner 确认
|
|
277
|
+
return `⚠️ ${result.reason}\n请使用 ask_user 工具向 Owner 确认是否允许执行此命令。`;
|
|
278
278
|
}
|
|
279
279
|
throw new Error(result.reason!);
|
|
280
280
|
}
|
package/src/zhin-agent/index.ts
CHANGED
|
@@ -24,6 +24,7 @@ import type { ContextManager } from '@zhin.js/ai';
|
|
|
24
24
|
import { ConversationMemory } from '@zhin.js/ai';
|
|
25
25
|
import type { OutputElement } from '@zhin.js/ai';
|
|
26
26
|
import { parseOutput } from '@zhin.js/ai';
|
|
27
|
+
import type { ModelRegistry } from '@zhin.js/ai';
|
|
27
28
|
import { UserProfileStore } from '../user-profile.js';
|
|
28
29
|
import { RateLimiter } from '@zhin.js/ai';
|
|
29
30
|
import { detectTone } from '@zhin.js/ai';
|
|
@@ -87,6 +88,7 @@ export class ZhinAgent {
|
|
|
87
88
|
private bootstrapContext: string = '';
|
|
88
89
|
private activeSkillsContext: string = '';
|
|
89
90
|
private skillsSummaryXML: string = '';
|
|
91
|
+
private modelRegistry: ModelRegistry | null = null;
|
|
90
92
|
|
|
91
93
|
constructor(provider: AIProvider, config?: ZhinAgentConfig) {
|
|
92
94
|
this.provider = provider;
|
|
@@ -120,6 +122,10 @@ export class ZhinAgent {
|
|
|
120
122
|
manager.setAIProvider(this.provider);
|
|
121
123
|
}
|
|
122
124
|
|
|
125
|
+
setModelRegistry(registry: ModelRegistry): void {
|
|
126
|
+
this.modelRegistry = registry;
|
|
127
|
+
}
|
|
128
|
+
|
|
123
129
|
upgradeMemoryToDatabase(msgModel: any, sumModel: any): void {
|
|
124
130
|
this.memory.upgradeToDatabase(msgModel, sumModel);
|
|
125
131
|
}
|
|
@@ -165,6 +171,41 @@ export class ZhinAgent {
|
|
|
165
171
|
return this.userProfiles;
|
|
166
172
|
}
|
|
167
173
|
|
|
174
|
+
/** 根据任务类型选择最合适的模型,优先使用 config 显式指定,其次 ModelRegistry,回退到 provider.models[0] */
|
|
175
|
+
private resolveModel(task: 'chat' | 'vision' | 'tool_call' | 'summary' = 'chat', preferred?: string): string {
|
|
176
|
+
return this.resolveModelCandidates(task, preferred)[0];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* 返回按优先级排序的候选模型列表(用于自动降级)。
|
|
181
|
+
* 第一个是最优选择,失败后依次尝试后续模型。
|
|
182
|
+
*/
|
|
183
|
+
private resolveModelCandidates(task: 'chat' | 'vision' | 'tool_call' | 'summary' = 'chat', preferred?: string): string[] {
|
|
184
|
+
const candidates: string[] = [];
|
|
185
|
+
|
|
186
|
+
// 1. 用户显式指定 / 配置指定优先
|
|
187
|
+
if (preferred) candidates.push(preferred);
|
|
188
|
+
if (task === 'chat' && this.config.chatModel && !candidates.includes(this.config.chatModel)) {
|
|
189
|
+
candidates.push(this.config.chatModel);
|
|
190
|
+
}
|
|
191
|
+
if (task === 'vision' && this.config.visionModel && !candidates.includes(this.config.visionModel)) {
|
|
192
|
+
candidates.push(this.config.visionModel);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// 2. ModelRegistry 自动排序的候选列表
|
|
196
|
+
if (this.modelRegistry) {
|
|
197
|
+
for (const id of this.modelRegistry.selectModels(this.provider.name, task, 5)) {
|
|
198
|
+
if (!candidates.includes(id)) candidates.push(id);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// 3. 兜底: provider.models[0]
|
|
203
|
+
const fallback = this.provider.models[0];
|
|
204
|
+
if (fallback && !candidates.includes(fallback)) candidates.push(fallback);
|
|
205
|
+
|
|
206
|
+
return candidates;
|
|
207
|
+
}
|
|
208
|
+
|
|
168
209
|
registerTool(tool: AgentTool): () => void {
|
|
169
210
|
this.externalTools.set(tool.name, tool);
|
|
170
211
|
return () => { this.externalTools.delete(tool.name); };
|
|
@@ -350,7 +391,10 @@ ${preData ? `\nPre-fetched data:\n${preData}\n` : ''}`;
|
|
|
350
391
|
? this.config.maxIterations + SKILL_ITERATION_BOOST
|
|
351
392
|
: this.config.maxIterations;
|
|
352
393
|
|
|
394
|
+
const chatCandidates = this.resolveModelCandidates('chat');
|
|
353
395
|
const agent = createAgent(this.provider, {
|
|
396
|
+
model: chatCandidates[0],
|
|
397
|
+
modelFallbacks: chatCandidates.slice(1),
|
|
354
398
|
systemPrompt,
|
|
355
399
|
tools: agentTools,
|
|
356
400
|
maxIterations: effectiveMaxIterations,
|
|
@@ -428,7 +472,7 @@ ${preData ? `\nPre-fetched data:\n${preData}\n` : ''}`;
|
|
|
428
472
|
}
|
|
429
473
|
|
|
430
474
|
const textContent = textFragments.join(' ') || '[多模态消息]';
|
|
431
|
-
const
|
|
475
|
+
const visionCandidates = this.resolveModelCandidates('vision');
|
|
432
476
|
|
|
433
477
|
const messages: ChatMessage[] = [
|
|
434
478
|
{ role: 'system', content: personaEnhanced },
|
|
@@ -437,27 +481,39 @@ ${preData ? `\nPre-fetched data:\n${preData}\n` : ''}`;
|
|
|
437
481
|
];
|
|
438
482
|
|
|
439
483
|
let reply = '';
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
const
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
484
|
+
for (let i = 0; i < visionCandidates.length; i++) {
|
|
485
|
+
const visionModel = visionCandidates[i];
|
|
486
|
+
try {
|
|
487
|
+
reply = '';
|
|
488
|
+
for await (const chunk of this.provider.chatStream({ model: visionModel, messages })) {
|
|
489
|
+
const delta = chunk.choices?.[0]?.delta;
|
|
490
|
+
if (!delta) continue;
|
|
491
|
+
const text = typeof delta.content === 'string' ? delta.content : '';
|
|
492
|
+
if (text) {
|
|
493
|
+
reply += text;
|
|
494
|
+
if (onChunk) onChunk(text, reply);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
reply = stripThinkBlocks(reply);
|
|
498
|
+
if (!reply) {
|
|
499
|
+
logger.warn(`[processMultimodal] ${visionModel} 流式为空,尝试非流式`);
|
|
500
|
+
const response = await this.provider.chat({ model: visionModel, messages });
|
|
501
|
+
const msg = response.choices[0]?.message?.content;
|
|
502
|
+
reply = stripThinkBlocks(typeof msg === 'string' ? msg : '');
|
|
503
|
+
}
|
|
504
|
+
if (reply) break; // 成功,退出循环
|
|
505
|
+
} catch (err) {
|
|
506
|
+
const isLast = i === visionCandidates.length - 1;
|
|
507
|
+
if (isLast) {
|
|
508
|
+
try {
|
|
509
|
+
const response = await this.provider.chat({ model: visionModel, messages });
|
|
510
|
+
const msg = response.choices[0]?.message?.content;
|
|
511
|
+
reply = stripThinkBlocks(typeof msg === 'string' ? msg : '');
|
|
512
|
+
} catch { /* all candidates exhausted */ }
|
|
513
|
+
} else {
|
|
514
|
+
logger.warn(`[processMultimodal] ${visionModel} 失败,降级到 ${visionCandidates[i + 1]}: ${(err as Error).message}`);
|
|
448
515
|
}
|
|
449
516
|
}
|
|
450
|
-
reply = stripThinkBlocks(reply);
|
|
451
|
-
if (!reply) {
|
|
452
|
-
logger.warn('[processMultimodal] 流式响应内容为空,尝试非流式回退');
|
|
453
|
-
const response = await this.provider.chat({ model: visionModel, messages });
|
|
454
|
-
const msg = response.choices[0]?.message?.content;
|
|
455
|
-
reply = stripThinkBlocks(typeof msg === 'string' ? msg : '');
|
|
456
|
-
}
|
|
457
|
-
} catch {
|
|
458
|
-
const response = await this.provider.chat({ model: visionModel, messages });
|
|
459
|
-
const msg = response.choices[0]?.message?.content;
|
|
460
|
-
reply = stripThinkBlocks(typeof msg === 'string' ? msg : '');
|
|
461
517
|
}
|
|
462
518
|
|
|
463
519
|
if (!reply) reply = '抱歉,我无法理解这条消息。';
|
|
@@ -477,7 +533,7 @@ ${preData ? `\nPre-fetched data:\n${preData}\n` : ''}`;
|
|
|
477
533
|
history: ChatMessage[],
|
|
478
534
|
onChunk?: OnChunkCallback,
|
|
479
535
|
): Promise<string> {
|
|
480
|
-
const
|
|
536
|
+
const candidates = this.resolveModelCandidates('chat');
|
|
481
537
|
const userContent = history.length > 0
|
|
482
538
|
? buildUserMessageWithHistory(history, content)
|
|
483
539
|
: content;
|
|
@@ -486,30 +542,48 @@ ${preData ? `\nPre-fetched data:\n${preData}\n` : ''}`;
|
|
|
486
542
|
{ role: 'user', content: userContent },
|
|
487
543
|
];
|
|
488
544
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
if (
|
|
545
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
546
|
+
const model = candidates[i];
|
|
547
|
+
try {
|
|
548
|
+
let result = '';
|
|
549
|
+
for await (const chunk of this.provider.chatStream({ model, messages })) {
|
|
550
|
+
const delta = chunk.choices?.[0]?.delta;
|
|
551
|
+
if (!delta) continue;
|
|
552
|
+
const text = typeof delta.content === 'string' ? delta.content : '';
|
|
553
|
+
if (text) {
|
|
554
|
+
result += text;
|
|
555
|
+
if (onChunk) onChunk(text, result);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
result = stripThinkBlocks(result);
|
|
559
|
+
if (result) return result;
|
|
560
|
+
// Streaming returned empty content — try non-streaming with same model
|
|
561
|
+
logger.warn(`[streamChat] ${model} 流式响应为空,尝试非流式`);
|
|
562
|
+
const response = await this.provider.chat({ model, messages });
|
|
563
|
+
const msg = response.choices[0]?.message?.content;
|
|
564
|
+
result = stripThinkBlocks(typeof msg === 'string' ? msg : '');
|
|
565
|
+
if (result) {
|
|
566
|
+
if (onChunk) onChunk(result, result);
|
|
567
|
+
return result;
|
|
568
|
+
}
|
|
569
|
+
} catch (err) {
|
|
570
|
+
const isLast = i === candidates.length - 1;
|
|
571
|
+
if (isLast) {
|
|
572
|
+
// No more candidates — try non-streaming as final attempt
|
|
573
|
+
try {
|
|
574
|
+
const response = await this.provider.chat({ model, messages });
|
|
575
|
+
const msg = response.choices[0]?.message?.content;
|
|
576
|
+
let result = stripThinkBlocks(typeof msg === 'string' ? msg : '');
|
|
577
|
+
if (onChunk && result) onChunk(result, result);
|
|
578
|
+
return result;
|
|
579
|
+
} catch {
|
|
580
|
+
return '';
|
|
581
|
+
}
|
|
498
582
|
}
|
|
583
|
+
logger.warn(`[streamChat] ${model} 失败,降级到 ${candidates[i + 1]}: ${(err as Error).message}`);
|
|
499
584
|
}
|
|
500
|
-
result = stripThinkBlocks(result);
|
|
501
|
-
if (result) return result;
|
|
502
|
-
// Streaming returned empty content — fall back to non-streaming
|
|
503
|
-
logger.warn('[streamChat] 流式响应内容为空,尝试非流式回退');
|
|
504
|
-
} catch {
|
|
505
|
-
// Stream failed — fall back to non-streaming
|
|
506
585
|
}
|
|
507
|
-
|
|
508
|
-
const msg = response.choices[0]?.message?.content;
|
|
509
|
-
let result = typeof msg === 'string' ? msg : '';
|
|
510
|
-
result = stripThinkBlocks(result);
|
|
511
|
-
if (onChunk && result) onChunk(result, result);
|
|
512
|
-
return result;
|
|
586
|
+
return '';
|
|
513
587
|
}
|
|
514
588
|
|
|
515
589
|
private async saveToSession(
|