feat: v0.3.17 修复多项问题(sandbox/全局配置层/继承选项/配置刷新/附件提示/content_filter 错误处理)

- fix: sandbox: true → false(ESM preload 不兼容 sandbox 导致 window.metona 不可用,选择文件夹按钮无反应)
- feat: 全局配置层(GlobalConfigService)— LLM/Agent 等配置跨工作空间共享,切换工作空间后不再丢失
  - 读取时工作空间 DB 空值或默认值回退到全局 JSON
  - 写入时双写(DB + 全局 JSON)
  - 首次启动迁移旧配置到全局层
- fix: 工作空间继承选项显示条件放宽 + push 前校验避免覆盖目标已有文件(SOUL.md/agent.db)
- fix: config:changed IPC 广播 + 前端监听,修改 Agent 配置后详情栏 maxIterations 实时刷新
- feat: 上传图片/文件时在 System Prompt 注入附件提示,避免 AI 在工作空间查找用户上传的文件
- feat: content_filter 错误识别(ContentFilterError)+ 友好提示,替代原始 JSON 错误体透传
- fix: JSDoc 注释中 llm.* / agent.* / onboarding.completed 中的 */ 被解析为注释结束符
This commit is contained in:
2026-07-22 13:12:15 +08:00
parent 9af9984418
commit 3e5ddea72d
12 changed files with 506 additions and 32 deletions
+17 -13
View File
@@ -148,11 +148,11 @@ function WorkspaceSettings() {
setApplying(true);
try {
// 如果勾选了继承文件,从旧工作空间复制到新工作空间
// - SOUL.md: Agent 身份定义
// - .metona/agent.db: 数据库(会话/消息/记忆/Trace),后端白名单校验
// - SOUL.md: Agent 身份定义(仅目标缺少时才继承,避免覆盖已有定义)
// - .metona/agent.db: 数据库(仅目标不存在时才继承,避免覆盖已有数据)
const filesToInherit: string[] = [];
if (inheritSoul) filesToInherit.push('SOUL.md');
if (inheritDatabase) filesToInherit.push('.metona/agent.db');
if (inheritSoul && checkResult?.missingFiles?.includes('SOUL.md')) filesToInherit.push('SOUL.md');
if (inheritDatabase && !checkResult?.dbExists) filesToInherit.push('.metona/agent.db');
// #51 修复: 继承数据库前校验源数据库完整性,避免继承损坏的数据库导致新工作空间数据丢失
if (inheritDatabase && currentPath) {
@@ -277,18 +277,22 @@ function WorkspaceSettings() {
</Alert>
)}
{/* 继承选项(仅当当前有工作空间且新工作空间需要创建文件时显示) */}
{currentPath && currentPath !== pendingPath && (checkResult.isNewWorkspace || (checkResult.missingFiles && checkResult.missingFiles.length > 0)) && (
{/* 继承选项(当前有工作空间、目标不是同一目录、且目标有可继承的文件时显示) */}
{currentPath && currentPath !== pendingPath &&
(checkResult.missingFiles?.includes('SOUL.md') || !checkResult.dbExists) && (
<Stack spacing={0.5} sx={{ mt: 0.5 }}>
<Typography variant="caption" sx={{ fontWeight: 600, color: 'text.secondary' }}>
</Typography>
<FormControlLabel
control={<Checkbox size="small" checked={inheritSoul} onChange={(e) => setInheritSoul(e.target.checked)} />}
label={<Typography variant="caption">SOUL.md</Typography>}
/>
{/* 数据库继承:仅在新工作空间(空目录)时显示,避免覆盖已有工作空间的数据 */}
{checkResult.isNewWorkspace && (
{/* SOUL.md 继承:目标缺少 SOUL.md 时才允许勾选,避免覆盖已有定义 */}
{checkResult.missingFiles && checkResult.missingFiles.includes('SOUL.md') && (
<FormControlLabel
control={<Checkbox size="small" checked={inheritSoul} onChange={(e) => setInheritSoul(e.target.checked)} />}
label={<Typography variant="caption">SOUL.md</Typography>}
/>
)}
{/* 数据库继承:目标 .metona/agent.db 不存在时才显示,避免覆盖已有工作空间数据 */}
{!checkResult.dbExists && (
<>
<FormControlLabel
control={<Checkbox size="small" checked={inheritDatabase} onChange={(e) => setInheritDatabase(e.target.checked)} />}
+25 -1
View File
@@ -400,10 +400,15 @@ export function useAgentStream(): void {
getStore().setCurrentRunId(null);
getStore().setAgentStatus('error');
getStore().updateLastTraceStep({ completedAt: Date.now() });
// v0.3.17: 对 content_filtered 错误码显示更友好的提示
const errorCode = data.error?.code;
const errorMessage = data.error?.message ?? '未知错误';
getStore().addMessage({
id: genMsgId('error'),
role: 'system',
content: `错误: ${data.error?.message ?? '未知错误'}`,
content: errorCode === 'content_filtered'
? `⚠️ ${errorMessage}`
: `错误: ${errorMessage}`,
timestamp: Date.now(),
});
break;
@@ -596,4 +601,23 @@ export function useAgentStream(): void {
return () => unsubscribe();
}, []);
// v0.3.17: 监听配置变更广播,实时更新 store 中的配置字段
// 解决场景:用户在 SettingsModal 修改 agent.maxIterations 后,详情栏分母不刷新
useEffect(() => {
if (!window.metona?.config?.onChanged) return;
const unsubscribe = window.metona.config.onChanged((data: { key: string; value: unknown }) => {
const store = useAgentStore.getState();
const { key, value } = data;
// 按需更新 store 中缓存的配置字段
if (key === 'agent.maxIterations' && typeof value === 'number') {
store.setMaxIterations(value);
}
// 其他 agent.* 配置项若 store 有对应字段,可在此扩展
});
return () => unsubscribe();
}, []);
}
+4
View File
@@ -164,6 +164,8 @@ interface MetonaConfigAPI {
set: (key: string, value: unknown) => Promise<{ success: boolean; error?: string }>;
// v0.3.9: 批量保存配置,避免串行保存中间态触发 reloadAdapter 失败
setBatch: (entries: Array<{ key: string; value: unknown }>) => Promise<{ success: boolean; error?: string }>;
// v0.3.17: 监听配置变更广播(后端 config:set/setBatch 后触发,用于前端 store 实时更新)
onChanged: (callback: (data: { key: string; value: unknown }) => void) => () => void;
}
// ===== App API =====
@@ -186,6 +188,8 @@ interface MetonaWorkspaceCheckResult {
exists?: boolean;
missingFiles?: string[];
isNewWorkspace?: boolean;
/** 目标目录下 .metona/agent.db 是否存在(用于判断是否显示"继承数据库"选项) */
dbExists?: boolean;
reason?: string;
}