autosnippet 3.3.9 → 3.4.0
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 +1 -1
- package/config/default.json +1 -1
- package/dashboard/dist/assets/{index-DEU4tJtP.js → index-8b1Gf3Bb.js} +1 -1
- package/dashboard/dist/index.html +1 -1
- 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/domain/dimension/DimensionRegistry.d.ts +6 -4
- package/dist/lib/domain/dimension/DimensionRegistry.js +19 -23
- 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 +6 -2
- package/dist/lib/external/ai/providers/OpenAiProvider.d.ts +1 -1
- package/dist/lib/external/ai/providers/OpenAiProvider.js +7 -3
- package/dist/lib/external/mcp/handlers/bootstrap/MissionBriefingBuilder.js +10 -2
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +37 -4
- package/dist/lib/http/routes/ai.js +2 -2
- package/package.json +1 -1
|
@@ -32,6 +32,6 @@ export declare class ClaudeProvider extends AiProvider {
|
|
|
32
32
|
summarize(code: string): Promise<{}>;
|
|
33
33
|
embed(_text: string | string[]): Promise<never[]>;
|
|
34
34
|
supportsEmbedding(): boolean;
|
|
35
|
-
_post(url: string, body: Record<string, unknown
|
|
35
|
+
_post(url: string, body: Record<string, unknown>, externalSignal?: AbortSignal): Promise<ApiResponse>;
|
|
36
36
|
}
|
|
37
37
|
export default ClaudeProvider;
|
|
@@ -100,7 +100,7 @@ export class ClaudeProvider extends AiProvider {
|
|
|
100
100
|
body.tool_choice = { type: 'auto' };
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
|
-
const data = await this._post(`${CLAUDE_BASE}/messages`, body);
|
|
103
|
+
const data = await this._post(`${CLAUDE_BASE}/messages`, body, opts.abortSignal);
|
|
104
104
|
return this.#parseToolResponse(data);
|
|
105
105
|
}
|
|
106
106
|
// ─── 内部转换方法 ──────────────────────
|
|
@@ -241,7 +241,7 @@ export class ClaudeProvider extends AiProvider {
|
|
|
241
241
|
supportsEmbedding() {
|
|
242
242
|
return false;
|
|
243
243
|
}
|
|
244
|
-
async _post(url, body) {
|
|
244
|
+
async _post(url, body, externalSignal) {
|
|
245
245
|
if (!this.apiKey) {
|
|
246
246
|
const err = new Error('Claude API Key 未配置。请在 .env 中设置 ASD_CLAUDE_API_KEY,或运行 asd setup 完成配置。');
|
|
247
247
|
err.code = 'API_KEY_MISSING';
|
|
@@ -249,6 +249,9 @@ export class ClaudeProvider extends AiProvider {
|
|
|
249
249
|
}
|
|
250
250
|
const controller = new AbortController();
|
|
251
251
|
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
252
|
+
// 外部中止信号 → 联动本地 controller
|
|
253
|
+
const onExternalAbort = () => controller.abort();
|
|
254
|
+
externalSignal?.addEventListener('abort', onExternalAbort, { once: true });
|
|
252
255
|
try {
|
|
253
256
|
const res = await this._fetch(url, {
|
|
254
257
|
method: 'POST',
|
|
@@ -269,6 +272,7 @@ export class ClaudeProvider extends AiProvider {
|
|
|
269
272
|
}
|
|
270
273
|
finally {
|
|
271
274
|
clearTimeout(timer);
|
|
275
|
+
externalSignal?.removeEventListener('abort', onExternalAbort);
|
|
272
276
|
}
|
|
273
277
|
}
|
|
274
278
|
}
|
|
@@ -34,6 +34,6 @@ export declare class GoogleGeminiProvider extends AiProvider {
|
|
|
34
34
|
*/
|
|
35
35
|
chatWithStructuredOutput(prompt: string, opts?: StructuredOutputOptions): Promise<any>;
|
|
36
36
|
embed(text: string | string[]): Promise<number[] | number[][]>;
|
|
37
|
-
_post(url: string, body: Record<string, unknown
|
|
37
|
+
_post(url: string, body: Record<string, unknown>, externalSignal?: AbortSignal): Promise<ApiResponse>;
|
|
38
38
|
}
|
|
39
39
|
export default GoogleGeminiProvider;
|
|
@@ -108,7 +108,7 @@ export class GoogleGeminiProvider extends AiProvider {
|
|
|
108
108
|
body.systemInstruction = { parts: [{ text: systemPrompt }] };
|
|
109
109
|
}
|
|
110
110
|
const url = `${GEMINI_BASE}/models/${this.model}:generateContent?key=${this.apiKey}`;
|
|
111
|
-
const data = await this._post(url, body);
|
|
111
|
+
const data = await this._post(url, body, opts.abortSignal);
|
|
112
112
|
return this.#parseToolResponse(data);
|
|
113
113
|
});
|
|
114
114
|
}
|
|
@@ -356,7 +356,7 @@ export class GoogleGeminiProvider extends AiProvider {
|
|
|
356
356
|
}
|
|
357
357
|
return Array.isArray(text) ? results : results[0] || [];
|
|
358
358
|
}
|
|
359
|
-
async _post(url, body) {
|
|
359
|
+
async _post(url, body, externalSignal) {
|
|
360
360
|
if (!this.apiKey) {
|
|
361
361
|
const err = new Error('Google Gemini API Key 未配置。请在 .env 中设置 ASD_GOOGLE_API_KEY,或运行 asd setup 完成配置。');
|
|
362
362
|
err.code = 'API_KEY_MISSING';
|
|
@@ -364,6 +364,9 @@ export class GoogleGeminiProvider extends AiProvider {
|
|
|
364
364
|
}
|
|
365
365
|
const controller = new AbortController();
|
|
366
366
|
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
367
|
+
// 外部中止信号 → 联动本地 controller
|
|
368
|
+
const onExternalAbort = () => controller.abort();
|
|
369
|
+
externalSignal?.addEventListener('abort', onExternalAbort, { once: true });
|
|
367
370
|
try {
|
|
368
371
|
const res = await this._fetch(url, {
|
|
369
372
|
method: 'POST',
|
|
@@ -401,6 +404,7 @@ export class GoogleGeminiProvider extends AiProvider {
|
|
|
401
404
|
}
|
|
402
405
|
finally {
|
|
403
406
|
clearTimeout(timer);
|
|
407
|
+
externalSignal?.removeEventListener('abort', onExternalAbort);
|
|
404
408
|
}
|
|
405
409
|
}
|
|
406
410
|
}
|
|
@@ -37,6 +37,6 @@ export declare class OpenAiProvider extends AiProvider {
|
|
|
37
37
|
*/
|
|
38
38
|
chatWithStructuredOutput(prompt: string, opts?: StructuredOutputOptions): Promise<any>;
|
|
39
39
|
embed(text: string | string[]): Promise<any>;
|
|
40
|
-
_post(url: string, body: Record<string, unknown
|
|
40
|
+
_post(url: string, body: Record<string, unknown>, externalSignal?: AbortSignal): Promise<ApiResponse>;
|
|
41
41
|
}
|
|
42
42
|
export default OpenAiProvider;
|
|
@@ -14,7 +14,7 @@ export class OpenAiProvider extends AiProvider {
|
|
|
14
14
|
constructor(config = {}) {
|
|
15
15
|
super(config);
|
|
16
16
|
this.name = config.name || 'openai';
|
|
17
|
-
this.model = config.model || 'gpt-
|
|
17
|
+
this.model = config.model || 'gpt-5.4-mini';
|
|
18
18
|
this.apiKey = config.apiKey || process.env.ASD_OPENAI_API_KEY || '';
|
|
19
19
|
this.baseUrl = config.baseUrl || OPENAI_BASE;
|
|
20
20
|
this.embedModel = config.embedModel || 'text-embedding-3-small';
|
|
@@ -129,7 +129,7 @@ export class OpenAiProvider extends AiProvider {
|
|
|
129
129
|
else {
|
|
130
130
|
body.tool_choice = 'auto';
|
|
131
131
|
}
|
|
132
|
-
const data = await this._post(`${this.baseUrl}/chat/completions`, body);
|
|
132
|
+
const data = await this._post(`${this.baseUrl}/chat/completions`, body, opts.abortSignal);
|
|
133
133
|
return this.#parseToolResponse(data);
|
|
134
134
|
});
|
|
135
135
|
}
|
|
@@ -251,7 +251,7 @@ export class OpenAiProvider extends AiProvider {
|
|
|
251
251
|
return Array.isArray(text) ? texts.map(() => []) : [];
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
|
-
async _post(url, body) {
|
|
254
|
+
async _post(url, body, externalSignal) {
|
|
255
255
|
// Ollama 使用固定 dummy key,不需要校验
|
|
256
256
|
if (!this.apiKey && this.name !== 'ollama') {
|
|
257
257
|
const envKey = this.name === 'deepseek' ? 'ASD_DEEPSEEK_API_KEY' : 'ASD_OPENAI_API_KEY';
|
|
@@ -261,6 +261,9 @@ export class OpenAiProvider extends AiProvider {
|
|
|
261
261
|
}
|
|
262
262
|
const controller = new AbortController();
|
|
263
263
|
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
264
|
+
// 外部中止信号 → 联动本地 controller
|
|
265
|
+
const onExternalAbort = () => controller.abort();
|
|
266
|
+
externalSignal?.addEventListener('abort', onExternalAbort, { once: true });
|
|
264
267
|
try {
|
|
265
268
|
const res = await this._fetch(url, {
|
|
266
269
|
method: 'POST',
|
|
@@ -280,6 +283,7 @@ export class OpenAiProvider extends AiProvider {
|
|
|
280
283
|
}
|
|
281
284
|
finally {
|
|
282
285
|
clearTimeout(timer);
|
|
286
|
+
externalSignal?.removeEventListener('abort', onExternalAbort);
|
|
283
287
|
}
|
|
284
288
|
}
|
|
285
289
|
}
|
|
@@ -760,11 +760,19 @@ function buildExecutionPlan(activeDimensions) {
|
|
|
760
760
|
const scheduler = new TierScheduler();
|
|
761
761
|
const tiers = scheduler.getTiers();
|
|
762
762
|
const activeDimIds = new Set(activeDimensions.map((d) => d.id));
|
|
763
|
-
const tierLabels = [
|
|
763
|
+
const tierLabels = [
|
|
764
|
+
'基础数据层',
|
|
765
|
+
'规范 + 设计 + 网络',
|
|
766
|
+
'核心质量',
|
|
767
|
+
'领域专项',
|
|
768
|
+
'终端优化 + 总结',
|
|
769
|
+
];
|
|
764
770
|
const tierNotes = [
|
|
765
771
|
'这些维度相互独立,可以任意顺序分析。产出的上下文将帮助后续维度。',
|
|
766
772
|
'建议利用 Tier 1 中了解到的项目结构和代码特征。',
|
|
767
|
-
'
|
|
773
|
+
'利用前两层建立的架构和规范上下文深入分析。',
|
|
774
|
+
'各维度相对独立,可充分利用并行能力。',
|
|
775
|
+
'agent-guidelines 应综合前序所有维度的发现。',
|
|
768
776
|
];
|
|
769
777
|
const plan = tiers
|
|
770
778
|
.map((tierDimIds, index) => {
|
|
@@ -18,7 +18,7 @@ import path from 'node:path';
|
|
|
18
18
|
import { AgentMessage } from '#agent/AgentMessage.js';
|
|
19
19
|
import { ExplorationTracker } from '#agent/context/ExplorationTracker.js';
|
|
20
20
|
import { EpisodicConsolidator } from '#agent/domain/EpisodicConsolidator.js';
|
|
21
|
-
import {
|
|
21
|
+
import { computeAnalystBudget } from '#agent/domain/insight-analyst.js';
|
|
22
22
|
import { MemoryCoordinator } from '#agent/memory/MemoryCoordinator.js';
|
|
23
23
|
import { MemoryEmbeddingStore } from '#agent/memory/MemoryEmbeddingStore.js';
|
|
24
24
|
import { PersistentMemory } from '#agent/memory/PersistentMemory.js';
|
|
@@ -600,9 +600,9 @@ export async function fillDimensionsV3(view, dimensions) {
|
|
|
600
600
|
// ── 引擎增强参数 (PipelineStrategy → reactLoop 透传) ──
|
|
601
601
|
contextWindow: agentFactory?.createContextWindow({ isSystem: true }),
|
|
602
602
|
// B1 fix: 分析阶段使用 analyst 策略 (SCAN→EXPLORE→VERIFY→SUMMARIZE)
|
|
603
|
-
//
|
|
604
|
-
//
|
|
605
|
-
tracker: ExplorationTracker.resolve({ source: 'system', strategy: 'analyst' },
|
|
603
|
+
// B3 fix: 透传完整 ANALYST_BUDGET
|
|
604
|
+
// B4 fix: 自适应预算 — 根据项目文件数缩放 maxIterations (24~40)
|
|
605
|
+
tracker: ExplorationTracker.resolve({ source: 'system', strategy: 'analyst' }, computeAnalystBudget(projectInfo.fileCount || 0)),
|
|
606
606
|
trace: memoryCoordinator.getActiveContext(analystScopeId),
|
|
607
607
|
memoryCoordinator,
|
|
608
608
|
sharedState: {
|
|
@@ -826,6 +826,7 @@ export async function fillDimensionsV3(view, dimensions) {
|
|
|
826
826
|
source: 'enhanced-pipeline-strategy',
|
|
827
827
|
});
|
|
828
828
|
const dimTokenUsage = combinedTokenUsage;
|
|
829
|
+
const qualityScores = artifact.qualityReport;
|
|
829
830
|
const dimResult = {
|
|
830
831
|
candidateCount: producerResult.candidateCount,
|
|
831
832
|
rejectedCount: producerResult.rejectedCount || 0,
|
|
@@ -836,6 +837,13 @@ export async function fillDimensionsV3(view, dimensions) {
|
|
|
836
837
|
tokenUsage: dimTokenUsage,
|
|
837
838
|
analysisText: analysisReport.analysisText,
|
|
838
839
|
referencedFilesList: analysisReport.referencedFiles || [],
|
|
840
|
+
qualityGate: qualityScores
|
|
841
|
+
? {
|
|
842
|
+
totalScore: qualityScores.totalScore,
|
|
843
|
+
scores: qualityScores.scores,
|
|
844
|
+
action: gateResult?.action || (runResult?.degraded ? 'degrade' : 'pass'),
|
|
845
|
+
}
|
|
846
|
+
: null,
|
|
839
847
|
};
|
|
840
848
|
dimensionStats[dimId] = dimResult;
|
|
841
849
|
// P3: 保存 checkpoint — 仅当有实质分析内容时(避免 degraded/空结果污染后续 run)
|
|
@@ -1061,6 +1069,30 @@ export async function fillDimensionsV3(view, dimensions) {
|
|
|
1061
1069
|
`~${consolidationResult.total.updated} UPDATE, ` +
|
|
1062
1070
|
`⊕${consolidationResult.total.merged} MERGE | ` +
|
|
1063
1071
|
`Total: ${smStats.total} memories (avg importance: ${smStats.avgImportance})`);
|
|
1072
|
+
// 按类型和来源分布
|
|
1073
|
+
logger.info(`[Insight-v3] Memory by type: ${Object.entries(smStats.byType)
|
|
1074
|
+
.map(([t, n]) => `${t}=${n}`)
|
|
1075
|
+
.join(', ')} | ` +
|
|
1076
|
+
`by source: ${Object.entries(smStats.bySource)
|
|
1077
|
+
.map(([s, n]) => `${s}=${n}`)
|
|
1078
|
+
.join(', ')}`);
|
|
1079
|
+
// 蒸馏管线详情 (来自 EpisodicConsolidator 增强返回值)
|
|
1080
|
+
const cr = consolidationResult;
|
|
1081
|
+
if (cr.perDimension) {
|
|
1082
|
+
const perDim = cr.perDimension;
|
|
1083
|
+
const topDims = Object.entries(perDim)
|
|
1084
|
+
.sort(([, a], [, b]) => b - a)
|
|
1085
|
+
.slice(0, 6);
|
|
1086
|
+
logger.info(`[Insight-v3] Memory per-dimension (top ${topDims.length}): ${topDims.map(([d, n]) => `${d}=${n}`).join(', ')}`);
|
|
1087
|
+
}
|
|
1088
|
+
if (cr.importanceDistribution) {
|
|
1089
|
+
const hist = cr.importanceDistribution;
|
|
1090
|
+
const histStr = Object.entries(hist)
|
|
1091
|
+
.sort(([a], [b]) => Number(a) - Number(b))
|
|
1092
|
+
.map(([k, v]) => `imp${k}=${v}`)
|
|
1093
|
+
.join(' ');
|
|
1094
|
+
logger.info(`[Insight-v3] Importance histogram: ${histStr}`);
|
|
1095
|
+
}
|
|
1064
1096
|
}
|
|
1065
1097
|
else {
|
|
1066
1098
|
logger.warn('[Insight-v3] Database not available — skipping Semantic Memory consolidation');
|
|
@@ -1163,6 +1195,7 @@ export async function fillDimensionsV3(view, dimensions) {
|
|
|
1163
1195
|
durationMs: stat.durationMs || 0,
|
|
1164
1196
|
toolCallCount: stat.toolCallCount || 0,
|
|
1165
1197
|
tokenUsage: stat.tokenUsage || { input: 0, output: 0 },
|
|
1198
|
+
qualityGate: stat.qualityGate || null,
|
|
1166
1199
|
};
|
|
1167
1200
|
}
|
|
1168
1201
|
// Phase E: 附加 Code Entity Graph 拓扑到报告
|
|
@@ -70,9 +70,9 @@ router.get('/providers', async (req, res) => {
|
|
|
70
70
|
};
|
|
71
71
|
const providers = [
|
|
72
72
|
{ id: 'google', label: 'Google Gemini', defaultModel: 'gemini-3-flash-preview' },
|
|
73
|
-
{ id: 'openai', label: 'OpenAI', defaultModel: 'gpt-
|
|
73
|
+
{ id: 'openai', label: 'OpenAI', defaultModel: 'gpt-5.4' },
|
|
74
74
|
{ id: 'deepseek', label: 'DeepSeek', defaultModel: 'deepseek-chat' },
|
|
75
|
-
{ id: 'claude', label: 'Claude', defaultModel: 'claude-
|
|
75
|
+
{ id: 'claude', label: 'Claude', defaultModel: 'claude-sonnet-4-20250514' },
|
|
76
76
|
{ id: 'ollama', label: 'Ollama', defaultModel: 'llama3' },
|
|
77
77
|
{ id: 'mock', label: 'Mock (测试)', defaultModel: 'mock-l3' },
|
|
78
78
|
].map((p) => ({
|