autosnippet 3.3.9 → 3.4.1
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 +44 -19
- package/config/default.json +1 -1
- package/dashboard/dist/assets/{index-DEU4tJtP.js → index-BX6r2fiy.js} +40 -40
- package/dashboard/dist/assets/index-BvZcGN02.css +1 -0
- package/dashboard/dist/index.html +2 -2
- package/dist/lib/agent/AgentRuntime.js +13 -1
- package/dist/lib/agent/AgentRuntimeTypes.d.ts +2 -0
- package/dist/lib/agent/PipelineStrategy.js +32 -2
- package/dist/lib/agent/context/ContextWindow.d.ts +2 -1
- package/dist/lib/agent/context/ContextWindow.js +18 -4
- package/dist/lib/agent/context/ExplorationTracker.js +6 -1
- package/dist/lib/agent/context/exploration/ExplorationStrategies.js +2 -1
- package/dist/lib/agent/core/LoopContext.d.ts +3 -0
- package/dist/lib/agent/core/LoopContext.js +3 -0
- package/dist/lib/agent/domain/EpisodicConsolidator.d.ts +5 -0
- package/dist/lib/agent/domain/EpisodicConsolidator.js +60 -5
- package/dist/lib/agent/domain/insight-analyst.d.ts +16 -0
- package/dist/lib/agent/domain/insight-analyst.js +38 -0
- package/dist/lib/agent/domain/insight-gate.js +12 -0
- package/dist/lib/agent/memory/MemoryConsolidator.js +17 -0
- package/dist/lib/core/AstAnalyzer.js +0 -1
- package/dist/lib/core/ast/lang-dart.js +0 -1
- package/dist/lib/core/ast/lang-go.js +0 -1
- package/dist/lib/core/ast/lang-java.js +0 -1
- package/dist/lib/core/ast/lang-javascript.js +0 -1
- package/dist/lib/core/ast/lang-objc.js +0 -1
- package/dist/lib/core/ast/lang-python.js +0 -1
- package/dist/lib/core/ast/lang-rust.js +0 -1
- package/dist/lib/core/ast/lang-swift.js +0 -1
- package/dist/lib/core/ast/lang-typescript.js +0 -1
- package/dist/lib/domain/dimension/DimensionRegistry.d.ts +6 -4
- package/dist/lib/domain/dimension/DimensionRegistry.js +19 -23
- package/dist/lib/external/ai/AiFactory.d.ts +14 -0
- package/dist/lib/external/ai/AiFactory.js +33 -1
- package/dist/lib/external/ai/AiProvider.d.ts +2 -0
- package/dist/lib/external/ai/AiProvider.js +4 -0
- package/dist/lib/external/ai/providers/ClaudeProvider.d.ts +1 -1
- package/dist/lib/external/ai/providers/ClaudeProvider.js +6 -2
- package/dist/lib/external/ai/providers/GoogleGeminiProvider.d.ts +1 -1
- package/dist/lib/external/ai/providers/GoogleGeminiProvider.js +13 -5
- package/dist/lib/external/ai/providers/OpenAiProvider.d.ts +1 -1
- package/dist/lib/external/ai/providers/OpenAiProvider.js +8 -4
- package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +10 -2
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.d.ts +1 -0
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +39 -5
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +2 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +4 -0
- package/dist/lib/external/mcp/handlers/guard.js +11 -6
- package/dist/lib/http/routes/ai.js +20 -3
- package/dist/lib/infrastructure/vector/IndexingPipeline.js +6 -1
- package/dist/lib/injection/modules/AiModule.js +22 -1
- package/dist/lib/service/bootstrap/BootstrapTaskManager.d.ts +7 -0
- package/dist/lib/service/bootstrap/BootstrapTaskManager.js +17 -0
- package/dist/lib/service/guard/ComplianceReporter.js +5 -1
- package/dist/lib/service/guard/GuardCheckEngine.d.ts +12 -1
- package/dist/lib/service/guard/GuardCheckEngine.js +36 -4
- package/dist/lib/service/guard/GuardCodeChecks.js +27 -9
- package/dist/lib/service/guard/SourceFileCollector.d.ts +3 -2
- package/dist/lib/service/guard/SourceFileCollector.js +3 -3
- package/dist/lib/service/search/SearchEngine.js +165 -61
- package/dist/lib/service/task/PrimeSearchPipeline.js +17 -2
- package/dist/lib/service/vector/VectorService.js +10 -1
- package/dist/lib/shared/LanguageService.d.ts +12 -0
- package/dist/lib/shared/LanguageService.js +85 -0
- package/dist/lib/shared/schemas/http-requests.d.ts +4 -0
- package/dist/lib/shared/schemas/http-requests.js +4 -0
- package/package.json +1 -1
- package/dashboard/dist/assets/index-DHJ1Dj7u.css +0 -1
|
@@ -70,6 +70,8 @@ export class ExplorationTracker {
|
|
|
70
70
|
#submitToolName = 'submit_knowledge';
|
|
71
71
|
/** 管线类型标识 — 统一场景判别(替代 submitToolName / strategy.name 字符串比较) */
|
|
72
72
|
#pipelineType;
|
|
73
|
+
/** 当前阶段开始时间(用于 dwell time 统计) */
|
|
74
|
+
#phaseStartTime = Date.now();
|
|
73
75
|
/**
|
|
74
76
|
* @param strategy 策略配置对象
|
|
75
77
|
* @param budget 预算配置 { maxIterations, searchBudget, ... }
|
|
@@ -446,8 +448,10 @@ export class ExplorationTracker {
|
|
|
446
448
|
}
|
|
447
449
|
#transitionTo(newPhase) {
|
|
448
450
|
const oldPhase = this.#phase;
|
|
451
|
+
const dwellMs = Date.now() - this.#phaseStartTime;
|
|
449
452
|
this.#transitionFromPhase = oldPhase;
|
|
450
453
|
this.#phase = newPhase;
|
|
454
|
+
this.#phaseStartTime = Date.now();
|
|
451
455
|
this.#metrics.phaseRounds = 0;
|
|
452
456
|
this.#metrics.searchRoundsInPhase = 0;
|
|
453
457
|
// 重置停滞计数器 — 防止跨阶段累积导致级联式过早转换
|
|
@@ -456,7 +460,8 @@ export class ExplorationTracker {
|
|
|
456
460
|
this.#metrics.roundsSinceSubmit = 0;
|
|
457
461
|
this.#metrics.consecutiveIdleRounds = 0;
|
|
458
462
|
this.#justTransitioned = true;
|
|
459
|
-
this.#logger.info(`[ExplorationTracker] ${oldPhase} → ${newPhase} (iter=${this.#metrics.iteration}, submits=${this.#metrics.submitCount},
|
|
463
|
+
this.#logger.info(`[ExplorationTracker] ${oldPhase} → ${newPhase} (iter=${this.#metrics.iteration}, submits=${this.#metrics.submitCount}, ` +
|
|
464
|
+
`dwellMs=${dwellMs}, files=${this.#metrics.uniqueFiles.size}, patterns=${this.#metrics.uniquePatterns.size})`);
|
|
460
465
|
// Phase 3: 发射阶段转换信号
|
|
461
466
|
if (this.#signalBus) {
|
|
462
467
|
const terminalPhase = this.#getTerminalPhase();
|
|
@@ -66,7 +66,8 @@ export const STRATEGY_ANALYST = {
|
|
|
66
66
|
phases: ['SCAN', 'EXPLORE', 'VERIFY', 'SUMMARIZE'],
|
|
67
67
|
transitions: {
|
|
68
68
|
'SCAN→EXPLORE': {
|
|
69
|
-
|
|
69
|
+
// 2 轮结构扫描足够获取项目骨架(目录 + 关键文件列表),将 1 轮还给 EXPLORE
|
|
70
|
+
onMetrics: (m) => m.iteration >= 2,
|
|
70
71
|
onTextResponse: false,
|
|
71
72
|
},
|
|
72
73
|
'EXPLORE→VERIFY': {
|
|
@@ -62,6 +62,7 @@ interface LoopContextConfig {
|
|
|
62
62
|
context?: Record<string, unknown>;
|
|
63
63
|
contextWindow?: ContextWindow | null;
|
|
64
64
|
toolChoiceOverride?: string | null;
|
|
65
|
+
abortSignal?: AbortSignal | null;
|
|
65
66
|
}
|
|
66
67
|
export declare class LoopContext {
|
|
67
68
|
/** 统一消息适配器 */
|
|
@@ -110,6 +111,8 @@ export declare class LoopContext {
|
|
|
110
111
|
contextWindow: ContextWindow | null;
|
|
111
112
|
/** 首轮 toolChoice 覆盖 ('required'/'auto'/'none') */
|
|
112
113
|
toolChoiceOverride: string | null;
|
|
114
|
+
/** 外部中止信号 — hard timeout 时取消进行中的 LLM 调用 */
|
|
115
|
+
abortSignal: AbortSignal | null;
|
|
113
116
|
constructor(config: LoopContextConfig);
|
|
114
117
|
/** 是否为 system 场景 */
|
|
115
118
|
get isSystem(): boolean;
|
|
@@ -60,6 +60,8 @@ export class LoopContext {
|
|
|
60
60
|
contextWindow;
|
|
61
61
|
/** 首轮 toolChoice 覆盖 ('required'/'auto'/'none') */
|
|
62
62
|
toolChoiceOverride;
|
|
63
|
+
/** 外部中止信号 — hard timeout 时取消进行中的 LLM 调用 */
|
|
64
|
+
abortSignal;
|
|
63
65
|
constructor(config) {
|
|
64
66
|
this.messages = config.messages;
|
|
65
67
|
this.tracker = (config.tracker || null);
|
|
@@ -76,6 +78,7 @@ export class LoopContext {
|
|
|
76
78
|
this.context = config.context || {};
|
|
77
79
|
this.contextWindow = config.contextWindow || null;
|
|
78
80
|
this.toolChoiceOverride = config.toolChoiceOverride || null;
|
|
81
|
+
this.abortSignal = (config.abortSignal || null);
|
|
79
82
|
this.loopStartTime = Date.now();
|
|
80
83
|
}
|
|
81
84
|
// ─── 计算属性 ───
|
|
@@ -97,6 +97,11 @@ export declare class EpisodicConsolidator {
|
|
|
97
97
|
};
|
|
98
98
|
total: ConsolidateResult;
|
|
99
99
|
durationMs: number;
|
|
100
|
+
perDimension: {
|
|
101
|
+
[k: string]: number;
|
|
102
|
+
};
|
|
103
|
+
importanceDistribution: Record<number, number>;
|
|
104
|
+
entityCount: number;
|
|
100
105
|
};
|
|
101
106
|
}
|
|
102
107
|
export default EpisodicConsolidator;
|
|
@@ -25,16 +25,18 @@ import Logger from '#infra/logging/Logger.js';
|
|
|
25
25
|
* - "XX 采用了 YY"
|
|
26
26
|
*/
|
|
27
27
|
const FACT_PATTERNS = [
|
|
28
|
-
//
|
|
28
|
+
// Chinese
|
|
29
29
|
/(?:项目|工程|代码库)(?:使用|采用|基于|遵循)了?\s*([^,。,.\n]{5,60})/g,
|
|
30
|
-
// "主要/核心 XXX 是 YYY"
|
|
31
30
|
/(?:主要|核心|主|主力)\s*(\S+)\s*(?:是|为|使用)\s*([^,。,.\n]{3,40})/g,
|
|
32
|
-
// "发现了? N 个 XXX"
|
|
33
31
|
/(?:发现|找到|扫描到|识别|共有|包含)\s*了?\s*(\d+)\s*个?\s*([^,。,.\n]{2,30})/g,
|
|
34
|
-
// "XXX 是唯一的/主要的 YYY"
|
|
35
32
|
/(\S{2,20})\s*是\s*(?:唯一的?|主要的?|核心的?|全局的?)\s*([^,。,.\n]{3,30})/g,
|
|
36
|
-
// "使用了 XXX 前缀/后缀/命名"
|
|
37
33
|
/(?:使用|采用|遵循)了?\s*(\S{1,10})\s*(?:前缀|后缀|命名|约定|规范)/g,
|
|
34
|
+
// English
|
|
35
|
+
/(?:the\s+)?project\s+(?:uses?|adopts?|relies\s+on|follows?)\s+([^.,\n]{5,60})/gi,
|
|
36
|
+
/(?:found|discovered|identified|detected)\s+(\d+)\s+([^.,\n]{3,40})/gi,
|
|
37
|
+
/(?:the\s+)?(?:primary|main|core)\s+(\S+)\s+(?:is|are)\s+([^.,\n]{3,40})/gi,
|
|
38
|
+
/(?:all|every)\s+([^.,\n]{3,30})\s+(?:use|adopt|follow|implement)\s+([^.,\n]{3,40})/gi,
|
|
39
|
+
/(?:there\s+(?:is|are))\s+(\d+)\s+([^.,\n]{3,40})/gi,
|
|
38
40
|
];
|
|
39
41
|
/**
|
|
40
42
|
* 匹配洞察性陈述:
|
|
@@ -43,9 +45,14 @@ const FACT_PATTERNS = [
|
|
|
43
45
|
* - "建议/推荐 XXX"
|
|
44
46
|
*/
|
|
45
47
|
const INSIGHT_PATTERNS = [
|
|
48
|
+
// Chinese
|
|
46
49
|
/([^,。,.\n]{5,40})(?:暗示|表明|说明|意味着|揭示)\s*([^,。,.\n]{5,60})/g,
|
|
47
50
|
/([^,。,.\n]{3,20})\s*(?:与|和)\s*([^,。,.\n]{3,20})\s*(?:耦合|关联|存在依赖|有关系)/g,
|
|
48
51
|
/(?:建议|推荐|应该|需要)\s*([^,。,.\n]{5,60})/g,
|
|
52
|
+
// English
|
|
53
|
+
/([^.,\n]{5,40})\s+(?:suggests?|indicates?|implies?|reveals?)\s+(?:that\s+)?([^.,\n]{5,60})/gi,
|
|
54
|
+
/([^.,\n]{3,20})\s+(?:is|are)\s+(?:tightly\s+)?(?:coupled|linked|related)\s+(?:to|with)\s+([^.,\n]{3,30})/gi,
|
|
55
|
+
/(?:recommend|should|consider|suggest)\s+([^.,\n]{5,60})/gi,
|
|
49
56
|
];
|
|
50
57
|
// ──────────────────────────────────────────────────────────────
|
|
51
58
|
// EpisodicConsolidator 类
|
|
@@ -81,9 +88,15 @@ export class EpisodicConsolidator {
|
|
|
81
88
|
const textFactMemories = this.#extractFromAnalysisText(sessionStore);
|
|
82
89
|
// 5. 合并所有候选, 使用 consolidate 去重
|
|
83
90
|
const allCandidates = [...findingMemories, ...insightMemories, ...textFactMemories];
|
|
91
|
+
// ── 结构化统计日志 ──
|
|
92
|
+
const dimStats = this.#computeDimStats(allCandidates);
|
|
93
|
+
const importanceDist = this.#computeImportanceDistribution(allCandidates);
|
|
94
|
+
const entityCount = allCandidates.reduce((sum, c) => sum + (c.relatedEntities?.length || 0), 0);
|
|
84
95
|
this.#logger.info(`[Consolidator] Extracted ${allCandidates.length} candidate memories: ` +
|
|
85
96
|
`${findingMemories.length} findings, ${insightMemories.length} insights, ` +
|
|
86
97
|
`${textFactMemories.length} text facts`);
|
|
98
|
+
this.#logger.info(`[Consolidator] Per-dimension: ${dimStats.map((d) => `${d.dim}=${d.count}`).join(', ')}`);
|
|
99
|
+
this.#logger.info(`[Consolidator] Importance distribution: ${importanceDist} | Entities extracted: ${entityCount}`);
|
|
87
100
|
const result = this.#semanticMemory.consolidate(allCandidates, { bootstrapSession });
|
|
88
101
|
const durationMs = Date.now() - t0;
|
|
89
102
|
this.#logger.info(`[Consolidator] Consolidation complete in ${durationMs}ms: ` +
|
|
@@ -95,6 +108,9 @@ export class EpisodicConsolidator {
|
|
|
95
108
|
textFacts: { extracted: textFactMemories.length },
|
|
96
109
|
total: result,
|
|
97
110
|
durationMs,
|
|
111
|
+
perDimension: Object.fromEntries(dimStats.map((d) => [d.dim, d.count])),
|
|
112
|
+
importanceDistribution: this.#importanceHistogram(allCandidates),
|
|
113
|
+
entityCount,
|
|
98
114
|
};
|
|
99
115
|
}
|
|
100
116
|
// ─── 提取器 ───────────────────────────────────────────
|
|
@@ -273,6 +289,45 @@ export class EpisodicConsolidator {
|
|
|
273
289
|
return memories;
|
|
274
290
|
}
|
|
275
291
|
// ─── 辅助方法 ─────────────────────────────────────────
|
|
292
|
+
/** 按维度聚合候选数量 */
|
|
293
|
+
#computeDimStats(candidates) {
|
|
294
|
+
const counts = new Map();
|
|
295
|
+
for (const c of candidates) {
|
|
296
|
+
const dim = c.sourceDimension || 'unknown';
|
|
297
|
+
counts.set(dim, (counts.get(dim) || 0) + 1);
|
|
298
|
+
}
|
|
299
|
+
return [...counts.entries()]
|
|
300
|
+
.map(([dim, count]) => ({ dim, count }))
|
|
301
|
+
.sort((a, b) => b.count - a.count);
|
|
302
|
+
}
|
|
303
|
+
/** 生成重要性分布字符串: "[1-3]=N [4-6]=N [7-10]=N" */
|
|
304
|
+
#computeImportanceDistribution(candidates) {
|
|
305
|
+
let low = 0;
|
|
306
|
+
let mid = 0;
|
|
307
|
+
let high = 0;
|
|
308
|
+
for (const c of candidates) {
|
|
309
|
+
const imp = c.importance || 5;
|
|
310
|
+
if (imp <= 3) {
|
|
311
|
+
low++;
|
|
312
|
+
}
|
|
313
|
+
else if (imp <= 6) {
|
|
314
|
+
mid++;
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
high++;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return `[1-3]=${low} [4-6]=${mid} [7-10]=${high}`;
|
|
321
|
+
}
|
|
322
|
+
/** 构建重要性直方图对象 (供返回值使用) */
|
|
323
|
+
#importanceHistogram(candidates) {
|
|
324
|
+
const hist = {};
|
|
325
|
+
for (const c of candidates) {
|
|
326
|
+
const imp = c.importance || 5;
|
|
327
|
+
hist[imp] = (hist[imp] || 0) + 1;
|
|
328
|
+
}
|
|
329
|
+
return hist;
|
|
330
|
+
}
|
|
276
331
|
/**
|
|
277
332
|
* 从文本中提取实体名 (类名/文件名/模块名)
|
|
278
333
|
*
|
|
@@ -61,6 +61,7 @@ interface CodeEntityGraphLike {
|
|
|
61
61
|
}
|
|
62
62
|
export declare const ANALYST_SYSTEM_PROMPT = "\u4F60\u662F\u4E00\u4F4D\u9AD8\u7EA7\u8F6F\u4EF6\u67B6\u6784\u5E08\uFF0C\u6B63\u5728\u6DF1\u5EA6\u5206\u6790\u4E00\u4E2A\u771F\u5B9E\u9879\u76EE\u7684\u67D0\u4E2A\u7EF4\u5EA6\u3002\n\n## \u6267\u884C\u8BA1\u5212\n\u4F60\u6709 **N \u8F6E**\u5DE5\u5177\u8C03\u7528\u673A\u4F1A\uFF08\u7CFB\u7EDF\u4F1A\u544A\u77E5\u5177\u4F53\u6570\u5B57\uFF09\u3002\u8BF7\u4E25\u683C\u6309\u4EE5\u4E0B\u8282\u594F\u5206\u914D\uFF1A\n\n| \u9636\u6BB5 | \u8F6E\u6B21\u5360\u6BD4 | \u76EE\u6807 |\n|------|---------|------|\n| 1. \u5168\u5C40\u626B\u63CF | \u7B2C 1-3 \u8F6E | get_project_overview + list_project_structure \u4E86\u89E3\u9879\u76EE\u7ED3\u6784 |\n| 2. \u7ED3\u6784\u5316\u63A2\u7D22 | \u7B2C 4-N\u00D760% \u8F6E | get_class_hierarchy / get_class_info \u7406\u89E3\u6838\u5FC3\u7C7B\uFF1Bsearch_project_code \u6279\u91CF\u641C\u7D22\u5173\u952E\u6A21\u5F0F |\n| 3. \u6DF1\u5EA6\u9A8C\u8BC1 | \u7B2C N\u00D760%-N\u00D780% \u8F6E | read_project_file \u9605\u8BFB\u5173\u952E\u5B9E\u73B0\uFF0C\u786E\u8BA4\u7EC6\u8282 |\n| 4. \u8F93\u51FA\u603B\u7ED3 | \u6700\u540E 20% | **\u505C\u6B62\u8C03\u7528\u5DE5\u5177**\uFF0C\u76F4\u63A5\u8F93\u51FA\u4F60\u7684\u5206\u6790\u6587\u672C |\n\n## \u5173\u952E\u89C4\u5219\n- **\u5230\u8FBE 80% \u8F6E\u6B21\u65F6\u5FC5\u987B\u5F00\u59CB\u5199\u603B\u7ED3**\uFF0C\u4E0D\u8981\u7B49\u7CFB\u7EDF\u63D0\u9192\n- \u6BCF\u4E00\u8F6E\u90FD\u5FC5\u987B\u8C03\u7528\u5DE5\u5177\u83B7\u53D6\u65B0\u4FE1\u606F\uFF0C\u4E0D\u8981\u82B1\u8F6E\u6B21\u5728\u7EAF\u6587\u672C\u601D\u8003\u4E0A\n- \u4E0D\u8981\u91CD\u590D\u641C\u7D22\u76F8\u540C\u5173\u952E\u8BCD\u6216\u8BFB\u53D6\u76F8\u540C\u6587\u4EF6\uFF08\u7CFB\u7EDF\u4F1A\u8FD4\u56DE\u7F13\u5B58\u5E76\u6263\u8F6E\u6B21\uFF09\n\n## \u5DE5\u5177\u6548\u7387\n- **\u6279\u91CF\u641C\u7D22**: search_project_code({ patterns: [\"keywordA\", \"keywordB\", \"keywordC\"] }) \u2014 \u4E00\u6B21\u641C 3-5 \u4E2A\n- **\u6279\u91CF\u8BFB\u6587\u4EF6**: read_project_file({ filePaths: [\"a.m\", \"b.m\", \"c.m\"] }) \u2014 \u4E00\u6B21\u8BFB 3-5 \u4E2A\n- **\u7ED3\u6784\u5316\u67E5\u8BE2\u4F18\u5148**: get_class_hierarchy / get_class_info \u6BD4\u6587\u672C\u641C\u7D22\u66F4\u7CBE\u786E\u9AD8\u6548\n\n## \u8F93\u51FA\u8981\u6C42\n\u8F93\u51FA\u4F60\u7684\u5206\u6790\u53D1\u73B0\uFF0C\u5305\u62EC\u5177\u4F53\u7684\u6587\u4EF6\u5B8C\u6574\u76F8\u5BF9\u8DEF\u5F84\uFF08\u4ECE\u9879\u76EE\u6839\u76EE\u5F55\u5F00\u59CB\uFF09\u548C\u884C\u53F7\u3002\n\u6BCF\u4E2A\u6587\u4EF6\u5F15\u7528\u683C\u5F0F: (\u6765\u6E90: Full/Relative/Path/FileName.ext:\u884C\u53F7)\n\u7981\u6B62\u53EA\u5199\u6587\u4EF6\u540D\uFF0C\u5FC5\u987B\u5199\u4ECE\u9879\u76EE\u6839\u5F00\u59CB\u7684\u5B8C\u6574\u8DEF\u5F84\u3002\n\u6807\u6CE8\u6BCF\u4E2A\u53D1\u73B0\u6240\u5C5E\u7684\u6A21\u5757/\u5305\u540D\u3002\n\u7528\u81EA\u7136\u8BED\u8A00\u63CF\u8FF0\u4F60\u7684\u7406\u89E3\uFF0C\u4E0D\u9700\u8981\u7279\u5B9A\u683C\u5F0F\u3002";
|
|
63
63
|
export declare const ANALYST_TOOLS: string[];
|
|
64
|
+
/** 默认 Analyst 预算(24 轮基线) */
|
|
64
65
|
export declare const ANALYST_BUDGET: {
|
|
65
66
|
maxIterations: number;
|
|
66
67
|
searchBudget: number;
|
|
@@ -69,6 +70,21 @@ export declare const ANALYST_BUDGET: {
|
|
|
69
70
|
softSubmitLimit: number;
|
|
70
71
|
idleRoundsToExit: number;
|
|
71
72
|
};
|
|
73
|
+
/**
|
|
74
|
+
* 根据项目规模自适应计算 Analyst 预算
|
|
75
|
+
*
|
|
76
|
+
* 策略: 以文件数为主要缩放因子,保持 searchBudget/maxIterations 的比例关系。
|
|
77
|
+
* - ≤40 文件: 基线 24 轮(小型项目无需额外预算)
|
|
78
|
+
* - 41~100 文件: 线性插值到 32 轮
|
|
79
|
+
* - 101~200 文件: 线性插值到 40 轮
|
|
80
|
+
* - >200 文件: 封顶 40 轮(避免单维度成本失控)
|
|
81
|
+
*
|
|
82
|
+
* searchBudget 按比例随 maxIterations 缩放(保持 75%)。
|
|
83
|
+
* timeoutMs 按比例随 maxIterations 缩放(基线 300s 对应 24 轮)。
|
|
84
|
+
*/
|
|
85
|
+
export declare function computeAnalystBudget(fileCount: number): typeof ANALYST_BUDGET & {
|
|
86
|
+
timeoutMs: number;
|
|
87
|
+
};
|
|
72
88
|
/** Panorama context — module role, layer, coupling, gaps */
|
|
73
89
|
interface PanoramaContextLike {
|
|
74
90
|
moduleRole: string | null;
|
|
@@ -72,6 +72,7 @@ export const ANALYST_TOOLS = [
|
|
|
72
72
|
// ──────────────────────────────────────────────────────────────────
|
|
73
73
|
// Analyst 预算 — 使用 analyst 策略(自由探索,无阶段约束)
|
|
74
74
|
// ──────────────────────────────────────────────────────────────────
|
|
75
|
+
/** 默认 Analyst 预算(24 轮基线) */
|
|
75
76
|
export const ANALYST_BUDGET = {
|
|
76
77
|
maxIterations: 24,
|
|
77
78
|
searchBudget: 18,
|
|
@@ -80,6 +81,43 @@ export const ANALYST_BUDGET = {
|
|
|
80
81
|
softSubmitLimit: 0,
|
|
81
82
|
idleRoundsToExit: 2,
|
|
82
83
|
};
|
|
84
|
+
/**
|
|
85
|
+
* 根据项目规模自适应计算 Analyst 预算
|
|
86
|
+
*
|
|
87
|
+
* 策略: 以文件数为主要缩放因子,保持 searchBudget/maxIterations 的比例关系。
|
|
88
|
+
* - ≤40 文件: 基线 24 轮(小型项目无需额外预算)
|
|
89
|
+
* - 41~100 文件: 线性插值到 32 轮
|
|
90
|
+
* - 101~200 文件: 线性插值到 40 轮
|
|
91
|
+
* - >200 文件: 封顶 40 轮(避免单维度成本失控)
|
|
92
|
+
*
|
|
93
|
+
* searchBudget 按比例随 maxIterations 缩放(保持 75%)。
|
|
94
|
+
* timeoutMs 按比例随 maxIterations 缩放(基线 300s 对应 24 轮)。
|
|
95
|
+
*/
|
|
96
|
+
export function computeAnalystBudget(fileCount) {
|
|
97
|
+
const clamped = Math.max(0, fileCount);
|
|
98
|
+
let maxIter;
|
|
99
|
+
if (clamped <= 40) {
|
|
100
|
+
maxIter = 24;
|
|
101
|
+
}
|
|
102
|
+
else if (clamped <= 100) {
|
|
103
|
+
// 40→100 文件: 24→32 轮(线性插值)
|
|
104
|
+
maxIter = Math.round(24 + ((clamped - 40) / 60) * 8);
|
|
105
|
+
}
|
|
106
|
+
else if (clamped <= 200) {
|
|
107
|
+
// 100→200 文件: 32→40 轮
|
|
108
|
+
maxIter = Math.round(32 + ((clamped - 100) / 100) * 8);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
maxIter = 40;
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
...ANALYST_BUDGET,
|
|
115
|
+
maxIterations: maxIter,
|
|
116
|
+
searchBudget: Math.round(maxIter * 0.75),
|
|
117
|
+
// 超时随轮次等比缩放: 24轮→300s, 40轮→500s
|
|
118
|
+
timeoutMs: Math.round((maxIter / 24) * 300_000),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
83
121
|
/**
|
|
84
122
|
* 构建 Analyst Prompt
|
|
85
123
|
*
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
*
|
|
15
15
|
* @module insight-gate
|
|
16
16
|
*/
|
|
17
|
+
import Logger from '#infra/logging/Logger.js';
|
|
17
18
|
import { EvidenceCollector, } from './EvidenceCollector.js';
|
|
19
|
+
const logger = Logger.getInstance();
|
|
18
20
|
// ──────────────────────────────────────────────────────────────────
|
|
19
21
|
// AnalysisReport 构建
|
|
20
22
|
// ──────────────────────────────────────────────────────────────────
|
|
@@ -376,6 +378,16 @@ export function insightGateEvaluator(source, phaseResults, strategyContext = {})
|
|
|
376
378
|
? buildAnalysisArtifact(source, dimId, projectGraph, activeContext)
|
|
377
379
|
: buildAnalysisReport(source, dimId, projectGraph);
|
|
378
380
|
const gate = analysisQualityGate(artifact, { outputType: outputType || 'analysis' });
|
|
381
|
+
const qr = artifact.qualityReport;
|
|
382
|
+
if (qr?.scores) {
|
|
383
|
+
logger.info(`[QualityGate] dim="${dimId}" action=${gate.pass ? 'pass' : gate.action} ` +
|
|
384
|
+
`total=${qr.totalScore} depth=${qr.scores.depthScore} breadth=${qr.scores.breadthScore} ` +
|
|
385
|
+
`evidence=${qr.scores.evidenceScore} coherence=${qr.scores.coherenceScore}` +
|
|
386
|
+
(qr.suggestions.length > 0 ? ` suggestions=[${qr.suggestions.join('; ')}]` : ''));
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
logger.info(`[QualityGate] dim="${dimId}" action=${gate.pass ? 'pass' : gate.action} reason="${gate.reason || 'v1-rules'}" (v1 fallback)`);
|
|
390
|
+
}
|
|
379
391
|
return {
|
|
380
392
|
action: gate.action || (gate.pass ? 'pass' : 'retry'),
|
|
381
393
|
reason: gate.reason || '',
|
|
@@ -17,6 +17,8 @@ import { MemoryStore } from './MemoryStore.js';
|
|
|
17
17
|
/** 相似度阈值 */
|
|
18
18
|
const SIMILARITY_UPDATE = 0.85; // ≥85% 同义 → UPDATE
|
|
19
19
|
const SIMILARITY_MERGE = 0.6; // ≥60% 相关 → MERGE
|
|
20
|
+
/** 详细日志开关 (合并时记录每次 MERGE/UPDATE/REPLACE 的内容摘要) */
|
|
21
|
+
const VERBOSE_CONSOLIDATION = true;
|
|
20
22
|
// ─── 矛盾检测模式 (Mem0 风格冲突解决) ─────────────────
|
|
21
23
|
/** 中文否定/禁止模式 */
|
|
22
24
|
const NEGATION_PATTERNS_ZH = /不(再)?使用|不(再)?用|禁止|废弃|移除|取消|停止|不要|不采用|弃用|淘汰/;
|
|
@@ -68,6 +70,9 @@ export class MemoryConsolidator {
|
|
|
68
70
|
accessCount: topMatch.access_count + 1,
|
|
69
71
|
});
|
|
70
72
|
stats.updated++;
|
|
73
|
+
if (VERBOSE_CONSOLIDATION) {
|
|
74
|
+
this.#logDebug(`UPDATE sim=${(topMatch.similarity ?? 0).toFixed(2)}: "${content.substring(0, 40)}..." → existing "${topMatch.content.substring(0, 40)}..."`);
|
|
75
|
+
}
|
|
71
76
|
}
|
|
72
77
|
else if ((topMatch.similarity ?? 0) >= SIMILARITY_MERGE) {
|
|
73
78
|
// MERGE: 相关但不同 → 合并信息
|
|
@@ -79,6 +84,9 @@ export class MemoryConsolidator {
|
|
|
79
84
|
relatedMemories: [...existingRelated, `merged:${Date.now()}`],
|
|
80
85
|
});
|
|
81
86
|
stats.merged++;
|
|
87
|
+
if (VERBOSE_CONSOLIDATION) {
|
|
88
|
+
this.#logDebug(`MERGE sim=${(topMatch.similarity ?? 0).toFixed(2)}: "${content.substring(0, 40)}..." ⊕ "${topMatch.content.substring(0, 40)}..."`);
|
|
89
|
+
}
|
|
82
90
|
}
|
|
83
91
|
else {
|
|
84
92
|
this.#store.add({ ...candidate, bootstrapSession });
|
|
@@ -299,6 +307,15 @@ export class MemoryConsolidator {
|
|
|
299
307
|
return 'fact';
|
|
300
308
|
}
|
|
301
309
|
}
|
|
310
|
+
#logDebug(msg) {
|
|
311
|
+
const formatted = `[MemoryConsolidator] ${msg}`;
|
|
312
|
+
if (this.#logger?.debug) {
|
|
313
|
+
this.#logger.debug(formatted);
|
|
314
|
+
}
|
|
315
|
+
else if (this.#logger?.info) {
|
|
316
|
+
this.#logger.info(formatted);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
302
319
|
#log(msg) {
|
|
303
320
|
const formatted = `[MemoryConsolidator] ${msg}`;
|
|
304
321
|
if (this.#logger?.info) {
|
|
@@ -38,10 +38,12 @@ export declare function resolveActiveDimensions(primaryLang: string, detectedFra
|
|
|
38
38
|
/**
|
|
39
39
|
* 构建 Tier 分层调度计划
|
|
40
40
|
*
|
|
41
|
-
* 基于每个维度的 tierHint
|
|
42
|
-
* -
|
|
43
|
-
* -
|
|
44
|
-
* -
|
|
41
|
+
* 基于每个维度的 tierHint 字段动态分为 N 层 (不再硬编码 3 层):
|
|
42
|
+
* - tierHint=1: 基础数据层 — architecture + 语言/框架条件维度
|
|
43
|
+
* - tierHint=2: 规范+设计层 — coding-standards, design-patterns 等
|
|
44
|
+
* - tierHint=3+: 实践+质量层 — 按声明值自动分桶
|
|
45
|
+
*
|
|
46
|
+
* 未声明 tierHint 的维度默认归入最后一层 (tierHint=max 或 3)。
|
|
45
47
|
*/
|
|
46
48
|
export declare function buildTierPlan(activeDims?: readonly UnifiedDimension[]): string[][];
|
|
47
49
|
/**
|
|
@@ -145,7 +145,7 @@ const D7_NETWORKING_API = {
|
|
|
145
145
|
weight: 0.7,
|
|
146
146
|
suggestedTopics: ['api-contract', 'retry-strategy', 'request-pattern'],
|
|
147
147
|
relatedRoles: ['networking'],
|
|
148
|
-
tierHint:
|
|
148
|
+
tierHint: 2,
|
|
149
149
|
displayGroup: 'data-event-flow',
|
|
150
150
|
};
|
|
151
151
|
const D8_UI_INTERACTION = {
|
|
@@ -163,7 +163,7 @@ const D8_UI_INTERACTION = {
|
|
|
163
163
|
weight: 0.7,
|
|
164
164
|
suggestedTopics: ['component-pattern', 'lifecycle', 'navigation'],
|
|
165
165
|
relatedRoles: ['ui', 'feature'],
|
|
166
|
-
tierHint:
|
|
166
|
+
tierHint: 4,
|
|
167
167
|
displayGroup: 'architecture',
|
|
168
168
|
};
|
|
169
169
|
const D9_TESTING_QUALITY = {
|
|
@@ -181,7 +181,7 @@ const D9_TESTING_QUALITY = {
|
|
|
181
181
|
weight: 0.9,
|
|
182
182
|
suggestedTopics: ['unit-test', 'mock-strategy', 'ci-cd'],
|
|
183
183
|
relatedRoles: [],
|
|
184
|
-
tierHint:
|
|
184
|
+
tierHint: 4,
|
|
185
185
|
displayGroup: 'best-practice',
|
|
186
186
|
};
|
|
187
187
|
const D10_SECURITY_AUTH = {
|
|
@@ -199,7 +199,7 @@ const D10_SECURITY_AUTH = {
|
|
|
199
199
|
weight: 1.0,
|
|
200
200
|
suggestedTopics: ['authentication', 'authorization', 'encryption'],
|
|
201
201
|
relatedRoles: ['networking', 'service'],
|
|
202
|
-
tierHint:
|
|
202
|
+
tierHint: 4,
|
|
203
203
|
displayGroup: 'best-practice',
|
|
204
204
|
};
|
|
205
205
|
const D11_PERFORMANCE_OPTIMIZATION = {
|
|
@@ -217,7 +217,7 @@ const D11_PERFORMANCE_OPTIMIZATION = {
|
|
|
217
217
|
weight: 0.8,
|
|
218
218
|
suggestedTopics: ['memory-management', 'lazy-loading', 'rendering'],
|
|
219
219
|
relatedRoles: ['ui', 'storage'],
|
|
220
|
-
tierHint:
|
|
220
|
+
tierHint: 5,
|
|
221
221
|
displayGroup: 'data-event-flow',
|
|
222
222
|
};
|
|
223
223
|
const D12_OBSERVABILITY_LOGGING = {
|
|
@@ -235,7 +235,7 @@ const D12_OBSERVABILITY_LOGGING = {
|
|
|
235
235
|
weight: 0.7,
|
|
236
236
|
suggestedTopics: ['logging-standard', 'event-tracking', 'diagnostics'],
|
|
237
237
|
relatedRoles: ['service', 'core'],
|
|
238
|
-
tierHint:
|
|
238
|
+
tierHint: 5,
|
|
239
239
|
displayGroup: 'data-event-flow',
|
|
240
240
|
};
|
|
241
241
|
const D13_AGENT_GUIDELINES = {
|
|
@@ -253,7 +253,7 @@ const D13_AGENT_GUIDELINES = {
|
|
|
253
253
|
weight: 0.6,
|
|
254
254
|
suggestedTopics: ['constraints', 'deprecated-api', 'agent-rules'],
|
|
255
255
|
relatedRoles: [],
|
|
256
|
-
tierHint:
|
|
256
|
+
tierHint: 5,
|
|
257
257
|
displayGroup: 'best-practice',
|
|
258
258
|
};
|
|
259
259
|
// ═══════════════════════════════════════════════════════════
|
|
@@ -569,28 +569,24 @@ export function resolveActiveDimensions(primaryLang, detectedFrameworks = []) {
|
|
|
569
569
|
/**
|
|
570
570
|
* 构建 Tier 分层调度计划
|
|
571
571
|
*
|
|
572
|
-
* 基于每个维度的 tierHint
|
|
573
|
-
* -
|
|
574
|
-
* -
|
|
575
|
-
* -
|
|
572
|
+
* 基于每个维度的 tierHint 字段动态分为 N 层 (不再硬编码 3 层):
|
|
573
|
+
* - tierHint=1: 基础数据层 — architecture + 语言/框架条件维度
|
|
574
|
+
* - tierHint=2: 规范+设计层 — coding-standards, design-patterns 等
|
|
575
|
+
* - tierHint=3+: 实践+质量层 — 按声明值自动分桶
|
|
576
|
+
*
|
|
577
|
+
* 未声明 tierHint 的维度默认归入最后一层 (tierHint=max 或 3)。
|
|
576
578
|
*/
|
|
577
579
|
export function buildTierPlan(activeDims = DIMENSION_REGISTRY) {
|
|
578
|
-
const
|
|
579
|
-
const tier2 = [];
|
|
580
|
-
const tier3 = [];
|
|
580
|
+
const tierMap = new Map();
|
|
581
581
|
for (const dim of activeDims) {
|
|
582
582
|
const hint = dim.tierHint ?? 3;
|
|
583
|
-
if (hint
|
|
584
|
-
|
|
585
|
-
}
|
|
586
|
-
else if (hint === 2) {
|
|
587
|
-
tier2.push(dim.id);
|
|
588
|
-
}
|
|
589
|
-
else {
|
|
590
|
-
tier3.push(dim.id);
|
|
583
|
+
if (!tierMap.has(hint)) {
|
|
584
|
+
tierMap.set(hint, []);
|
|
591
585
|
}
|
|
586
|
+
tierMap.get(hint).push(dim.id);
|
|
592
587
|
}
|
|
593
|
-
|
|
588
|
+
// 按 tier 编号升序排列,过滤空层
|
|
589
|
+
return [...tierMap.entries()].sort(([a], [b]) => a - b).map(([, dims]) => dims);
|
|
594
590
|
}
|
|
595
591
|
/**
|
|
596
592
|
* 将 Recipe 分类到最匹配的维度
|
|
@@ -27,10 +27,23 @@ export declare function isGeoOrProviderError(err: unknown): boolean;
|
|
|
27
27
|
* 当主 provider 调用失败(地理限制等)时自动切换到备选 provider
|
|
28
28
|
*/
|
|
29
29
|
export declare function getProviderWithFallback(): Promise<ClaudeProvider | GoogleGeminiProvider | MockProvider | OpenAiProvider | null>;
|
|
30
|
+
/**
|
|
31
|
+
* 创建独立的 Embedding Provider
|
|
32
|
+
*
|
|
33
|
+
* 当 ASD_EMBED_PROVIDER 被设置时,创建一个专用于 embedding 的 provider 实例,
|
|
34
|
+
* 使 embedding 和 LLM 生成可以使用不同的提供商/模型。
|
|
35
|
+
*
|
|
36
|
+
* 典型场景:LLM 用 Google Gemini,Embedding 用本地 Ollama + qwen3-embedding
|
|
37
|
+
*
|
|
38
|
+
* @returns 独立的 embed provider,或 null(未配置时)
|
|
39
|
+
*/
|
|
40
|
+
export declare function createEmbedProvider(): ReturnType<typeof createProvider> | null;
|
|
30
41
|
/** 获取当前 AI 配置信息(同步,用于 UI 展示) */
|
|
31
42
|
export declare function getAiConfigInfo(): {
|
|
32
43
|
provider: string;
|
|
33
44
|
model: string;
|
|
45
|
+
embedProvider: string;
|
|
46
|
+
embedModel: string;
|
|
34
47
|
hasKey: boolean;
|
|
35
48
|
keys: {
|
|
36
49
|
google: boolean;
|
|
@@ -46,6 +59,7 @@ export { MockProvider } from './providers/MockProvider.js';
|
|
|
46
59
|
export { OpenAiProvider } from './providers/OpenAiProvider.js';
|
|
47
60
|
declare const _default: {
|
|
48
61
|
createProvider: typeof createProvider;
|
|
62
|
+
createEmbedProvider: typeof createEmbedProvider;
|
|
49
63
|
autoDetectProvider: typeof autoDetectProvider;
|
|
50
64
|
getAiConfigInfo: typeof getAiConfigInfo;
|
|
51
65
|
getProviderWithFallback: typeof getProviderWithFallback;
|