feat: 升级至 v0.2.2 — 工作空间路径注入、Provider 切换修复、编码与样式优化

功能增强:
- System Prompt 注入当前工作空间路径到动态区(LLM 可使用绝对路径调用工具)
- ContextBuilder.buildSystemPrompt 新增 workspacePath 参数

Provider 切换修复:
- reloadAdapter 返回 boolean,失败时 sendMessage 中止发送
- 切换 Provider 时自动清空 apiKey(不同 Provider key 不通用)
- apiKey 为空时显示警告提示
- Provider 切换事件加 sessionId 字段

编码修复:
- run_command 使用 encoding: 'buffer' 获取原始字节
- 新增 decodeBuffer 智能解码:UTF-8 严格 → GBK → UTF-8 宽松
- 修复不响应 chcp 的 Windows 命令中文乱码问题

样式优化:
- 代码块底色改用主题变量(灰底主题色文字,双主题适配)
- 表格标题 th/td 底色和文字色改用主题变量
- CodeBlock 组件 pre 背景从 secondary.main 改为 background.default
- 设置面板已自动执行工具行 opacity 0.8→0.15(淡绿底,文字清晰)

版本号 0.2.1 → 0.2.2
This commit is contained in:
thzxx
2026-07-12 13:46:09 +08:00
parent 6e49c44742
commit aa13a98f63
9 changed files with 96 additions and 32 deletions
+18 -8
View File
@@ -7,6 +7,7 @@ import { Dialog, DialogContent, DialogTitle, Button, TextField, Select, MenuItem
import { X, Settings, Bot, Wrench, Server, Palette, FileText, Eye, EyeOff, FolderOpen, Globe } from 'lucide-react';
import { useUIStore, type ThemeMode } from '@renderer/stores/ui-store';
import { useAgentStore } from '@renderer/stores/agent-store';
import { PROVIDER_LABELS } from '@renderer/lib/constants';
type SettingsTab = 'workspace' | 'llm' | 'agent' | 'tools' | 'mcp' | 'searxng' | 'appearance' | 'logs';
const TABS: { id: SettingsTab; label: string; icon: typeof Settings }[] = [
@@ -118,11 +119,13 @@ function LLMSettings() {
}
}, [provider, numCtx]);
// 切换 Provider 时自动填充默认 URL + 清空 Ollama 的 apiKey
// 切换 Provider 时自动填充默认 URL + 清空 apiKey(不同 Provider 的 key 不通用)
const handleProviderChange = (newProvider: string) => {
const oldProvider = provider;
setProvider(newProvider);
// Ollama 不需要 API Key,切换到 Ollama 时清空旧 key
if (newProvider === 'ollama' && apiKey) {
// 切换 Provider 时清空 apiKey(不同 Provider 的 key 格式不同,避免用旧 key 调用新 API 导致 401
// Ollama 不需要 apiKey,也一并清空
if (oldProvider !== newProvider && apiKey) {
setApiKey('');
}
// 自动填充默认 URL(仅在 URL 为空或与旧 provider 默认 URL 匹配时)
@@ -146,9 +149,16 @@ function LLMSettings() {
<TextField size="small" label="API Base URL" value={baseURL} onChange={(e) => setBaseURL(e.target.value)} placeholder="如 https://api.deepseek.com" />
<TextField size="small" label="模型名称" value={model} onChange={(e) => setModel(e.target.value)} placeholder="如 deepseek-v4-pro、qwen3:latest" />
{provider !== 'ollama' && (
<TextField size="small" label="API Key" type={showKey ? 'text' : 'password'} value={apiKey} onChange={(e) => setApiKey(e.target.value)} placeholder="sk-..."
slotProps={{ input: { endAdornment: <IconButton size="small" onClick={() => setShowKey(!showKey)}>{showKey ? <EyeOff size={14} /> : <Eye size={14} />}</IconButton> } }}
/>
<>
<TextField size="small" label="API Key" type={showKey ? 'text' : 'password'} value={apiKey} onChange={(e) => setApiKey(e.target.value)} placeholder="sk-..."
slotProps={{ input: { endAdornment: <IconButton size="small" onClick={() => setShowKey(!showKey)}>{showKey ? <EyeOff size={14} /> : <Eye size={14} />}</IconButton> } }}
/>
{!apiKey && (
<Typography variant="caption" sx={{ color: 'warning.main', fontSize: 11 }}>
{PROVIDER_LABELS[provider] ?? provider} API Key
</Typography>
)}
</>
)}
{provider === 'ollama' && (
<TextField
@@ -292,9 +302,9 @@ function ToolsSettings() {
</Typography>
) : (
autoExecToolDetails.map((t) => (
<Stack key={t.name} direction="row" sx={{ py: 1, px: 1.5, borderRadius: 1.5, bgcolor: 'success.main', opacity: 0.8, justifyContent: 'space-between', alignItems: 'center' }}>
<Stack key={t.name} direction="row" sx={{ py: 1, px: 1.5, borderRadius: 1.5, bgcolor: 'success.main', opacity: 0.15, justifyContent: 'space-between', alignItems: 'center' }}>
<Stack direction="row" spacing={1} sx={{ alignItems: 'center', minWidth: 0, flex: 1 }}>
<Typography variant="body2" sx={{ fontFamily: 'monospace', fontSize: 12 }}>{t.name}</Typography>
<Typography variant="body2" sx={{ fontFamily: 'monospace', fontSize: 12, color: 'text.primary' }}>{t.name}</Typography>
<Chip label="自动" size="small" color="success" sx={{ height: 16, fontSize: 9 }} />
</Stack>
<Button size="small" color="warning" variant="outlined" sx={{ fontSize: 10, minWidth: 70 }} onClick={() => handleSetAutoExec(t.name, false)}>