@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.
@@ -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.19",
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.17",
18
- "@zhin.js/core": "1.0.56"
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",
@@ -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: '要向用户提出的问题文本' }, true)
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: '等待用户回复的超时时间(秒),默认 120' })
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
- switch (questionType) {
818
- case 'number': {
819
- const defaultNum = args.default_value != null ? Number(args.default_value) : undefined;
820
- const result = await prompt.number(args.question, timeoutMs, defaultNum, '输入超时,已取消');
821
- return String(result);
822
- }
823
- case 'confirm': {
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 `用户未响应或输入错误: ${errMsg(e)}`;
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: permissions.permissionLevel,
172
+ senderPermissionLevel: permissionLevel,
161
173
  isGroupAdmin: permissions.isGroupAdmin,
162
174
  isGroupOwner: permissions.isGroupOwner,
163
- isBotAdmin: permissions.isBotAdmin,
164
- isOwner: permissions.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[] {
@@ -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
  }
@@ -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 visionModel = this.config.visionModel || this.provider.models[0];
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
- try {
441
- for await (const chunk of this.provider.chatStream({ model: visionModel, messages })) {
442
- const delta = chunk.choices?.[0]?.delta;
443
- if (!delta) continue;
444
- const text = typeof delta.content === 'string' ? delta.content : '';
445
- if (text) {
446
- reply += text;
447
- if (onChunk) onChunk(text, reply);
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 model = this.provider.models[0];
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
- try {
490
- let result = '';
491
- for await (const chunk of this.provider.chatStream({ model, messages })) {
492
- const delta = chunk.choices?.[0]?.delta;
493
- if (!delta) continue;
494
- const text = typeof delta.content === 'string' ? delta.content : '';
495
- if (text) {
496
- result += text;
497
- if (onChunk) onChunk(text, result);
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
- const response = await this.provider.chat({ model, messages });
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(