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:
@@ -163,6 +163,29 @@ export function registerAllIPCHandlers(
|
||||
log.warn('[AGENT] Memory retrieval failed, proceeding without memories:', err);
|
||||
}
|
||||
|
||||
// 附件提示注入:用户直接上传的文件/图片,避免 LLM 误以为需要在工作空间查找
|
||||
// 解决场景:用户上传图片后,AI 先在工作空间找图片,找不到才意识到是用户上传的
|
||||
const attachments = (userMessage as MetonaMessage & { attachments?: Array<{ name: string; type: string }> }).attachments;
|
||||
if (Array.isArray(attachments) && attachments.length > 0) {
|
||||
const attachmentList = attachments.map((att, i) => {
|
||||
const typeLabel = att.type === 'image' ? 'image' : att.type === 'text' ? 'text file' : 'file';
|
||||
const note = att.type === 'image'
|
||||
? 'visible via vision capability, do NOT search in workspace'
|
||||
: att.type === 'text'
|
||||
? 'content already inlined in the user message, do NOT search in workspace'
|
||||
: 'uploaded directly by user, do NOT search in workspace';
|
||||
return `${i + 1}. [${typeLabel}] ${att.name} — ${note}`;
|
||||
}).join('\n');
|
||||
|
||||
const attachmentBlock = `## User Attachments (Direct Upload)\nThe following files were uploaded directly by the user to this conversation. They are inline attachments, NOT workspace files:\n${attachmentList}`;
|
||||
|
||||
systemPrompt.dynamicReminders = systemPrompt.dynamicReminders
|
||||
? `${systemPrompt.dynamicReminders}\n\n---\n\n${attachmentBlock}`
|
||||
: attachmentBlock;
|
||||
|
||||
log.debug(`[AGENT] Injected ${attachments.length} attachment hints into system prompt`);
|
||||
}
|
||||
|
||||
// 监听 Agent Loop 事件
|
||||
// F8: 主进程 text_delta 节流合并
|
||||
// 问题:主进程 1:1 转发所有流式事件,text_delta 频率 30-50 次/秒,
|
||||
@@ -817,6 +840,11 @@ export function registerAllIPCHandlers(
|
||||
log.info(`[CONFIG] Log level updated to ${level}`);
|
||||
}
|
||||
|
||||
// 广播配置变更事件,前端监听后更新 store(如 maxIterations 显示)
|
||||
if (!mainWindow.isDestroyed()) {
|
||||
mainWindow.webContents.send('config:changed', { key, value });
|
||||
}
|
||||
|
||||
// 工作空间路径变更时写入独立文件(下次启动生效)
|
||||
if (key === 'workspace.path') {
|
||||
try {
|
||||
@@ -978,6 +1006,13 @@ export function registerAllIPCHandlers(
|
||||
log.info(`[CONFIG] Log level updated to ${logLevelValue}`);
|
||||
}
|
||||
|
||||
// 第四步半:广播所有配置变更事件,前端监听后更新 store
|
||||
if (!mainWindow.isDestroyed()) {
|
||||
for (const { key, value } of entries) {
|
||||
mainWindow.webContents.send('config:changed', { key, value });
|
||||
}
|
||||
}
|
||||
|
||||
// 第五步:工作空间路径写入独立文件(下次启动生效)
|
||||
if (workspacePathValue) {
|
||||
try {
|
||||
@@ -1061,7 +1096,7 @@ export function registerAllIPCHandlers(
|
||||
|
||||
// ===== 工作空间校验与继承 =====
|
||||
|
||||
// 校验工作空间路径:检测路径有效性 + 4 个必需文件状态
|
||||
// 校验工作空间路径:检测路径有效性 + 必需文件状态 + 数据库是否存在
|
||||
ipcMain.handle('workspace:check', async (_event, targetPath: string) => {
|
||||
if (!targetPath || typeof targetPath !== 'string') {
|
||||
return { valid: false, reason: '路径不能为空' };
|
||||
@@ -1080,6 +1115,7 @@ export function registerAllIPCHandlers(
|
||||
exists: false,
|
||||
missingFiles: ['SOUL.md', 'MEMORY.md'],
|
||||
isNewWorkspace: true,
|
||||
dbExists: false,
|
||||
reason: '目录不存在,将在切换后自动创建',
|
||||
};
|
||||
}
|
||||
@@ -1101,12 +1137,16 @@ export function registerAllIPCHandlers(
|
||||
if (!existsSync(join(resolvedPath, f))) missingFiles.push(f);
|
||||
}
|
||||
|
||||
// 校验 4: 检测 .metona/agent.db 是否存在(用于判断是否显示"继承数据库"选项)
|
||||
const dbExists = existsSync(join(resolvedPath, '.metona', 'agent.db'));
|
||||
|
||||
return {
|
||||
valid: true,
|
||||
path: resolvedPath,
|
||||
exists: true,
|
||||
missingFiles,
|
||||
isNewWorkspace: missingFiles.length === requiredFiles.length,
|
||||
dbExists,
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user