fix: MiMo 上下文窗口 1M + Agnes 多模态支持 Base64
This commit is contained in:
@@ -332,8 +332,8 @@ Metona 通过统一的 `IMetonaProviderAdapter` 接口抽象了所有 LLM Provid
|
|||||||
| 适配器 | Provider | 模型 | 上下文 | 流式格式 | Thinking | 多模态 |
|
| 适配器 | Provider | 模型 | 上下文 | 流式格式 | Thinking | 多模态 |
|
||||||
|:---|:---|:---|:---|:---|:---|:---|
|
|:---|:---|:---|:---|:---|:---|:---|
|
||||||
| **DeepSeekAdapter** | `deepseek` | deepseek-v4-pro / deepseek-v4-flash | 1M tokens | SSE | `thinking.type` + `reasoning_effort` | 否 |
|
| **DeepSeekAdapter** | `deepseek` | deepseek-v4-pro / deepseek-v4-flash | 1M tokens | SSE | `thinking.type` + `reasoning_effort` | 否 |
|
||||||
| **AgnesAdapter** | `agnes` | agnes-2.0-flash | 1M tokens | SSE | `chat_template_kwargs` / Anthropic 兼容 | 是 (URL) |
|
| **AgnesAdapter** | `agnes` | agnes-2.0-flash | 1M tokens | SSE | `chat_template_kwargs` / Anthropic 兼容 | 是 (URL + Base64) |
|
||||||
| **MimoAdapter** | `mimo` | mimo-v2.5-pro / mimo-v2.5 | 131K tokens | SSE | `thinking.type: enabled` | 是 (URL + Base64) |
|
| **MimoAdapter** | `mimo` | mimo-v2.5-pro / mimo-v2.5 | 1M tokens | SSE | `thinking.type: enabled` | 是 (URL + Base64) |
|
||||||
| **OllamaAdapter** | `ollama` | qwen3 / gemma3 / deepseek-r1 等 | 可配 (num_ctx) | NDJSON | `think` 参数 | 是 (Base64) |
|
| **OllamaAdapter** | `ollama` | qwen3 / gemma3 / deepseek-r1 等 | 可配 (num_ctx) | NDJSON | `think` 参数 | 是 (Base64) |
|
||||||
|
|
||||||
### 适配器核心能力
|
### 适配器核心能力
|
||||||
@@ -622,7 +622,7 @@ VITE_APP_TITLE=MetonaAI Desktop
|
|||||||
| `agent.confirmationTimeoutMs` | `120000` | 确认弹窗超时 (30s ~ 600s) |
|
| `agent.confirmationTimeoutMs` | `120000` | 确认弹窗超时 (30s ~ 600s) |
|
||||||
| `deepseek.contextWindow` | `1000000` | DeepSeek 上下文窗口 |
|
| `deepseek.contextWindow` | `1000000` | DeepSeek 上下文窗口 |
|
||||||
| `agnes.contextWindow` | `1000000` | Agnes 上下文窗口 |
|
| `agnes.contextWindow` | `1000000` | Agnes 上下文窗口 |
|
||||||
| `mimo.contextWindow` | `131072` | MiMo 上下文窗口 |
|
| `mimo.contextWindow` | `1000000` | MiMo 上下文窗口 |
|
||||||
| `ollama.numCtx` | `4096` | Ollama num_ctx 参数 |
|
| `ollama.numCtx` | `4096` | Ollama num_ctx 参数 |
|
||||||
|
|
||||||
### SearXNG 元搜索引擎 (可选)
|
### SearXNG 元搜索引擎 (可选)
|
||||||
@@ -664,7 +664,7 @@ MetonaAI-Desktop/
|
|||||||
│ │ │ ├── 📄 base-adapter.ts # 抽象基类 (fetchWithTimeout)
|
│ │ │ ├── 📄 base-adapter.ts # 抽象基类 (fetchWithTimeout)
|
||||||
│ │ │ ├── 📄 deepseek.adapter.ts # DeepSeek v4 (SSE, 1M ctx)
|
│ │ │ ├── 📄 deepseek.adapter.ts # DeepSeek v4 (SSE, 1M ctx)
|
||||||
│ │ │ ├── 📄 agnes-ai.adapter.ts # Agnes AI 2.0 (SSE, 多模态)
|
│ │ │ ├── 📄 agnes-ai.adapter.ts # Agnes AI 2.0 (SSE, 多模态)
|
||||||
│ │ │ ├── 📄 mimo.adapter.ts # MiMo 2.5 (SSE, 131K ctx)
|
│ │ │ ├── 📄 mimo.adapter.ts # MiMo 2.5 (SSE, 1M ctx)
|
||||||
│ │ │ ├── 📄 ollama.adapter.ts # Ollama (NDJSON, 600 行)
|
│ │ │ ├── 📄 ollama.adapter.ts # Ollama (NDJSON, 600 行)
|
||||||
│ │ │ └── 📂 shared/ # 共享: OpenAI 格式 · SSE 解析
|
│ │ │ └── 📂 shared/ # 共享: OpenAI 格式 · SSE 解析
|
||||||
│ │ ├── 📂 tools/ # 工具系统
|
│ │ ├── 📂 tools/ # 工具系统
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* Agnes AI Provider Adapter
|
* Agnes AI Provider Adapter
|
||||||
*
|
*
|
||||||
* OpenAI 兼容 API。支持 Tool Calling、Thinking 模式、多模态(图片)。
|
* OpenAI 兼容 API。支持 Tool Calling、Thinking 模式、多模态(图片 — URL + Base64)。
|
||||||
*
|
*
|
||||||
* 独立继承 BaseAdapter,通过 shared/openai-format 和 shared/sse-stream 复用
|
* 独立继承 BaseAdapter,通过 shared/openai-format 和 shared/sse-stream 复用
|
||||||
* OpenAI 兼容格式构建和 SSE 流式解析逻辑。不与其他 Provider Adapter 耦合。
|
* OpenAI 兼容格式构建和 SSE 流式解析逻辑。不与其他 Provider Adapter 耦合。
|
||||||
@@ -37,7 +37,7 @@ export class AgnesAdapter extends BaseAdapter {
|
|||||||
maxOutputTokens: 65_536,
|
maxOutputTokens: 65_536,
|
||||||
supportsToolCalling: true,
|
supportsToolCalling: true,
|
||||||
supportsThinking: true,
|
supportsThinking: true,
|
||||||
description: 'Agnes AI 快速版,1M 上下文,支持多模态图片与思考模式',
|
description: 'Agnes AI 快速版,1M 上下文,支持多模态图片(URL + Base64)与思考模式',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -136,6 +136,7 @@ export class AgnesAdapter extends BaseAdapter {
|
|||||||
*
|
*
|
||||||
* Agnes AI 特有参数:
|
* Agnes AI 特有参数:
|
||||||
* - 多模态图片:user 消息的 images[] → OpenAI content 数组 [{type:"text"}, {type:"image_url"}]
|
* - 多模态图片:user 消息的 images[] → OpenAI content 数组 [{type:"text"}, {type:"image_url"}]
|
||||||
|
* 支持 HTTPS URL 或 base64 Data URI(与 MiMo 一致)
|
||||||
* - chat_template_kwargs: { enable_thinking: true } — 启用思考模式(非 thinking 字段)
|
* - chat_template_kwargs: { enable_thinking: true } — 启用思考模式(非 thinking 字段)
|
||||||
* - 默认 max_tokens: 65536(1M 上下文,65.5K 最大输出)
|
* - 默认 max_tokens: 65536(1M 上下文,65.5K 最大输出)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* MiMo (Xiaomi) Provider Adapter
|
* MiMo (Xiaomi) Provider Adapter
|
||||||
*
|
*
|
||||||
* 基于 OpenAI 兼容 API。支持 Tool Calling、Thinking 模式、流式输出。
|
* 基于 OpenAI 兼容 API。支持 Tool Calling、Thinking 模式、流式输出。
|
||||||
* 模型: mimo-v2.5-pro(131072 max_tokens)/ mimo-v2.5(32768 max_tokens)
|
* 模型: mimo-v2.5-pro(1M 上下文 / 131072 max_tokens)/ mimo-v2.5(1M 上下文 / 32768 max_tokens)
|
||||||
*
|
*
|
||||||
* 独立继承 BaseAdapter,通过 shared/openai-format 和 shared/sse-stream 复用
|
* 独立继承 BaseAdapter,通过 shared/openai-format 和 shared/sse-stream 复用
|
||||||
* OpenAI 兼容格式构建和 SSE 流式解析逻辑。不与其他 Provider Adapter 耦合。
|
* OpenAI 兼容格式构建和 SSE 流式解析逻辑。不与其他 Provider Adapter 耦合。
|
||||||
@@ -31,13 +31,12 @@ export class MimoAdapter extends BaseAdapter {
|
|||||||
readonly supportsThinking = true;
|
readonly supportsThinking = true;
|
||||||
|
|
||||||
// MiMo 模型元信息
|
// MiMo 模型元信息
|
||||||
// mimo-v2.5-pro: 131072 max_completion_tokens;mimo-v2.5: 32768
|
// mimo-v2.5-pro: 1M 上下文(与 DeepSeek 一致)/ 131072 max_tokens;mimo-v2.5: 1M 上下文 / 32768 max_tokens
|
||||||
// 官方未公布上下文窗口大小,保守设为 131072(与 pro 的 max_output 一致)
|
|
||||||
private static readonly MODEL_INFO: Record<string, MetonaModelInfo> = {
|
private static readonly MODEL_INFO: Record<string, MetonaModelInfo> = {
|
||||||
'mimo-v2.5-pro': {
|
'mimo-v2.5-pro': {
|
||||||
id: 'mimo-v2.5-pro',
|
id: 'mimo-v2.5-pro',
|
||||||
name: 'MiMo V2.5 Pro',
|
name: 'MiMo V2.5 Pro',
|
||||||
contextWindow: 131_072,
|
contextWindow: 1_000_000,
|
||||||
maxOutputTokens: 131_072,
|
maxOutputTokens: 131_072,
|
||||||
supportsToolCalling: true,
|
supportsToolCalling: true,
|
||||||
supportsThinking: true,
|
supportsThinking: true,
|
||||||
@@ -46,7 +45,7 @@ export class MimoAdapter extends BaseAdapter {
|
|||||||
'mimo-v2.5': {
|
'mimo-v2.5': {
|
||||||
id: 'mimo-v2.5',
|
id: 'mimo-v2.5',
|
||||||
name: 'MiMo V2.5',
|
name: 'MiMo V2.5',
|
||||||
contextWindow: 131_072,
|
contextWindow: 1_000_000,
|
||||||
maxOutputTokens: 32_768,
|
maxOutputTokens: 32_768,
|
||||||
supportsToolCalling: true,
|
supportsToolCalling: true,
|
||||||
supportsThinking: true,
|
supportsThinking: true,
|
||||||
@@ -143,7 +142,7 @@ export class MimoAdapter extends BaseAdapter {
|
|||||||
return this.config.contextWindow;
|
return this.config.contextWindow;
|
||||||
}
|
}
|
||||||
const modelInfo = MimoAdapter.MODEL_INFO[this.config.defaultModel];
|
const modelInfo = MimoAdapter.MODEL_INFO[this.config.defaultModel];
|
||||||
return modelInfo?.contextWindow ?? 131_072;
|
return modelInfo?.contextWindow ?? 1_000_000;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 私有方法 ==========
|
// ========== 私有方法 ==========
|
||||||
@@ -153,6 +152,7 @@ export class MimoAdapter extends BaseAdapter {
|
|||||||
*
|
*
|
||||||
* MiMo 特有参数:
|
* MiMo 特有参数:
|
||||||
* - 多模态图片:user 消息的 images[] → OpenAI content 数组 [{type:"text"}, {type:"image_url"}]
|
* - 多模态图片:user 消息的 images[] → OpenAI content 数组 [{type:"text"}, {type:"image_url"}]
|
||||||
|
* 支持 HTTPS URL 或 base64 Data URI
|
||||||
* - thinking: { type: "enabled" / "disabled" } — 与 DeepSeek 一致
|
* - thinking: { type: "enabled" / "disabled" } — 与 DeepSeek 一致
|
||||||
* - max_completion_tokens — 非 max_tokens(MiMo 使用新字段名)
|
* - max_completion_tokens — 非 max_tokens(MiMo 使用新字段名)
|
||||||
* - stream_options: { include_usage: true } — 流式返回 usage
|
* - stream_options: { include_usage: true } — 流式返回 usage
|
||||||
|
|||||||
@@ -394,8 +394,8 @@ export class DatabaseService {
|
|||||||
// v0.3.1: DeepSeek/Agnes 改为可配置,不再写死 1M
|
// v0.3.1: DeepSeek/Agnes 改为可配置,不再写死 1M
|
||||||
{ key: 'deepseek.contextWindow', value: '1000000', category: 'deepseek' },
|
{ key: 'deepseek.contextWindow', value: '1000000', category: 'deepseek' },
|
||||||
{ key: 'agnes.contextWindow', value: '1000000', category: 'agnes' },
|
{ key: 'agnes.contextWindow', value: '1000000', category: 'agnes' },
|
||||||
// v0.3.4: MiMo 上下文窗口(官方未公布,保守设为 131072)
|
// v0.3.4: MiMo 上下文窗口(与 DeepSeek 一致,1M)
|
||||||
{ key: 'mimo.contextWindow', value: '131072', category: 'mimo' },
|
{ key: 'mimo.contextWindow', value: '1000000', category: 'mimo' },
|
||||||
|
|
||||||
// Onboarding
|
// Onboarding
|
||||||
{ key: 'onboarding.completed', value: 'false', category: 'general' },
|
{ key: 'onboarding.completed', value: 'false', category: 'general' },
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export const SEED_DEFAULTS: Record<string, unknown> = {
|
|||||||
'ollama.numCtx': null,
|
'ollama.numCtx': null,
|
||||||
'deepseek.contextWindow': 1000000,
|
'deepseek.contextWindow': 1000000,
|
||||||
'agnes.contextWindow': 1000000,
|
'agnes.contextWindow': 1000000,
|
||||||
'mimo.contextWindow': 131072,
|
'mimo.contextWindow': 1000000,
|
||||||
'onboarding.completed': false,
|
'onboarding.completed': false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ export function OnboardingWizard(): React.JSX.Element | null {
|
|||||||
const DEFAULT_CTX: Record<string, number | null> = {
|
const DEFAULT_CTX: Record<string, number | null> = {
|
||||||
deepseek: 1_000_000,
|
deepseek: 1_000_000,
|
||||||
agnes: 1_000_000,
|
agnes: 1_000_000,
|
||||||
mimo: 131_072,
|
mimo: 1_000_000,
|
||||||
ollama: null,
|
ollama: null,
|
||||||
};
|
};
|
||||||
// 上下文窗口校验:ollama 允许空,最小 512;其他 provider 最小 4096
|
// 上下文窗口校验:ollama 允许空,最小 512;其他 provider 最小 4096
|
||||||
|
|||||||
@@ -364,7 +364,7 @@ function LLMSettings() {
|
|||||||
// v0.3.1: DeepSeek/Agnes/MiMo contextWindow 可配置(不再写死)
|
// v0.3.1: DeepSeek/Agnes/MiMo contextWindow 可配置(不再写死)
|
||||||
const [dsCtxWindow, setDsCtxWindow] = useState<number>(1000000);
|
const [dsCtxWindow, setDsCtxWindow] = useState<number>(1000000);
|
||||||
const [agnesCtxWindow, setAgnesCtxWindow] = useState<number>(1000000);
|
const [agnesCtxWindow, setAgnesCtxWindow] = useState<number>(1000000);
|
||||||
const [mimoCtxWindow, setMimoCtxWindow] = useState<number>(131072);
|
const [mimoCtxWindow, setMimoCtxWindow] = useState<number>(1000000);
|
||||||
const [showKey, setShowKey] = useState(false);
|
const [showKey, setShowKey] = useState(false);
|
||||||
const [loaded, setLoaded] = useState(false);
|
const [loaded, setLoaded] = useState(false);
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
@@ -608,11 +608,11 @@ function LLMSettings() {
|
|||||||
label="上下文窗口 (contextWindow)"
|
label="上下文窗口 (contextWindow)"
|
||||||
type="number"
|
type="number"
|
||||||
value={mimoCtxWindow}
|
value={mimoCtxWindow}
|
||||||
onChange={(e) => setMimoCtxWindow(Number(e.target.value) || 131072)}
|
onChange={(e) => setMimoCtxWindow(Number(e.target.value) || 1000000)}
|
||||||
placeholder="如 32768、65536、131072"
|
placeholder="如 65536、131072、1000000"
|
||||||
slotProps={{ htmlInput: { min: 4096, step: 4096 } }}
|
slotProps={{ htmlInput: { min: 4096, step: 4096 } }}
|
||||||
error={mimoCtxError}
|
error={mimoCtxError}
|
||||||
helperText={mimoCtxError ? '最小值为 4096' : '官方未公布具体值,默认 131072,用于压缩判断'}
|
helperText={mimoCtxError ? '最小值为 4096' : '默认 1000000(1M),用于上下文压缩判断'}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user