autosnippet 3.2.7 → 3.2.9
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 +13 -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 +26 -29
- package/lib/cli/SetupService.js +1 -1
- package/lib/core/AstAnalyzer.js +27 -5
- package/lib/core/analysis/CallEdgeResolver.js +402 -0
- package/lib/core/analysis/CallGraphAnalyzer.js +367 -0
- package/lib/core/analysis/CallSiteExtractor.js +629 -0
- package/lib/core/analysis/DataFlowInferrer.js +57 -0
- package/lib/core/analysis/ImportPathResolver.js +189 -0
- package/lib/core/analysis/ImportRecord.js +105 -0
- package/lib/core/analysis/SymbolTableBuilder.js +211 -0
- package/lib/core/ast/ProjectGraph.js +8 -0
- package/lib/core/ast/lang-dart.js +352 -5
- package/lib/core/ast/lang-go.js +212 -10
- package/lib/core/ast/lang-java.js +205 -1
- package/lib/core/ast/lang-kotlin.js +330 -1
- package/lib/core/ast/lang-python.js +31 -2
- package/lib/core/ast/lang-rust.js +284 -3
- package/lib/core/ast/lang-swift.js +180 -1
- package/lib/core/ast/lang-typescript.js +290 -1
- package/lib/core/discovery/index.js +2 -2
- package/lib/external/ai/AiProvider.js +66 -172
- package/lib/external/ai/providers/GoogleGeminiProvider.js +23 -1
- package/lib/external/mcp/McpServer.js +1 -0
- 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 +22 -1
- package/lib/external/mcp/handlers/bootstrap/pipeline/IncrementalBootstrap.js +1 -1
- package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-configs.js +2 -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 +311 -162
- package/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +102 -7
- package/lib/external/mcp/handlers/bootstrap/shared/dimension-sop.js +1 -1
- package/lib/external/mcp/handlers/bootstrap-external.js +9 -2
- package/lib/external/mcp/handlers/bootstrap-internal.js +19 -8
- package/lib/external/mcp/handlers/consolidated.js +9 -0
- package/lib/external/mcp/handlers/dimension-complete-external.js +6 -6
- package/lib/external/mcp/handlers/guard.js +3 -3
- package/lib/external/mcp/handlers/structure.js +62 -0
- package/lib/external/mcp/handlers/wiki-external.js +66 -3
- package/lib/external/mcp/tools.js +36 -1
- 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 +9 -5
- package/lib/http/routes/remote.js +149 -270
- 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 +70 -28
- package/lib/platform/ScreenCaptureService.js +177 -0
- package/lib/platform/ios/index.js +2 -2
- package/lib/platform/ios/routes/spm.js +2 -2
- package/lib/platform/ios/spm/PackageSwiftParser.js +14 -3
- package/lib/platform/ios/spm/SpmDiscoverer.js +123 -17
- package/lib/platform/ios/spm/{SpmService.js → SpmHelper.js} +43 -675
- package/lib/platform/ios/xcode/XcodeWriteUtils.js +1 -1
- package/lib/service/agent/AgentEventBus.js +207 -0
- package/lib/service/agent/AgentFactory.js +490 -0
- package/lib/service/agent/AgentMessage.js +240 -0
- package/lib/service/agent/AgentRouter.js +228 -0
- package/lib/service/agent/AgentRuntime.js +1016 -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 +408 -0
- package/lib/service/{chat → agent/context}/ContextWindow.js +37 -12
- package/lib/service/{chat → agent/context}/ExplorationTracker.js +77 -22
- package/lib/service/{chat → agent/core}/ChatAgentPrompts.js +14 -2
- 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 +19 -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} +91 -123
- package/lib/service/agent/domain/insight-producer.js +267 -0
- package/lib/service/agent/domain/scan-prompts.js +105 -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 +3 -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 +5 -4
- package/lib/service/{chat → agent}/memory/index.js +1 -1
- package/lib/service/agent/policies.js +442 -0
- package/lib/service/agent/presets.js +303 -0
- package/lib/service/agent/strategies.js +717 -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/ast-graph.js +229 -32
- 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 +33 -22
- package/lib/service/{chat → agent}/tools/infrastructure.js +6 -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/cursor/CursorDeliveryPipeline.js +167 -1
- package/lib/service/knowledge/CodeEntityGraph.js +327 -2
- package/lib/service/knowledge/KnowledgeService.js +5 -1
- package/lib/service/module/ModuleService.js +49 -73
- package/lib/service/skills/SignalCollector.js +26 -19
- package/lib/service/snippet/codecs/VSCodeCodec.js +1 -1
- package/lib/service/wiki/WikiGenerator.js +1 -1
- package/lib/shared/FieldSpec.js +1 -1
- package/lib/shared/PathGuard.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-BaGY7kJI.css +0 -1
- package/dashboard/dist/assets/index-DfHY_3ln.js +0 -128
- package/lib/core/discovery/SpmDiscoverer.js +0 -5
- package/lib/external/mcp/handlers/bootstrap/pipeline/EpisodicMemory.js +0 -749
- 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 -357
- 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/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,94 +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,
|
|
60
|
+
/^>\s*(?:searchHints|remainingTasks|candidateCount|crossRefs|keyFindings|gaps)\s*[::][^\n]*\n?/gm,
|
|
61
|
+
/^\*{0,2}(?:请在|请直接|请确保|请务必|现在开始|输出你的|不要输出|不要再|不要包含)\s*[^。\n]*(?:分析文本|分析总结|分析报告|JSON|工具|输出|文本|报告)[^。\n]*[。.]?\s*\*{0,2}$/gm,
|
|
62
|
+
/^\*{0,2}重要\s*[::][^。\n]*\*{0,2}$/gm,
|
|
63
|
+
/^注意[::]\s*到达第\s*\d+\s*轮时[^\n]*$/gm,
|
|
64
|
+
/^第\s*\d+\/\d+\s*轮\s*\|[^\n]*$/gm,
|
|
92
65
|
];
|
|
93
66
|
let cleaned = text;
|
|
94
67
|
for (const pat of patterns) {
|
|
95
68
|
cleaned = cleaned.replace(pat, '');
|
|
96
69
|
}
|
|
97
|
-
// 移除可能残留的空行堆积
|
|
98
70
|
cleaned = cleaned.replace(/\n{3,}/g, '\n\n').trim();
|
|
99
71
|
return cleaned;
|
|
100
72
|
}
|
|
101
73
|
|
|
102
74
|
/**
|
|
103
|
-
* 从 Analyst 的执行结果构建 AnalysisReport
|
|
75
|
+
* 从 Analyst 的执行结果构建 AnalysisReport (v1)
|
|
104
76
|
*
|
|
105
|
-
* @param {object} analystResult —
|
|
106
|
-
* @param {string} analystResult.reply — Analyst 的自然语言分析文本
|
|
107
|
-
* @param {Array} analystResult.toolCalls — 工具调用记录
|
|
77
|
+
* @param {object} analystResult — { reply, toolCalls }
|
|
108
78
|
* @param {string} dimensionId — 维度 ID
|
|
109
|
-
* @param {object} [projectGraph] — ProjectGraph 实例
|
|
79
|
+
* @param {object} [projectGraph] — ProjectGraph 实例
|
|
110
80
|
* @returns {AnalysisReport}
|
|
111
81
|
*/
|
|
112
82
|
export function buildAnalysisReport(analystResult, dimensionId, projectGraph = null) {
|
|
@@ -129,7 +99,6 @@ export function buildAnalysisReport(analystResult, dimensionId, projectGraph = n
|
|
|
129
99
|
if (args.pattern || args.query) {
|
|
130
100
|
searchQueries.push(args.pattern || args.query);
|
|
131
101
|
}
|
|
132
|
-
// 从搜索结果中提取文件路径
|
|
133
102
|
if (typeof result === 'string') {
|
|
134
103
|
const fileMatches = result.match(
|
|
135
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
|
|
@@ -147,7 +116,6 @@ export function buildAnalysisReport(analystResult, dimensionId, projectGraph = n
|
|
|
147
116
|
case 'get_class_info':
|
|
148
117
|
if (args.className) {
|
|
149
118
|
classesExplored.push(args.className);
|
|
150
|
-
// 从 ProjectGraph 反查文件路径
|
|
151
119
|
if (projectGraph) {
|
|
152
120
|
const info = projectGraph.getClassInfo(args.className);
|
|
153
121
|
if (info?.filePath) {
|
|
@@ -172,7 +140,7 @@ export function buildAnalysisReport(analystResult, dimensionId, projectGraph = n
|
|
|
172
140
|
}
|
|
173
141
|
}
|
|
174
142
|
|
|
175
|
-
//
|
|
143
|
+
// 从分析文本中提取文件路径
|
|
176
144
|
const text = sanitizeAnalysisText(analystResult.reply || '');
|
|
177
145
|
const FILE_EXT_RE =
|
|
178
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;
|
|
@@ -208,80 +176,72 @@ export function buildAnalysisReport(analystResult, dimensionId, projectGraph = n
|
|
|
208
176
|
* 从 Analyst 执行结果构建 AnalysisArtifact (v2 增强版)
|
|
209
177
|
*
|
|
210
178
|
* 在 v1 AnalysisReport 基础上增加:
|
|
211
|
-
* - evidenceMap: 文件 → 代码片段 + 摘要
|
|
179
|
+
* - evidenceMap: 文件 → 代码片段 + 摘要
|
|
212
180
|
* - explorationLog: 工具调用意图 + 结果摘要序列
|
|
213
|
-
* - negativeSignals: 搜索但未找到的模式
|
|
181
|
+
* - negativeSignals: 搜索但未找到的模式
|
|
214
182
|
* - findings: 来自 ActiveContext 的结构化发现
|
|
215
183
|
* - qualityReport: 多维度质量评分
|
|
216
184
|
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
* @param {object} analystResult — ChatAgent.execute() 返回值
|
|
185
|
+
* @param {object} analystResult — { reply, toolCalls }
|
|
220
186
|
* @param {string} dimensionId — 维度 ID
|
|
221
187
|
* @param {object} [projectGraph] — ProjectGraph 实例
|
|
222
|
-
* @param {object} [activeContext] — ActiveContext 实例
|
|
188
|
+
* @param {object} [activeContext] — ActiveContext 实例
|
|
223
189
|
* @returns {AnalysisArtifact}
|
|
224
190
|
*/
|
|
225
191
|
export function buildAnalysisArtifact(analystResult, dimensionId, projectGraph = null, activeContext = null) {
|
|
226
192
|
const toolCalls = analystResult.toolCalls || [];
|
|
227
193
|
|
|
228
|
-
// §1: 构建 v1 报告 (复用已有逻辑获取 referencedFiles, searchQueries 等)
|
|
229
194
|
const baseReport = buildAnalysisReport(analystResult, dimensionId, projectGraph);
|
|
230
195
|
|
|
231
|
-
// §2: 从工具调用中收集结构化证据
|
|
232
196
|
const collector = new EvidenceCollector();
|
|
233
197
|
for (let i = 0; i < toolCalls.length; i++) {
|
|
234
198
|
collector.processToolCall(toolCalls[i], i);
|
|
235
199
|
}
|
|
236
200
|
const evidence = collector.build();
|
|
237
201
|
|
|
238
|
-
// §3: 从 ActiveContext 获取结构化发现 (保持与 distill() 一致的规范形状)
|
|
239
202
|
const distilled = activeContext?.distill() || { keyFindings: [], toolCallSummary: [] };
|
|
240
203
|
const findings = distilled.keyFindings.map((f) => ({
|
|
241
204
|
finding: f.finding,
|
|
242
|
-
evidence: f.evidence
|
|
205
|
+
evidence: typeof f.evidence === 'string' ? f.evidence : Array.isArray(f.evidence) ? f.evidence.join(', ') : f.evidence ? String(f.evidence) : '',
|
|
243
206
|
importance: f.importance,
|
|
244
207
|
}));
|
|
245
208
|
|
|
246
|
-
// §4: 合并引用文件 (v1 提取 + evidenceMap 中的文件)
|
|
247
209
|
const allFiles = new Set(baseReport.referencedFiles);
|
|
248
210
|
for (const filePath of evidence.evidenceMap.keys()) {
|
|
249
211
|
allFiles.add(filePath);
|
|
250
212
|
}
|
|
251
213
|
|
|
252
|
-
// §5: 计算多维度质量评分
|
|
253
214
|
const qualityReport = buildQualityScores(
|
|
254
215
|
baseReport.analysisText,
|
|
255
216
|
findings,
|
|
256
217
|
evidence,
|
|
257
218
|
);
|
|
258
219
|
|
|
259
|
-
// §6: 构建 AnalysisArtifact (v1 超集)
|
|
260
220
|
return {
|
|
261
|
-
//
|
|
221
|
+
// Layer 1: Core
|
|
262
222
|
analysisText: baseReport.analysisText,
|
|
263
223
|
findings,
|
|
264
224
|
referencedFiles: [...allFiles],
|
|
265
225
|
dimensionId,
|
|
266
226
|
|
|
267
|
-
//
|
|
227
|
+
// Layer 2: Detail
|
|
268
228
|
evidenceMap: evidence.evidenceMap,
|
|
269
229
|
explorationLog: evidence.explorationLog,
|
|
270
230
|
negativeSignals: evidence.negativeSignals,
|
|
271
231
|
|
|
272
|
-
//
|
|
232
|
+
// Layer 3: Raw
|
|
273
233
|
fullToolTrace: toolCalls,
|
|
274
234
|
|
|
275
|
-
//
|
|
235
|
+
// Quality
|
|
276
236
|
qualityReport,
|
|
277
237
|
|
|
278
|
-
//
|
|
238
|
+
// Metadata
|
|
279
239
|
metadata: {
|
|
280
240
|
...baseReport.metadata,
|
|
281
241
|
artifactVersion: 2,
|
|
282
242
|
},
|
|
283
243
|
|
|
284
|
-
//
|
|
244
|
+
// v1 backward compat
|
|
285
245
|
searchQueries: baseReport.searchQueries,
|
|
286
246
|
classesExplored: baseReport.classesExplored,
|
|
287
247
|
};
|
|
@@ -294,21 +254,15 @@ export function buildAnalysisArtifact(analystResult, dimensionId, projectGraph =
|
|
|
294
254
|
/**
|
|
295
255
|
* 计算 AnalysisArtifact 的多维度质量评分
|
|
296
256
|
*
|
|
297
|
-
* 4
|
|
298
|
-
* depthScore (30%)
|
|
257
|
+
* 4 维度各 0-100, 加权:
|
|
258
|
+
* depthScore (30%) — 文件覆盖深度
|
|
299
259
|
* breadthScore (20%) — 工具使用广度
|
|
300
260
|
* evidenceScore (30%) — 证据充分性
|
|
301
261
|
* coherenceScore (20%) — 分析连贯性
|
|
302
|
-
*
|
|
303
|
-
* @param {string} analysisText — 清洗后分析文本
|
|
304
|
-
* @param {Array} findings — 结构化发现
|
|
305
|
-
* @param {object} evidence — EvidenceCollector.build() 结果
|
|
306
|
-
* @returns {{ scores: object, totalScore: number, suggestions: string[] }}
|
|
307
262
|
*/
|
|
308
263
|
function buildQualityScores(analysisText, findings, evidence) {
|
|
309
264
|
const scores = {};
|
|
310
265
|
|
|
311
|
-
// §1: depthScore — 文件覆盖深度
|
|
312
266
|
const uniqueFilesRead = evidence.evidenceMap?.size || 0;
|
|
313
267
|
const snippetCount = [...(evidence.evidenceMap?.values() || [])].reduce(
|
|
314
268
|
(sum, e) => sum + e.codeSnippets.length,
|
|
@@ -316,7 +270,6 @@ function buildQualityScores(analysisText, findings, evidence) {
|
|
|
316
270
|
);
|
|
317
271
|
scores.depthScore = Math.min(100, uniqueFilesRead * 15 + snippetCount * 5);
|
|
318
272
|
|
|
319
|
-
// §2: breadthScore — 工具种类 + 有效率
|
|
320
273
|
const toolTypes = new Set((evidence.explorationLog || []).map((e) => e.tool));
|
|
321
274
|
const logLen = evidence.explorationLog?.length || 0;
|
|
322
275
|
const effectiveRatio = logLen > 0
|
|
@@ -324,7 +277,6 @@ function buildQualityScores(analysisText, findings, evidence) {
|
|
|
324
277
|
: 0;
|
|
325
278
|
scores.breadthScore = Math.min(100, toolTypes.size * 20 + effectiveRatio * 40);
|
|
326
279
|
|
|
327
|
-
// §3: evidenceScore — 发现数量 + 有证据的发现比例
|
|
328
280
|
const findingCount = findings?.length || 0;
|
|
329
281
|
const evidencedFindings = (findings || []).filter((f) => f.evidence && f.evidence.length > 0).length;
|
|
330
282
|
scores.evidenceScore =
|
|
@@ -332,7 +284,6 @@ function buildQualityScores(analysisText, findings, evidence) {
|
|
|
332
284
|
? Math.min(100, (evidencedFindings / findingCount) * 60 + findingCount * 10)
|
|
333
285
|
: 0;
|
|
334
286
|
|
|
335
|
-
// §4: coherenceScore — 文本长度 + 结构标记
|
|
336
287
|
const textLen = analysisText?.length || 0;
|
|
337
288
|
const hasHeaders = /#{1,3}\s/.test(analysisText || '');
|
|
338
289
|
const hasLists = /\d+\.\s|[-•]\s/.test(analysisText || '');
|
|
@@ -344,7 +295,6 @@ function buildQualityScores(analysisText, findings, evidence) {
|
|
|
344
295
|
(findingCount >= 3 ? 20 : findingCount * 7),
|
|
345
296
|
);
|
|
346
297
|
|
|
347
|
-
// 加权总分
|
|
348
298
|
const totalScore = Math.round(
|
|
349
299
|
scores.depthScore * 0.3 +
|
|
350
300
|
scores.breadthScore * 0.2 +
|
|
@@ -352,7 +302,6 @@ function buildQualityScores(analysisText, findings, evidence) {
|
|
|
352
302
|
scores.coherenceScore * 0.2,
|
|
353
303
|
);
|
|
354
304
|
|
|
355
|
-
// 改进建议
|
|
356
305
|
const suggestions = [];
|
|
357
306
|
if (scores.depthScore < 50) suggestions.push('Need more read_project_file to examine code');
|
|
358
307
|
if (scores.evidenceScore < 50) suggestions.push('Findings lack file-level evidence');
|
|
@@ -366,11 +315,11 @@ function buildQualityScores(analysisText, findings, evidence) {
|
|
|
366
315
|
// ──────────────────────────────────────────────────────────────────
|
|
367
316
|
|
|
368
317
|
/**
|
|
369
|
-
* 分析质量门控
|
|
318
|
+
* 分析质量门控
|
|
370
319
|
*
|
|
371
320
|
* 自动检测 v1 (AnalysisReport) 和 v2 (AnalysisArtifact):
|
|
372
|
-
* - v2: 从 qualityReport.totalScore
|
|
373
|
-
* - v1:
|
|
321
|
+
* - v2: 从 qualityReport.totalScore 计算
|
|
322
|
+
* - v1: 使用 4 条规则
|
|
374
323
|
*
|
|
375
324
|
* @param {AnalysisReport|AnalysisArtifact} report
|
|
376
325
|
* @param {object} [options]
|
|
@@ -378,17 +327,12 @@ function buildQualityScores(analysisText, findings, evidence) {
|
|
|
378
327
|
* @returns {{ pass: boolean, reason?: string, action?: 'retry' | 'degrade' }}
|
|
379
328
|
*/
|
|
380
329
|
export function analysisQualityGate(report, options = {}) {
|
|
381
|
-
// v2: AnalysisArtifact 带有 qualityReport
|
|
382
330
|
if (report.qualityReport?.scores) {
|
|
383
331
|
return applyGateThresholds(report.qualityReport, options);
|
|
384
332
|
}
|
|
385
|
-
// v1: 原有逻辑
|
|
386
333
|
return analysisQualityGateV1(report, options);
|
|
387
334
|
}
|
|
388
335
|
|
|
389
|
-
/**
|
|
390
|
-
* v2 质量门控 — 基于多维度评分 + 阈值
|
|
391
|
-
*/
|
|
392
336
|
function applyGateThresholds(qualityReport, options = {}) {
|
|
393
337
|
const { totalScore } = qualityReport;
|
|
394
338
|
const needsCandidates = options.outputType === 'dual' || options.outputType === 'candidate';
|
|
@@ -411,26 +355,18 @@ function applyGateThresholds(qualityReport, options = {}) {
|
|
|
411
355
|
};
|
|
412
356
|
}
|
|
413
357
|
|
|
414
|
-
/**
|
|
415
|
-
* v1 质量门控 — 原有 4 条规则 (保留向后兼容)
|
|
416
|
-
*/
|
|
417
358
|
function analysisQualityGateV1(report, options = {}) {
|
|
418
359
|
const needsCandidates = options.outputType === 'dual' || options.outputType === 'candidate';
|
|
419
|
-
// 需要产出候选的维度要求更高门槛
|
|
420
360
|
const minChars = needsCandidates ? 400 : 200;
|
|
421
361
|
const minFileRefs = needsCandidates ? 3 : 2;
|
|
422
362
|
|
|
423
|
-
// 规则 1: 最少字符数 — 分析太短说明未充分探索
|
|
424
363
|
if (report.analysisText.length < minChars) {
|
|
425
364
|
return { pass: false, reason: 'Analysis too short', action: 'retry' };
|
|
426
365
|
}
|
|
427
|
-
|
|
428
|
-
// 规则 2: 最少引用文件数 — 未引用文件说明未看代码
|
|
429
366
|
if (report.referencedFiles.length < minFileRefs) {
|
|
430
367
|
return { pass: false, reason: 'Too few file references', action: 'retry' };
|
|
431
368
|
}
|
|
432
369
|
|
|
433
|
-
// 规则 3: 检测"拒绝回答"模式
|
|
434
370
|
const refusalPatterns = [
|
|
435
371
|
/I cannot|I'm unable|I don't have access/i,
|
|
436
372
|
/无法分析|无法访问|没有足够/,
|
|
@@ -439,9 +375,6 @@ function analysisQualityGateV1(report, options = {}) {
|
|
|
439
375
|
return { pass: false, reason: 'Agent refused to analyze', action: 'degrade' };
|
|
440
376
|
}
|
|
441
377
|
|
|
442
|
-
// 规则 4: 内容实质性检查 — 有结构化内容或足够多的探索
|
|
443
|
-
// v3.1: 放宽条件 — tool calling 模式下 AI 往往不输出 markdown 格式
|
|
444
|
-
// 只要分析足够长且引用了足够多的文件,就认为有实质性内容
|
|
445
378
|
const hasStructure =
|
|
446
379
|
/#{1,3}\s/.test(report.analysisText) ||
|
|
447
380
|
/\d+\.\s/.test(report.analysisText) ||
|
|
@@ -457,7 +390,7 @@ function analysisQualityGateV1(report, options = {}) {
|
|
|
457
390
|
}
|
|
458
391
|
|
|
459
392
|
/**
|
|
460
|
-
* 构建重试提示
|
|
393
|
+
* 构建重试提示
|
|
461
394
|
*
|
|
462
395
|
* @param {string} reason — Gate 失败原因
|
|
463
396
|
* @returns {string}
|
|
@@ -475,32 +408,67 @@ export function buildRetryPrompt(reason) {
|
|
|
475
408
|
return hints[reason] || '请更深入地分析代码,引用至少 3 个具体文件,每个发现都要有代码证据。';
|
|
476
409
|
}
|
|
477
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
|
+
|
|
478
446
|
// ──────────────────────────────────────────────────────────────────
|
|
479
447
|
// 类型定义 (JSDoc)
|
|
480
448
|
// ──────────────────────────────────────────────────────────────────
|
|
481
449
|
|
|
482
450
|
/**
|
|
483
451
|
* @typedef {object} AnalysisReport
|
|
484
|
-
* @property {string} analysisText
|
|
485
|
-
* @property {string[]} referencedFiles
|
|
486
|
-
* @property {string[]} searchQueries
|
|
487
|
-
* @property {string[]} classesExplored
|
|
488
|
-
* @property {string} dimensionId
|
|
452
|
+
* @property {string} analysisText
|
|
453
|
+
* @property {string[]} referencedFiles
|
|
454
|
+
* @property {string[]} searchQueries
|
|
455
|
+
* @property {string[]} classesExplored
|
|
456
|
+
* @property {string} dimensionId
|
|
489
457
|
* @property {object} metadata — { iterations, toolCallCount }
|
|
490
458
|
*/
|
|
491
459
|
|
|
492
460
|
/**
|
|
493
461
|
* @typedef {object} AnalysisArtifact
|
|
494
|
-
* @property {string} analysisText
|
|
495
|
-
* @property {Array<{claim: string, evidence: string[], importance: number, source: string}>} findings
|
|
496
|
-
* @property {string[]} referencedFiles
|
|
497
|
-
* @property {string} dimensionId
|
|
498
|
-
* @property {Map<string, import('./EvidenceCollector.js').EvidenceEntry>} evidenceMap
|
|
499
|
-
* @property {import('./EvidenceCollector.js').ExplorationEntry[]} explorationLog
|
|
500
|
-
* @property {import('./EvidenceCollector.js').NegativeSignal[]} negativeSignals
|
|
501
|
-
* @property {Array} [fullToolTrace]
|
|
502
|
-
* @property {{ scores: object, totalScore: number, suggestions: string[] }} qualityReport
|
|
503
|
-
* @property {object} metadata
|
|
504
|
-
* @property {string[]} searchQueries
|
|
505
|
-
* @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
|
|
506
474
|
*/
|