fix: make local knowledge bases ready for daily use

Knowledge selection was shared globally, document readiness overstated usable content, and important import and source-management paths exposed technical details or lacked safe recovery actions. Knowledge scope now persists per conversation, readiness reflects real processing channels, and the workspace guides users from creation and import into cited chat with controlled source actions.

Release note: 知识库现按对话保存使用范围,准确区分可用、处理中和失败文档,并提供更简洁的创建、检索测试、来源打开、删除确认和失败重试流程。
This commit is contained in:
mesalogo
2026-09-05 15:51:07 +08:00
parent d5fa0ec67c
commit dd8289fdef
29 changed files with 1395 additions and 87 deletions
@@ -3954,6 +3954,9 @@ describe('AssistantDatabase', () => {
provider: 'model',
profileId: '00000000-0000-4000-8000-000000000299'
},
knowledgeLibraryIds: [
'00000000-0000-4000-8000-000000000214'
],
knowledgeRetrievalMode: 'always',
title: '发布讨论',
updatedAt: 1_775_000_000_000,
@@ -4055,6 +4058,9 @@ describe('AssistantDatabase', () => {
provider: 'model',
profileId: '00000000-0000-4000-8000-000000000299'
},
knowledgeLibraryIds: [
'00000000-0000-4000-8000-000000000214'
],
knowledgeRetrievalMode: 'always',
messages: [
expect.objectContaining({
@@ -4442,6 +4448,9 @@ describe('AssistantDatabase', () => {
provider: 'model',
profileId: channelDefaultProfileId
},
knowledgeLibraryIds: [
'00000000-0000-4000-8000-000000000559'
],
knowledgeRetrievalMode: 'always',
contextMetrics: {
runtimeSelectionKey: `model:${channelDefaultProfileId}`,
@@ -4550,6 +4559,9 @@ describe('AssistantDatabase', () => {
provider: 'model',
profileId: channelDefaultProfileId
},
knowledgeLibraryIds: [
'00000000-0000-4000-8000-000000000559'
],
knowledgeRetrievalMode: 'always',
branch: {
sourceConversationId,
@@ -4623,6 +4635,7 @@ describe('AssistantDatabase', () => {
id: branch.id,
projectId: branch.projectId,
runtimeSelection: branch.runtimeSelection,
knowledgeLibraryIds: branch.knowledgeLibraryIds,
knowledgeRetrievalMode: branch.knowledgeRetrievalMode,
branch: branch.branch,
title: '发布方案讨论 · 分支(独立更新)',
+15 -6
View File
@@ -1033,6 +1033,7 @@ function interruptActiveToolBlocks(
}
const conversationContextStateSchema = conversationSnapshotSchema.pick({
knowledgeLibraryIds: true,
contextMetrics: true,
contextCompressionState: true
})
@@ -1041,7 +1042,7 @@ function parseConversationContextState(
value: string | null
): Pick<
ConversationSnapshot,
'contextMetrics' | 'contextCompressionState'
'knowledgeLibraryIds' | 'contextMetrics' | 'contextCompressionState'
> {
if (!value) {
return {}
@@ -1059,12 +1060,14 @@ function parseConversationContextState(
function serializeConversationContextState(
conversation: Pick<
ConversationSnapshot,
'contextMetrics' | 'contextCompressionState'
'knowledgeLibraryIds' | 'contextMetrics' | 'contextCompressionState'
>
): string | null {
return conversation.contextMetrics ||
return conversation.knowledgeLibraryIds !== undefined ||
conversation.contextMetrics ||
conversation.contextCompressionState
? JSON.stringify({
knowledgeLibraryIds: conversation.knowledgeLibraryIds,
contextMetrics: conversation.contextMetrics,
contextCompressionState: conversation.contextCompressionState
})
@@ -1081,9 +1084,9 @@ function toConversationSnapshot(
runtimeSelection: parseRuntimeSelection(
conversation.runtime_selection_json
),
...parseConversationContextState(conversation.context_state_json),
knowledgeRetrievalMode:
conversation.knowledge_retrieval_mode ?? undefined,
...parseConversationContextState(conversation.context_state_json),
...(conversation.channel &&
conversation.conversation_type &&
conversation.account_display
@@ -2992,7 +2995,7 @@ export class AssistantDatabase {
const source = database
.prepare(
`SELECT id, project_id, runtime_selection_json,
knowledge_retrieval_mode, title
knowledge_retrieval_mode, context_state_json, title
FROM conversations
WHERE id = ? AND status = 'active' AND channel IS NULL`
)
@@ -3002,6 +3005,7 @@ export class AssistantDatabase {
project_id: string | null
runtime_selection_json: string | null
knowledge_retrieval_mode: 'auto' | 'always' | null
context_state_json: string | null
title: string
}
| undefined
@@ -3052,13 +3056,18 @@ export class AssistantDatabase {
knowledge_retrieval_mode, context_state_json, work_mode,
title, branch_source_conversation_id, branch_source_title,
status, created_at, updated_at)
VALUES (?, ?, ?, ?, NULL, 'ask', ?, ?, ?, 'active', ?, ?)`
VALUES (?, ?, ?, ?, ?, 'ask', ?, ?, ?, 'active', ?, ?)`
)
.run(
destinationConversationId,
source.project_id,
source.runtime_selection_json,
source.knowledge_retrieval_mode,
serializeConversationContextState({
knowledgeLibraryIds:
parseConversationContextState(source.context_state_json)
.knowledgeLibraryIds
}),
input.title,
source.id,
source.title,