From 020a9ad0dcad965d786fd268a306bec072ef3f99 Mon Sep 17 00:00:00 2001 From: mesalogo Date: Thu, 10 Sep 2026 10:36:26 +0800 Subject: [PATCH] fix: retain conversation retrieval settings for scheduled messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Persist the conversation knowledge retrieval mode across restarts so timed messages use the saved setting. Clarify shared conversation authorization in the scheduled-task documentation and correct the renderer test query type. Validation: 374 focused tests passed; typecheck and lint passed. The full suite had two failures that passed on focused reruns. Real remote validation remains blocked by the temporary harness SDK module loading error; no model requests were made. Release note: 修复会话知识检索模式在重启后丢失的问题,定时消息继续使用会话保存的检索设置,并同步任务授权说明。 --- .../task-and-job/scheduled-task-prd.md | 10 ++-- src/main/assistant/assistant-database.test.ts | 4 +- src/main/assistant/assistant-database.ts | 54 ++++++++++--------- src/renderer/src/App.test.tsx | 2 +- 4 files changed, 38 insertions(+), 32 deletions(-) diff --git a/docs/features/task-and-job/scheduled-task-prd.md b/docs/features/task-and-job/scheduled-task-prd.md index 4706d4c0..8e352839 100644 --- a/docs/features/task-and-job/scheduled-task-prd.md +++ b/docs/features/task-and-job/scheduled-task-prd.md @@ -162,12 +162,10 @@ GoodBuddy Desktop · 项目工作目录 ### 6.3 审批 -- Execute 继续遵守当前 Runtime、GoodBuddy 原生能力和工具审批控制。 -- 已启用且按现有策略允许自动执行的工具可以在后台运行。 -- 需要额外确认的动作进入 `waiting_approval`,暂停所属 Job 并发送应用内及桌面通知。 -- 用户批准后继续同一个 Job/Run;拒绝后按协议失败、跳过或请求调整。 -- 定时触发不能把高风险、越界或未授权动作转换成自动批准。 -- 结果未知的外部副作用进入 `outcome_unknown`,不得自动重试。 +- 使用普通会话的授权和提问流程。Agent Runtime 的 Execute 工具调用无需通用 GoodBuddy 审批,工具活动仍显示在会话中。 +- GoodBuddy 配置修改等原生确认保持各自的确认流程。需要用户回答的问题显示在关联会话中,不因定时触发直接判为失败。 +- Ask 在 Runtime 边界保持只读;计划不增加另一层工具限制。 +- `outcome_unknown` 等高级执行治理尚未实现,见第 2 节的范围说明。 ## 7. 触发器 diff --git a/src/main/assistant/assistant-database.test.ts b/src/main/assistant/assistant-database.test.ts index ffdc2d15..0cedf5a5 100644 --- a/src/main/assistant/assistant-database.test.ts +++ b/src/main/assistant/assistant-database.test.ts @@ -148,6 +148,7 @@ describe('AssistantDatabase', () => { const { messages, ...header } = conversation database.saveLocalConversations([{ header: { ...header, workMode: 'execute', + knowledgeRetrievalMode: 'always', runtimeSelection: { provider: 'continue' } }, messages }]) const existing = database.createSchedule({ @@ -159,7 +160,8 @@ describe('AssistantDatabase', () => { database.close() database.initialize('C:\\Workspace') expect(database.getConversation(conversation.id)).toMatchObject({ - workMode: 'execute', runtimeSelection: { provider: 'continue' } + workMode: 'execute', runtimeSelection: { provider: 'continue' }, + knowledgeRetrievalMode: 'always' }) database.close() }) diff --git a/src/main/assistant/assistant-database.ts b/src/main/assistant/assistant-database.ts index e05b69aa..5d7f382a 100644 --- a/src/main/assistant/assistant-database.ts +++ b/src/main/assistant/assistant-database.ts @@ -1049,6 +1049,7 @@ function interruptActiveToolBlocks( const conversationContextStateSchema = conversationSnapshotSchema.pick({ workMode: true, knowledgeLibraryIds: true, + knowledgeRetrievalMode: true, contextMetrics: true, contextCompressionState: true }) @@ -1057,7 +1058,7 @@ function parseConversationContextState( value: string | null ): Pick< ConversationSnapshot, - 'workMode' | 'knowledgeLibraryIds' | 'contextMetrics' | 'contextCompressionState' + 'workMode' | 'knowledgeLibraryIds' | 'knowledgeRetrievalMode' | 'contextMetrics' | 'contextCompressionState' > { if (!value) { return {} @@ -1075,15 +1076,18 @@ function parseConversationContextState( function serializeConversationContextState( conversation: Pick< ConversationSnapshot, - 'workMode' | 'knowledgeLibraryIds' | 'contextMetrics' | 'contextCompressionState' + 'workMode' | 'knowledgeLibraryIds' | 'knowledgeRetrievalMode' | 'contextMetrics' | 'contextCompressionState' > ): string | null { - return conversation.workMode !== undefined || conversation.knowledgeLibraryIds !== undefined || + return conversation.workMode !== undefined || + conversation.knowledgeLibraryIds !== undefined || + conversation.knowledgeRetrievalMode !== undefined || conversation.contextMetrics || conversation.contextCompressionState ? JSON.stringify({ workMode: conversation.workMode, knowledgeLibraryIds: conversation.knowledgeLibraryIds, + knowledgeRetrievalMode: conversation.knowledgeRetrievalMode, contextMetrics: conversation.contextMetrics, contextCompressionState: conversation.contextCompressionState }) @@ -5974,29 +5978,31 @@ export class AssistantDatabase { const database = this.requireDatabase() database.exec('BEGIN IMMEDIATE') try { - const result = database - .prepare( - `UPDATE conversation_queue_items - SET status = 'pending' - WHERE id = ? AND status = 'dispatching'` - ) - .run(itemId) - if ( - result.changes !== 1 && - !this.requireDatabase() + const result = database .prepare( - `SELECT 1 - FROM conversation_queue_items - WHERE id = ? AND status = 'pending'` + `UPDATE conversation_queue_items + SET status = 'pending' + WHERE id = ? AND status = 'dispatching'` ) - .get(itemId) - ) { - throw new Error('待发送消息不存在或状态已变化') - } - database.prepare(`UPDATE schedule_runs SET status = 'pending' - WHERE id = (SELECT schedule_run_id FROM conversation_queue_items WHERE id = ?) - AND status = 'running'`).run(itemId) - database.exec('COMMIT') + .run(itemId) + if ( + result.changes !== 1 && + !database + .prepare( + `SELECT 1 + FROM conversation_queue_items + WHERE id = ? AND status = 'pending'` + ) + .get(itemId) + ) { + throw new Error('待发送消息不存在或状态已变化') + } + database.prepare( + `UPDATE schedule_runs SET status = 'pending' + WHERE id = (SELECT schedule_run_id FROM conversation_queue_items WHERE id = ?) + AND status = 'running'` + ).run(itemId) + database.exec('COMMIT') } catch (error) { database.exec('ROLLBACK') throw error diff --git a/src/renderer/src/App.test.tsx b/src/renderer/src/App.test.tsx index 5f19646c..29e58fb0 100644 --- a/src/renderer/src/App.test.tsx +++ b/src/renderer/src/App.test.tsx @@ -6403,7 +6403,7 @@ describe("App", () => { fireEvent.change(screen.getByLabelText("向 GoodBuddy 提问"), { target: { value: "Verify inherited model" }, }); - fireEvent.click(screen.getByRole("button", { name: "发送", exact: true })); + fireEvent.click(screen.getByRole("button", { name: "发送" })); await waitFor(() => { const saved = vi.mocked(api.conversations.saveLocal).mock.calls .flatMap(([conversations]) => conversations)