autosnippet 3.2.8 → 3.2.10
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/bin/cli.js +6 -5
- package/dashboard/dist/assets/index-BTAsOZv2.js +128 -0
- package/dashboard/dist/assets/index-C_72Ct98.css +1 -0
- package/dashboard/dist/index.html +2 -2
- package/lib/cli/AiScanService.js +23 -26
- package/lib/cli/SetupService.js +1 -1
- package/lib/cli/deploy/FileManifest.js +1 -1
- package/lib/core/AstAnalyzer.js +1 -1
- package/lib/core/discovery/index.js +2 -2
- package/lib/external/ai/AiProvider.js +66 -172
- package/lib/external/ai/providers/GoogleGeminiProvider.js +29 -5
- package/lib/external/mcp/handlers/bootstrap/BootstrapSession.js +1 -1
- package/lib/external/mcp/handlers/bootstrap/ExternalSubmissionTracker.js +3 -3
- package/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +1 -1
- package/lib/external/mcp/handlers/bootstrap/pipeline/IncrementalBootstrap.js +1 -1
- package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.js +8 -8
- package/lib/external/mcp/handlers/bootstrap/pipeline/noAiFallback.js +1 -1
- package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +291 -204
- package/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +7 -6
- package/lib/external/mcp/handlers/bootstrap/shared/dimension-sop.js +1 -1
- package/lib/external/mcp/handlers/bootstrap-internal.js +2 -2
- package/lib/external/mcp/handlers/dimension-complete-external.js +6 -6
- package/lib/http/HttpServer.js +1 -1
- package/lib/http/middleware/requestLogger.js +1 -0
- package/lib/http/routes/ai.js +240 -35
- package/lib/http/routes/candidates.js +2 -3
- package/lib/http/routes/extract.js +13 -11
- package/lib/http/routes/modules.js +2 -2
- package/lib/http/routes/recipes.js +5 -5
- package/lib/http/routes/remote.js +134 -255
- package/lib/http/routes/violations.js +0 -54
- package/lib/http/utils/sse-sessions.js +1 -1
- package/lib/infrastructure/logging/Logger.js +5 -4
- package/lib/infrastructure/monitoring/PerformanceMonitor.js +3 -2
- package/lib/injection/ServiceContainer.js +64 -17
- package/lib/platform/ScreenCaptureService.js +177 -0
- package/lib/platform/ios/routes/spm.js +2 -2
- package/lib/service/agent/AgentEventBus.js +207 -0
- package/lib/service/agent/AgentFactory.js +535 -0
- package/lib/service/agent/AgentMessage.js +240 -0
- package/lib/service/agent/AgentRouter.js +228 -0
- package/lib/service/agent/AgentRuntime.js +1056 -0
- package/lib/service/agent/AgentState.js +217 -0
- package/lib/service/agent/IntentClassifier.js +331 -0
- package/lib/service/agent/LarkTransport.js +389 -0
- package/lib/service/agent/capabilities.js +409 -0
- package/lib/service/{chat → agent/context}/ContextWindow.js +37 -12
- package/lib/service/{chat → agent/context}/ExplorationTracker.js +112 -33
- package/lib/service/{chat → agent/core}/ChatAgentPrompts.js +5 -3
- package/lib/service/agent/core/LoopContext.js +170 -0
- package/lib/service/agent/core/MessageAdapter.js +223 -0
- package/lib/service/agent/core/ToolExecutionPipeline.js +376 -0
- package/lib/service/{chat → agent/domain}/ChatAgentTasks.js +15 -98
- package/lib/service/{chat → agent/domain}/EpisodicConsolidator.js +7 -7
- package/lib/service/{chat → agent/domain}/EvidenceCollector.js +4 -2
- package/lib/service/{chat/AnalystAgent.js → agent/domain/insight-analyst.js} +37 -172
- package/lib/service/{chat/HandoffProtocol.js → agent/domain/insight-gate.js} +85 -135
- package/lib/service/agent/domain/insight-producer.js +270 -0
- package/lib/service/agent/domain/scan-prompts.js +444 -0
- package/lib/service/agent/forced-summary.js +266 -0
- package/lib/service/agent/index.js +91 -0
- package/lib/service/{chat → agent}/memory/ActiveContext.js +29 -1
- package/lib/service/{chat → agent}/memory/MemoryCoordinator.js +7 -7
- package/lib/service/{chat/ProjectSemanticMemory.js → agent/memory/PersistentMemory.js} +359 -89
- package/lib/service/{chat → agent}/memory/SessionStore.js +1 -1
- package/lib/service/{chat → agent}/memory/index.js +1 -1
- package/lib/service/agent/policies.js +442 -0
- package/lib/service/agent/presets.js +305 -0
- package/lib/service/agent/strategies.js +756 -0
- package/lib/service/{chat → agent/tools}/ToolRegistry.js +3 -3
- package/lib/service/agent/tools/ai-analysis.js +75 -0
- package/lib/service/{chat → agent}/tools/composite.js +2 -1
- package/lib/service/{chat → agent}/tools/guard.js +1 -121
- package/lib/service/{chat → agent}/tools/index.js +27 -21
- package/lib/service/{chat → agent}/tools/infrastructure.js +1 -1
- package/lib/service/agent/tools/knowledge-graph.js +112 -0
- package/lib/service/agent/tools/scan-recipe.js +189 -0
- package/lib/service/agent/tools/system-interaction.js +476 -0
- package/lib/service/automation/DirectiveDetector.js +0 -1
- package/lib/service/automation/FileWatcher.js +0 -8
- package/lib/service/automation/handlers/CreateHandler.js +7 -3
- package/lib/service/automation/handlers/DraftHandler.js +7 -6
- package/lib/service/module/ModuleService.js +40 -73
- package/lib/service/skills/SignalCollector.js +26 -19
- package/lib/service/snippet/codecs/VSCodeCodec.js +1 -1
- package/lib/shared/FieldSpec.js +1 -1
- package/lib/shared/StyleGuide.js +1 -1
- package/package.json +4 -1
- package/resources/native-ui/screenshot.swift +228 -0
- package/dashboard/dist/assets/index-D5jiDBQG.css +0 -1
- package/dashboard/dist/assets/index-e5OKj-Ni.js +0 -128
- package/lib/core/discovery/SpmDiscoverer.js +0 -5
- package/lib/external/mcp/handlers/bootstrap/pipeline/EpisodicMemory.js +0 -750
- package/lib/external/mcp/handlers/bootstrap/pipeline/ToolResultCache.js +0 -277
- package/lib/http/routes/spm.js +0 -5
- package/lib/infrastructure/external/XcodeAutomation.js +0 -15
- package/lib/service/chat/ChatAgent.js +0 -1602
- package/lib/service/chat/Memory.js +0 -161
- package/lib/service/chat/ProducerAgent.js +0 -431
- package/lib/service/chat/ReasoningTrace.js +0 -523
- package/lib/service/chat/TaskPipeline.js +0 -357
- package/lib/service/chat/WorkingMemory.js +0 -359
- package/lib/service/chat/memory/PersistentMemory.js +0 -450
- package/lib/service/chat/tools/ai-analysis.js +0 -267
- package/lib/service/chat/tools/knowledge-graph.js +0 -234
- package/lib/service/chat/tools.js +0 -18
- package/lib/service/snippet/PlaceholderConverter.js +0 -5
- package/lib/service/snippet/codecs/XcodeCodec.js +0 -5
- /package/lib/service/{chat → agent}/ConversationStore.js +0 -0
- /package/lib/service/{chat → agent}/tools/_shared.js +0 -0
- /package/lib/service/{chat → agent}/tools/ast-graph.js +0 -0
- /package/lib/service/{chat → agent}/tools/lifecycle.js +0 -0
- /package/lib/service/{chat → agent}/tools/project-access.js +0 -0
- /package/lib/service/{chat → agent}/tools/query.js +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ChatAgentTasks —
|
|
2
|
+
* ChatAgentTasks — Agent 预定义任务方法
|
|
3
3
|
*
|
|
4
|
-
* 每个任务接收 context 对象: {
|
|
5
|
-
* -
|
|
4
|
+
* 每个任务接收 context 对象: { invokeAgent, aiProvider, container, logger }
|
|
5
|
+
* - invokeAgent(toolName, params) — 直接执行工具 handler(纯数据工具)
|
|
6
6
|
* - aiProvider — AI Provider 实例
|
|
7
7
|
* - container — ServiceContainer
|
|
8
8
|
* - logger — Logger 实例
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
* 2. 顺便返回质量评估建议
|
|
15
15
|
*/
|
|
16
16
|
export async function taskCheckAndSubmit(context, { candidate, projectRoot }) {
|
|
17
|
-
const {
|
|
17
|
+
const { invokeAgent, aiProvider } = context;
|
|
18
18
|
|
|
19
19
|
// Step 1: 查重
|
|
20
|
-
const duplicates = await
|
|
20
|
+
const duplicates = await invokeAgent('check_duplicate', {
|
|
21
21
|
candidate,
|
|
22
22
|
projectRoot,
|
|
23
23
|
threshold: 0.5,
|
|
@@ -61,102 +61,19 @@ ${highSim.map((s) => `- ${s.title} (相似度: ${s.similarity})`).join('\n')}
|
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
63
|
* 任务: 批量发现 Recipe 间的知识图谱关系
|
|
64
|
-
*
|
|
64
|
+
* 委托给 AgentFactory.discoverRelations (独立 Explore → Synthesize 管线)
|
|
65
65
|
*/
|
|
66
66
|
export async function taskDiscoverAllRelations(context, { batchSize = 20 } = {}) {
|
|
67
|
-
const {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (!knowledgeService) {
|
|
71
|
-
throw new Error('KnowledgeService 不可用');
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (!aiProvider) {
|
|
75
|
-
throw new Error('AI Provider 未配置,请先设置 API Key');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// 获取所有活跃知识条目
|
|
79
|
-
const { items = [], data = [] } = await knowledgeService.list(
|
|
80
|
-
{ lifecycle: 'active' },
|
|
81
|
-
{ page: 1, pageSize: 500 }
|
|
82
|
-
);
|
|
83
|
-
const recipes = items.length > 0 ? items : data;
|
|
84
|
-
if (recipes.length < 2) {
|
|
85
|
-
return {
|
|
86
|
-
discovered: 0,
|
|
87
|
-
totalPairs: 0,
|
|
88
|
-
message: `只有 ${recipes.length} 条 Recipe,至少需要 2 条`,
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// 按 batch 分组分析
|
|
93
|
-
const pairs = [];
|
|
94
|
-
for (let i = 0; i < recipes.length; i++) {
|
|
95
|
-
for (let j = i + 1; j < recipes.length; j++) {
|
|
96
|
-
pairs.push([recipes[i], recipes[j]]);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
let discovered = 0;
|
|
101
|
-
const results = [];
|
|
102
|
-
let batchErrors = 0;
|
|
103
|
-
|
|
104
|
-
// 分批处理,单批失败不终止整体
|
|
105
|
-
for (let b = 0; b < pairs.length; b += batchSize) {
|
|
106
|
-
const batch = pairs.slice(b, b + batchSize);
|
|
107
|
-
try {
|
|
108
|
-
const result = await executeTool('discover_relations', {
|
|
109
|
-
recipePairs: batch.map(([a, b]) => ({
|
|
110
|
-
a: {
|
|
111
|
-
id: a.id,
|
|
112
|
-
title: a.title,
|
|
113
|
-
category: a.category,
|
|
114
|
-
language: a.language,
|
|
115
|
-
code: String(a.content || a.code || '').substring(0, 500),
|
|
116
|
-
},
|
|
117
|
-
b: {
|
|
118
|
-
id: b.id,
|
|
119
|
-
title: b.title,
|
|
120
|
-
category: b.category,
|
|
121
|
-
language: b.language,
|
|
122
|
-
code: String(b.content || b.code || '').substring(0, 500),
|
|
123
|
-
},
|
|
124
|
-
})),
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
if (result.error) {
|
|
128
|
-
batchErrors++;
|
|
129
|
-
logger.warn(
|
|
130
|
-
`[DiscoverRelations] Batch ${Math.floor(b / batchSize) + 1} error: ${result.error}`
|
|
131
|
-
);
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
if (result.relations) {
|
|
135
|
-
discovered += result.relations.length;
|
|
136
|
-
results.push(...result.relations);
|
|
137
|
-
}
|
|
138
|
-
} catch (err) {
|
|
139
|
-
batchErrors++;
|
|
140
|
-
logger.warn(
|
|
141
|
-
`[DiscoverRelations] Batch ${Math.floor(b / batchSize) + 1} threw: ${err.message}`
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return {
|
|
147
|
-
discovered,
|
|
148
|
-
totalPairs: pairs.length,
|
|
149
|
-
totalBatches: Math.ceil(pairs.length / batchSize),
|
|
150
|
-
batchErrors,
|
|
151
|
-
relations: results,
|
|
152
|
-
};
|
|
67
|
+
const { container } = context;
|
|
68
|
+
const agentFactory = container.get('agentFactory');
|
|
69
|
+
return agentFactory.discoverRelations({ batchSize });
|
|
153
70
|
}
|
|
154
71
|
|
|
155
72
|
/**
|
|
156
73
|
* 任务: 批量 AI 补全候选语义字段
|
|
157
74
|
*/
|
|
158
75
|
export async function taskFullEnrich(context, { status = 'pending', maxCount = 50 } = {}) {
|
|
159
|
-
const {
|
|
76
|
+
const { invokeAgent, container } = context;
|
|
160
77
|
|
|
161
78
|
const knowledgeService = container.get('knowledgeService');
|
|
162
79
|
|
|
@@ -179,7 +96,7 @@ export async function taskFullEnrich(context, { status = 'pending', maxCount = 5
|
|
|
179
96
|
return { enriched: 0, message: 'All candidates already enriched' };
|
|
180
97
|
}
|
|
181
98
|
|
|
182
|
-
const result = await
|
|
99
|
+
const result = await invokeAgent('enrich_candidate', {
|
|
183
100
|
candidateIds: needEnrich.map((c) => c.id).slice(0, 20),
|
|
184
101
|
});
|
|
185
102
|
|
|
@@ -191,7 +108,7 @@ export async function taskFullEnrich(context, { status = 'pending', maxCount = 5
|
|
|
191
108
|
* 对活跃 Recipe 逐个评分,返回低于阈值的列表
|
|
192
109
|
*/
|
|
193
110
|
export async function taskQualityAudit(context, { threshold = 0.6, maxCount = 100 } = {}) {
|
|
194
|
-
const {
|
|
111
|
+
const { invokeAgent, container } = context;
|
|
195
112
|
|
|
196
113
|
const knowledgeService = container.get('knowledgeService');
|
|
197
114
|
|
|
@@ -208,7 +125,7 @@ export async function taskQualityAudit(context, { threshold = 0.6, maxCount = 10
|
|
|
208
125
|
const gradeDistribution = { A: 0, B: 0, C: 0, D: 0, F: 0 };
|
|
209
126
|
|
|
210
127
|
for (const recipe of recipes) {
|
|
211
|
-
const scoreResult = await
|
|
128
|
+
const scoreResult = await invokeAgent('quality_score', { recipe });
|
|
212
129
|
if (scoreResult.grade) {
|
|
213
130
|
gradeDistribution[scoreResult.grade] = (gradeDistribution[scoreResult.grade] || 0) + 1;
|
|
214
131
|
}
|
|
@@ -239,14 +156,14 @@ export async function taskQualityAudit(context, { threshold = 0.6, maxCount = 10
|
|
|
239
156
|
* 对代码运行全部 Guard 规则 + 生成修复建议
|
|
240
157
|
*/
|
|
241
158
|
export async function taskGuardFullScan(context, { code, language, filePath } = {}) {
|
|
242
|
-
const {
|
|
159
|
+
const { invokeAgent, aiProvider } = context;
|
|
243
160
|
|
|
244
161
|
if (!code) {
|
|
245
162
|
return { error: 'code is required' };
|
|
246
163
|
}
|
|
247
164
|
|
|
248
165
|
// Step 1: 静态检查
|
|
249
|
-
const checkResult = await
|
|
166
|
+
const checkResult = await invokeAgent('guard_check_code', {
|
|
250
167
|
code,
|
|
251
168
|
language: language || 'unknown',
|
|
252
169
|
scope: 'project',
|
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
* EpisodicConsolidator — Episodic → Semantic 固化引擎
|
|
3
3
|
*
|
|
4
4
|
* Bootstrap 完成后,将 SessionStore (Tier 2) 中的维度分析结果
|
|
5
|
-
* 提炼为结构化记忆,固化到
|
|
5
|
+
* 提炼为结构化记忆,固化到 PersistentMemory (Tier 3)。
|
|
6
6
|
*
|
|
7
7
|
* 固化策略 (规则化,无需额外 AI 调用):
|
|
8
8
|
* 1. 从每个维度的 findings 提取 fact 记忆
|
|
9
9
|
* 2. 从 Tier Reflections 的 crossDimensionPatterns 提取 insight 记忆
|
|
10
10
|
* 3. 从 analysisText 中提取项目级别事实 (正则匹配)
|
|
11
|
-
* 4. 使用
|
|
11
|
+
* 4. 使用 PersistentMemory.consolidate() 进行去重和合并
|
|
12
12
|
*
|
|
13
13
|
* @module EpisodicConsolidator
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import Logger from '
|
|
16
|
+
import Logger from '../../../infrastructure/logging/Logger.js';
|
|
17
17
|
|
|
18
18
|
// ──────────────────────────────────────────────────────────────
|
|
19
19
|
// 正则: 从分析文本中提取陈述性知识
|
|
@@ -57,14 +57,14 @@ const INSIGHT_PATTERNS = [
|
|
|
57
57
|
// ──────────────────────────────────────────────────────────────
|
|
58
58
|
|
|
59
59
|
export class EpisodicConsolidator {
|
|
60
|
-
/** @type {import('
|
|
60
|
+
/** @type {import('../memory/PersistentMemory.js').PersistentMemory} */
|
|
61
61
|
#semanticMemory;
|
|
62
62
|
|
|
63
63
|
/** @type {import('../../infrastructure/logging/Logger.js').default} */
|
|
64
64
|
#logger;
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
|
-
* @param {import('
|
|
67
|
+
* @param {import('../memory/PersistentMemory.js').PersistentMemory} semanticMemory
|
|
68
68
|
* @param {object} [opts]
|
|
69
69
|
* @param {object} [opts.logger]
|
|
70
70
|
*/
|
|
@@ -74,9 +74,9 @@ export class EpisodicConsolidator {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
/**
|
|
77
|
-
* 执行固化: SessionStore →
|
|
77
|
+
* 执行固化: SessionStore → PersistentMemory
|
|
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 记忆
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* EvidenceCollector.js — 从 Analyst 工具调用中收集结构化证据
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* 类型化的证据地图、探索日志和负空间信号,供 Producer
|
|
4
|
+
* Bootstrap 质量门控核心组件: 将 Analyst 阶段的 toolCall 序列转化为
|
|
5
|
+
* 类型化的证据地图、探索日志和负空间信号,供 Producer 阶段直接引用。
|
|
6
|
+
*
|
|
7
|
+
* 被 bootstrap-gate.js (buildAnalysisArtifact) 调用。
|
|
6
8
|
*
|
|
7
9
|
* 设计原则:
|
|
8
10
|
* - 不保留原始工具返回值 (体积过大)
|
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* insight-analyst.js — Insight Analyst 领域函数
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* -
|
|
6
|
-
* -
|
|
7
|
-
* -
|
|
4
|
+
* 从旧 AnalystAgent.js 提取的纯领域逻辑:
|
|
5
|
+
* - Analyst System Prompt
|
|
6
|
+
* - 工具白名单
|
|
7
|
+
* - 预算常量
|
|
8
|
+
* - 9 段式 Prompt 构建器
|
|
8
9
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
10
|
+
* 被 PipelineStrategy 的 bootstrap preset 直接引用。
|
|
11
|
+
* 不再包含任何 Agent 类 — Agent 由 AgentRuntime + PipelineStrategy 驱动。
|
|
11
12
|
*
|
|
12
|
-
* @module
|
|
13
|
+
* @module insight-analyst
|
|
13
14
|
*/
|
|
14
15
|
|
|
15
|
-
import
|
|
16
|
-
import { analysisQualityGate, buildAnalysisReport, buildAnalysisArtifact, buildRetryPrompt } from './HandoffProtocol.js';
|
|
17
|
-
import { getDimensionSOP } from '../../external/mcp/handlers/bootstrap/shared/dimension-sop.js';
|
|
16
|
+
import { getDimensionSOP } from '../../../external/mcp/handlers/bootstrap/shared/dimension-sop.js';
|
|
18
17
|
|
|
19
18
|
// ──────────────────────────────────────────────────────────────────
|
|
20
19
|
// System Prompt — Analyst 专用 (~100 tokens)
|
|
21
20
|
// ──────────────────────────────────────────────────────────────────
|
|
22
21
|
|
|
23
|
-
const ANALYST_SYSTEM_PROMPT = `你是一位高级软件架构师,正在深度分析一个真实项目的某个维度。
|
|
22
|
+
export const ANALYST_SYSTEM_PROMPT = `你是一位高级软件架构师,正在深度分析一个真实项目的某个维度。
|
|
24
23
|
|
|
25
24
|
## 执行计划
|
|
26
25
|
你有 **N 轮**工具调用机会(系统会告知具体数字)。请严格按以下节奏分配:
|
|
@@ -50,7 +49,7 @@ const ANALYST_SYSTEM_PROMPT = `你是一位高级软件架构师,正在深度
|
|
|
50
49
|
// Analyst 可用工具白名单 — 只做探索,不做提交
|
|
51
50
|
// ──────────────────────────────────────────────────────────────────
|
|
52
51
|
|
|
53
|
-
const ANALYST_TOOLS = [
|
|
52
|
+
export const ANALYST_TOOLS = [
|
|
54
53
|
// AST 结构化分析
|
|
55
54
|
'get_project_overview',
|
|
56
55
|
'get_class_hierarchy',
|
|
@@ -77,30 +76,42 @@ const ANALYST_TOOLS = [
|
|
|
77
76
|
// Analyst 预算 — 使用 analyst 策略(自由探索,无阶段约束)
|
|
78
77
|
// ──────────────────────────────────────────────────────────────────
|
|
79
78
|
|
|
80
|
-
const ANALYST_BUDGET = {
|
|
81
|
-
maxIterations: 24,
|
|
82
|
-
searchBudget: 18,
|
|
83
|
-
searchBudgetGrace: 10,
|
|
84
|
-
maxSubmits: 0,
|
|
79
|
+
export const ANALYST_BUDGET = {
|
|
80
|
+
maxIterations: 24,
|
|
81
|
+
searchBudget: 18,
|
|
82
|
+
searchBudgetGrace: 10,
|
|
83
|
+
maxSubmits: 0,
|
|
85
84
|
softSubmitLimit: 0,
|
|
86
|
-
idleRoundsToExit: 2,
|
|
85
|
+
idleRoundsToExit: 2,
|
|
87
86
|
};
|
|
88
87
|
|
|
89
88
|
// ──────────────────────────────────────────────────────────────────
|
|
90
|
-
// 维度 Prompt 模板
|
|
89
|
+
// 维度 Prompt 模板 (9 段式)
|
|
91
90
|
// ──────────────────────────────────────────────────────────────────
|
|
92
91
|
|
|
93
92
|
/**
|
|
94
93
|
* 构建 Analyst Prompt
|
|
95
|
-
*
|
|
94
|
+
*
|
|
95
|
+
* 9 段结构:
|
|
96
|
+
* §1 任务描述
|
|
97
|
+
* §2 维度指引
|
|
98
|
+
* §3 SOP (分析步骤 + 常见错误)
|
|
99
|
+
* §4 输出要求
|
|
100
|
+
* §5 工具提示
|
|
101
|
+
* §6 前序维度上下文 (SessionStore / DimensionContext)
|
|
102
|
+
* §7 Tier Reflection 洞察
|
|
103
|
+
* §8 历史语义记忆 (Tier 3)
|
|
104
|
+
* §9 代码实体图谱 (Phase E)
|
|
105
|
+
*
|
|
106
|
+
* @param {object} dimConfig — 维度配置 { id, label, guide, focusKeywords, outputType }
|
|
96
107
|
* @param {object} projectInfo — { name, lang, fileCount }
|
|
97
108
|
* @param {object} [dimensionContext] — DimensionContext 实例 (跨维度上下文)
|
|
98
|
-
* @param {object} [episodicMemory] —
|
|
99
|
-
* @param {object} [semanticMemory] —
|
|
109
|
+
* @param {object} [episodicMemory] — SessionStore 实例 (v4.0 增强上下文)
|
|
110
|
+
* @param {object} [semanticMemory] — PersistentMemory 实例 (v4.1 历史记忆)
|
|
100
111
|
* @param {object} [codeEntityGraph] — CodeEntityGraph 实例 (Phase E 代码实体图谱)
|
|
101
112
|
* @returns {string}
|
|
102
113
|
*/
|
|
103
|
-
function buildAnalystPrompt(
|
|
114
|
+
export function buildAnalystPrompt(
|
|
104
115
|
dimConfig,
|
|
105
116
|
projectInfo,
|
|
106
117
|
dimensionContext,
|
|
@@ -137,8 +148,6 @@ function buildAnalystPrompt(
|
|
|
137
148
|
}
|
|
138
149
|
}
|
|
139
150
|
} else if (dimConfig.guide) {
|
|
140
|
-
// 回退: 无 SOP 的维度使用 guide 作为关注要点
|
|
141
|
-
// guide 格式如 "命名约定、注释风格、文件组织规范",按分隔符拆分为列表
|
|
142
151
|
const items = dimConfig.guide.split(/[、,,/]/).map(s => s.trim()).filter(Boolean);
|
|
143
152
|
if (items.length > 1) {
|
|
144
153
|
parts.push(`重点关注:\n${items.map((f) => `- ${f}`).join('\n')}`);
|
|
@@ -170,8 +179,6 @@ ${depthHint}
|
|
|
170
179
|
parts.push('使用 get_previous_evidence 工具查询前序维度对特定文件/类的分析证据,避免重复搜索。');
|
|
171
180
|
|
|
172
181
|
// §6 前序维度分析摘要 (Tier 2+ 才有)
|
|
173
|
-
// v4.0: 优先使用 EpisodicMemory (更丰富的发现 + 文件清单 + 交叉引用),
|
|
174
|
-
// 回退到 DimensionContext (兼容)
|
|
175
182
|
if (episodicMemory) {
|
|
176
183
|
const emContext = episodicMemory.buildContextForDimension(
|
|
177
184
|
dimConfig.id,
|
|
@@ -204,7 +211,7 @@ ${depthHint}
|
|
|
204
211
|
}
|
|
205
212
|
}
|
|
206
213
|
|
|
207
|
-
// §8: 历史语义记忆 (Tier 3)
|
|
214
|
+
// §8: 历史语义记忆 (Tier 3)
|
|
208
215
|
if (semanticMemory) {
|
|
209
216
|
try {
|
|
210
217
|
const query = `${dimConfig.label} ${dimConfig.guide || ''} ${projectInfo.lang}`;
|
|
@@ -221,7 +228,7 @@ ${depthHint}
|
|
|
221
228
|
}
|
|
222
229
|
}
|
|
223
230
|
|
|
224
|
-
// §9: 代码实体图谱 (Phase E)
|
|
231
|
+
// §9: 代码实体图谱 (Phase E)
|
|
225
232
|
if (codeEntityGraph) {
|
|
226
233
|
try {
|
|
227
234
|
const graphCtx = codeEntityGraph.generateContextForAgent({ maxEntities: 20, maxEdges: 40 });
|
|
@@ -236,145 +243,3 @@ ${depthHint}
|
|
|
236
243
|
|
|
237
244
|
return parts.join('\n\n');
|
|
238
245
|
}
|
|
239
|
-
|
|
240
|
-
// ──────────────────────────────────────────────────────────────────
|
|
241
|
-
// AnalystAgent 类
|
|
242
|
-
// ──────────────────────────────────────────────────────────────────
|
|
243
|
-
|
|
244
|
-
export class AnalystAgent {
|
|
245
|
-
/** @type {import('./ChatAgent.js').ChatAgent} */
|
|
246
|
-
#chatAgent;
|
|
247
|
-
|
|
248
|
-
/** @type {import('../../core/ast/ProjectGraph.js').default} */
|
|
249
|
-
#projectGraph;
|
|
250
|
-
|
|
251
|
-
/** @type {import('../../infrastructure/logging/Logger.js').default} */
|
|
252
|
-
#logger;
|
|
253
|
-
|
|
254
|
-
/** @type {number} Gate 最大重试次数 */
|
|
255
|
-
#maxRetries;
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* @param {object} chatAgent — ChatAgent 实例
|
|
259
|
-
* @param {object} [projectGraph] — ProjectGraph 实例
|
|
260
|
-
* @param {object} [options]
|
|
261
|
-
* @param {number} [options.maxRetries=1] — Gate 失败最大重试次数
|
|
262
|
-
*/
|
|
263
|
-
constructor(chatAgent, projectGraph = null, options = {}) {
|
|
264
|
-
this.#chatAgent = chatAgent;
|
|
265
|
-
this.#projectGraph = projectGraph;
|
|
266
|
-
this.#logger = Logger.getInstance();
|
|
267
|
-
this.#maxRetries = options.maxRetries ?? 1;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* 分析指定维度
|
|
272
|
-
*
|
|
273
|
-
* @param {object} dimConfig — 维度配置 { id, label, guide, focusKeywords }
|
|
274
|
-
* @param {object} projectInfo — { name, lang, fileCount }
|
|
275
|
-
* @param {object} [options]
|
|
276
|
-
* @param {string} [options.sessionId] — Bootstrap session ID
|
|
277
|
-
* @param {object} [options.dimensionContext] — DimensionContext 实例
|
|
278
|
-
* @returns {Promise<import('./HandoffProtocol.js').AnalysisReport>}
|
|
279
|
-
*/
|
|
280
|
-
async analyze(dimConfig, projectInfo, options = {}) {
|
|
281
|
-
const dimId = dimConfig.id;
|
|
282
|
-
const prompt = buildAnalystPrompt(
|
|
283
|
-
dimConfig,
|
|
284
|
-
projectInfo,
|
|
285
|
-
options.dimensionContext,
|
|
286
|
-
options.memoryCoordinator?.getSessionStore(), // v5.0: SessionStore 提供跨维度上下文
|
|
287
|
-
options.semanticMemory, // v4.1: ProjectSemanticMemory 历史记忆
|
|
288
|
-
options.codeEntityGraph // Phase E: CodeEntityGraph 代码实体图谱
|
|
289
|
-
);
|
|
290
|
-
|
|
291
|
-
this.#logger.info(
|
|
292
|
-
`[AnalystAgent] ▶ analyzing dimension "${dimId}" — prompt ${prompt.length} chars`
|
|
293
|
-
);
|
|
294
|
-
|
|
295
|
-
let retries = 0;
|
|
296
|
-
let lastReport = null;
|
|
297
|
-
|
|
298
|
-
while (retries <= this.#maxRetries) {
|
|
299
|
-
const execPrompt =
|
|
300
|
-
retries === 0
|
|
301
|
-
? prompt
|
|
302
|
-
: `${prompt}\n\n${buildRetryPrompt(lastReport?._gateReason || 'Analysis too short')}`;
|
|
303
|
-
|
|
304
|
-
try {
|
|
305
|
-
const result = await this.#chatAgent.execute(execPrompt, {
|
|
306
|
-
source: 'system',
|
|
307
|
-
conversationId: options.sessionId ? `analyst-${options.sessionId}-${dimId}` : undefined,
|
|
308
|
-
budget: ANALYST_BUDGET,
|
|
309
|
-
systemPromptOverride: ANALYST_SYSTEM_PROMPT,
|
|
310
|
-
allowedTools: ANALYST_TOOLS,
|
|
311
|
-
strategy: 'analyst',
|
|
312
|
-
temperature: 0.4,
|
|
313
|
-
dimensionMeta: {
|
|
314
|
-
id: dimId,
|
|
315
|
-
outputType: 'analysis',
|
|
316
|
-
allowedKnowledgeTypes: dimConfig.allowedKnowledgeTypes || [],
|
|
317
|
-
},
|
|
318
|
-
// v5.0: 统一 MemoryCoordinator
|
|
319
|
-
memoryCoordinator: options.memoryCoordinator || undefined,
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
// v5.0: 当有 MemoryCoordinator 时使用 ActiveContext 的 distill 结果
|
|
323
|
-
// 构建 AnalysisArtifact (包含 evidenceMap/findings/negativeSignals)
|
|
324
|
-
// 使用显式 scopeId 确保并行执行安全
|
|
325
|
-
const analystScopeId = `${dimId}:analyst`;
|
|
326
|
-
const ac = options.memoryCoordinator?.getActiveContext(analystScopeId);
|
|
327
|
-
const report = ac
|
|
328
|
-
? buildAnalysisArtifact(result, dimId, this.#projectGraph, ac)
|
|
329
|
-
: buildAnalysisReport(result, dimId, this.#projectGraph);
|
|
330
|
-
|
|
331
|
-
// 附加推理链数据(如果 ChatAgent 返回了 ReasoningTrace)
|
|
332
|
-
if (result.reasoningTrace) {
|
|
333
|
-
report.reasoningStats = result.reasoningTrace.getStats();
|
|
334
|
-
report.thoughts = result.reasoningTrace.getThoughts();
|
|
335
|
-
}
|
|
336
|
-
if (result.reasoningQuality) {
|
|
337
|
-
report.reasoningQuality = result.reasoningQuality;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// 质量门控 — 传入 outputType 以调整门槛
|
|
341
|
-
const gate = analysisQualityGate(report, {
|
|
342
|
-
outputType: dimConfig.outputType || 'analysis',
|
|
343
|
-
});
|
|
344
|
-
if (gate.pass) {
|
|
345
|
-
this.#logger.info(
|
|
346
|
-
`[AnalystAgent] ✅ dimension "${dimId}" — ${report.analysisText.length} chars, ${report.referencedFiles.length} files referenced, ${report.metadata.toolCallCount} tool calls`
|
|
347
|
-
);
|
|
348
|
-
return report;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
this.#logger.warn(
|
|
352
|
-
`[AnalystAgent] ⚠ Gate failed for "${dimId}": ${gate.reason} (action=${gate.action})`
|
|
353
|
-
);
|
|
354
|
-
|
|
355
|
-
if (gate.action === 'degrade') {
|
|
356
|
-
// 直接降级 — 不重试
|
|
357
|
-
report._gateResult = gate;
|
|
358
|
-
return report;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// retry
|
|
362
|
-
lastReport = report;
|
|
363
|
-
lastReport._gateReason = gate.reason;
|
|
364
|
-
retries++;
|
|
365
|
-
} catch (err) {
|
|
366
|
-
this.#logger.error(`[AnalystAgent] ❌ dimension "${dimId}" error: ${err.message}`);
|
|
367
|
-
// 返回空 report
|
|
368
|
-
return buildAnalysisReport({ reply: '', toolCalls: [] }, dimId, this.#projectGraph);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// 重试耗尽 — 返回最后一次结果
|
|
373
|
-
this.#logger.warn(`[AnalystAgent] Retries exhausted for "${dimId}" — returning last report`);
|
|
374
|
-
return (
|
|
375
|
-
lastReport || buildAnalysisReport({ reply: '', toolCalls: [] }, dimId, this.#projectGraph)
|
|
376
|
-
);
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
export default AnalystAgent;
|