@zooique/memora 3.0.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +161 -1033
- package/README.en.md +46 -39
- package/README.md +40 -35
- package/config.example.json +1 -8
- package/dist/agent/agent.d.ts +88 -80
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/agent.js +272 -221
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/assembler.d.ts +22 -21
- package/dist/agent/assembler.d.ts.map +1 -1
- package/dist/agent/assembler.js +120 -46
- package/dist/agent/assembler.js.map +1 -1
- package/dist/agent/backgroundTasks.d.ts +194 -0
- package/dist/agent/backgroundTasks.d.ts.map +1 -0
- package/dist/agent/backgroundTasks.js +314 -0
- package/dist/agent/backgroundTasks.js.map +1 -0
- package/dist/agent/budget.d.ts +23 -5
- package/dist/agent/budget.d.ts.map +1 -1
- package/dist/agent/budget.js +8 -2
- package/dist/agent/budget.js.map +1 -1
- package/dist/agent/builtinToolHandlers.d.ts +29 -9
- package/dist/agent/builtinToolHandlers.d.ts.map +1 -1
- package/dist/agent/builtinToolHandlers.js +53 -13
- package/dist/agent/builtinToolHandlers.js.map +1 -1
- package/dist/agent/builtinTools.d.ts +15 -1
- package/dist/agent/builtinTools.d.ts.map +1 -1
- package/dist/agent/builtinTools.js +111 -30
- package/dist/agent/builtinTools.js.map +1 -1
- package/dist/agent/constants.d.ts +31 -6
- package/dist/agent/constants.d.ts.map +1 -1
- package/dist/agent/constants.js +38 -8
- package/dist/agent/constants.js.map +1 -1
- package/dist/agent/contextManager.d.ts +8 -0
- package/dist/agent/contextManager.d.ts.map +1 -1
- package/dist/agent/contextManager.js +45 -3
- package/dist/agent/contextManager.js.map +1 -1
- package/dist/agent/contextPreparer.d.ts +1 -1
- package/dist/agent/contextPreparer.d.ts.map +1 -1
- package/dist/agent/contextPreparer.js +15 -10
- package/dist/agent/contextPreparer.js.map +1 -1
- package/dist/agent/guardRail.d.ts +12 -1
- package/dist/agent/guardRail.d.ts.map +1 -1
- package/dist/agent/guardRail.js +37 -2
- package/dist/agent/guardRail.js.map +1 -1
- package/dist/agent/loop.d.ts +319 -34
- package/dist/agent/loop.d.ts.map +1 -1
- package/dist/agent/loop.js +713 -110
- package/dist/agent/loop.js.map +1 -1
- package/dist/agent/managers/archiveCoordinator.d.ts +19 -4
- package/dist/agent/managers/archiveCoordinator.d.ts.map +1 -1
- package/dist/agent/managers/archiveCoordinator.js +25 -4
- package/dist/agent/managers/archiveCoordinator.js.map +1 -1
- package/dist/agent/managers/chatLockManager.d.ts +3 -9
- package/dist/agent/managers/chatLockManager.d.ts.map +1 -1
- package/dist/agent/managers/chatLockManager.js +7 -25
- package/dist/agent/managers/chatLockManager.js.map +1 -1
- package/dist/agent/managers/llmCaller.d.ts.map +1 -1
- package/dist/agent/managers/llmCaller.js +27 -1
- package/dist/agent/managers/llmCaller.js.map +1 -1
- package/dist/agent/managers/loopMetrics.d.ts +14 -0
- package/dist/agent/managers/loopMetrics.d.ts.map +1 -1
- package/dist/agent/managers/loopMetrics.js +15 -0
- package/dist/agent/managers/loopMetrics.js.map +1 -1
- package/dist/agent/managers/memoryInspector.d.ts +13 -15
- package/dist/agent/managers/memoryInspector.d.ts.map +1 -1
- package/dist/agent/managers/memoryInspector.js +38 -49
- package/dist/agent/managers/memoryInspector.js.map +1 -1
- package/dist/agent/managers/roundSummaryGenerator.d.ts +31 -1
- package/dist/agent/managers/roundSummaryGenerator.d.ts.map +1 -1
- package/dist/agent/managers/roundSummaryGenerator.js +81 -6
- package/dist/agent/managers/roundSummaryGenerator.js.map +1 -1
- package/dist/agent/managers/sessionArchiver.d.ts +35 -3
- package/dist/agent/managers/sessionArchiver.d.ts.map +1 -1
- package/dist/agent/managers/sessionArchiver.js +34 -3
- package/dist/agent/managers/sessionArchiver.js.map +1 -1
- package/dist/agent/managers/sessionManager.d.ts +21 -88
- package/dist/agent/managers/sessionManager.d.ts.map +1 -1
- package/dist/agent/managers/sessionManager.js +94 -278
- package/dist/agent/managers/sessionManager.js.map +1 -1
- package/dist/agent/managers/toolCallHelpers.d.ts +109 -28
- package/dist/agent/managers/toolCallHelpers.d.ts.map +1 -1
- package/dist/agent/managers/toolCallHelpers.js +93 -37
- package/dist/agent/managers/toolCallHelpers.js.map +1 -1
- package/dist/agent/messageHistory.d.ts.map +1 -1
- package/dist/agent/messageHistory.js +9 -5
- package/dist/agent/messageHistory.js.map +1 -1
- package/dist/agent/seed/orchestrator.d.ts +12 -1
- package/dist/agent/seed/orchestrator.d.ts.map +1 -1
- package/dist/agent/seed/orchestrator.js +15 -4
- package/dist/agent/seed/orchestrator.js.map +1 -1
- package/dist/agent/seed/prepare.d.ts.map +1 -1
- package/dist/agent/seed/prepare.js +9 -4
- package/dist/agent/seed/prepare.js.map +1 -1
- package/dist/agent/seed/types.d.ts +11 -4
- package/dist/agent/seed/types.d.ts.map +1 -1
- package/dist/agent/seed/types.js +2 -2
- package/dist/agent/textSanitize.d.ts +36 -0
- package/dist/agent/textSanitize.d.ts.map +1 -0
- package/dist/agent/textSanitize.js +55 -0
- package/dist/agent/textSanitize.js.map +1 -0
- package/dist/agent/toolExecutor.d.ts +97 -26
- package/dist/agent/toolExecutor.d.ts.map +1 -1
- package/dist/agent/toolExecutor.js +444 -78
- package/dist/agent/toolExecutor.js.map +1 -1
- package/dist/agent/toolLedger.d.ts +93 -41
- package/dist/agent/toolLedger.d.ts.map +1 -1
- package/dist/agent/toolLedger.js +114 -42
- package/dist/agent/toolLedger.js.map +1 -1
- package/dist/agent/toolResultCache.js +1 -1
- package/dist/agent/toolResultOffload.d.ts +8 -0
- package/dist/agent/toolResultOffload.d.ts.map +1 -1
- package/dist/agent/toolResultOffload.js +10 -3
- package/dist/agent/toolResultOffload.js.map +1 -1
- package/dist/agent/toolRunner.d.ts +16 -7
- package/dist/agent/toolRunner.d.ts.map +1 -1
- package/dist/agent/toolRunner.js +74 -29
- package/dist/agent/toolRunner.js.map +1 -1
- package/dist/agent/tracer.d.ts +13 -1
- package/dist/agent/tracer.d.ts.map +1 -1
- package/dist/agent/types.d.ts +74 -30
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/code-exec/types.d.ts +9 -0
- package/dist/code-exec/types.d.ts.map +1 -1
- package/dist/index.d.ts +28 -41
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +65 -54
- package/dist/index.js.map +1 -1
- package/dist/logging/logger.d.ts +4 -1
- package/dist/logging/logger.d.ts.map +1 -1
- package/dist/logging/logger.js +5 -2
- package/dist/logging/logger.js.map +1 -1
- package/dist/memory/gcService.d.ts.map +1 -1
- package/dist/memory/gcService.js +3 -5
- package/dist/memory/gcService.js.map +1 -1
- package/dist/memory/inMemorySessionStore.d.ts +2 -2
- package/dist/memory/inMemorySessionStore.js +2 -2
- package/dist/memory/inMemoryStorage.d.ts +4 -3
- package/dist/memory/inMemoryStorage.d.ts.map +1 -1
- package/dist/memory/inMemoryStorage.js +2 -2
- package/dist/memory/inMemoryStorage.js.map +1 -1
- package/dist/memory/nodeSqliteStorage.d.ts +17 -0
- package/dist/memory/nodeSqliteStorage.d.ts.map +1 -0
- package/dist/memory/nodeSqliteStorage.js +393 -0
- package/dist/memory/nodeSqliteStorage.js.map +1 -0
- package/dist/memory/projectManager.d.ts +10 -20
- package/dist/memory/projectManager.d.ts.map +1 -1
- package/dist/memory/projectManager.js +27 -41
- package/dist/memory/projectManager.js.map +1 -1
- package/dist/memory/roundStore.d.ts +143 -82
- package/dist/memory/roundStore.d.ts.map +1 -1
- package/dist/memory/roundStore.js +4 -15
- package/dist/memory/roundStore.js.map +1 -1
- package/dist/memory/roundSummaryLookup.d.ts +26 -0
- package/dist/memory/roundSummaryLookup.d.ts.map +1 -0
- package/dist/memory/roundSummaryLookup.js +19 -0
- package/dist/memory/roundSummaryLookup.js.map +1 -0
- package/dist/memory/sessionStore.d.ts +19 -2
- package/dist/memory/sessionStore.d.ts.map +1 -1
- package/dist/memory/sessionStore.js.map +1 -1
- package/dist/memory/sourceValidation.d.ts +2 -13
- package/dist/memory/sourceValidation.d.ts.map +1 -1
- package/dist/memory/sourceValidation.js +5 -16
- package/dist/memory/sourceValidation.js.map +1 -1
- package/dist/memory/storageInterface.d.ts +26 -16
- package/dist/memory/storageInterface.d.ts.map +1 -1
- package/dist/memory/supersedeResolve.d.ts +39 -0
- package/dist/memory/supersedeResolve.d.ts.map +1 -0
- package/dist/memory/supersedeResolve.js +16 -0
- package/dist/memory/supersedeResolve.js.map +1 -0
- package/dist/memory/types.d.ts +10 -2
- package/dist/memory/types.d.ts.map +1 -1
- package/dist/memory/types.js +6 -1
- package/dist/memory/types.js.map +1 -1
- package/dist/role-pack/rolePackManager.d.ts +74 -33
- package/dist/role-pack/rolePackManager.d.ts.map +1 -1
- package/dist/role-pack/rolePackManager.js +112 -53
- package/dist/role-pack/rolePackManager.js.map +1 -1
- package/dist/role-pack/strategyKeys.d.ts +44 -0
- package/dist/role-pack/strategyKeys.d.ts.map +1 -1
- package/dist/role-pack/strategyKeys.js +55 -0
- package/dist/role-pack/strategyKeys.js.map +1 -1
- package/dist/role-pack/strategyResolver.d.ts +6 -1
- package/dist/role-pack/strategyResolver.d.ts.map +1 -1
- package/dist/role-pack/strategyResolver.js +20 -2
- package/dist/role-pack/strategyResolver.js.map +1 -1
- package/dist/role-pack/types.d.ts +5 -1
- package/dist/role-pack/types.d.ts.map +1 -1
- package/dist/security/confirmEntries.d.ts +44 -0
- package/dist/security/confirmEntries.d.ts.map +1 -0
- package/dist/security/confirmEntries.js +59 -0
- package/dist/security/confirmEntries.js.map +1 -0
- package/dist/security/pathGuard.d.ts +42 -6
- package/dist/security/pathGuard.d.ts.map +1 -1
- package/dist/security/pathGuard.js +126 -5
- package/dist/security/pathGuard.js.map +1 -1
- package/dist/skill/skillScriptRunner.d.ts +147 -15
- package/dist/skill/skillScriptRunner.d.ts.map +1 -1
- package/dist/skill/skillScriptRunner.js +479 -68
- package/dist/skill/skillScriptRunner.js.map +1 -1
- package/dist/utils/backgroundTask.d.ts +56 -34
- package/dist/utils/backgroundTask.d.ts.map +1 -1
- package/dist/utils/backgroundTask.js +130 -99
- package/dist/utils/backgroundTask.js.map +1 -1
- package/dist/utils/configResourceManager.d.ts +6 -2
- package/dist/utils/configResourceManager.d.ts.map +1 -1
- package/dist/utils/configResourceManager.js +8 -2
- package/dist/utils/configResourceManager.js.map +1 -1
- package/dist/utils/errors.d.ts +12 -2
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +12 -2
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/eventEmitter.d.ts +76 -23
- package/dist/utils/eventEmitter.d.ts.map +1 -1
- package/dist/utils/eventEmitter.js +23 -3
- package/dist/utils/eventEmitter.js.map +1 -1
- package/dist/utils/time.d.ts +8 -5
- package/dist/utils/time.d.ts.map +1 -1
- package/dist/utils/time.js +8 -5
- package/dist/utils/time.js.map +1 -1
- package/dist/utils/toError.d.ts +1 -1
- package/dist/utils/toError.js +1 -1
- package/dist/web-fetch/loginWall.d.ts +39 -0
- package/dist/web-fetch/loginWall.d.ts.map +1 -0
- package/dist/web-fetch/loginWall.js +78 -0
- package/dist/web-fetch/loginWall.js.map +1 -0
- package/dist/web-fetch/types.d.ts +8 -0
- package/dist/web-fetch/types.d.ts.map +1 -1
- package/dist/web-fetch/webFetchProvider.d.ts.map +1 -1
- package/dist/web-fetch/webFetchProvider.js +3 -1
- package/dist/web-fetch/webFetchProvider.js.map +1 -1
- package/dist/web-search/fetchWebSearchProvider.js +28 -23
- package/dist/web-search/fetchWebSearchProvider.js.map +1 -1
- package/docs/architecture/role-pack-authoring-guide.md +3 -1
- package/docs/architecture/role-pack-spec.md +2 -1
- package/docs/memora-api-reference.md +1349 -1175
- package/docs/memora-/345/215/207/347/272/247/346/214/207/345/215/227-4.x-/345/210/260-5.0.0.md +385 -0
- package/docs/memora-/346/216/245/345/205/245/346/214/207/345/215/227.md +91 -52
- package/docs/role-pack-/345/274/200/346/224/276/351/224/256/346/214/207/345/215/227.md +148 -148
- package/package.json +9 -4
- package/role-packs/README.md +41 -40
- package/role-packs/memora/345/212/251/346/211/213/rules.md +4 -4
- package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/manifest.json +1 -0
- package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/persona.md +1 -1
- package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/rules.md +1 -0
- package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/emotion-wave.md +1 -1
- package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/foreshadow.md +1 -1
- package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/outline-expand.md +32 -5
- package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/project-init/scripts/init-novel-project.mjs +10 -6
- package/role-packs//345/205/261/351/270/243/345/260/217/350/257/264/345/256/266/skills/story-bible.md +3 -1
- package/role-packs//347/231/275/350/257/235/346/226/271/346/241/210/350/256/276/350/256/241/345/270/210/manifest.json +1 -0
- package/dist/agent/managers/dedupManager.d.ts +0 -85
- package/dist/agent/managers/dedupManager.d.ts.map +0 -1
- package/dist/agent/managers/dedupManager.js +0 -248
- package/dist/agent/managers/dedupManager.js.map +0 -1
- package/dist/agent/managers/goalConsistencyChecker.d.ts +0 -42
- package/dist/agent/managers/goalConsistencyChecker.d.ts.map +0 -1
- package/dist/agent/managers/goalConsistencyChecker.js +0 -178
- package/dist/agent/managers/goalConsistencyChecker.js.map +0 -1
- package/dist/agent/managers/llmJudgeHelper.d.ts +0 -21
- package/dist/agent/managers/llmJudgeHelper.d.ts.map +0 -1
- package/dist/agent/managers/llmJudgeHelper.js +0 -32
- package/dist/agent/managers/llmJudgeHelper.js.map +0 -1
- package/dist/agent/managers/memoryAdvisor.d.ts +0 -105
- package/dist/agent/managers/memoryAdvisor.d.ts.map +0 -1
- package/dist/agent/managers/memoryAdvisor.js +0 -322
- package/dist/agent/managers/memoryAdvisor.js.map +0 -1
- package/dist/agent/managers/memoryGovernance.d.ts +0 -24
- package/dist/agent/managers/memoryGovernance.d.ts.map +0 -1
- package/dist/agent/managers/memoryGovernance.js +0 -46
- package/dist/agent/managers/memoryGovernance.js.map +0 -1
- package/dist/memory/governance.d.ts +0 -17
- package/dist/memory/governance.d.ts.map +0 -1
- package/dist/memory/governance.js +0 -17
- package/dist/memory/governance.js.map +0 -1
- package/dist/memory/projectRegistry.d.ts +0 -47
- package/dist/memory/projectRegistry.d.ts.map +0 -1
- package/dist/memory/projectRegistry.js +0 -151
- package/dist/memory/projectRegistry.js.map +0 -1
- package/dist/utils/recallDefaults.d.ts +0 -16
- package/dist/utils/recallDefaults.d.ts.map +0 -1
- package/dist/utils/recallDefaults.js +0 -16
- package/dist/utils/recallDefaults.js.map +0 -1
package/dist/agent/agent.js
CHANGED
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
* 负责组件组装和核心对话编排,领域专属操作委托给专职 Manager
|
|
6
6
|
* (RolePackManager / ToolExecutor / SkillManager / MemoryInspector)。
|
|
7
7
|
*/
|
|
8
|
-
import { isAbsolute } from 'node:path';
|
|
9
|
-
import { getBaseName } from '../utils/path.js';
|
|
10
8
|
import { AGENT_CONSTANTS } from '../agent/constants.js';
|
|
11
9
|
import { ProjectManager } from '../memory/projectManager.js';
|
|
12
10
|
import { SecurityGuard } from '../security/pathGuard.js';
|
|
@@ -15,17 +13,16 @@ import { isTemperature, MAX_OUTPUT_LIMIT } from '../role-pack/strategyKeys.js';
|
|
|
15
13
|
import { resolveCapabilityTools } from '../role-pack/capabilityMap.js';
|
|
16
14
|
import { SessionNamer } from '../agent/managers/sessionNamer.js';
|
|
17
15
|
import { createDefaultGCService } from '../memory/gcService.js';
|
|
18
|
-
import { assembleComponents, buildSystemPromptPrefix } from '../agent/assembler.js';
|
|
16
|
+
import { assembleComponents, buildSystemPromptPrefix, buildEnvironmentContextBlock, } from '../agent/assembler.js';
|
|
19
17
|
import { estimateTokensMessages } from '../agent/contextManager.js';
|
|
20
18
|
import { SeedOrchestrator } from '../agent/seed/index.js';
|
|
21
19
|
import { chatBusyError, configError, isAbortError, isTimeoutAbortSignal, isTimeoutError, } from '../utils/errors.js';
|
|
22
20
|
import { toError } from '../utils/toError.js';
|
|
23
21
|
import { ChatLockManager } from '../agent/managers/chatLockManager.js';
|
|
24
|
-
import { MemoryGovernance } from '../agent/managers/memoryGovernance.js';
|
|
25
22
|
import { ArchiveCoordinator, } from '../agent/managers/archiveCoordinator.js';
|
|
26
23
|
import { TypedEventEmitter, AGENT_EVENTS, AGENT_EVENT_SET, } from '../utils/eventEmitter.js';
|
|
27
24
|
import { logger } from '../logging/logger.js';
|
|
28
|
-
import {
|
|
25
|
+
import { isValidSessionId, splitSessionId } from '../utils/time.js';
|
|
29
26
|
// ─── 模块级常量 ─────────────────────────────────────────
|
|
30
27
|
// ─── Agent 门面类 ───────────────────────────────────────
|
|
31
28
|
/**
|
|
@@ -44,7 +41,7 @@ export class Agent extends TypedEventEmitter {
|
|
|
44
41
|
#backgroundProvider;
|
|
45
42
|
/** Provider 路由选择器(多模型路由基础,可选) */
|
|
46
43
|
#providerRouter = null;
|
|
47
|
-
// 运行时组件(init 后填充)——宿主 getter 契约字段(
|
|
44
|
+
// 运行时组件(init 后填充)——宿主 getter 契约字段(memory/works/polish/sessionManager 等)保持独立
|
|
48
45
|
projectManager = null;
|
|
49
46
|
history = null;
|
|
50
47
|
loop = null;
|
|
@@ -55,8 +52,6 @@ export class Agent extends TypedEventEmitter {
|
|
|
55
52
|
_rolePackManager = null;
|
|
56
53
|
// 拆分出的专职 Manager
|
|
57
54
|
memoryInspector = null;
|
|
58
|
-
/** 记忆治理统一门面(L0/L1/L2/L3 + 诊断) */
|
|
59
|
-
_governance = null;
|
|
60
55
|
/** TextPolishManager(文本润色管理器,LLM 语法修正 + 表达优化) */
|
|
61
56
|
textPolisher = null;
|
|
62
57
|
/** 会话管理器(从 Agent 拆分出的会话管理职责) */
|
|
@@ -69,12 +64,11 @@ export class Agent extends TypedEventEmitter {
|
|
|
69
64
|
* 减少门面扁平字段数;宿主 getter 契约字段(memory/works/polish 等)不在此列。
|
|
70
65
|
*/
|
|
71
66
|
internals = {
|
|
72
|
-
dedupManager: null,
|
|
73
|
-
memoryAdvisor: null,
|
|
74
67
|
sessionArchiver: null,
|
|
75
68
|
sessionNamer: null,
|
|
76
69
|
roundSummaryGenerator: null,
|
|
77
70
|
contextPreparer: null,
|
|
71
|
+
backgroundTasks: null,
|
|
78
72
|
chatLockManager: null,
|
|
79
73
|
archiveCoordinator: null,
|
|
80
74
|
seedOrchestrator: null,
|
|
@@ -98,12 +92,18 @@ export class Agent extends TypedEventEmitter {
|
|
|
98
92
|
* 用 Set 去重——同一 source 只需补执行一次。
|
|
99
93
|
*/
|
|
100
94
|
pendingConfigReload = new Set();
|
|
95
|
+
/**
|
|
96
|
+
* 对话期间被 chatLock 拒掉的归档模式切换:**末次为准**(不排队——VS Code 设置本身也是后写覆盖)。
|
|
97
|
+
*
|
|
98
|
+
* 与 pendingConfigReload 同族:轮终(chat() / resumeExecution() 的 frame 退出)统一补执行,
|
|
99
|
+
* 语义见 flushPendingTurnEndTasks。null = 无待补执行的切换。
|
|
100
|
+
*/
|
|
101
|
+
pendingArchiveMode = null;
|
|
101
102
|
constructor(opts) {
|
|
102
103
|
super();
|
|
103
104
|
this.#config = {
|
|
104
105
|
projectPath: opts.projectPath,
|
|
105
106
|
dataDir: opts.dataDir,
|
|
106
|
-
registryDir: opts.registryDir,
|
|
107
107
|
maxContextTokens: opts.maxContextTokens ?? AGENT_CONSTANTS.DEFAULT_MAX_CONTEXT_TOKENS,
|
|
108
108
|
// per-LLM 输出预算默认值(token):宿主 per-LLM 配置透传;undefined = 不传 max_tokens
|
|
109
109
|
//(回服务端默认)。与角色包策略 act.outputLimit 的最终关系由 buildChatOptions 取更小值。
|
|
@@ -131,6 +131,8 @@ export class Agent extends TypedEventEmitter {
|
|
|
131
131
|
fetchProvider: opts.fetchProvider,
|
|
132
132
|
codeExecutionProvider: opts.codeExecutionProvider,
|
|
133
133
|
projectSearchProvider: opts.projectSearchProvider,
|
|
134
|
+
// 宿主环境提供者(可选):system prompt 注入运行环境事实段(命令执行能力方案 §10.4-②)
|
|
135
|
+
environmentProvider: opts.environmentProvider,
|
|
134
136
|
// 脚本执行 node 路径(可选):宿主注入真实 node 路径,避免无独立 node 时 ENOENT
|
|
135
137
|
scriptNodePath: opts.scriptNodePath,
|
|
136
138
|
// 禁用技能清单(配置形态启停):透传装配 → SkillManager 过滤 L1/L2/L3
|
|
@@ -149,12 +151,13 @@ export class Agent extends TypedEventEmitter {
|
|
|
149
151
|
// ─── 生命周期 ─────────────────────────────────────────
|
|
150
152
|
/**
|
|
151
153
|
* 初始化 Agent:加载索引、组装内部组件
|
|
154
|
+
*
|
|
155
|
+
* ⚠️ **项目在构造时钉死**(`AgentOptions.projectPath`),`init()` **不接受路径覆盖参数**——
|
|
156
|
+
* 形态定案「一个 Agent = 一个项目」:换项目请宿主新建一个 Agent 实例,不要在单实例内改绑
|
|
157
|
+
* (原 `init(projectPathOverride?)` 于 PR-SWITCH-2 删除:它与该原则直接冲突,且全仓零调用)。
|
|
152
158
|
*/
|
|
153
|
-
async init(
|
|
159
|
+
async init() {
|
|
154
160
|
await this.disposePreviousInstance();
|
|
155
|
-
if (projectPathOverride) {
|
|
156
|
-
this.#config.projectPath = projectPathOverride;
|
|
157
|
-
}
|
|
158
161
|
const pctx = await this.initializeProject();
|
|
159
162
|
await this.assembleComponents(pctx);
|
|
160
163
|
this.pctx = pctx;
|
|
@@ -164,6 +167,8 @@ export class Agent extends TypedEventEmitter {
|
|
|
164
167
|
this._initialized = true;
|
|
165
168
|
// 注册暂停超时归档(同进程暂停超时:30min 无心跳则归档清理)
|
|
166
169
|
this.registerPauseTimeoutArchiver();
|
|
170
|
+
// 注册会话离场归档(切换/分叉使会话脱离当前态时归档其摘要元数据)
|
|
171
|
+
this.registerSessionArchiveOnLeave();
|
|
167
172
|
this.registerWorkProjectionRefresh();
|
|
168
173
|
// 注:不加载持久化检查点——中止/断电一律走
|
|
169
174
|
// 「中断轮补全为完整 turn 身份 → 参与下一轮」,不存在跨重启恢复;
|
|
@@ -185,12 +190,25 @@ export class Agent extends TypedEventEmitter {
|
|
|
185
190
|
/**
|
|
186
191
|
* 注册暂停超时归档处理器(SessionManager 两条超时路径——启动加载与运行时定时器——统一在此消费)
|
|
187
192
|
* 注册在 init() 内(close() 的 removeAllListeners + init 起始的 disposePreviousInstance 保证实例周期内恰好一个监听器),
|
|
188
|
-
* 挂在生命周期稳定的 Agent
|
|
193
|
+
* 挂在生命周期稳定的 Agent 上,组件重装配后仍有效。
|
|
189
194
|
*/
|
|
190
195
|
registerPauseTimeoutArchiver() {
|
|
191
196
|
this.on(AGENT_EVENTS.sessionPauseTimedOut, (payload) => {
|
|
192
197
|
// pendingPauseReason 由 resetToRunning() 内部统一清理
|
|
193
198
|
//(checkPauseTimeout 经 sessionManager resetToRunning 已覆盖,此处无需再补 cancelPendingPause)。
|
|
199
|
+
//
|
|
200
|
+
// 在途提问清理(配对不变量守卫):宿主侧 ASK_TIMEOUT 定时器活在 webview 里,
|
|
201
|
+
// 而本面板未启用 retainContextWhenHidden ⇒ 面板隐藏/销毁即失,提问超时只能由
|
|
202
|
+
// 内核 30min 暂停超时兜底。兜底路径若只清检查点、不清在途提问,messages 尾部会留下
|
|
203
|
+
// assistant(tool_calls) 而 ask_user 无配对 tool 消息——下一次 chat 装配即被
|
|
204
|
+
// OpenAI 兼容端以 400 拒绝。补此调用后与宿主超时路径同构(同一守卫,非新增判据)。
|
|
205
|
+
// cancelAsk 对「无在途提问」天然 no-op,无条件调用安全;失败不阻断归档(隔离而非吞没)。
|
|
206
|
+
try {
|
|
207
|
+
this.cancelAsk();
|
|
208
|
+
}
|
|
209
|
+
catch (err) {
|
|
210
|
+
logger.warn({ err }, '暂停超时清理在途提问失败(不阻断会话归档)');
|
|
211
|
+
}
|
|
194
212
|
const { sessionId, date, session } = payload;
|
|
195
213
|
if (!date || !session)
|
|
196
214
|
return;
|
|
@@ -202,6 +220,36 @@ export class Agent extends TypedEventEmitter {
|
|
|
202
220
|
});
|
|
203
221
|
});
|
|
204
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* 注册「会话离场归档」处理器:会话因切换/分叉不再是当前会话时,对其做会话级归档
|
|
225
|
+
* (summary/keyTopics 写入 SessionMeta,供 list_sessions 路标与宿主历史菜单悬停摘要)。
|
|
226
|
+
* 两条触发源:
|
|
227
|
+
* - sessionSwitched(switchToSession 切走旧会话):载荷已含旧会话 date/session;
|
|
228
|
+
* - sessionForked(forkSession 从源会话分出新支):载荷 from 为完整会话标识,此处拆解。
|
|
229
|
+
* 注册在 init() 内(与 registerPauseTimeoutArchiver 同生命周期,close 的 removeAllListeners 兜底)。
|
|
230
|
+
* fire-and-forget:归档失败不阻塞切换/分叉主流程,仅记录。
|
|
231
|
+
*/
|
|
232
|
+
registerSessionArchiveOnLeave() {
|
|
233
|
+
this.on(AGENT_EVENTS.sessionSwitched, (payload) => {
|
|
234
|
+
const { date, session, fromSessionId } = payload;
|
|
235
|
+
this.internals.archiveCoordinator
|
|
236
|
+
?.archiveSession(date, session, { autoTriggered: true })
|
|
237
|
+
.catch((err) => {
|
|
238
|
+
logger.warn({ err, sessionId: fromSessionId }, '会话切走后自动归档失败');
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
this.on(AGENT_EVENTS.sessionForked, (payload) => {
|
|
242
|
+
// from 为完整会话标识(YYYY-MM-DD-会话名);非法格式无归档对象,静默跳过
|
|
243
|
+
if (!isValidSessionId(payload.from))
|
|
244
|
+
return;
|
|
245
|
+
const { date, session } = splitSessionId(payload.from);
|
|
246
|
+
this.internals.archiveCoordinator
|
|
247
|
+
?.archiveSession(date, session, { autoTriggered: true })
|
|
248
|
+
.catch((err) => {
|
|
249
|
+
logger.warn({ err, sessionId: payload.from }, '分叉源会话自动归档失败');
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
}
|
|
205
253
|
/**
|
|
206
254
|
* 关闭旧实例(如果已初始化),失败不阻塞重建
|
|
207
255
|
*/
|
|
@@ -222,7 +270,6 @@ export class Agent extends TypedEventEmitter {
|
|
|
222
270
|
this.projectManager = new ProjectManager({
|
|
223
271
|
dataDir: this.#config.dataDir,
|
|
224
272
|
storage: this.#config.storage,
|
|
225
|
-
registryDir: this.#config.registryDir,
|
|
226
273
|
// SecurityGuard 由 Agent 层创建,解除 memory→security 反向依赖
|
|
227
274
|
createSecurityGuard: (projectPath, memoraDir, configDir, agentDataDir) => new SecurityGuard(projectPath, memoraDir, this.#config.allowedPaths, this.#config.confirmWrites, this.#config.permission, this.#config.confirmScripts, configDir ?? this.#config.configDir, agentDataDir ?? this.#config.dataDir),
|
|
228
275
|
});
|
|
@@ -246,7 +293,7 @@ export class Agent extends TypedEventEmitter {
|
|
|
246
293
|
createPostInitComponents(_pctx) {
|
|
247
294
|
// chat() 并发锁管理器(生命周期与 Agent 实例一致)
|
|
248
295
|
this.internals.chatLockManager = new ChatLockManager();
|
|
249
|
-
// 孤儿 Round 垃圾回收服务:roundStore+storage
|
|
296
|
+
// 孤儿 Round 垃圾回收服务:roundStore+storage 均为构造期稳定注入(不随组件重装配变化),
|
|
250
297
|
// 每日周期清理 refCount=0 且超龄的孤立问答闭环(崩溃残留 pending / 已删会话遗留),防止存储膨胀。
|
|
251
298
|
// shouldSkip:对话进行中跳过本次(minAgeMs 判龄对长任务不可靠,防进行中轮被误清)
|
|
252
299
|
if (this.#config.roundStore && this.#config.storage) {
|
|
@@ -270,11 +317,9 @@ export class Agent extends TypedEventEmitter {
|
|
|
270
317
|
this.emit(AGENT_EVENTS.sessionTitleUpdated, { sessionId, title });
|
|
271
318
|
},
|
|
272
319
|
});
|
|
273
|
-
// 记忆治理统一门面(去重 / 冲突 / 诊断)
|
|
274
|
-
this._governance = new MemoryGovernance(this.internals.dedupManager, this.internals.memoryAdvisor);
|
|
275
320
|
// 种子 turn 编排器(turn 唯一编排真理源):依赖 sessionManager/loop/history 等
|
|
276
321
|
// 均已就绪(assembleComponents 已完成 + sessionNamer 本方法前段创建),在此构造一次。
|
|
277
|
-
// getParts()
|
|
322
|
+
// getParts() 惰性取当前组件——组件重装配后仍取到最新引用。
|
|
278
323
|
this.internals.seedOrchestrator = this.createSeedOrchestrator();
|
|
279
324
|
}
|
|
280
325
|
/**
|
|
@@ -288,7 +333,7 @@ export class Agent extends TypedEventEmitter {
|
|
|
288
333
|
*/
|
|
289
334
|
createSeedOrchestrator() {
|
|
290
335
|
return new SeedOrchestrator({
|
|
291
|
-
// 组件快照经 getter
|
|
336
|
+
// 组件快照经 getter 惰性取当前引用:组件重装配后仍读到最新(关键)
|
|
292
337
|
getParts: () => ({
|
|
293
338
|
loop: this.loop,
|
|
294
339
|
history: this.history,
|
|
@@ -298,8 +343,11 @@ export class Agent extends TypedEventEmitter {
|
|
|
298
343
|
sessionNamer: this.internals.sessionNamer,
|
|
299
344
|
roundSummaryGenerator: this.internals.roundSummaryGenerator,
|
|
300
345
|
}),
|
|
346
|
+
// 后台任务槽位调度器(实例级,装配期由 assembler 创建):摘要/会话命名 fire-and-forget 经此
|
|
347
|
+
backgroundTasks: this.internals.backgroundTasks,
|
|
301
348
|
tracer: this.#config.tracer ?? null,
|
|
302
|
-
|
|
349
|
+
// 归档模式经 getter 惰性取:setArchiveMode 轮内/轮终改值后 span 标注仍为真(同 getParts)
|
|
350
|
+
archiveMode: () => this.#config.archiveMode,
|
|
303
351
|
messages: this.#config.messages,
|
|
304
352
|
// 门面私有能力经回调注入 seed(物理实现仍在门面)
|
|
305
353
|
applyRolePackToolExposure: () => this.applyRolePackToolExposure(),
|
|
@@ -349,9 +397,10 @@ export class Agent extends TypedEventEmitter {
|
|
|
349
397
|
// 仅当本调用仍是当前锁持有者时才清理资源(token 校验)
|
|
350
398
|
this.internals.chatLockManager?.release(myToken);
|
|
351
399
|
cleanupExternalSignal();
|
|
352
|
-
// turn 结束自动收尾:非暂停态无条件清理任务表(turn 内能力,不跨 turn
|
|
353
|
-
|
|
354
|
-
|
|
400
|
+
// turn 结束自动收尾:非暂停态无条件清理任务表(turn 内能力,不跨 turn 残留);
|
|
401
|
+
// 清空前产出 plan_snapshot 快照 chunk(任务项完成态落盘真源)
|
|
402
|
+
yield* this.clearPlanOnTurnEnd();
|
|
403
|
+
await this.flushPendingTurnEndTasks();
|
|
355
404
|
}
|
|
356
405
|
}
|
|
357
406
|
/**
|
|
@@ -377,9 +426,32 @@ export class Agent extends TypedEventEmitter {
|
|
|
377
426
|
return { myToken, internalAbort, cleanupExternalSignal, combinedSignal: internalAbort.signal };
|
|
378
427
|
}
|
|
379
428
|
/**
|
|
380
|
-
*
|
|
429
|
+
* 补执行对话期间暂存的**轮终任务**(当前两类:配置重载 source、归档模式切换)
|
|
430
|
+
*
|
|
431
|
+
* 挂载点 = **两处**都必须挂,缺一即同族缺陷(见 clearPlanOnTurnEnd 的「单一收口点」注释):
|
|
432
|
+
* - chat() 的 finally(本文件 chat() 生成器收尾块)
|
|
433
|
+
* - resumeExecution() 的 finally——缺它则「暂停→续跑」期间暂存的项滞留到下一次 chat(),
|
|
434
|
+
* 用户若不再发问则**永久丢失**(2026-10-16 实证:此前仅 chat() 挂点存在,该缺陷为空头承诺)。
|
|
435
|
+
*
|
|
436
|
+
* 位置约束:必须在 release(myToken) **之后** ⇒ 到达时 chatLock 已释放,此处再申请不会撞 busy。
|
|
437
|
+
* 语义 = 「流退出」(generator frame exit)而非「turn 真正收场(非 paused)」:
|
|
438
|
+
* 暂停边界同样会执行本方法,这与「暂停期间直接改 = 即时生效」的现状一致(ADR-041 §2)。
|
|
439
|
+
*
|
|
440
|
+
* 失败策略:**成功才清槽**。失败保留暂存 + logger.warn,顺延下一个安全点(幂等保证重复应用无害)。
|
|
441
|
+
* ⚠ 下方 reloadConfig 段仍是既有的「先 clear 再尝试」(失败即丢失)——同族债已登记,本批不动其行为。
|
|
381
442
|
*/
|
|
382
|
-
async
|
|
443
|
+
async flushPendingTurnEndTasks() {
|
|
444
|
+
if (this.pendingArchiveMode !== null) {
|
|
445
|
+
const mode = this.pendingArchiveMode;
|
|
446
|
+
try {
|
|
447
|
+
// 复用公开入口而非直改字段:幂等判定与 archiveModeChanged 回执走同一条路径
|
|
448
|
+
this.setArchiveMode(mode);
|
|
449
|
+
this.pendingArchiveMode = null; // 仅成功后清槽
|
|
450
|
+
}
|
|
451
|
+
catch (err) {
|
|
452
|
+
logger.warn({ err, mode }, '轮终补执行归档模式切换失败,保留暂存待下一个安全点');
|
|
453
|
+
}
|
|
454
|
+
}
|
|
383
455
|
if (this.pendingConfigReload.size === 0)
|
|
384
456
|
return;
|
|
385
457
|
const pending = Array.from(this.pendingConfigReload);
|
|
@@ -394,16 +466,9 @@ export class Agent extends TypedEventEmitter {
|
|
|
394
466
|
}
|
|
395
467
|
}
|
|
396
468
|
}
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
* 宿主在"无进展超时"确认 generator 挂起后调用,使用户能立即发起新对话(否则需等锁超时)。
|
|
401
|
-
* 安全机制委托 ChatLockManager.forceRelease:递增 token 让原 chat() 的 finally 跳过清理、abort signal 让响应点退出;
|
|
402
|
-
* 原 generator 仍可能后台运行但不影响新调用。幂等(未忙时 no-op)。
|
|
403
|
-
*/
|
|
404
|
-
forceReleaseChatLock() {
|
|
405
|
-
this.internals.chatLockManager?.forceRelease();
|
|
406
|
-
}
|
|
469
|
+
// 删后注记(2026-10-16 · 5.0.0):曾有公开 forceReleaseChatLock()——注释称宿主在「无进展超时」
|
|
470
|
+
// 后调用以强行释放对话锁,实际宿主全仓零真实调用(仅一句注释提及),承诺的兜底从未接线。
|
|
471
|
+
// 底层 ChatLockManager.forceRelease 随之无调用者,一并拆除(close 路径仍用 dispose 释放锁)。勿加回。
|
|
407
472
|
/**
|
|
408
473
|
* 发送用户消息,非流式返回完整回复
|
|
409
474
|
*/
|
|
@@ -497,8 +562,12 @@ export class Agent extends TypedEventEmitter {
|
|
|
497
562
|
// 无条件清空任务表(除非再次暂停——pauseMeta 由 loop 在边界重新挂起,guard 保留)。
|
|
498
563
|
// 必须无条件清:若仅全 done 才清,resume 以非 done 且未重暂停结束(如某任务项标 blocked
|
|
499
564
|
// 后收尾)时 plan 残留 → 跨 turn 污染下一个 chat()。
|
|
500
|
-
// 两处 turn-end 清理统一为 clearPlanOnTurnEnd(单一收口点),plan 严格 turn 内、不跨 turn
|
|
501
|
-
|
|
565
|
+
// 两处 turn-end 清理统一为 clearPlanOnTurnEnd(单一收口点),plan 严格 turn 内、不跨 turn 残留;
|
|
566
|
+
// 清空前产出 plan_snapshot 快照 chunk(任务项完成态落盘真源)
|
|
567
|
+
yield* this.clearPlanOnTurnEnd();
|
|
568
|
+
// 与 chat() 同构:补执行对话期间暂存的轮终任务(归档模式 / 配置重载)。
|
|
569
|
+
// 缺本行 ⇒ 「暂停→续跑」半程内被拒切的偏好滞留到下一次 chat(),用户不再发问则永久丢失。
|
|
570
|
+
await this.flushPendingTurnEndTasks();
|
|
502
571
|
}
|
|
503
572
|
}
|
|
504
573
|
/**
|
|
@@ -518,17 +587,16 @@ export class Agent extends TypedEventEmitter {
|
|
|
518
587
|
let paused = false;
|
|
519
588
|
try {
|
|
520
589
|
for await (const chunk of source) {
|
|
521
|
-
// 内核事实驱动:loop 在 step 边界真正挂起时状态机才翻 PAUSED
|
|
522
|
-
// 与 requestPause 空闲分支同源,须传 lowRisk=true 保持同一暂停事件契约(否则流中暂停计入连续暂停配额)
|
|
590
|
+
// 内核事实驱动:loop 在 step 边界真正挂起时状态机才翻 PAUSED,非申请即翻转
|
|
523
591
|
if (chunk.type === 'paused') {
|
|
524
592
|
const pendingInfo = this._sessionManager?.consumePendingPause();
|
|
525
|
-
//
|
|
526
|
-
//
|
|
527
|
-
//
|
|
593
|
+
// 原因/来源唯一真源 = 状态机 pendingPause:用户暂停与提问挂起**同源**注册
|
|
594
|
+
// (提问挂起经 assembler 的 onPendingQuestion → requestPause(reason,'agent'),
|
|
595
|
+
// 见 assembler.ts)。此处不另设第二载体,否则同一事实两个真源即漂移。
|
|
528
596
|
const pauseReason = pendingInfo?.reason ?? '用户主动暂停';
|
|
529
597
|
const pauseSource = pendingInfo?.source ?? 'user';
|
|
530
|
-
|
|
531
|
-
this.
|
|
598
|
+
// pauseMeta 不在此写——唯一写入点已收口到 SessionManager.pause()(本方法转发调用)。
|
|
599
|
+
this.pause(pauseReason, pauseSource);
|
|
532
600
|
paused = true;
|
|
533
601
|
}
|
|
534
602
|
yield chunk;
|
|
@@ -605,11 +673,10 @@ export class Agent extends TypedEventEmitter {
|
|
|
605
673
|
}
|
|
606
674
|
/**
|
|
607
675
|
* 暂停会话(用户/Agent/系统均可触发,暂停前自动创建检查点)
|
|
608
|
-
* @param lowRisk 低风险暂停不计入连续暂停计数(默认 false)
|
|
609
676
|
*/
|
|
610
|
-
pause(reason, source = 'user'
|
|
677
|
+
pause(reason, source = 'user') {
|
|
611
678
|
this.assertInitialized('pause');
|
|
612
|
-
return this.requireSessionManager.pause(reason, source
|
|
679
|
+
return this.requireSessionManager.pause(reason, source);
|
|
613
680
|
}
|
|
614
681
|
/**
|
|
615
682
|
* 恢复会话(从 PAUSED 恢复到 RUNNING)
|
|
@@ -632,7 +699,7 @@ export class Agent extends TypedEventEmitter {
|
|
|
632
699
|
const status = sm.status;
|
|
633
700
|
if (status === 'error') {
|
|
634
701
|
throw configError('会话异常', '会话处于异常状态,无法接收新消息', [
|
|
635
|
-
'先标记 error.recovered=true 并调用 agent.recover()',
|
|
702
|
+
'先标记 error.recovered=true 并调用 agent.sessionManager.recover()',
|
|
636
703
|
]);
|
|
637
704
|
}
|
|
638
705
|
if (status === 'paused') {
|
|
@@ -668,7 +735,7 @@ export class Agent extends TypedEventEmitter {
|
|
|
668
735
|
// 空闲守卫:无活跃流时暂停无消费方——若此时同步翻状态机并落盘 checkpoint,
|
|
669
736
|
// 「turn 已完成后的暂停」会把会话钉在 paused,后续新输入被宿主路由成
|
|
670
737
|
// supplement(新意图被吞成"上一个回答的补充",毒化闭环节点;loop 无流消费的延迟翻转亦无意义)。
|
|
671
|
-
// 任务已结束 = 暂停申请作废,返回 false
|
|
738
|
+
// 任务已结束 = 暂停申请作废,返回 false 供宿主明确反馈;ask_user 提问挂起在
|
|
672
739
|
// 流中(_flowActive=true)不经过此分支,不受影响。
|
|
673
740
|
// ⚠ 判据必须用 _flowActive(流活跃)而非 chatLock.isBusy(锁持有)——chatLock 锁
|
|
674
741
|
// 180s 超时后自动释放(不中断生成流),长任务运行超锁期后 isBusy=false 但流
|
|
@@ -740,9 +807,18 @@ export class Agent extends TypedEventEmitter {
|
|
|
740
807
|
* 归属:插话同时以「补充」交互输入持久化到当前闭环节点(interactiveInputs),
|
|
741
808
|
* 保证跨重启重放时插话内容不丢失、不分裂新轮。持久化 fire-and-forget(appendUser 内部
|
|
742
809
|
* 已 catch 写入失败,仅记日志),不阻塞插话本身。
|
|
810
|
+
*
|
|
811
|
+
* 上限裁决:loop 待注入插话达 LOOP_CONSTANTS.MAX_PENDING_INTERJECTIONS 时**整条拒收**——
|
|
812
|
+
* 先入队后持久化(顺序即语义):拒收时零入队、零落盘、零上屏(调用方据返回值提示用户)。
|
|
813
|
+
*
|
|
814
|
+
* @returns true=已入队并持久化;false=已达上限被拒收(未入队未落盘)
|
|
743
815
|
*/
|
|
744
816
|
interject(content) {
|
|
745
817
|
this.assertInitialized('interject');
|
|
818
|
+
// 先入队(上限裁决在此):满员拒收时不可写盘——队列没进、落盘却写 = 数据不一致
|
|
819
|
+
const accepted = this.requireLoop.interject(content);
|
|
820
|
+
if (!accepted)
|
|
821
|
+
return false;
|
|
746
822
|
// 持久化插话为闭环节点交互补充输入(roundId 非空时才写;空=无在途闭环,跳过)
|
|
747
823
|
const closureRoundId = this.loop?.getCurrentRoundId();
|
|
748
824
|
if (closureRoundId) {
|
|
@@ -751,7 +827,7 @@ export class Agent extends TypedEventEmitter {
|
|
|
751
827
|
kind: 'supplement',
|
|
752
828
|
});
|
|
753
829
|
}
|
|
754
|
-
|
|
830
|
+
return true;
|
|
755
831
|
}
|
|
756
832
|
/**
|
|
757
833
|
* 删除待注入的插话(宿主 UI 层用户后悔)。与 interject 对称。
|
|
@@ -804,14 +880,13 @@ export class Agent extends TypedEventEmitter {
|
|
|
804
880
|
this.assertInitialized('answerQuestion');
|
|
805
881
|
return this.requireLoop.answerQuestion(answers);
|
|
806
882
|
}
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
appendPlanItem
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
}
|
|
883
|
+
// 删后注记(2026-10-17 · 5.0.0,PUB-API-PRUNE-2):Agent 面类曾有 4 个纯转发门面——
|
|
884
|
+
// appendPlanItem / triggerError / recover / injectSystemMessage——均 3-13 行薄委托
|
|
885
|
+
// (sessionManager / loop 层实现),宿主零调用 + 手册零承诺 + 真身在对应类公开可用
|
|
886
|
+
// (sessionManager.appendPlanItem/triggerError/recover、loop.injectSystemMessage)。
|
|
887
|
+
// 与 loadSessionMessages 同型裁决:转门口不留。getActiveStrategy 经复核**保留**——
|
|
888
|
+
// 它不是转发门面(rolePackManager 无同名方法),是 Agent 级策略读取器且内部自用
|
|
889
|
+
// (buildChatOptionsFromStrategy),「读当前生效策略」属合理外部能力。
|
|
815
890
|
/**
|
|
816
891
|
* 卸载运行态挂载物:清空检查点计划与任务项推进日志(宿主任务流结束/停止/异常广播 idle 前调用),
|
|
817
892
|
* 回到"空闲 = 无挂载物"的资源层常态;会话历史与记忆等资源层内容不受影响。
|
|
@@ -833,9 +908,14 @@ export class Agent extends TypedEventEmitter {
|
|
|
833
908
|
* 故保留不清;恢复完成后该 turn 最终退出时仍会走本方法无条件清空。
|
|
834
909
|
*
|
|
835
910
|
* 运行时状态(plan/planItemLog)清空,但对话记录里的 round-block 折叠块已沉淀为历史(不落盘删除)。
|
|
836
|
-
* 挂点:chat() 与 resumeExecution 的 finally 块(generator close 时触发,确保所有 yield
|
|
911
|
+
* 挂点:chat() 与 resumeExecution 的 finally 块(generator close 时触发,确保所有 yield 已被宿主消费)。
|
|
912
|
+
*
|
|
913
|
+
* 清空前产出一条 `plan_snapshot` chunk(任务表全量终态):turn 结束后宿主落盘轨由此获得
|
|
914
|
+
* 任务项完成态的唯一结构化真源(重放恢复绿勾用);中断轮同样经过本方法 → 中断轮也拍。
|
|
915
|
+
* 委托为同步 generator(`yield*` 消费),快照 chunk 尽力交付、清空动作经内部 try/finally
|
|
916
|
+
* 无条件执行——即使宿主提前终止流(快照未被消费),plan 也不跨 turn 残留(行为与改造前一致)。
|
|
837
917
|
*/
|
|
838
|
-
clearPlanOnTurnEnd() {
|
|
918
|
+
*clearPlanOnTurnEnd() {
|
|
839
919
|
const sm = this._sessionManager;
|
|
840
920
|
if (!sm)
|
|
841
921
|
return;
|
|
@@ -844,51 +924,26 @@ export class Agent extends TypedEventEmitter {
|
|
|
844
924
|
return;
|
|
845
925
|
if (cp.pauseMeta)
|
|
846
926
|
return; // 暂停态:turn 未真正结束,恢复时需继续用 plan,保留不清
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
if (this._sessionManager?.status === 'paused')
|
|
858
|
-
return true;
|
|
859
|
-
// 错误态不展示"继续":error 态由检查点恢复回填进入,须显式处理(重新开始或 recover),避免点了静默无反应
|
|
860
|
-
if (this._sessionManager?.status === 'error')
|
|
861
|
-
return false;
|
|
862
|
-
// 仅 pending/active(可推进)任务项计入"可续跑"——blocked 不续(全 blocked 由 isPlanAllBlocked 拦,
|
|
863
|
-
// 避免全 blocked 计划按钮可点但 resumeExecution 早退)。判定走 SessionManager.hasInflightPlan
|
|
864
|
-
// 单一真理源(禁内联谓词,SSOT 见 sessionManager.ts hasInflightPlan 注释),与 prepare/loop 同源。
|
|
865
|
-
const hasPendingPlan = this._sessionManager?.hasInflightPlan() ?? false;
|
|
866
|
-
return this.requireLoop.isInAutonomousStep || hasPendingPlan;
|
|
867
|
-
}
|
|
868
|
-
/**
|
|
869
|
-
* 触发会话异常(公开 API,宿主显式调用):仅 RUNNING 状态可触发,异常时自动创建检查点保存状态。
|
|
870
|
-
* 生产内部无调用者——运行时异常(LLM 超时/工具失败)走 yield {type:'error'} 事件流不翻状态机;
|
|
871
|
-
* 本 API 供宿主在自定义异常(如外部服务故障)显式触发,或经检查点恢复回填进入 ERROR 态。
|
|
872
|
-
*/
|
|
873
|
-
triggerError(cause) {
|
|
874
|
-
this.assertInitialized('triggerError');
|
|
875
|
-
return this.requireSessionManager.triggerError(cause);
|
|
876
|
-
}
|
|
877
|
-
/**
|
|
878
|
-
* 从异常恢复:校验恢复条件(error.recovered === true 且 cause 已解除)
|
|
879
|
-
*/
|
|
880
|
-
recover() {
|
|
881
|
-
this.assertInitialized('recover');
|
|
882
|
-
return this.requireSessionManager.recover();
|
|
927
|
+
try {
|
|
928
|
+
// 清空前拍快照:此刻 plan 仍完整(含各任务项最终 status)
|
|
929
|
+
yield {
|
|
930
|
+
type: 'plan_snapshot',
|
|
931
|
+
items: cp.plan.map((item) => ({ planItemId: item.id, status: item.status })),
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
finally {
|
|
935
|
+
sm.clearPlan();
|
|
936
|
+
}
|
|
883
937
|
}
|
|
884
938
|
/**
|
|
885
939
|
* 创建会话检查点:快照当前运行时状态(热记忆等),生成纯内存态快照
|
|
886
940
|
* (不落盘、无序列化/恢复路径——中止/断电走「中断轮补全为完整 turn」)。
|
|
887
|
-
*
|
|
941
|
+
* 返回值恒非空:未 init 时由 assertInitialized/requireSessionManager 抛错(configError),
|
|
942
|
+
* 不返回 null——null 仅属于 getCheckpoint()(首个检查点尚未创建)。
|
|
888
943
|
*/
|
|
889
|
-
createCheckpoint(
|
|
944
|
+
createCheckpoint() {
|
|
890
945
|
this.assertInitialized('createCheckpoint');
|
|
891
|
-
return this.requireSessionManager.createCheckpoint(
|
|
946
|
+
return this.requireSessionManager.createCheckpoint();
|
|
892
947
|
}
|
|
893
948
|
/**
|
|
894
949
|
* 获取当前检查点
|
|
@@ -897,30 +952,38 @@ export class Agent extends TypedEventEmitter {
|
|
|
897
952
|
this.assertInitialized('getCheckpoint');
|
|
898
953
|
return this.requireSessionManager.getCheckpoint();
|
|
899
954
|
}
|
|
955
|
+
// 删后注记(2026-10-16 · 5.0.0,按 SSOT/不带伤裁决提前于 DEPRECATE-1 周期删除):曾有公开
|
|
956
|
+
// getRecentToolExecutions()——聚合检查点 completedToolCalls 的「工具执行历史」出口,
|
|
957
|
+
// 内核+宿主+手册三面零消费(loop 域 tool_start/tool_result 事件流才是宿主可自聚合的真源,
|
|
958
|
+
// 本出口是多余中间层)。勿加回;观测需求经事件流自聚合。
|
|
900
959
|
/**
|
|
901
|
-
*
|
|
960
|
+
* 后台任务只读快照(宿主 UI 出口 · 见 `docs/方案-后台任务可见性与kill入口-20261004.md` §2.1)
|
|
902
961
|
*
|
|
903
|
-
*
|
|
904
|
-
*
|
|
905
|
-
*
|
|
906
|
-
*
|
|
962
|
+
* 委托 loop → `BackgroundTaskRegistry.list()`。返回**只读投影**
|
|
963
|
+
* (taskId / command / startedAt / status / result?),不含进程句柄——
|
|
964
|
+
* 宿主拿它渲染列表,但**无从操纵进程**(注册表按 Agent 实例隔离,
|
|
965
|
+
* 导出注册表类会让宿主跨会话 kill,故只出方法不出类)。
|
|
907
966
|
*
|
|
908
|
-
*
|
|
909
|
-
*
|
|
967
|
+
* ⚠️ 未初始化**抛 `configError`**(与既有门面同构,`assertInitialized` 是门面统一契约)——
|
|
968
|
+
* 调用方须自行保证 init 完成,本方法不做静默降级(静默返回空会把「未初始化」
|
|
969
|
+
* 伪装成「没有后台任务」)。
|
|
910
970
|
*/
|
|
911
|
-
|
|
912
|
-
this.assertInitialized('
|
|
913
|
-
|
|
914
|
-
if (!calls || calls.length === 0)
|
|
915
|
-
return [];
|
|
916
|
-
// 取最近 limit 条并浅拷贝,避免宿主引用改动污染检查点(FIFO 封顶后 slice 安全)
|
|
917
|
-
return calls.slice(-limit).map((r) => ({ ...r }));
|
|
971
|
+
listBackgroundTasks() {
|
|
972
|
+
this.assertInitialized('listBackgroundTasks');
|
|
973
|
+
return this.requireLoop.getBackgroundTasks();
|
|
918
974
|
}
|
|
919
975
|
/**
|
|
920
|
-
*
|
|
976
|
+
* 终止后台任务(宿主 UI 出口 · 同上 §2.1)
|
|
977
|
+
*
|
|
978
|
+
* 委托 loop → `BackgroundTaskRegistry.kill()`:先取已捕获输出快照再杀树,
|
|
979
|
+
* 返回终态投影(用户点「终止」即等价于模型调 `kill_command`)。
|
|
980
|
+
*
|
|
981
|
+
* @returns 终态投影;`taskId` 不存在 → `null`
|
|
982
|
+
* @throws 未初始化时抛 `configError`(同 `listBackgroundTasks`)
|
|
921
983
|
*/
|
|
922
|
-
|
|
923
|
-
this.
|
|
984
|
+
killBackgroundTask(taskId) {
|
|
985
|
+
this.assertInitialized('killBackgroundTask');
|
|
986
|
+
return this.requireLoop.killBackgroundTask(taskId);
|
|
924
987
|
}
|
|
925
988
|
/**
|
|
926
989
|
* 从指定 Round 位置分叉当前会话(委托至 SessionManager):
|
|
@@ -975,58 +1038,6 @@ export class Agent extends TypedEventEmitter {
|
|
|
975
1038
|
}
|
|
976
1039
|
await namer.ensureSessionTitle(result.date, result.newSession, firstUserContent);
|
|
977
1040
|
}
|
|
978
|
-
/**
|
|
979
|
-
* 切换到指定项目:切换后自动 rebuildComponents();Agent 级记忆存储(宿主注入,实例不随项目切换重建)保留,项目级配置(.memora/)重新加载
|
|
980
|
-
*
|
|
981
|
-
* `nameOrPath` 只接受两种输入:① 项目注册表中的项目名(依赖注册表跨项目共享,见 dataDir/registryDir);
|
|
982
|
-
* ② 项目根目录的**绝对路径**。二者都不满足时抛 configError——否则相对串会以 process.cwd()
|
|
983
|
-
* 为基准解析,静默造出非预期的项目目录并占用其锁。
|
|
984
|
-
*/
|
|
985
|
-
async switchProject(nameOrPath) {
|
|
986
|
-
this.assertInitialized('switchProject', ['projectManager', 'provider']);
|
|
987
|
-
// 对话进行中切换项目会导致 loop/history 引用被替换,工作记忆与持久化状态不一致
|
|
988
|
-
this.assertNotBusy('切换项目');
|
|
989
|
-
const pm = this.projectManager;
|
|
990
|
-
const projects = pm.list;
|
|
991
|
-
let target = projects.find((p) => p.name === nameOrPath || p.path === nameOrPath);
|
|
992
|
-
if (!target) {
|
|
993
|
-
const nameOrPathLower = nameOrPath.toLowerCase();
|
|
994
|
-
target = projects.find((p) => p.name.toLowerCase() === nameOrPathLower || p.path.toLowerCase() === nameOrPathLower);
|
|
995
|
-
}
|
|
996
|
-
// 注册表未命中时按路径处理。相对路径会以 process.cwd() 为基准解析——宿主进程的 cwd
|
|
997
|
-
// 不具项目语义,会静默创建出非预期的项目目录并占用其锁,故只接受绝对路径。
|
|
998
|
-
if (!target && !isAbsolute(nameOrPath)) {
|
|
999
|
-
throw configError('项目切换失败', `「${nameOrPath}」既不是已注册的项目名,也不是绝对路径`, [
|
|
1000
|
-
'按名切换:先经 agent.projects.registerProject(项目路径, 项目名) 注册,并保证注册表跨项目共享(多项目共用同一 dataDir 或 registryDir)',
|
|
1001
|
-
'按路径切换:传入项目根目录的绝对路径',
|
|
1002
|
-
]);
|
|
1003
|
-
}
|
|
1004
|
-
const projectPath = target ? target.path : nameOrPath;
|
|
1005
|
-
const projectName = target ? target.name : getBaseName(nameOrPath);
|
|
1006
|
-
const newPctx = await pm.initProject(projectPath, projectName, this.#config.configDir);
|
|
1007
|
-
// 记录源项目路径(用于事件),切换前 pctx 可能不存在(首次初始化)
|
|
1008
|
-
const fromProjectPath = this.pctx?.projectPath ?? null;
|
|
1009
|
-
// 先尝试重建组件,失败时回滚 pctx 防止状态不一致
|
|
1010
|
-
try {
|
|
1011
|
-
this.pctx = newPctx;
|
|
1012
|
-
await this.rebuildComponents();
|
|
1013
|
-
}
|
|
1014
|
-
catch (err) {
|
|
1015
|
-
// 回滚:恢复旧 pctx(若存在)
|
|
1016
|
-
if (fromProjectPath) {
|
|
1017
|
-
logger.warn({ err: toError(err) }, 'switchProject: 组件重建失败,回滚项目上下文');
|
|
1018
|
-
this.pctx = { projectPath: fromProjectPath };
|
|
1019
|
-
}
|
|
1020
|
-
throw err;
|
|
1021
|
-
}
|
|
1022
|
-
// 发射项目切换事件(供宿主 UI 刷新项目相关界面)
|
|
1023
|
-
this.emit(AGENT_EVENTS.projectSwitched, {
|
|
1024
|
-
from: fromProjectPath,
|
|
1025
|
-
to: projectPath,
|
|
1026
|
-
projectName,
|
|
1027
|
-
});
|
|
1028
|
-
return newPctx;
|
|
1029
|
-
}
|
|
1030
1041
|
// ─── 组件组装 ─────────────────────────────────────────
|
|
1031
1042
|
/**
|
|
1032
1043
|
* 组装所有运行时组件(一行委托给 assembler 工厂)
|
|
@@ -1092,6 +1103,17 @@ export class Agent extends TypedEventEmitter {
|
|
|
1092
1103
|
this.loop.onContextWindowChanged = (effectiveTokens) => {
|
|
1093
1104
|
this.internals.contextPreparer?.setMaxContextTokens(effectiveTokens);
|
|
1094
1105
|
};
|
|
1106
|
+
// 后台任务自然终态 → Agent 事件面(脱管后 turn 已结束,宿主挂在 turn 生命周期上的
|
|
1107
|
+
// 推送时机覆盖不到「任务自然跑完」,缺此事件 UI 会一直显示假活跃的「运行中」。见方案文档 §5.2.2)。
|
|
1108
|
+
// 走既有 TypedEventEmitter:宿主 bindAgentNoticeEvents 的「先 off 再 on」幂等模式适用。
|
|
1109
|
+
// 主动 kill 不发此事件(注册表刻意不回调),kill 后的 UI 刷新由宿主 kill 路径自行回推。
|
|
1110
|
+
this.loop.setBackgroundTaskSettledEmitter((task) => {
|
|
1111
|
+
this.emit('backgroundTaskSettled', {
|
|
1112
|
+
taskId: task.taskId,
|
|
1113
|
+
command: task.command,
|
|
1114
|
+
status: task.status,
|
|
1115
|
+
});
|
|
1116
|
+
});
|
|
1095
1117
|
this.toolExec = result.toolExec;
|
|
1096
1118
|
this.skillManager = result.skillManager;
|
|
1097
1119
|
this._rolePackManager = result.rolePackManager;
|
|
@@ -1100,8 +1122,6 @@ export class Agent extends TypedEventEmitter {
|
|
|
1100
1122
|
this.emit(AGENT_EVENTS.rolePackSwitchLocked, { reason, lockedSeconds });
|
|
1101
1123
|
});
|
|
1102
1124
|
this.memoryInspector = result.memoryInspector;
|
|
1103
|
-
this.internals.dedupManager = result.dedupManager;
|
|
1104
|
-
this.internals.memoryAdvisor = result.memoryAdvisor;
|
|
1105
1125
|
this.workProjection = result.workProjection;
|
|
1106
1126
|
this.internals.sessionArchiver = result.sessionArchiver;
|
|
1107
1127
|
this.textPolisher = result.textPolisher;
|
|
@@ -1110,6 +1130,9 @@ export class Agent extends TypedEventEmitter {
|
|
|
1110
1130
|
this._sessionManager = result.sessionManager;
|
|
1111
1131
|
// 输入增强管线由组装器创建,Agent 只保留编排调用点
|
|
1112
1132
|
this.internals.contextPreparer = result.contextPreparer;
|
|
1133
|
+
// 后台任务槽位调度器(实例级):assembler 创建时已注入 toolExec(命中 touch);
|
|
1134
|
+
// 此处持有 → 下方创建 seedOrchestrator 时注入 SeedDeps(摘要/命名)+ close() 单点等待。
|
|
1135
|
+
this.internals.backgroundTasks = result.backgroundTasks;
|
|
1113
1136
|
}
|
|
1114
1137
|
// ─── Provider 管理 ────────────────────────────────────
|
|
1115
1138
|
setProvider(provider) {
|
|
@@ -1184,10 +1207,29 @@ export class Agent extends TypedEventEmitter {
|
|
|
1184
1207
|
}
|
|
1185
1208
|
// ─── 归档模式管理 ───────────────────────────
|
|
1186
1209
|
/**
|
|
1187
|
-
*
|
|
1210
|
+
* 运行时切换归档模式:**对话进行中不即时生效** → 暂存期望值 + 抛错,由 flushPendingTurnEndTasks 补执行。
|
|
1211
|
+
*
|
|
1212
|
+
* 契约与 reloadConfig(source) 逐字同构:
|
|
1213
|
+
* - busy 时 **既暂存、又抛错**——抛错是「已排期到轮终」的传输方式,不是「静默接受」。
|
|
1214
|
+
* 宿主据此走 catch 分支向用户如实说明「运行时将在当前对话结束后生效」(settingsPanel.setArchiveMode)。
|
|
1215
|
+
* - 补执行点:chat() / resumeExecution() 的 finally(流退出),见 flushPendingTurnEndTasks。
|
|
1216
|
+
*
|
|
1217
|
+
* ⚠ 守卫用 chatLock.isBusy(`assertNotBusy` 同源),而该锁 180s 超时会**自动释放且不中断生成流**
|
|
1218
|
+
* (见 ChatLockManager.acquire 计时器)⇒ 长轮跑过 180s 后本方法会即时生效而非暂存,
|
|
1219
|
+
* 此时本轮的**后半程**即按新模式归档。这是既有判据的缺陷,非本方法引入;
|
|
1220
|
+
* 判据统一问题已登记专项(本批不动判据),此处如实注明而非回避。
|
|
1188
1221
|
*/
|
|
1189
1222
|
setArchiveMode(mode) {
|
|
1190
|
-
this.
|
|
1223
|
+
if (this.internals.chatLockManager?.isBusy) {
|
|
1224
|
+
// 先暂存后抛:任何一次拒切都排期到轮终,用户偏好既不会丢也不会被伪造为「已生效」
|
|
1225
|
+
// (最坏情况还有「装配期读持久化配置注入」兜底,见 extension.ts getOrCreateAgent)。
|
|
1226
|
+
this.pendingArchiveMode = mode;
|
|
1227
|
+
logger.info({ mode }, '对话进行中,归档模式切换已暂存,将在流退出时补执行');
|
|
1228
|
+
throw chatBusyError('切换归档模式');
|
|
1229
|
+
}
|
|
1230
|
+
// 清槽落点必须在幂等 return **之前**(三条出口全覆盖):
|
|
1231
|
+
// 否则「即时改成当前值」会命中幂等直接 return,旧暂存仍在轮终覆盖用户最后一次表态。
|
|
1232
|
+
this.pendingArchiveMode = null;
|
|
1191
1233
|
const prev = this.#config.archiveMode;
|
|
1192
1234
|
if (prev === mode)
|
|
1193
1235
|
return; // 幂等:无变更直接返回
|
|
@@ -1263,7 +1305,11 @@ export class Agent extends TypedEventEmitter {
|
|
|
1263
1305
|
const globalSkillList = this.skillManager?.buildSkillList() ?? '';
|
|
1264
1306
|
// 作品投影装配块:缓存于 manager(装配时刷新 + register_work 更新),同步读取即可
|
|
1265
1307
|
const workProjectionContext = this.workProjection?.contextBlock() ?? '';
|
|
1266
|
-
|
|
1308
|
+
// 运行环境事实段(命令执行能力方案 §10.4-②):同步取宿主快照并格式化(未注入 → 空串不注入)。
|
|
1309
|
+
// getEnvironment 为同步接口,刷新路径(本函数为同步 void)可无等待拉取最新快照;
|
|
1310
|
+
// 环境事实是低频变化数据,宿主可自行缓存,内核每次重建前缀即拉最新。
|
|
1311
|
+
const environmentContext = buildEnvironmentContextBlock(this.#config.environmentProvider?.getEnvironment() ?? null);
|
|
1312
|
+
const newPrefix = buildSystemPromptPrefix(rolePackPrompt, globalSkillList, undefined, workProjectionContext, environmentContext);
|
|
1267
1313
|
this.loop.refreshRolePackPrefix(newPrefix);
|
|
1268
1314
|
// 角色包底盘占用随切换实时更新(不依赖跑 prepare):装配此刻即确定的真值
|
|
1269
1315
|
this.loop.setRolePackBaseTokens(estimateTokensMessages([{ content: newPrefix }]));
|
|
@@ -1324,8 +1370,8 @@ export class Agent extends TypedEventEmitter {
|
|
|
1324
1370
|
/**
|
|
1325
1371
|
* 手动归档会话(更新 SessionMeta,委托 ArchiveCoordinator)
|
|
1326
1372
|
*
|
|
1327
|
-
* 适用于 manual
|
|
1328
|
-
* options 透传给 ArchiveCoordinator
|
|
1373
|
+
* 适用于 manual 模式(用户手动触发;自动归档由内核监听器在会话切走/分叉离场/暂停超时时触发)。
|
|
1374
|
+
* options 透传给 ArchiveCoordinator:内核自动触发传 { autoTriggered: true }(按其模式判断),
|
|
1329
1375
|
* 用户手动触发省略 options(默认 autoTriggered=false,无条件执行)。
|
|
1330
1376
|
*
|
|
1331
1377
|
* @returns 归档结果(updatedFields 可能为空,表示无归档价值或 LLM 失败)
|
|
@@ -1336,7 +1382,9 @@ export class Agent extends TypedEventEmitter {
|
|
|
1336
1382
|
}
|
|
1337
1383
|
// ─── 配置重载(事件驱动) ───────────────────────
|
|
1338
1384
|
/**
|
|
1339
|
-
*
|
|
1385
|
+
* 从 configDir 重新扫描指定 source 并更新内存缓存(设定记忆纯文件装载,不写记忆库)。
|
|
1386
|
+
* **空闲时**使当前会话立即生效(无需重启);**对话进行中**则暂存 source 并抛错(见下方 busy 分支),
|
|
1387
|
+
* 由 flushPendingTurnEndTasks 在流退出时补执行——故此处不宜读作「无条件立即生效」。
|
|
1340
1388
|
* - 'skill' → SkillManager.reload() 重扫 skills/
|
|
1341
1389
|
* - 'rolePack' → RolePackManager.reload() 重扫 role-packs/(保持激活角色,刷新 AgentLoop 前缀)
|
|
1342
1390
|
* - 'rule' → 经角色包管理机制热更新(即 rolePack)
|
|
@@ -1393,17 +1441,6 @@ export class Agent extends TypedEventEmitter {
|
|
|
1393
1441
|
return result;
|
|
1394
1442
|
}
|
|
1395
1443
|
// ─── 组件访问 ─────────────────────────────────────────
|
|
1396
|
-
/**
|
|
1397
|
-
* 重建内部组件(history / loop / managers):通常由 switchProject() 自动触发,仅强制刷新时手动调用
|
|
1398
|
-
*/
|
|
1399
|
-
async rebuildComponents() {
|
|
1400
|
-
// 对话进行中重建会导致 loop/history 引用被替换,工作记忆与持久化状态不一致
|
|
1401
|
-
this.assertNotBusy('重建组件');
|
|
1402
|
-
if (!this.pctx)
|
|
1403
|
-
return;
|
|
1404
|
-
// assembleComponents 内部重建 history/loop/managers,并返回新创建的 sessionManager
|
|
1405
|
-
await this.assembleComponents(this.pctx);
|
|
1406
|
-
}
|
|
1407
1444
|
// ─── 守卫方法 ───────────────────────────────────────────
|
|
1408
1445
|
/**
|
|
1409
1446
|
* 检查 Agent 是否已初始化(methodName 用于错误消息,requires 为需检查的组件列表)
|
|
@@ -1518,34 +1555,47 @@ export class Agent extends TypedEventEmitter {
|
|
|
1518
1555
|
this.internals.gcService?.stopPeriodic();
|
|
1519
1556
|
this.internals.gcService = null;
|
|
1520
1557
|
// 等待 WorkProjection 无 inflight 概念(作品投影改为用户主动触发同步写,无后台 LLM 任务)
|
|
1521
|
-
//
|
|
1522
|
-
//
|
|
1558
|
+
// 背景任务统一由下方调度器等待兜底
|
|
1559
|
+
// 关键约束:等待**本实例**后台任务在途任务完成(如 touchScores)。
|
|
1523
1560
|
// 否则 close 后后台任务仍可能 upsert 已关闭的 storage,触发写失效或异常。
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1561
|
+
const backgroundTasks = this.internals.backgroundTasks;
|
|
1562
|
+
if (backgroundTasks) {
|
|
1563
|
+
try {
|
|
1564
|
+
const awaited = await backgroundTasks.awaitPending(AGENT_CONSTANTS.SHUTDOWN_ARCHIVE_TIMEOUT_MS);
|
|
1565
|
+
// 超时后丢弃**未启动**的排队任务(只清队列,不中断在途)——防关后从队列启动新任务写已关 storage
|
|
1566
|
+
const discarded = backgroundTasks.cancelPending();
|
|
1567
|
+
if (awaited > 0) {
|
|
1568
|
+
logger.debug({ awaited, discarded }, 'close: 背景任务等待结束(awaited = 初始在途数,超时放弃时非完成数)');
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
catch (err) {
|
|
1572
|
+
logger.warn({ err: toError(err) }, 'close: 后台任务等待失败');
|
|
1528
1573
|
}
|
|
1529
1574
|
}
|
|
1530
|
-
|
|
1531
|
-
|
|
1575
|
+
// 后台「命令」任务实例终态收割——与上方 BackgroundTaskScheduler 是同名异物:
|
|
1576
|
+
// 上方等的是归档/打分/命名类内存副作用,此处杀的是注册表(BackgroundTaskRegistry)持有的 shell 子进程。
|
|
1577
|
+
// turn 终态刻意脱管不杀(跨轮存活),但注册表按 Agent 实例隔离,实例销毁后任务
|
|
1578
|
+
// 不可寻址,不杀就是 OS 层孤儿(观察点 ⑧ 真机实锤:父进程退出后 ping.exe 仍在)。
|
|
1579
|
+
// 本调用同时注销注册表的 exit 兜底钩子(close 内同步杀树若因关窗窗口赶不上,
|
|
1580
|
+
// exit 钩子是第二触发通路——两通路共用 terminate 单点,非两套机制)。
|
|
1581
|
+
// 须在 nullifyAllComponents(loop 置 null)之前。
|
|
1582
|
+
const killedBackgroundCommands = this.loop?.shutdownBackgroundTasks() ?? 0;
|
|
1583
|
+
if (killedBackgroundCommands > 0) {
|
|
1584
|
+
logger.info({ count: killedBackgroundCommands }, 'close: 收割存活后台命令任务');
|
|
1532
1585
|
}
|
|
1533
1586
|
// 处理 pending 暂停残留:关闭前确保状态机与检查点一致
|
|
1534
1587
|
const sm = this._sessionManager;
|
|
1535
1588
|
if (sm?.isPausePending()) {
|
|
1536
1589
|
const pendingInfo = sm.pendingPauseInfo;
|
|
1537
1590
|
logger.warn({ reason: pendingInfo?.reason, source: pendingInfo?.source }, 'close() 时存在未消费的暂停请求,已自动清理');
|
|
1538
|
-
// 若状态机仍 running,同步翻 paused
|
|
1539
|
-
// 系统清理不消耗连续暂停配额 → lowRisk=true
|
|
1591
|
+
// 若状态机仍 running,同步翻 paused 使检查点内存态一致(无需触发挂起,仅修正一致性)
|
|
1540
1592
|
if (sm.status === 'running') {
|
|
1541
|
-
sm.pause('close 清理残留暂停', 'system'
|
|
1593
|
+
sm.pause('close 清理残留暂停', 'system');
|
|
1542
1594
|
}
|
|
1543
1595
|
sm.cancelPendingPause();
|
|
1544
1596
|
}
|
|
1545
1597
|
// 清理 SessionManager(须先于 nullifyAllComponents,destroy 需访问其内部状态)
|
|
1546
1598
|
if (this._sessionManager) {
|
|
1547
|
-
// 清脏后再 destroy(纯内存,无落盘;检查点不落盘,本调用为保留语义边界的 no-op)
|
|
1548
|
-
this._sessionManager.flushOnShutdown();
|
|
1549
1599
|
this._sessionManager.destroy();
|
|
1550
1600
|
}
|
|
1551
1601
|
// ArchiveCoordinator 无定时器,仅释放引用
|
|
@@ -1577,6 +1627,7 @@ export class Agent extends TypedEventEmitter {
|
|
|
1577
1627
|
// 清理次要状态字段,防止 re-init 后残留上一会话状态
|
|
1578
1628
|
this._lastInteractionAt = null;
|
|
1579
1629
|
this.pendingConfigReload.clear();
|
|
1630
|
+
this.pendingArchiveMode = null;
|
|
1580
1631
|
}
|
|
1581
1632
|
/**
|
|
1582
1633
|
* 统一 null 化所有组件字段(新增 Manager 时在此追加一行);带副作用的清理仍由 close() 显式调用,顺序敏感不可合并
|
|
@@ -1589,7 +1640,6 @@ export class Agent extends TypedEventEmitter {
|
|
|
1589
1640
|
this.skillManager = null;
|
|
1590
1641
|
this._rolePackManager = null;
|
|
1591
1642
|
this.memoryInspector = null;
|
|
1592
|
-
this._governance = null;
|
|
1593
1643
|
this.workProjection = null;
|
|
1594
1644
|
this.textPolisher = null;
|
|
1595
1645
|
this._sessionManager = null;
|
|
@@ -1597,12 +1647,11 @@ export class Agent extends TypedEventEmitter {
|
|
|
1597
1647
|
this.pctx = null;
|
|
1598
1648
|
// 纯内部组件聚合整体置 null(新增内部组件只需在字段声明与 createPostInitComponents 登记)
|
|
1599
1649
|
this.internals = {
|
|
1600
|
-
dedupManager: null,
|
|
1601
|
-
memoryAdvisor: null,
|
|
1602
1650
|
sessionArchiver: null,
|
|
1603
1651
|
sessionNamer: null,
|
|
1604
1652
|
roundSummaryGenerator: null,
|
|
1605
1653
|
contextPreparer: null,
|
|
1654
|
+
backgroundTasks: null,
|
|
1606
1655
|
chatLockManager: null,
|
|
1607
1656
|
archiveCoordinator: null,
|
|
1608
1657
|
seedOrchestrator: null,
|
|
@@ -1657,18 +1706,21 @@ export class Agent extends TypedEventEmitter {
|
|
|
1657
1706
|
get lastInteractionAt() {
|
|
1658
1707
|
return this._lastInteractionAt;
|
|
1659
1708
|
}
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1709
|
+
// 删后注记(2026-10-18 · 5.0.0,批次 GOVERNANCE-SRC-1 方案②「整链退役」,用户拍板):
|
|
1710
|
+
// 曾有公开 getter `governance`(MemoryGovernance 门面:deduplicate / detectConflicts /
|
|
1711
|
+
// sourceHealth / suggest)。退役理由 = **结构性恒空**,非「暂时没人用」:四个方法里三个
|
|
1712
|
+
// 逐 `GOVERNANCE_SOURCES` 取样,而该常量自「设定记忆归角色包」后固定为空数组 ⇒
|
|
1713
|
+
// deduplicate 恒 0 条 / detectConflicts 恒 skippedReason / suggest(undefined) 恒 [];
|
|
1714
|
+
// 仅 sourceHealth 走 getAllSources() 有效,而其信息已由 `memory.stats().bySource` 覆盖。
|
|
1715
|
+
// 治理模型现为写时取代(roundSummaryGenerator 的 supersedeSimilar + supersededBy)。
|
|
1716
|
+
// 连带拆除:MemoryAdvisor / DedupManager / GOVERNANCE_SOURCES / llmJudgeHelper /
|
|
1717
|
+
// recallDefaults / dedupCompleted 事件 + 宿主 suggestions 通道。勿加回。
|
|
1664
1718
|
// ─── 运行时指标 ────────────────────────────────
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
return readBackgroundTaskStats();
|
|
1671
|
-
}
|
|
1719
|
+
// 删后注记(2026-10-16 · 5.0.0,按 SSOT/不带伤裁决提前于 DEPRECATE-1 周期删除):曾有公开
|
|
1720
|
+
// getBackgroundTaskStats()——转发 utils 后台任务统计快照(pending/completed/failed),
|
|
1721
|
+
// 宿主零消费;连带 utils 层 getBackgroundTaskStats 函数、BackgroundTaskStats 接口与
|
|
1722
|
+
// stats 的 completed/failed 只写字段一并拆除(pending 仍服务后台任务等待/收口)。
|
|
1723
|
+
// 勿加回;后台健康度观测需求出现时经事件流或专用诊断面重建。
|
|
1672
1724
|
/**
|
|
1673
1725
|
* 获取 Agent 运行时指标快照(可观测性):聚合 AgentLoop 指标与 Agent 层治理指标;
|
|
1674
1726
|
* 未初始化返回全零默认值(不抛异常),纯只读同步零副作用,适合宿主定期轮询监控面板。
|
|
@@ -1693,6 +1745,9 @@ export class Agent extends TypedEventEmitter {
|
|
|
1693
1745
|
unparsedToolIntentCount: 0,
|
|
1694
1746
|
ledgerStubEchoCount: 0,
|
|
1695
1747
|
readDedupBlockCount: 0,
|
|
1748
|
+
// B4 口径:执行层闸门归 blocked(不再与 failureCount 双计),见字段 JSDoc
|
|
1749
|
+
toolBlockedCount: 0,
|
|
1750
|
+
toolBlockedWithFailureCount: 0,
|
|
1696
1751
|
},
|
|
1697
1752
|
context: { truncationCount: 0, messageCount: 0, estimatedTokens: 0 },
|
|
1698
1753
|
plan: { taskTableWriteCount: 0, planItemBoundaryCount: 0 },
|
|
@@ -1733,10 +1788,6 @@ export class Agent extends TypedEventEmitter {
|
|
|
1733
1788
|
get memory() {
|
|
1734
1789
|
return this.memoryInspector;
|
|
1735
1790
|
}
|
|
1736
|
-
/** 项目管理器(返回 null 表示 Agent 未初始化) */
|
|
1737
|
-
get projects() {
|
|
1738
|
-
return this.projectManager;
|
|
1739
|
-
}
|
|
1740
1791
|
/** 安全守卫(写入确认回调注册:`onWriteConfirmation` 返回 true 放行、false 拒绝;未初始化/projectPath 未设为 null) */
|
|
1741
1792
|
get security() {
|
|
1742
1793
|
return this.pctx?.security ?? null;
|