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,12 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* insight-gate.js — Insight 质量门控领域函数
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* 从旧 HandoffProtocol.js 完整迁移的纯函数模块:
|
|
5
|
+
* - 分析文本清洗 (sanitizeAnalysisText)
|
|
6
|
+
* - AnalysisReport 构建 (v1)
|
|
7
|
+
* - AnalysisArtifact 构建 (v2, 含 evidenceMap/findings/negativeSignals)
|
|
8
|
+
* - 多维度质量评分 (buildQualityScores)
|
|
9
|
+
* - 质量门控 (v1 + v2)
|
|
10
|
+
* - 重试 Prompt 构建
|
|
11
|
+
* - PipelineStrategy gate.evaluator 适配器 (insightGateEvaluator)
|
|
8
12
|
*
|
|
9
|
-
*
|
|
13
|
+
* 被 PipelineStrategy 的 bootstrap preset 直接引用。
|
|
14
|
+
*
|
|
15
|
+
* @module insight-gate
|
|
10
16
|
*/
|
|
11
17
|
|
|
12
18
|
import { EvidenceCollector } from './EvidenceCollector.js';
|
|
@@ -19,111 +25,58 @@ import { EvidenceCollector } from './EvidenceCollector.js';
|
|
|
19
25
|
* 清理 Analyst 分析文本中可能泄漏的系统 nudge / graceful exit 指令。
|
|
20
26
|
* 这些内容如果传给 Producer,会干扰其正常工作流。
|
|
21
27
|
*/
|
|
22
|
-
function sanitizeAnalysisText(text) {
|
|
28
|
+
export function sanitizeAnalysisText(text) {
|
|
23
29
|
if (!text) {
|
|
24
30
|
return '';
|
|
25
31
|
}
|
|
26
|
-
// 移除 graceful exit nudge 及 digest 模板指令
|
|
27
32
|
const patterns = [
|
|
28
33
|
/\*{0,2}⚠️?\s*(?:你已使用|轮次即将耗尽|仅剩|请立即停止|必须立即结束)[^\n]*\n?/gi,
|
|
29
34
|
/\*{0,2}请立即停止所有工具调用[^\n]*\*{0,2}\n?/gi,
|
|
30
35
|
/请在回复中直接输出\s*dimensionDigest\s*JSON[^\n]*\n?/gi,
|
|
31
36
|
/> ?(?:remainingTasks|如果所有信号都已覆盖)[^\n]*\n?/gi,
|
|
32
37
|
/> ?⚠️ 严禁输出任何非 JSON 内容[^\n]*\n?/gi,
|
|
33
|
-
// 移除 AI 回显的 dimensionDigest JSON 块(对 Producer 无价值且会干扰)
|
|
34
38
|
/```json\s*\n\s*\{\s*"dimensionDigest"\s*:[\s\S]*?\n```/g,
|
|
35
|
-
|
|
36
|
-
// ── AI 思考伪影清理 ──
|
|
37
|
-
|
|
38
|
-
// 轮次/阶段计数器(如 "第 18/24 轮 | 验证阶段 | 剩余 6 轮")
|
|
39
39
|
/^-{2,3}\s*\n\s*第\s*\d+\/\d+\s*轮[^\n]*\n(-{2,3}\s*\n)?/gm,
|
|
40
|
-
// 独立分隔线 + 空内容
|
|
41
40
|
/^-{3}\s*$/gm,
|
|
42
|
-
|
|
43
|
-
// AI 规划/反思段落("计划偏差分析"、"最终总结阶段" 等)
|
|
44
41
|
/^#{1,3}\s*(?:计划偏差分析|最终总结阶段|执行计划|下一步计划|分析计划)\s*\n[\s\S]*?(?=\n#{1,3}\s|\n\n(?=[^#\s-]))/gm,
|
|
45
|
-
|
|
46
|
-
// 系统提示回显("(提示: ...)")
|
|
47
42
|
/^\(提示[::][^)]*\)\s*\n?/gm,
|
|
48
|
-
|
|
49
|
-
// AI 英文思考泄漏("Wait, I have enough information..."、"Let me..."、"I'll stop here...")
|
|
50
43
|
/^(?:Wait,|Let me|I'll stop here|I will stop|I need to|I should|I have enough)[^\n]*\n?/gm,
|
|
51
|
-
|
|
52
|
-
// 工具提示循环("尝试使用 `tool_name`..."、"- 尝试使用...")
|
|
53
44
|
/^[-•]\s*尝试使用\s*`[^`]+`[^\n]*\n?/gm,
|
|
54
45
|
/^💡\s*提示[::]?\s*\n?/gm,
|
|
55
|
-
|
|
56
|
-
// 请继续 / 请接续 单行(AI 被截断后的续写请求)
|
|
57
46
|
/^请(?:继续|接续)[。.]?\s*$/gm,
|
|
58
|
-
|
|
59
|
-
// 📊 中期反思块("📊 中期反思 (第 N/M 轮, X% 预算):" 及后续所有内容直到下一个 ## 或 📊)
|
|
60
47
|
/📊\s*中期反思\s*\([^)]*\):?\s*\n(?:[\s\S]*?(?=\n#{1,3}\s(?!探索计划|第\s*\d)|\n(?=📊)|$))/gm,
|
|
61
|
-
|
|
62
|
-
// AI 思考方向列表("你最近的思考方向:" + 编号列表 + 嵌套的探索计划)
|
|
63
48
|
/^你最近的思考方向:\s*\n(?:[\s\S]*?(?=\n#{1,3}\s(?!探索计划|第\s*\d)|\n(?=📊)|$))/gm,
|
|
64
|
-
|
|
65
|
-
// AI 探索计划标题("### 探索计划")— 这是 AI 内部规划,不应出现在最终输出中
|
|
66
49
|
/^#{1,3}\s*探索计划\s*\n(?:[\s\S]*?(?=\n#{1,3}\s(?!探索计划)|\n\n(?=[^#\s\d-])|\n(?=📊)|$))/gm,
|
|
67
|
-
// 编号前缀的探索计划(" 1. ### 探索计划" + 紧随的编号列表项)
|
|
68
50
|
/^\s*\d+\.\s+#{1,3}\s*探索计划[^\n]*\n(?:\d+\.\s+\*{0,2}[^\n]*\n?)*/gm,
|
|
69
|
-
|
|
70
|
-
// AI 轮次标题("### 第 N 轮:..." 开头的规划/反思段落)
|
|
71
51
|
/^#{1,3}\s*第\s*\d+\s*轮[::][^\n]*\n(?:[\s\S]*?(?=\n#{1,3}\s(?!探索计划|第\s*\d)|\n\n(?=#{1,3}\s)|\n(?=📊)|$))/gm,
|
|
72
|
-
|
|
73
|
-
// 行动效率统计行("行动效率: 最近 N 轮中 X% 获取到新信息")
|
|
74
52
|
/^行动效率[::][^\n]*\n?/gm,
|
|
75
53
|
/^累计[::]\s*\d+\s*文件[^\n]*\n?/gm,
|
|
76
|
-
|
|
77
|
-
// 计划进度("📋 计划进度: 0/1 步骤已完成")
|
|
78
54
|
/^📋\s*计划进度[::][^\n]*\n?/gm,
|
|
79
|
-
|
|
80
|
-
// 请评估提示块("请评估: 1. ...")
|
|
81
55
|
/^请评估[::]\s*\n(?:\s*\d+\.\s+[^\n]*\n?)*/gm,
|
|
82
|
-
|
|
83
|
-
// AI 对话提示回显("(请在继续调用工具前...)", "(由于当前已是第 N 轮...)", "(注意: 每一轮都必须...)")
|
|
84
56
|
/^\([请由注](?:在继续|于当前|意[::])[^)]*\)\s*\n?/gm,
|
|
85
|
-
|
|
86
|
-
// AI 步骤进度与计划更新("已经读取,未完成步骤..."、"计划更新:..."、"更新后的计划:...")
|
|
87
57
|
/^(?:\d+\.\s+)?(?:`[^`]*`\s+)?(?:已经读取|未完成步骤仅剩|计划更新|更新后的计划)[^\n]*\n?/gm,
|
|
88
58
|
/^更新后的计划[::]\s*\n(?:\s*\d+\.\s+[^\n]*\n?)*/gm,
|
|
89
|
-
|
|
90
|
-
// 纯数字编号残留行(清理被上面 pattern 删除后留下的孤立编号)
|
|
91
59
|
/^\s*\d+\.\s*$/gm,
|
|
92
|
-
|
|
93
|
-
// ── v5.1: Nudge 指令回显清理 ──
|
|
94
|
-
|
|
95
|
-
// AI 回显的 dimensionDigest 模板说明行("> searchHints: ...", "> candidateCount: ...")
|
|
96
60
|
/^>\s*(?:searchHints|remainingTasks|candidateCount|crossRefs|keyFindings|gaps)\s*[::][^\n]*\n?/gm,
|
|
97
|
-
|
|
98
|
-
// AI 回显的输出指令("请在 JSON 后紧跟...", "请直接输出...", "现在开始输出...", "输出你的...")
|
|
99
61
|
/^\*{0,2}(?:请在|请直接|请确保|请务必|现在开始|输出你的|不要输出|不要再|不要包含)\s*[^。\n]*(?:分析文本|分析总结|分析报告|JSON|工具|输出|文本|报告)[^。\n]*[。.]?\s*\*{0,2}$/gm,
|
|
100
|
-
|
|
101
|
-
// AI 回显的"重要"强调指令
|
|
102
62
|
/^\*{0,2}重要\s*[::][^。\n]*\*{0,2}$/gm,
|
|
103
|
-
|
|
104
|
-
// AI 回显的"注意"行("注意:到达第 N 轮时...")
|
|
105
63
|
/^注意[::]\s*到达第\s*\d+\s*轮时[^\n]*$/gm,
|
|
106
|
-
|
|
107
|
-
// AI 回显的轮次进度行("第 19/24 轮 | ⚠ 总结阶段 — 请停止工具调用,直接输出分析文本 | 剩余 5 轮")
|
|
108
64
|
/^第\s*\d+\/\d+\s*轮\s*\|[^\n]*$/gm,
|
|
109
65
|
];
|
|
110
66
|
let cleaned = text;
|
|
111
67
|
for (const pat of patterns) {
|
|
112
68
|
cleaned = cleaned.replace(pat, '');
|
|
113
69
|
}
|
|
114
|
-
// 移除可能残留的空行堆积
|
|
115
70
|
cleaned = cleaned.replace(/\n{3,}/g, '\n\n').trim();
|
|
116
71
|
return cleaned;
|
|
117
72
|
}
|
|
118
73
|
|
|
119
74
|
/**
|
|
120
|
-
* 从 Analyst 的执行结果构建 AnalysisReport
|
|
75
|
+
* 从 Analyst 的执行结果构建 AnalysisReport (v1)
|
|
121
76
|
*
|
|
122
|
-
* @param {object} analystResult —
|
|
123
|
-
* @param {string} analystResult.reply — Analyst 的自然语言分析文本
|
|
124
|
-
* @param {Array} analystResult.toolCalls — 工具调用记录
|
|
77
|
+
* @param {object} analystResult — { reply, toolCalls }
|
|
125
78
|
* @param {string} dimensionId — 维度 ID
|
|
126
|
-
* @param {object} [projectGraph] — ProjectGraph 实例
|
|
79
|
+
* @param {object} [projectGraph] — ProjectGraph 实例
|
|
127
80
|
* @returns {AnalysisReport}
|
|
128
81
|
*/
|
|
129
82
|
export function buildAnalysisReport(analystResult, dimensionId, projectGraph = null) {
|
|
@@ -146,7 +99,6 @@ export function buildAnalysisReport(analystResult, dimensionId, projectGraph = n
|
|
|
146
99
|
if (args.pattern || args.query) {
|
|
147
100
|
searchQueries.push(args.pattern || args.query);
|
|
148
101
|
}
|
|
149
|
-
// 从搜索结果中提取文件路径
|
|
150
102
|
if (typeof result === 'string') {
|
|
151
103
|
const fileMatches = result.match(
|
|
152
104
|
/(?:^|\n)([\w/.-]+\.(?:go|mod|sum|py|pyi|java|kt|kts|js|ts|jsx|tsx|mjs|cjs|swift|m|h|c|cpp|cc|hpp|cs|rb|rs|sql|json|yaml|yml|toml|xml|html|css|scss|less|sh|md|txt|gradle|properties|proto|vue|svelte|graphql|cfg|conf|ini|env|lock|rst))(?::\d+)?/gi
|
|
@@ -164,7 +116,6 @@ export function buildAnalysisReport(analystResult, dimensionId, projectGraph = n
|
|
|
164
116
|
case 'get_class_info':
|
|
165
117
|
if (args.className) {
|
|
166
118
|
classesExplored.push(args.className);
|
|
167
|
-
// 从 ProjectGraph 反查文件路径
|
|
168
119
|
if (projectGraph) {
|
|
169
120
|
const info = projectGraph.getClassInfo(args.className);
|
|
170
121
|
if (info?.filePath) {
|
|
@@ -189,7 +140,7 @@ export function buildAnalysisReport(analystResult, dimensionId, projectGraph = n
|
|
|
189
140
|
}
|
|
190
141
|
}
|
|
191
142
|
|
|
192
|
-
//
|
|
143
|
+
// 从分析文本中提取文件路径
|
|
193
144
|
const text = sanitizeAnalysisText(analystResult.reply || '');
|
|
194
145
|
const FILE_EXT_RE =
|
|
195
146
|
/[\w/.-]+\.(?:go|mod|sum|py|pyi|java|kt|kts|js|ts|jsx|tsx|mjs|cjs|swift|m|h|c|cpp|cc|hpp|cs|rb|rs|sql|json|yaml|yml|toml|xml|html|css|scss|less|sh|md|txt|gradle|properties|proto|vue|svelte|graphql|cfg|conf|ini|env|lock|rst)\b/gi;
|
|
@@ -225,81 +176,72 @@ export function buildAnalysisReport(analystResult, dimensionId, projectGraph = n
|
|
|
225
176
|
* 从 Analyst 执行结果构建 AnalysisArtifact (v2 增强版)
|
|
226
177
|
*
|
|
227
178
|
* 在 v1 AnalysisReport 基础上增加:
|
|
228
|
-
* - evidenceMap: 文件 → 代码片段 + 摘要
|
|
179
|
+
* - evidenceMap: 文件 → 代码片段 + 摘要
|
|
229
180
|
* - explorationLog: 工具调用意图 + 结果摘要序列
|
|
230
|
-
* - negativeSignals: 搜索但未找到的模式
|
|
181
|
+
* - negativeSignals: 搜索但未找到的模式
|
|
231
182
|
* - findings: 来自 ActiveContext 的结构化发现
|
|
232
183
|
* - qualityReport: 多维度质量评分
|
|
233
184
|
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
236
|
-
* @param {object} analystResult — ChatAgent.execute() 返回值
|
|
185
|
+
* @param {object} analystResult — { reply, toolCalls }
|
|
237
186
|
* @param {string} dimensionId — 维度 ID
|
|
238
187
|
* @param {object} [projectGraph] — ProjectGraph 实例
|
|
239
|
-
* @param {object} [activeContext] — ActiveContext 实例
|
|
188
|
+
* @param {object} [activeContext] — ActiveContext 实例
|
|
240
189
|
* @returns {AnalysisArtifact}
|
|
241
190
|
*/
|
|
242
191
|
export function buildAnalysisArtifact(analystResult, dimensionId, projectGraph = null, activeContext = null) {
|
|
243
192
|
const toolCalls = analystResult.toolCalls || [];
|
|
244
193
|
|
|
245
|
-
// §1: 构建 v1 报告 (复用已有逻辑获取 referencedFiles, searchQueries 等)
|
|
246
194
|
const baseReport = buildAnalysisReport(analystResult, dimensionId, projectGraph);
|
|
247
195
|
|
|
248
|
-
// §2: 从工具调用中收集结构化证据
|
|
249
196
|
const collector = new EvidenceCollector();
|
|
250
197
|
for (let i = 0; i < toolCalls.length; i++) {
|
|
251
198
|
collector.processToolCall(toolCalls[i], i);
|
|
252
199
|
}
|
|
253
200
|
const evidence = collector.build();
|
|
254
201
|
|
|
255
|
-
// §3: 从 ActiveContext 获取结构化发现 (保持与 distill() 一致的规范形状)
|
|
256
202
|
const distilled = activeContext?.distill() || { keyFindings: [], toolCallSummary: [] };
|
|
257
203
|
const findings = distilled.keyFindings.map((f) => ({
|
|
258
204
|
finding: f.finding,
|
|
259
|
-
// P0 Fix: evidence 可能是 array/object,强制 string
|
|
260
205
|
evidence: typeof f.evidence === 'string' ? f.evidence : Array.isArray(f.evidence) ? f.evidence.join(', ') : f.evidence ? String(f.evidence) : '',
|
|
261
206
|
importance: f.importance,
|
|
262
207
|
}));
|
|
263
208
|
|
|
264
|
-
// §4: 合并引用文件 (v1 提取 + evidenceMap 中的文件)
|
|
265
209
|
const allFiles = new Set(baseReport.referencedFiles);
|
|
266
210
|
for (const filePath of evidence.evidenceMap.keys()) {
|
|
267
211
|
allFiles.add(filePath);
|
|
268
212
|
}
|
|
269
213
|
|
|
270
|
-
// §5: 计算多维度质量评分
|
|
271
214
|
const qualityReport = buildQualityScores(
|
|
272
215
|
baseReport.analysisText,
|
|
273
216
|
findings,
|
|
274
217
|
evidence,
|
|
275
218
|
);
|
|
276
219
|
|
|
277
|
-
// §6: 构建 AnalysisArtifact (v1 超集)
|
|
278
220
|
return {
|
|
279
|
-
//
|
|
221
|
+
// Layer 1: Core
|
|
280
222
|
analysisText: baseReport.analysisText,
|
|
281
223
|
findings,
|
|
282
224
|
referencedFiles: [...allFiles],
|
|
283
225
|
dimensionId,
|
|
284
226
|
|
|
285
|
-
//
|
|
227
|
+
// Layer 2: Detail
|
|
286
228
|
evidenceMap: evidence.evidenceMap,
|
|
287
229
|
explorationLog: evidence.explorationLog,
|
|
288
230
|
negativeSignals: evidence.negativeSignals,
|
|
289
231
|
|
|
290
|
-
//
|
|
232
|
+
// Layer 3: Raw
|
|
291
233
|
fullToolTrace: toolCalls,
|
|
292
234
|
|
|
293
|
-
//
|
|
235
|
+
// Quality
|
|
294
236
|
qualityReport,
|
|
295
237
|
|
|
296
|
-
//
|
|
238
|
+
// Metadata
|
|
297
239
|
metadata: {
|
|
298
240
|
...baseReport.metadata,
|
|
299
241
|
artifactVersion: 2,
|
|
300
242
|
},
|
|
301
243
|
|
|
302
|
-
//
|
|
244
|
+
// v1 backward compat
|
|
303
245
|
searchQueries: baseReport.searchQueries,
|
|
304
246
|
classesExplored: baseReport.classesExplored,
|
|
305
247
|
};
|
|
@@ -312,21 +254,15 @@ export function buildAnalysisArtifact(analystResult, dimensionId, projectGraph =
|
|
|
312
254
|
/**
|
|
313
255
|
* 计算 AnalysisArtifact 的多维度质量评分
|
|
314
256
|
*
|
|
315
|
-
* 4
|
|
316
|
-
* depthScore (30%)
|
|
257
|
+
* 4 维度各 0-100, 加权:
|
|
258
|
+
* depthScore (30%) — 文件覆盖深度
|
|
317
259
|
* breadthScore (20%) — 工具使用广度
|
|
318
260
|
* evidenceScore (30%) — 证据充分性
|
|
319
261
|
* coherenceScore (20%) — 分析连贯性
|
|
320
|
-
*
|
|
321
|
-
* @param {string} analysisText — 清洗后分析文本
|
|
322
|
-
* @param {Array} findings — 结构化发现
|
|
323
|
-
* @param {object} evidence — EvidenceCollector.build() 结果
|
|
324
|
-
* @returns {{ scores: object, totalScore: number, suggestions: string[] }}
|
|
325
262
|
*/
|
|
326
263
|
function buildQualityScores(analysisText, findings, evidence) {
|
|
327
264
|
const scores = {};
|
|
328
265
|
|
|
329
|
-
// §1: depthScore — 文件覆盖深度
|
|
330
266
|
const uniqueFilesRead = evidence.evidenceMap?.size || 0;
|
|
331
267
|
const snippetCount = [...(evidence.evidenceMap?.values() || [])].reduce(
|
|
332
268
|
(sum, e) => sum + e.codeSnippets.length,
|
|
@@ -334,7 +270,6 @@ function buildQualityScores(analysisText, findings, evidence) {
|
|
|
334
270
|
);
|
|
335
271
|
scores.depthScore = Math.min(100, uniqueFilesRead * 15 + snippetCount * 5);
|
|
336
272
|
|
|
337
|
-
// §2: breadthScore — 工具种类 + 有效率
|
|
338
273
|
const toolTypes = new Set((evidence.explorationLog || []).map((e) => e.tool));
|
|
339
274
|
const logLen = evidence.explorationLog?.length || 0;
|
|
340
275
|
const effectiveRatio = logLen > 0
|
|
@@ -342,7 +277,6 @@ function buildQualityScores(analysisText, findings, evidence) {
|
|
|
342
277
|
: 0;
|
|
343
278
|
scores.breadthScore = Math.min(100, toolTypes.size * 20 + effectiveRatio * 40);
|
|
344
279
|
|
|
345
|
-
// §3: evidenceScore — 发现数量 + 有证据的发现比例
|
|
346
280
|
const findingCount = findings?.length || 0;
|
|
347
281
|
const evidencedFindings = (findings || []).filter((f) => f.evidence && f.evidence.length > 0).length;
|
|
348
282
|
scores.evidenceScore =
|
|
@@ -350,7 +284,6 @@ function buildQualityScores(analysisText, findings, evidence) {
|
|
|
350
284
|
? Math.min(100, (evidencedFindings / findingCount) * 60 + findingCount * 10)
|
|
351
285
|
: 0;
|
|
352
286
|
|
|
353
|
-
// §4: coherenceScore — 文本长度 + 结构标记
|
|
354
287
|
const textLen = analysisText?.length || 0;
|
|
355
288
|
const hasHeaders = /#{1,3}\s/.test(analysisText || '');
|
|
356
289
|
const hasLists = /\d+\.\s|[-•]\s/.test(analysisText || '');
|
|
@@ -362,7 +295,6 @@ function buildQualityScores(analysisText, findings, evidence) {
|
|
|
362
295
|
(findingCount >= 3 ? 20 : findingCount * 7),
|
|
363
296
|
);
|
|
364
297
|
|
|
365
|
-
// 加权总分
|
|
366
298
|
const totalScore = Math.round(
|
|
367
299
|
scores.depthScore * 0.3 +
|
|
368
300
|
scores.breadthScore * 0.2 +
|
|
@@ -370,7 +302,6 @@ function buildQualityScores(analysisText, findings, evidence) {
|
|
|
370
302
|
scores.coherenceScore * 0.2,
|
|
371
303
|
);
|
|
372
304
|
|
|
373
|
-
// 改进建议
|
|
374
305
|
const suggestions = [];
|
|
375
306
|
if (scores.depthScore < 50) suggestions.push('Need more read_project_file to examine code');
|
|
376
307
|
if (scores.evidenceScore < 50) suggestions.push('Findings lack file-level evidence');
|
|
@@ -384,11 +315,11 @@ function buildQualityScores(analysisText, findings, evidence) {
|
|
|
384
315
|
// ──────────────────────────────────────────────────────────────────
|
|
385
316
|
|
|
386
317
|
/**
|
|
387
|
-
* 分析质量门控
|
|
318
|
+
* 分析质量门控
|
|
388
319
|
*
|
|
389
320
|
* 自动检测 v1 (AnalysisReport) 和 v2 (AnalysisArtifact):
|
|
390
|
-
* - v2: 从 qualityReport.totalScore
|
|
391
|
-
* - v1:
|
|
321
|
+
* - v2: 从 qualityReport.totalScore 计算
|
|
322
|
+
* - v1: 使用 4 条规则
|
|
392
323
|
*
|
|
393
324
|
* @param {AnalysisReport|AnalysisArtifact} report
|
|
394
325
|
* @param {object} [options]
|
|
@@ -396,17 +327,12 @@ function buildQualityScores(analysisText, findings, evidence) {
|
|
|
396
327
|
* @returns {{ pass: boolean, reason?: string, action?: 'retry' | 'degrade' }}
|
|
397
328
|
*/
|
|
398
329
|
export function analysisQualityGate(report, options = {}) {
|
|
399
|
-
// v2: AnalysisArtifact 带有 qualityReport
|
|
400
330
|
if (report.qualityReport?.scores) {
|
|
401
331
|
return applyGateThresholds(report.qualityReport, options);
|
|
402
332
|
}
|
|
403
|
-
// v1: 原有逻辑
|
|
404
333
|
return analysisQualityGateV1(report, options);
|
|
405
334
|
}
|
|
406
335
|
|
|
407
|
-
/**
|
|
408
|
-
* v2 质量门控 — 基于多维度评分 + 阈值
|
|
409
|
-
*/
|
|
410
336
|
function applyGateThresholds(qualityReport, options = {}) {
|
|
411
337
|
const { totalScore } = qualityReport;
|
|
412
338
|
const needsCandidates = options.outputType === 'dual' || options.outputType === 'candidate';
|
|
@@ -429,26 +355,18 @@ function applyGateThresholds(qualityReport, options = {}) {
|
|
|
429
355
|
};
|
|
430
356
|
}
|
|
431
357
|
|
|
432
|
-
/**
|
|
433
|
-
* v1 质量门控 — 原有 4 条规则 (保留向后兼容)
|
|
434
|
-
*/
|
|
435
358
|
function analysisQualityGateV1(report, options = {}) {
|
|
436
359
|
const needsCandidates = options.outputType === 'dual' || options.outputType === 'candidate';
|
|
437
|
-
// 需要产出候选的维度要求更高门槛
|
|
438
360
|
const minChars = needsCandidates ? 400 : 200;
|
|
439
361
|
const minFileRefs = needsCandidates ? 3 : 2;
|
|
440
362
|
|
|
441
|
-
// 规则 1: 最少字符数 — 分析太短说明未充分探索
|
|
442
363
|
if (report.analysisText.length < minChars) {
|
|
443
364
|
return { pass: false, reason: 'Analysis too short', action: 'retry' };
|
|
444
365
|
}
|
|
445
|
-
|
|
446
|
-
// 规则 2: 最少引用文件数 — 未引用文件说明未看代码
|
|
447
366
|
if (report.referencedFiles.length < minFileRefs) {
|
|
448
367
|
return { pass: false, reason: 'Too few file references', action: 'retry' };
|
|
449
368
|
}
|
|
450
369
|
|
|
451
|
-
// 规则 3: 检测"拒绝回答"模式
|
|
452
370
|
const refusalPatterns = [
|
|
453
371
|
/I cannot|I'm unable|I don't have access/i,
|
|
454
372
|
/无法分析|无法访问|没有足够/,
|
|
@@ -457,9 +375,6 @@ function analysisQualityGateV1(report, options = {}) {
|
|
|
457
375
|
return { pass: false, reason: 'Agent refused to analyze', action: 'degrade' };
|
|
458
376
|
}
|
|
459
377
|
|
|
460
|
-
// 规则 4: 内容实质性检查 — 有结构化内容或足够多的探索
|
|
461
|
-
// v3.1: 放宽条件 — tool calling 模式下 AI 往往不输出 markdown 格式
|
|
462
|
-
// 只要分析足够长且引用了足够多的文件,就认为有实质性内容
|
|
463
378
|
const hasStructure =
|
|
464
379
|
/#{1,3}\s/.test(report.analysisText) ||
|
|
465
380
|
/\d+\.\s/.test(report.analysisText) ||
|
|
@@ -475,7 +390,7 @@ function analysisQualityGateV1(report, options = {}) {
|
|
|
475
390
|
}
|
|
476
391
|
|
|
477
392
|
/**
|
|
478
|
-
* 构建重试提示
|
|
393
|
+
* 构建重试提示
|
|
479
394
|
*
|
|
480
395
|
* @param {string} reason — Gate 失败原因
|
|
481
396
|
* @returns {string}
|
|
@@ -493,32 +408,67 @@ export function buildRetryPrompt(reason) {
|
|
|
493
408
|
return hints[reason] || '请更深入地分析代码,引用至少 3 个具体文件,每个发现都要有代码证据。';
|
|
494
409
|
}
|
|
495
410
|
|
|
411
|
+
// ──────────────────────────────────────────────────────────────────
|
|
412
|
+
// PipelineStrategy gate.evaluator 适配器
|
|
413
|
+
// ──────────────────────────────────────────────────────────────────
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* 面向 PipelineStrategy gate.evaluator 的包装函数。
|
|
417
|
+
*
|
|
418
|
+
* 将 PipelineStrategy 的 (source, phaseResults, strategyContext) 签名
|
|
419
|
+
* 适配到 buildAnalysisArtifact + analysisQualityGate 调用链。
|
|
420
|
+
*
|
|
421
|
+
* @param {object} source — 前一阶段 (analyze) 的 reactLoop 返回值
|
|
422
|
+
* @param {object} phaseResults — 所有阶段结果
|
|
423
|
+
* @param {object} strategyContext — orchestrator 注入的运行时上下文
|
|
424
|
+
* @returns {{ action: 'pass'|'retry'|'degrade', reason: string, artifact: object }}
|
|
425
|
+
*/
|
|
426
|
+
export function insightGateEvaluator(source, phaseResults, strategyContext = {}) {
|
|
427
|
+
if (!source?.reply) {
|
|
428
|
+
return { action: 'degrade', reason: 'No analysis output', artifact: null };
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const { projectGraph, activeContext, dimId, outputType } = strategyContext;
|
|
432
|
+
|
|
433
|
+
const artifact = activeContext
|
|
434
|
+
? buildAnalysisArtifact(source, dimId, projectGraph, activeContext)
|
|
435
|
+
: buildAnalysisReport(source, dimId, projectGraph);
|
|
436
|
+
|
|
437
|
+
const gate = analysisQualityGate(artifact, { outputType: outputType || 'analysis' });
|
|
438
|
+
|
|
439
|
+
return {
|
|
440
|
+
action: gate.action || (gate.pass ? 'pass' : 'retry'),
|
|
441
|
+
reason: gate.reason || '',
|
|
442
|
+
artifact,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
496
446
|
// ──────────────────────────────────────────────────────────────────
|
|
497
447
|
// 类型定义 (JSDoc)
|
|
498
448
|
// ──────────────────────────────────────────────────────────────────
|
|
499
449
|
|
|
500
450
|
/**
|
|
501
451
|
* @typedef {object} AnalysisReport
|
|
502
|
-
* @property {string} analysisText
|
|
503
|
-
* @property {string[]} referencedFiles
|
|
504
|
-
* @property {string[]} searchQueries
|
|
505
|
-
* @property {string[]} classesExplored
|
|
506
|
-
* @property {string} dimensionId
|
|
452
|
+
* @property {string} analysisText
|
|
453
|
+
* @property {string[]} referencedFiles
|
|
454
|
+
* @property {string[]} searchQueries
|
|
455
|
+
* @property {string[]} classesExplored
|
|
456
|
+
* @property {string} dimensionId
|
|
507
457
|
* @property {object} metadata — { iterations, toolCallCount }
|
|
508
458
|
*/
|
|
509
459
|
|
|
510
460
|
/**
|
|
511
461
|
* @typedef {object} AnalysisArtifact
|
|
512
|
-
* @property {string} analysisText
|
|
513
|
-
* @property {Array<{claim: string, evidence: string[], importance: number, source: string}>} findings
|
|
514
|
-
* @property {string[]} referencedFiles
|
|
515
|
-
* @property {string} dimensionId
|
|
516
|
-
* @property {Map<string, import('./EvidenceCollector.js').EvidenceEntry>} evidenceMap
|
|
517
|
-
* @property {import('./EvidenceCollector.js').ExplorationEntry[]} explorationLog
|
|
518
|
-
* @property {import('./EvidenceCollector.js').NegativeSignal[]} negativeSignals
|
|
519
|
-
* @property {Array} [fullToolTrace]
|
|
520
|
-
* @property {{ scores: object, totalScore: number, suggestions: string[] }} qualityReport
|
|
521
|
-
* @property {object} metadata
|
|
522
|
-
* @property {string[]} searchQueries
|
|
523
|
-
* @property {string[]} classesExplored
|
|
462
|
+
* @property {string} analysisText
|
|
463
|
+
* @property {Array<{claim: string, evidence: string[], importance: number, source: string}>} findings
|
|
464
|
+
* @property {string[]} referencedFiles
|
|
465
|
+
* @property {string} dimensionId
|
|
466
|
+
* @property {Map<string, import('./EvidenceCollector.js').EvidenceEntry>} evidenceMap
|
|
467
|
+
* @property {import('./EvidenceCollector.js').ExplorationEntry[]} explorationLog
|
|
468
|
+
* @property {import('./EvidenceCollector.js').NegativeSignal[]} negativeSignals
|
|
469
|
+
* @property {Array} [fullToolTrace]
|
|
470
|
+
* @property {{ scores: object, totalScore: number, suggestions: string[] }} qualityReport
|
|
471
|
+
* @property {object} metadata
|
|
472
|
+
* @property {string[]} searchQueries
|
|
473
|
+
* @property {string[]} classesExplored
|
|
524
474
|
*/
|