autosnippet 3.2.4 → 3.2.6
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/README.md +2 -4
- package/bin/cli.js +164 -145
- package/config/constitution.yaml +2 -0
- package/dashboard/dist/assets/{index-DNOHYBhy.css → index-BaGY7kJI.css} +1 -1
- package/dashboard/dist/assets/{index-6itPuGFl.js → index-DfHY_3ln.js} +25 -25
- package/dashboard/dist/index.html +2 -2
- package/lib/cli/CliLogger.js +78 -0
- package/lib/cli/SetupService.js +9 -718
- package/lib/cli/UpgradeService.js +23 -398
- package/lib/cli/deploy/FileDeployer.js +562 -0
- package/lib/cli/deploy/FileManifest.js +272 -0
- package/lib/external/mcp/McpServer.js +22 -26
- package/lib/external/mcp/autoApproveInjector.js +1 -0
- package/lib/external/mcp/handlers/bootstrap/BootstrapSession.js +5 -5
- package/lib/external/mcp/handlers/bootstrap/pipeline/EpisodicMemory.js +25 -3
- package/lib/external/mcp/handlers/bootstrap/pipeline/IncrementalBootstrap.js +6 -6
- package/lib/external/mcp/handlers/bootstrap/pipeline/ToolResultCache.js +4 -0
- package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.js +5 -5
- package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +89 -44
- package/lib/external/mcp/handlers/consolidated.js +8 -9
- package/lib/external/mcp/handlers/dimension-complete-external.js +4 -4
- package/lib/external/mcp/handlers/guard.js +283 -5
- package/lib/external/mcp/handlers/task.js +183 -9
- package/lib/external/mcp/tools.js +32 -81
- package/lib/http/routes/task.js +55 -0
- package/lib/service/chat/AnalystAgent.js +12 -12
- package/lib/service/chat/ChatAgent.js +227 -545
- package/lib/service/chat/ChatAgentPrompts.js +9 -11
- package/lib/service/chat/ContextWindow.js +2 -296
- package/lib/service/chat/EpisodicConsolidator.js +15 -15
- package/lib/service/chat/ExplorationTracker.js +1262 -0
- package/lib/service/chat/HandoffProtocol.js +8 -9
- package/lib/service/chat/Memory.js +4 -0
- package/lib/service/chat/ProducerAgent.js +9 -6
- package/lib/service/chat/ProjectSemanticMemory.js +4 -0
- package/lib/service/chat/ReasoningTrace.js +182 -0
- package/lib/service/chat/WorkingMemory.js +4 -0
- package/lib/service/chat/memory/ActiveContext.js +910 -0
- package/lib/service/chat/memory/MemoryCoordinator.js +662 -0
- package/lib/service/chat/memory/PersistentMemory.js +450 -0
- package/lib/service/chat/memory/SessionStore.js +896 -0
- package/lib/service/chat/memory/index.js +13 -0
- package/lib/service/chat/tools/ast-graph.js +17 -16
- package/lib/service/cursor/AgentInstructionsGenerator.js +76 -47
- package/lib/service/cursor/FileProtection.js +4 -1
- package/lib/service/guard/GuardCheckEngine.js +10 -3
- package/lib/service/task/TaskGraphService.js +3 -3
- package/lib/shared/LanguageService.js +2 -1
- package/package.json +1 -1
- package/skills/autosnippet-intent/SKILL.md +1 -3
- package/skills/autosnippet-recipes/SKILL.md +1 -3
- package/templates/claude-code/commands/prime.md +19 -0
- package/templates/claude-code/hooks/autosnippet-session.sh +63 -0
- package/templates/claude-code/settings.json +21 -0
- package/templates/copilot-instructions.md +64 -177
- package/templates/cursor-hooks/commands/prime.md +12 -0
- package/templates/cursor-hooks/hooks/session-start.sh +10 -0
- package/templates/cursor-hooks/hooks.json +11 -0
- package/templates/cursor-rules/autosnippet-conventions.mdc +52 -3
- package/templates/cursor-rules/autosnippet-workflow.mdc +51 -27
- package/lib/external/mcp/handlers/decide.js +0 -109
- package/lib/external/mcp/handlers/ready.js +0 -42
- package/lib/service/chat/ReasoningLayer.js +0 -888
- package/templates/claude-hooks.yaml +0 -19
|
@@ -7,17 +7,10 @@ import fs from 'node:fs';
|
|
|
7
7
|
/**
|
|
8
8
|
* 构建原生函数调用模式的系统提示词
|
|
9
9
|
*
|
|
10
|
-
* 设计原则:
|
|
11
|
-
* - 精简: bootstrap 模式不注入 SOUL.md 人格(节省 ~500 token)
|
|
12
|
-
* - 分层: 静态指令放 systemPrompt,动态上下文放 user prompt
|
|
13
|
-
* - 控制通过 PhaseRouter 状态机实现,不通过追加 user 消息
|
|
14
|
-
* - 工具描述已通过 functionDeclarations 传递,不重复
|
|
15
|
-
*
|
|
16
10
|
* @param {object} options
|
|
17
11
|
* @param {string} options.currentSource — 'user' | 'system'
|
|
18
12
|
* @param {string} options.projectBriefingCache — 项目概况缓存文本
|
|
19
|
-
* @param {
|
|
20
|
-
* @param {import('./ProjectSemanticMemory.js').ProjectSemanticMemory|null} options.semanticMemory — Tier 3 语义记忆
|
|
13
|
+
* @param {object} [options.memoryCoordinator] — MemoryCoordinator 实例
|
|
21
14
|
* @param {object} options.budget — 预算配置
|
|
22
15
|
* @param {string} options.soulPath — SOUL.md 文件路径
|
|
23
16
|
* @returns {string}
|
|
@@ -25,8 +18,7 @@ import fs from 'node:fs';
|
|
|
25
18
|
export function buildNativeToolSystemPrompt({
|
|
26
19
|
currentSource,
|
|
27
20
|
projectBriefingCache,
|
|
28
|
-
|
|
29
|
-
semanticMemory,
|
|
21
|
+
memoryCoordinator,
|
|
30
22
|
budget = {},
|
|
31
23
|
soulPath,
|
|
32
24
|
}) {
|
|
@@ -41,9 +33,15 @@ export function buildNativeToolSystemPrompt({
|
|
|
41
33
|
/* SOUL.md not available */
|
|
42
34
|
}
|
|
43
35
|
|
|
36
|
+
// v5.0: 通过 coordinator 构建静态记忆 section
|
|
37
|
+
let memorySection = '';
|
|
38
|
+
if (memoryCoordinator) {
|
|
39
|
+
memorySection = memoryCoordinator.buildStaticMemoryPrompt({ mode: 'user' });
|
|
40
|
+
}
|
|
41
|
+
|
|
44
42
|
return `${soulSection}
|
|
45
43
|
你是 AutoSnippet 项目的统一 AI 中心。项目内所有 AI 推理和分析都通过你执行。
|
|
46
|
-
${projectBriefingCache}${
|
|
44
|
+
${projectBriefingCache}${memorySection}
|
|
47
45
|
|
|
48
46
|
## 使用规则
|
|
49
47
|
1. 当需要查询数据时,直接调用相应工具。
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* 1. messages[0] 始终是原始 user prompt(不可删除)
|
|
12
12
|
* 2. assistant(toolCalls) 与其 tool results 是原子单元(不可拆分)
|
|
13
13
|
* 3. 每次 AI 调用前自动压缩到 TOKEN_BUDGET 以内
|
|
14
|
-
* 4. 不通过追加 user 消息来控制 AI 行为(由
|
|
14
|
+
* 4. 不通过追加 user 消息来控制 AI 行为(由 ExplorationTracker 管理)
|
|
15
15
|
*
|
|
16
16
|
* 三级递进压缩:
|
|
17
17
|
* L1 (60-80%): 截断旧的 tool results 内容
|
|
@@ -149,7 +149,7 @@ export class ContextWindow {
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
/**
|
|
152
|
-
* 追加阶段过渡引导消息 — 轻量级 user 消息,用于在
|
|
152
|
+
* 追加阶段过渡引导消息 — 轻量级 user 消息,用于在 ExplorationTracker 阶段转换时
|
|
153
153
|
* 向 AI 明确传达新阶段的行为期望。与 appendUserMessage 功能相同,
|
|
154
154
|
* 独立命名以便审计和搜索。
|
|
155
155
|
* @param {string} content
|
|
@@ -647,297 +647,3 @@ function limitFileContent(result, maxChars) {
|
|
|
647
647
|
|
|
648
648
|
return JSON.stringify(limited);
|
|
649
649
|
}
|
|
650
|
-
|
|
651
|
-
// ─── PhaseRouter ────────────────────────────────────────
|
|
652
|
-
|
|
653
|
-
/**
|
|
654
|
-
* 阶段路由器 — 管理 Agent ReAct 循环的阶段自动推进
|
|
655
|
-
*
|
|
656
|
-
* 取代散落在 while 循环中的多个状态变量:
|
|
657
|
-
* - wrapUpInjected → PRODUCE 阶段自动处理
|
|
658
|
-
* - searchOnlyRounds → EXPLORE 阶段自动计数
|
|
659
|
-
* - searchBudgetPromptInjected → EXPLORE→PRODUCE 自动转换
|
|
660
|
-
* - idleRoundsWithoutSubmit → PRODUCE 阶段自动计数
|
|
661
|
-
*
|
|
662
|
-
* 阶段流:
|
|
663
|
-
* candidate/dual: EXPLORE → PRODUCE → SUMMARIZE
|
|
664
|
-
* skill-only: EXPLORE → SUMMARIZE
|
|
665
|
-
*/
|
|
666
|
-
export class PhaseRouter {
|
|
667
|
-
/** @type {'EXPLORE'|'PRODUCE'|'SUMMARIZE'} */
|
|
668
|
-
#phase;
|
|
669
|
-
/** @type {number} 当前阶段内的轮次计数 */
|
|
670
|
-
#phaseRounds = 0;
|
|
671
|
-
/** @type {number} 连续无 submit 的轮次 */
|
|
672
|
-
#idleRounds = 0;
|
|
673
|
-
/** @type {number} 总迭代轮次 */
|
|
674
|
-
#totalIterations = 0;
|
|
675
|
-
/** @type {number} 总 submit 数 */
|
|
676
|
-
#totalSubmits = 0;
|
|
677
|
-
/** @type {Object} 预算配置 */
|
|
678
|
-
#budget;
|
|
679
|
-
/** @type {boolean} 是否为 skill-only 维度 */
|
|
680
|
-
#isSkillOnly;
|
|
681
|
-
/** @type {Object} 日志器 */
|
|
682
|
-
#logger;
|
|
683
|
-
|
|
684
|
-
/** @type {boolean} 是否因 maxIterations 强制进入 SUMMARIZE */
|
|
685
|
-
#forcedSummarize = false;
|
|
686
|
-
|
|
687
|
-
/**
|
|
688
|
-
* @param {Object} budget — 预算配置
|
|
689
|
-
* @param {boolean} isSkillOnly — 是否为 skill-only 维度
|
|
690
|
-
*/
|
|
691
|
-
constructor(budget, isSkillOnly = false) {
|
|
692
|
-
this.#budget = budget;
|
|
693
|
-
this.#isSkillOnly = isSkillOnly;
|
|
694
|
-
this.#phase = 'EXPLORE';
|
|
695
|
-
this.#logger = Logger.getInstance();
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
/**
|
|
699
|
-
* 获取当前阶段
|
|
700
|
-
* @returns {'EXPLORE'|'PRODUCE'|'SUMMARIZE'}
|
|
701
|
-
*/
|
|
702
|
-
get phase() {
|
|
703
|
-
return this.#phase;
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
/**
|
|
707
|
-
* 获取总迭代次数
|
|
708
|
-
* @returns {number}
|
|
709
|
-
*/
|
|
710
|
-
get totalIterations() {
|
|
711
|
-
return this.#totalIterations;
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
/**
|
|
715
|
-
* 获取总提交数
|
|
716
|
-
* @returns {number}
|
|
717
|
-
*/
|
|
718
|
-
get totalSubmits() {
|
|
719
|
-
return this.#totalSubmits;
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
/**
|
|
723
|
-
* 是否因 maxIterations 触顶而强制进入 SUMMARIZE(一次性标记)
|
|
724
|
-
* 调用后自动复位
|
|
725
|
-
* @returns {boolean}
|
|
726
|
-
*/
|
|
727
|
-
consumeForcedSummarize() {
|
|
728
|
-
if (this.#forcedSummarize) {
|
|
729
|
-
this.#forcedSummarize = false;
|
|
730
|
-
return true;
|
|
731
|
-
}
|
|
732
|
-
return false;
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
/**
|
|
736
|
-
* 获取当前阶段的 toolChoice
|
|
737
|
-
* @returns {'required'|'auto'|'none'}
|
|
738
|
-
*/
|
|
739
|
-
getToolChoice() {
|
|
740
|
-
switch (this.#phase) {
|
|
741
|
-
case 'EXPLORE':
|
|
742
|
-
// 最后一轮 EXPLORE 用 auto 保底
|
|
743
|
-
if (this.#phaseRounds >= this.#budget.searchBudget - 1) {
|
|
744
|
-
return 'auto';
|
|
745
|
-
}
|
|
746
|
-
return 'required';
|
|
747
|
-
case 'PRODUCE':
|
|
748
|
-
return 'auto';
|
|
749
|
-
case 'SUMMARIZE':
|
|
750
|
-
return 'none';
|
|
751
|
-
default:
|
|
752
|
-
return 'auto';
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
/**
|
|
757
|
-
* 是否应该退出主循环
|
|
758
|
-
* @returns {boolean}
|
|
759
|
-
*/
|
|
760
|
-
shouldExit() {
|
|
761
|
-
// 已在 SUMMARIZE 阶段 → 给 2 轮输出总结后退出
|
|
762
|
-
if (this.#phase === 'SUMMARIZE' && this.#phaseRounds >= 2) {
|
|
763
|
-
return true;
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
// 达到 maxIterations → 不硬退出,而是强制转入 SUMMARIZE 让 AI 在完整上下文中收尾
|
|
767
|
-
if (this.#totalIterations >= this.#budget.maxIterations && this.#phase !== 'SUMMARIZE') {
|
|
768
|
-
this.#logger.info(
|
|
769
|
-
`[PhaseRouter] maxIterations reached (${this.#totalIterations}/${this.#budget.maxIterations}), forcing → SUMMARIZE for graceful exit`
|
|
770
|
-
);
|
|
771
|
-
this.#forcedSummarize = true;
|
|
772
|
-
this.#transitionTo('SUMMARIZE');
|
|
773
|
-
// 返回 false 让主循环继续运行 SUMMARIZE 阶段的 2 轮收尾
|
|
774
|
-
return false;
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
// SUMMARIZE 阶段超限兜底(maxIterations + 2 轮 grace)
|
|
778
|
-
if (this.#totalIterations >= this.#budget.maxIterations + 2) {
|
|
779
|
-
return true;
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
return false;
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
/**
|
|
786
|
-
* 每轮迭代开始时调用 — 递增计数 + 检查阶段转换
|
|
787
|
-
*/
|
|
788
|
-
tick() {
|
|
789
|
-
this.#totalIterations++;
|
|
790
|
-
this.#phaseRounds++;
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
/**
|
|
794
|
-
* 根据本轮工具调用结果更新阶段
|
|
795
|
-
*
|
|
796
|
-
* @param {Object} roundResult — 本轮结果
|
|
797
|
-
* @param {Array} roundResult.functionCalls — AI 返回的工具调用(null 表示纯文本)
|
|
798
|
-
* @param {number} roundResult.submitCount — 本轮提交的候选数
|
|
799
|
-
* @param {boolean} roundResult.isTextOnly — AI 返回纯文本(无工具调用)
|
|
800
|
-
* @returns {{ transitioned: boolean, newPhase: string, exitReason?: string }}
|
|
801
|
-
*/
|
|
802
|
-
update(roundResult) {
|
|
803
|
-
const { submitCount = 0, isTextOnly = false } = roundResult;
|
|
804
|
-
this.#totalSubmits += submitCount;
|
|
805
|
-
|
|
806
|
-
// ── EXPLORE → PRODUCE/SUMMARIZE ──
|
|
807
|
-
if (this.#phase === 'EXPLORE') {
|
|
808
|
-
// 有提交 → 直接进入 PRODUCE
|
|
809
|
-
if (submitCount > 0) {
|
|
810
|
-
return this.#transitionTo(this.#isSkillOnly ? 'SUMMARIZE' : 'PRODUCE');
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
// 搜索轮次耗尽 → 转换
|
|
814
|
-
if (this.#phaseRounds >= this.#budget.searchBudget) {
|
|
815
|
-
const next = this.#isSkillOnly ? 'SUMMARIZE' : 'PRODUCE';
|
|
816
|
-
this.#logger.info(
|
|
817
|
-
`[PhaseRouter] search budget exhausted (${this.#phaseRounds}/${this.#budget.searchBudget}) → ${next}`
|
|
818
|
-
);
|
|
819
|
-
return this.#transitionTo(next);
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
// 文本回复(非工具调用)→ AI 可能在总结 → 转换
|
|
823
|
-
if (isTextOnly) {
|
|
824
|
-
const next = this.#isSkillOnly ? 'SUMMARIZE' : 'PRODUCE';
|
|
825
|
-
return this.#transitionTo(next);
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
return { transitioned: false, newPhase: this.#phase };
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
// ── PRODUCE → SUMMARIZE ──
|
|
832
|
-
if (this.#phase === 'PRODUCE') {
|
|
833
|
-
if (submitCount > 0) {
|
|
834
|
-
this.#idleRounds = 0;
|
|
835
|
-
} else {
|
|
836
|
-
this.#idleRounds++;
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
// 硬上限
|
|
840
|
-
if (this.#budget.maxSubmits > 0 && this.#totalSubmits >= this.#budget.maxSubmits) {
|
|
841
|
-
this.#logger.info(
|
|
842
|
-
`[PhaseRouter] hard submit cap reached (${this.#totalSubmits}/${this.#budget.maxSubmits}) → SUMMARIZE`
|
|
843
|
-
);
|
|
844
|
-
return this.#transitionTo('SUMMARIZE');
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
// 连续空转
|
|
848
|
-
if (this.#totalSubmits > 0 && this.#idleRounds >= this.#budget.idleRoundsToExit) {
|
|
849
|
-
this.#logger.info(`[PhaseRouter] idle rounds (${this.#idleRounds}) → SUMMARIZE`);
|
|
850
|
-
return this.#transitionTo('SUMMARIZE');
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
// 文本回复 — AI 可能在提交间分析或被引导提交
|
|
854
|
-
// 只在以下情况下认为 AI 主动结束:
|
|
855
|
-
// 1. 已有至少 1 次提交 (softSubmitLimit < totalSubmits 说明 AI 认为足够)
|
|
856
|
-
// 2. 或已在 PRODUCE 阶段停留多轮但 0 提交 (通过 searchBudgetGrace 兜底)
|
|
857
|
-
// 否则视为 AI 的中间分析,不立即退出
|
|
858
|
-
if (isTextOnly) {
|
|
859
|
-
if (this.#totalSubmits >= this.#budget.softSubmitLimit) {
|
|
860
|
-
this.#logger.info(
|
|
861
|
-
`[PhaseRouter] text reply after ${this.#totalSubmits} submits (≥ softLimit=${this.#budget.softSubmitLimit}) → SUMMARIZE`
|
|
862
|
-
);
|
|
863
|
-
return this.#transitionTo('SUMMARIZE');
|
|
864
|
-
}
|
|
865
|
-
// 未达 softLimit — 空转已在上方通用分支计数,不再额外递增
|
|
866
|
-
this.#logger.info(
|
|
867
|
-
`[PhaseRouter] text reply in PRODUCE — idleRounds=${this.#idleRounds}, totalSubmits=${this.#totalSubmits}, continuing`
|
|
868
|
-
);
|
|
869
|
-
return { transitioned: false, newPhase: this.#phase };
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
// PRODUCE 阶段容忍期耗尽且 0 提交 → 强制进入 SUMMARIZE
|
|
873
|
-
// 使用 PRODUCE 阶段内的轮次计数,而非 totalIterations
|
|
874
|
-
if (this.#phaseRounds >= this.#budget.searchBudgetGrace && this.#totalSubmits === 0) {
|
|
875
|
-
this.#logger.info(
|
|
876
|
-
`[PhaseRouter] PRODUCE grace exhausted (${this.#phaseRounds}/${this.#budget.searchBudgetGrace} rounds, 0 submits) → SUMMARIZE`
|
|
877
|
-
);
|
|
878
|
-
return this.#transitionTo('SUMMARIZE');
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
return { transitioned: false, newPhase: this.#phase };
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
// SUMMARIZE 阶段不转换
|
|
885
|
-
return { transitioned: false, newPhase: this.#phase };
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
/**
|
|
889
|
-
* 获取当前阶段的系统提示(注入到 systemPrompt 中,而非追加 user 消息)
|
|
890
|
-
* @returns {string|null}
|
|
891
|
-
*/
|
|
892
|
-
getPhaseHint() {
|
|
893
|
-
// 接近 maxIterations 上限时,无论处于哪个阶段都警告 AI
|
|
894
|
-
const remaining = this.#budget.maxIterations - this.#totalIterations;
|
|
895
|
-
if (remaining <= 2 && remaining > 0 && this.#phase !== 'SUMMARIZE') {
|
|
896
|
-
return `⚠️ 仅剩 ${remaining} 轮次即达上限,请尽快完成当前工作并准备输出总结。`;
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
switch (this.#phase) {
|
|
900
|
-
case 'EXPLORE':
|
|
901
|
-
if (this.#phaseRounds >= this.#budget.searchBudget - 2) {
|
|
902
|
-
return `搜索预算即将耗尽 (${this.#phaseRounds}/${this.#budget.searchBudget}),请准备提交候选或产出摘要。`;
|
|
903
|
-
}
|
|
904
|
-
return null;
|
|
905
|
-
|
|
906
|
-
case 'PRODUCE':
|
|
907
|
-
if (this.#totalSubmits === 0 && this.#phaseRounds >= 1) {
|
|
908
|
-
return this.#isSkillOnly
|
|
909
|
-
? '你已收集足够信息,请在回复中直接输出 dimensionDigest JSON。'
|
|
910
|
-
: '⚠️ 探索阶段已结束。你已收集了足够的项目信息,请 **立即** 调用 submit_knowledge 提交候选。不要继续搜索,直接提交。';
|
|
911
|
-
}
|
|
912
|
-
if (
|
|
913
|
-
this.#totalSubmits >= this.#budget.softSubmitLimit &&
|
|
914
|
-
this.#budget.softSubmitLimit > 0
|
|
915
|
-
) {
|
|
916
|
-
const remaining = this.#budget.maxSubmits - this.#totalSubmits;
|
|
917
|
-
return `已提交 ${this.#totalSubmits} 个候选(上限 ${this.#budget.maxSubmits})。${remaining > 0 ? `还可提交 ${remaining} 个。` : ''}如果还有值得记录的发现可以继续提交,否则请产出 dimensionDigest 总结。\n⚠️ 如果还有未处理的信号,请在 dimensionDigest 的 remainingTasks 字段中标记,下次运行时会续传。`;
|
|
918
|
-
}
|
|
919
|
-
return null;
|
|
920
|
-
|
|
921
|
-
case 'SUMMARIZE':
|
|
922
|
-
return null; // SUMMARIZE 阶段不注入额外 hint
|
|
923
|
-
|
|
924
|
-
default:
|
|
925
|
-
return null;
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
/**
|
|
930
|
-
* 执行阶段转换
|
|
931
|
-
* @private
|
|
932
|
-
*/
|
|
933
|
-
#transitionTo(newPhase) {
|
|
934
|
-
const oldPhase = this.#phase;
|
|
935
|
-
this.#phase = newPhase;
|
|
936
|
-
this.#phaseRounds = 0;
|
|
937
|
-
this.#idleRounds = 0;
|
|
938
|
-
this.#logger.info(
|
|
939
|
-
`[PhaseRouter] ${oldPhase} → ${newPhase} (iter=${this.#totalIterations}, submits=${this.#totalSubmits})`
|
|
940
|
-
);
|
|
941
|
-
return { transitioned: true, newPhase };
|
|
942
|
-
}
|
|
943
|
-
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* EpisodicConsolidator — Episodic → Semantic 固化引擎
|
|
3
3
|
*
|
|
4
|
-
* Bootstrap 完成后,将
|
|
4
|
+
* Bootstrap 完成后,将 SessionStore (Tier 2) 中的维度分析结果
|
|
5
5
|
* 提炼为结构化记忆,固化到 ProjectSemanticMemory (Tier 3)。
|
|
6
6
|
*
|
|
7
7
|
* 固化策略 (规则化,无需额外 AI 调用):
|
|
@@ -74,15 +74,15 @@ export class EpisodicConsolidator {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
/**
|
|
77
|
-
* 执行固化:
|
|
77
|
+
* 执行固化: SessionStore → ProjectSemanticMemory
|
|
78
78
|
*
|
|
79
|
-
* @param {import('
|
|
79
|
+
* @param {import('./memory/SessionStore.js').SessionStore} sessionStore
|
|
80
80
|
* @param {object} [opts]
|
|
81
81
|
* @param {string} [opts.bootstrapSession] — Bootstrap session ID
|
|
82
82
|
* @param {boolean} [opts.clearPrevious=false] — 是否先清除旧的 bootstrap 记忆
|
|
83
83
|
* @returns {{ findings: object, insights: object, textFacts: object, total: object }}
|
|
84
84
|
*/
|
|
85
|
-
consolidate(
|
|
85
|
+
consolidate(sessionStore, { bootstrapSession, clearPrevious = false } = {}) {
|
|
86
86
|
const t0 = Date.now();
|
|
87
87
|
|
|
88
88
|
// 可选: 清除旧的 bootstrap 记忆 (全量重跑场景)
|
|
@@ -95,13 +95,13 @@ export class EpisodicConsolidator {
|
|
|
95
95
|
this.#semanticMemory.compact();
|
|
96
96
|
|
|
97
97
|
// 2. 从 findings 提取 fact 记忆
|
|
98
|
-
const findingMemories = this.#extractFromFindings(
|
|
98
|
+
const findingMemories = this.#extractFromFindings(sessionStore);
|
|
99
99
|
|
|
100
100
|
// 3. 从 Tier Reflections 提取 insight 记忆
|
|
101
|
-
const insightMemories = this.#extractFromReflections(
|
|
101
|
+
const insightMemories = this.#extractFromReflections(sessionStore);
|
|
102
102
|
|
|
103
103
|
// 4. 从 analysisText 提取文本中的事实
|
|
104
|
-
const textFactMemories = this.#extractFromAnalysisText(
|
|
104
|
+
const textFactMemories = this.#extractFromAnalysisText(sessionStore);
|
|
105
105
|
|
|
106
106
|
// 5. 合并所有候选, 使用 consolidate 去重
|
|
107
107
|
const allCandidates = [...findingMemories, ...insightMemories, ...textFactMemories];
|
|
@@ -137,12 +137,12 @@ export class EpisodicConsolidator {
|
|
|
137
137
|
*
|
|
138
138
|
* 每个 finding 映射为一条 fact,importance 直接继承。
|
|
139
139
|
*/
|
|
140
|
-
#extractFromFindings(
|
|
140
|
+
#extractFromFindings(sessionStore) {
|
|
141
141
|
const memories = [];
|
|
142
|
-
const completedDims =
|
|
142
|
+
const completedDims = sessionStore.getCompletedDimensions();
|
|
143
143
|
|
|
144
144
|
for (const dimId of completedDims) {
|
|
145
|
-
const report =
|
|
145
|
+
const report = sessionStore.getDimensionReport(dimId);
|
|
146
146
|
if (!report?.findings) {
|
|
147
147
|
continue;
|
|
148
148
|
}
|
|
@@ -185,9 +185,9 @@ export class EpisodicConsolidator {
|
|
|
185
185
|
* suggestionsForNextTier → insight (分析建议)
|
|
186
186
|
* topFindings 中重要性 ≥ 7 的 → fact (高优先级重复确认)
|
|
187
187
|
*/
|
|
188
|
-
#extractFromReflections(
|
|
188
|
+
#extractFromReflections(sessionStore) {
|
|
189
189
|
const memories = [];
|
|
190
|
-
const json =
|
|
190
|
+
const json = sessionStore.toJSON();
|
|
191
191
|
const reflections = json.tierReflections || [];
|
|
192
192
|
|
|
193
193
|
for (const ref of reflections) {
|
|
@@ -253,13 +253,13 @@ export class EpisodicConsolidator {
|
|
|
253
253
|
*
|
|
254
254
|
* 仅提取高置信度的简短陈述 (≤100 字), 避免噪音。
|
|
255
255
|
*/
|
|
256
|
-
#extractFromAnalysisText(
|
|
256
|
+
#extractFromAnalysisText(sessionStore) {
|
|
257
257
|
const memories = [];
|
|
258
258
|
const seen = new Set(); // 去重
|
|
259
|
-
const completedDims =
|
|
259
|
+
const completedDims = sessionStore.getCompletedDimensions();
|
|
260
260
|
|
|
261
261
|
for (const dimId of completedDims) {
|
|
262
|
-
const report =
|
|
262
|
+
const report = sessionStore.getDimensionReport(dimId);
|
|
263
263
|
if (!report?.analysisText) {
|
|
264
264
|
continue;
|
|
265
265
|
}
|