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
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* forced-summary.js — 强制退出后的摘要生成
|
|
3
|
+
*
|
|
4
|
+
* 强制退出后的摘要生成独立模块,
|
|
5
|
+
* 供 AgentRuntime.reactLoop() 在循环退出后调用。
|
|
6
|
+
*
|
|
7
|
+
* 支持两种模式:
|
|
8
|
+
* - system: 输出 dimensionDigest JSON (供 Bootstrap 管线消费)
|
|
9
|
+
* - user: 输出人类可读的 Markdown 结构化总结 (前端 AI Chat 展示)
|
|
10
|
+
*
|
|
11
|
+
* @module forced-summary
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import Logger from '../../infrastructure/logging/Logger.js';
|
|
15
|
+
import { cleanFinalAnswer } from './core/ChatAgentPrompts.js';
|
|
16
|
+
|
|
17
|
+
const logger = Logger.getInstance();
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 生成强制摘要
|
|
21
|
+
*
|
|
22
|
+
* @param {Object} opts
|
|
23
|
+
* @param {import('../../external/ai/AiProvider.js').AiProvider} opts.aiProvider — LLM 提供商
|
|
24
|
+
* @param {string} [opts.source] — 'user' | 'system'
|
|
25
|
+
* @param {Array} opts.toolCalls — 工具调用记录
|
|
26
|
+
* @param {Object} [opts.tracker] — ExplorationTracker 实例
|
|
27
|
+
* @param {Object} [opts.contextWindow] — ContextWindow 实例 (用于避免超出 token)
|
|
28
|
+
* @param {string} opts.prompt — 原始用户 prompt
|
|
29
|
+
* @param {Object} [opts.tokenUsage] — token 用量 (会被修改)
|
|
30
|
+
* @returns {Promise<{ reply: string, tokenUsage: { input: number, output: number } }>}
|
|
31
|
+
*/
|
|
32
|
+
export async function produceForcedSummary({
|
|
33
|
+
aiProvider,
|
|
34
|
+
source,
|
|
35
|
+
toolCalls = [],
|
|
36
|
+
tracker,
|
|
37
|
+
contextWindow,
|
|
38
|
+
prompt,
|
|
39
|
+
tokenUsage,
|
|
40
|
+
}) {
|
|
41
|
+
const isSystem = source === 'system';
|
|
42
|
+
const iterations = tracker?.iteration || 0;
|
|
43
|
+
const resultTokenUsage = { input: 0, output: 0 };
|
|
44
|
+
|
|
45
|
+
logger.info(
|
|
46
|
+
`[ForcedSummary] ⚠ producing forced summary (${iterations} iters, ${toolCalls.length} calls, source=${source})`
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const candidateCount = toolCalls.filter(
|
|
50
|
+
tc => tc.tool === 'submit_knowledge' || tc.tool === 'submit_with_check'
|
|
51
|
+
).length;
|
|
52
|
+
|
|
53
|
+
let finalReply;
|
|
54
|
+
|
|
55
|
+
// 如果熔断器已打开,跳过 AI 调用直接合成摘要
|
|
56
|
+
const isCircuitOpen = aiProvider._circuitState === 'OPEN';
|
|
57
|
+
if (isCircuitOpen) {
|
|
58
|
+
logger.warn(
|
|
59
|
+
`[ForcedSummary] circuit breaker is OPEN — skipping AI summary, using synthetic ${isSystem ? 'digest' : 'summary'}`
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 收集工具调用摘要
|
|
64
|
+
const submitSummary = toolCalls
|
|
65
|
+
.filter(tc => tc.tool === 'submit_knowledge' || tc.tool === 'submit_with_check')
|
|
66
|
+
.map((tc, i) => `${i + 1}. ${tc.args?.title || tc.args?.category || tc.params?.title || tc.params?.category || 'untitled'}`)
|
|
67
|
+
.join('\n');
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
if (isCircuitOpen) {
|
|
71
|
+
throw new Error('circuit open — skip to synthetic summary');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let summaryPrompt;
|
|
75
|
+
let systemPrompt;
|
|
76
|
+
|
|
77
|
+
if (isSystem) {
|
|
78
|
+
// system 源: dimensionDigest JSON
|
|
79
|
+
summaryPrompt = `你已完成 ${iterations} 轮工具调用(共 ${toolCalls.length} 次),提交了 ${candidateCount} 个候选。
|
|
80
|
+
${submitSummary ? `已提交候选:\n${submitSummary}\n` : ''}
|
|
81
|
+
**必须**输出 dimensionDigest JSON(用 \`\`\`json 包裹):
|
|
82
|
+
\`\`\`json
|
|
83
|
+
{
|
|
84
|
+
"dimensionDigest": {
|
|
85
|
+
"summary": "本维度分析总结",
|
|
86
|
+
"candidateCount": ${candidateCount},
|
|
87
|
+
"keyFindings": ["发现1", "发现2"],
|
|
88
|
+
"crossRefs": {},
|
|
89
|
+
"gaps": ["未覆盖方面"],
|
|
90
|
+
"remainingTasks": [
|
|
91
|
+
{ "signal": "未处理信号名", "reason": "达到提交上限/时间限制", "priority": "high", "searchHints": ["搜索词"] }
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
\`\`\`
|
|
96
|
+
> remainingTasks: 列出本次未来得及处理的信号/主题。已全部覆盖则留空 \`[]\`。`;
|
|
97
|
+
systemPrompt = '直接输出 dimensionDigest JSON 总结,不要调用工具。';
|
|
98
|
+
} else {
|
|
99
|
+
// user 源: Markdown 结构化总结
|
|
100
|
+
const userQuestion = prompt ? `用户的原始问题:「${prompt.slice(0, 500)}」\n\n` : '';
|
|
101
|
+
const toolContextSummary = buildToolContextForUserSummary(toolCalls);
|
|
102
|
+
summaryPrompt = `${userQuestion}你刚才通过 ${toolCalls.length} 次工具调用分析了项目代码。以下是你调用过的工具和获取到的关键信息:
|
|
103
|
+
|
|
104
|
+
${toolContextSummary}
|
|
105
|
+
|
|
106
|
+
请基于以上收集到的信息,用**清晰易读的 Markdown** 格式撰写分析总结,直接回答用户的问题。
|
|
107
|
+
|
|
108
|
+
要求:
|
|
109
|
+
- 使用二级/三级标题组织内容
|
|
110
|
+
- 要有具体的代码文件路径、类名、模式名称等细节
|
|
111
|
+
- 关键发现用列表项罗列
|
|
112
|
+
- 如果发现了架构模式或最佳实践,用简短代码块举例
|
|
113
|
+
- 语言自然流畅,像一份技术分析报告`;
|
|
114
|
+
systemPrompt = '你是项目分析助手。请用纯 Markdown 格式输出结构清晰的分析总结,只输出人类可读的自然语言文档,不要输出 JSON 格式的数据。';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// 用空 messages 避免累积上下文导致 400
|
|
118
|
+
const summaryResult = await aiProvider.chatWithTools(summaryPrompt, {
|
|
119
|
+
messages: [],
|
|
120
|
+
toolChoice: 'none',
|
|
121
|
+
systemPrompt,
|
|
122
|
+
temperature: isSystem ? 0.3 : 0.5,
|
|
123
|
+
maxTokens: 8192,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
if (summaryResult.usage) {
|
|
127
|
+
resultTokenUsage.input += summaryResult.usage.inputTokens || 0;
|
|
128
|
+
resultTokenUsage.output += summaryResult.usage.outputTokens || 0;
|
|
129
|
+
}
|
|
130
|
+
// system 源: dimensionDigest JSON 是预期输出,不能被 cleanFinalAnswer 剥掉
|
|
131
|
+
finalReply = isSystem
|
|
132
|
+
? (summaryResult.text || '').trim()
|
|
133
|
+
: cleanFinalAnswer(summaryResult.text || '');
|
|
134
|
+
} catch (err) {
|
|
135
|
+
logger.warn(`[ForcedSummary] AI call failed: ${err.message}`);
|
|
136
|
+
|
|
137
|
+
if (isSystem) {
|
|
138
|
+
// system 源兜底: 合成 dimensionDigest JSON
|
|
139
|
+
const titles = toolCalls
|
|
140
|
+
.filter(tc => tc.tool === 'submit_knowledge' || tc.tool === 'submit_with_check')
|
|
141
|
+
.map(tc => tc.args?.title || tc.params?.title || 'untitled');
|
|
142
|
+
finalReply = `\`\`\`json
|
|
143
|
+
{
|
|
144
|
+
"dimensionDigest": {
|
|
145
|
+
"summary": "通过 ${toolCalls.length} 次工具调用分析了项目代码,提交了 ${candidateCount} 个候选。",
|
|
146
|
+
"candidateCount": ${candidateCount},
|
|
147
|
+
"keyFindings": ${JSON.stringify(titles.slice(0, 5))},
|
|
148
|
+
"crossRefs": {},
|
|
149
|
+
"gaps": ["AI 服务异常,部分分析未完成"]
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
\`\`\``;
|
|
153
|
+
} else {
|
|
154
|
+
// user 源兜底: 合成 Markdown 摘要
|
|
155
|
+
const toolNames = [...new Set(toolCalls.map(tc => tc.tool))];
|
|
156
|
+
const filesRead = toolCalls
|
|
157
|
+
.filter(tc => tc.tool === 'read_project_file')
|
|
158
|
+
.flatMap(tc => {
|
|
159
|
+
const p = tc.args || tc.params || {};
|
|
160
|
+
if (p.filePaths) return p.filePaths;
|
|
161
|
+
if (p.filePath) return [p.filePath];
|
|
162
|
+
return [];
|
|
163
|
+
})
|
|
164
|
+
.slice(0, 10);
|
|
165
|
+
const searches = toolCalls
|
|
166
|
+
.filter(tc => tc.tool === 'search_project_code' || tc.tool === 'semantic_search_code')
|
|
167
|
+
.map(tc => {
|
|
168
|
+
const p = tc.args || tc.params || {};
|
|
169
|
+
return p.patterns?.[0] || p.query || p.pattern;
|
|
170
|
+
})
|
|
171
|
+
.filter(Boolean)
|
|
172
|
+
.slice(0, 5);
|
|
173
|
+
|
|
174
|
+
finalReply = `## 分析总结\n\n通过 **${toolCalls.length} 次工具调用**探索了项目代码。\n\n`;
|
|
175
|
+
if (searches.length > 0) {
|
|
176
|
+
finalReply += `### 搜索的关键词\n${searches.map(s => `- \`${s}\``).join('\n')}\n\n`;
|
|
177
|
+
}
|
|
178
|
+
if (filesRead.length > 0) {
|
|
179
|
+
finalReply += `### 读取的文件\n${filesRead.map(f => `- \`${f}\``).join('\n')}\n\n`;
|
|
180
|
+
}
|
|
181
|
+
finalReply += `### 使用的工具\n${toolNames.map(t => `- ${t}`).join('\n')}\n\n`;
|
|
182
|
+
finalReply += '> ⚠️ AI 服务异常,未能生成完整分析。请稍后重试或缩小分析范围。';
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
logger.info(`[ForcedSummary] ✅ forced summary — ${finalReply.length} chars`);
|
|
187
|
+
return { reply: finalReply, tokenUsage: resultTokenUsage };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* 从工具调用记录中提取上下文摘要 (供 user 源强制总结使用)
|
|
192
|
+
* @param {Array} toolCalls
|
|
193
|
+
* @returns {string}
|
|
194
|
+
*/
|
|
195
|
+
function buildToolContextForUserSummary(toolCalls) {
|
|
196
|
+
const sections = [];
|
|
197
|
+
|
|
198
|
+
// 目录结构探索
|
|
199
|
+
const structureCalls = toolCalls.filter(tc => tc.tool === 'list_project_structure');
|
|
200
|
+
if (structureCalls.length > 0) {
|
|
201
|
+
const dirs = structureCalls.map(tc => (tc.args || tc.params)?.directory || '/').slice(0, 5);
|
|
202
|
+
sections.push(`**目录探索**: ${dirs.map(d => `\`${d}\``).join(', ')}`);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// 项目概况
|
|
206
|
+
const overviewCalls = toolCalls.filter(tc => tc.tool === 'get_project_overview');
|
|
207
|
+
if (overviewCalls.length > 0) {
|
|
208
|
+
sections.push('**项目概况**: 已获取');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// 代码搜索
|
|
212
|
+
const searchCalls = toolCalls.filter(
|
|
213
|
+
tc => tc.tool === 'search_project_code' || tc.tool === 'semantic_search_code'
|
|
214
|
+
);
|
|
215
|
+
if (searchCalls.length > 0) {
|
|
216
|
+
const queries = searchCalls
|
|
217
|
+
.map(tc => {
|
|
218
|
+
const p = tc.args || tc.params || {};
|
|
219
|
+
return p.patterns?.[0] || p.query || p.pattern;
|
|
220
|
+
})
|
|
221
|
+
.filter(Boolean)
|
|
222
|
+
.slice(0, 8);
|
|
223
|
+
sections.push(`**代码搜索** (${searchCalls.length} 次): ${queries.map(q => `\`${q}\``).join(', ')}`);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// 文件读取
|
|
227
|
+
const readCalls = toolCalls.filter(tc => tc.tool === 'read_project_file');
|
|
228
|
+
if (readCalls.length > 0) {
|
|
229
|
+
const files = readCalls
|
|
230
|
+
.flatMap(tc => {
|
|
231
|
+
const p = tc.args || tc.params || {};
|
|
232
|
+
if (p.filePaths) return p.filePaths;
|
|
233
|
+
if (p.filePath) return [p.filePath];
|
|
234
|
+
return [];
|
|
235
|
+
})
|
|
236
|
+
.slice(0, 10);
|
|
237
|
+
sections.push(`**文件读取** (${readCalls.length} 次): ${files.map(f => `\`${f}\``).join(', ')}`);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// AST 分析
|
|
241
|
+
const astCalls = toolCalls.filter(tc =>
|
|
242
|
+
['get_class_hierarchy', 'get_class_info', 'get_protocol_info', 'get_method_overrides', 'get_category_map'].includes(tc.tool)
|
|
243
|
+
);
|
|
244
|
+
if (astCalls.length > 0) {
|
|
245
|
+
const entities = astCalls
|
|
246
|
+
.map(tc => {
|
|
247
|
+
const p = tc.args || tc.params || {};
|
|
248
|
+
return p.className || p.name || p.protocolName || p.rootClass;
|
|
249
|
+
})
|
|
250
|
+
.filter(Boolean)
|
|
251
|
+
.slice(0, 5);
|
|
252
|
+
sections.push(`**AST 结构分析** (${astCalls.length} 次): ${entities.map(e => `\`${e}\``).join(', ')}`);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// 知识库搜索
|
|
256
|
+
const kbCalls = toolCalls.filter(tc =>
|
|
257
|
+
['search_knowledge', 'search_recipes', 'knowledge_overview'].includes(tc.tool)
|
|
258
|
+
);
|
|
259
|
+
if (kbCalls.length > 0) {
|
|
260
|
+
sections.push(`**知识库查询**: ${kbCalls.length} 次`);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return sections.length > 0 ? sections.join('\n') : '(工具调用记录为空)';
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export default produceForcedSummary;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AutoSnippet Agent 模块 — 统一出口
|
|
3
|
+
*
|
|
4
|
+
* @module service/agent
|
|
5
|
+
*
|
|
6
|
+
* 统一架构: ONE Runtime, 多种配置
|
|
7
|
+
*
|
|
8
|
+
* ┌──────── Transport ────────┐
|
|
9
|
+
* │ HTTP│Lark│CLI│MCP│... │ ← 渠道适配 (AgentMessage)
|
|
10
|
+
* └──────────┬────────────────┘
|
|
11
|
+
* │
|
|
12
|
+
* ┌──────────▼────────────────┐
|
|
13
|
+
* │ AgentRouter │ ← 意图 → Preset
|
|
14
|
+
* └──────────┬────────────────┘
|
|
15
|
+
* │
|
|
16
|
+
* ┌──────────▼────────────────┐
|
|
17
|
+
* │ AgentFactory │ ← Preset + DI → Runtime
|
|
18
|
+
* └──────────┬────────────────┘
|
|
19
|
+
* │
|
|
20
|
+
* ┌──────────▼────────────────────────────────────────┐
|
|
21
|
+
* │ AgentRuntime │
|
|
22
|
+
* │ │
|
|
23
|
+
* │ ┌──────────┐ ┌───────────┐ ┌────────────────┐ │
|
|
24
|
+
* │ │Capability│ │ Strategy │ │ Policy │ │
|
|
25
|
+
* │ │ 技能模块 │ │ 执行策略 │ │ 约束引擎 │ │
|
|
26
|
+
* │ ├──────────┤ ├───────────┤ ├────────────────┤ │
|
|
27
|
+
* │ │• 对话 │ │• Single │ │• Budget 预算 │ │
|
|
28
|
+
* │ │• 代码分析│ │• Pipeline │ │• Safety 安全 │ │
|
|
29
|
+
* │ │• 知识生产│ │• FanOut │ │• Quality 质量 │ │
|
|
30
|
+
* │ │• 系统交互│ │• Adaptive │ │ │ │
|
|
31
|
+
* │ └──────────┘ └───────────┘ └────────────────┘ │
|
|
32
|
+
* │ │
|
|
33
|
+
* │ ┌─────────────────────────────────────────┐ │
|
|
34
|
+
* │ │ ReAct Loop (Thought→Action→Observe) │ │
|
|
35
|
+
* │ └─────────────────────────────────────────┘ │
|
|
36
|
+
* └───────────────────────────────────────────────────┘
|
|
37
|
+
* │
|
|
38
|
+
* ┌──────────▼────────────────┐
|
|
39
|
+
* │ AgentState + EventBus │ ← 状态机 + 事件通信
|
|
40
|
+
* └──────────────────────────-┘
|
|
41
|
+
*
|
|
42
|
+
* Preset 配置表:
|
|
43
|
+
* | Preset | Capabilities | Strategy | Policies |
|
|
44
|
+
* |--------------|----------------------|-------------|------------------|
|
|
45
|
+
* | chat | Conv + Analysis | Single | Budget(8轮) |
|
|
46
|
+
* | bootstrap | Analysis + Knowledge | FanOut+Pipe | Budget+Quality |
|
|
47
|
+
* | scan | Analysis + Knowledge | Pipeline | Budget+Quality |
|
|
48
|
+
* | remote-exec | Conv+Analysis+System | Single | Budget+Safety |
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
// ── Infrastructure ──
|
|
52
|
+
export { AgentState, AgentPhase } from './AgentState.js';
|
|
53
|
+
export { AgentEventBus, AgentEvents } from './AgentEventBus.js';
|
|
54
|
+
export { AgentMessage, Channel } from './AgentMessage.js';
|
|
55
|
+
|
|
56
|
+
// ── Core ──
|
|
57
|
+
export { AgentRuntime } from './AgentRuntime.js';
|
|
58
|
+
export { AgentRouter, PresetName } from './AgentRouter.js';
|
|
59
|
+
export { AgentFactory } from './AgentFactory.js';
|
|
60
|
+
|
|
61
|
+
// ── Capabilities ──
|
|
62
|
+
export {
|
|
63
|
+
Capability,
|
|
64
|
+
Conversation,
|
|
65
|
+
CodeAnalysis,
|
|
66
|
+
KnowledgeProduction,
|
|
67
|
+
SystemInteraction,
|
|
68
|
+
CapabilityRegistry,
|
|
69
|
+
} from './capabilities.js';
|
|
70
|
+
|
|
71
|
+
// ── Strategies ──
|
|
72
|
+
export {
|
|
73
|
+
Strategy,
|
|
74
|
+
SingleStrategy,
|
|
75
|
+
PipelineStrategy,
|
|
76
|
+
FanOutStrategy,
|
|
77
|
+
AdaptiveStrategy,
|
|
78
|
+
StrategyRegistry,
|
|
79
|
+
} from './strategies.js';
|
|
80
|
+
|
|
81
|
+
// ── Policies ──
|
|
82
|
+
export {
|
|
83
|
+
Policy,
|
|
84
|
+
BudgetPolicy,
|
|
85
|
+
SafetyPolicy,
|
|
86
|
+
QualityGatePolicy,
|
|
87
|
+
PolicyEngine,
|
|
88
|
+
} from './policies.js';
|
|
89
|
+
|
|
90
|
+
// ── Presets ──
|
|
91
|
+
export { PRESETS, getPreset, resolveStrategy } from './presets.js';
|
|
@@ -148,6 +148,8 @@ export class ActiveContext {
|
|
|
148
148
|
#plan = null;
|
|
149
149
|
/** @type {Array<Plan>} */
|
|
150
150
|
#planHistory = [];
|
|
151
|
+
/** @type {boolean} 是否期待下一次响应包含计划 (由 ExplorationTracker 设置) */
|
|
152
|
+
#expectingPlan = false;
|
|
151
153
|
|
|
152
154
|
// ── 配置 ──
|
|
153
155
|
/** @type {number} 保留最近 N 轮原始观察 */
|
|
@@ -342,6 +344,11 @@ export class ActiveContext {
|
|
|
342
344
|
|
|
343
345
|
/**
|
|
344
346
|
* 从 AI 响应文本中提取计划,自动调用 setPlan/updatePlan
|
|
347
|
+
*
|
|
348
|
+
* 防御措施: 已存在计划时,仅在 #expectingPlan 为 true 时才覆盖。
|
|
349
|
+
* 这防止 reflection 回复中的编号列表(非计划的回应文本)污染已有计划。
|
|
350
|
+
* ExplorationTracker 在发送 plan elicitation / replan 时调用 expectPlan() 授权更新。
|
|
351
|
+
*
|
|
345
352
|
* @param {string} text — AI 完整响应文本
|
|
346
353
|
* @param {number} iteration — 当前轮次
|
|
347
354
|
* @returns {boolean} — 是否成功提取到计划
|
|
@@ -350,6 +357,11 @@ export class ActiveContext {
|
|
|
350
357
|
const planText = this.#extractPlanFromText(text);
|
|
351
358
|
if (!planText) return false;
|
|
352
359
|
|
|
360
|
+
// Guard: 已有计划时,仅在 expectPlan 授权下才覆盖
|
|
361
|
+
// 防止 reflection/convergence 回复中的编号列表被误捕获为 plan
|
|
362
|
+
if (this.#plan && !this.#expectingPlan) return false;
|
|
363
|
+
|
|
364
|
+
this.#expectingPlan = false;
|
|
353
365
|
if (this.#plan) {
|
|
354
366
|
this.#updatePlan(planText, iteration);
|
|
355
367
|
} else {
|
|
@@ -358,6 +370,14 @@ export class ActiveContext {
|
|
|
358
370
|
return true;
|
|
359
371
|
}
|
|
360
372
|
|
|
373
|
+
/**
|
|
374
|
+
* 标记「下一次响应可能包含计划」— 授权 extractAndSetPlan 覆盖已有计划
|
|
375
|
+
* 由 ExplorationTracker 在发送 plan elicitation / replan nudge 时调用。
|
|
376
|
+
*/
|
|
377
|
+
expectPlan() {
|
|
378
|
+
this.#expectingPlan = true;
|
|
379
|
+
}
|
|
380
|
+
|
|
361
381
|
/**
|
|
362
382
|
* 直接设置计划 (公开接口,供 ExplorationTracker 和测试使用)
|
|
363
383
|
* @param {string} planText
|
|
@@ -905,7 +925,15 @@ export class ActiveContext {
|
|
|
905
925
|
}
|
|
906
926
|
}
|
|
907
927
|
|
|
908
|
-
|
|
928
|
+
if (planLines.length < 2) return null;
|
|
929
|
+
|
|
930
|
+
// 防御: 拒绝 "大部分是疑问句" 的编号列表
|
|
931
|
+
// reflection nudge 的 "请评估: 1. ...是什么? 2. ...?" 会被 LLM 回显,
|
|
932
|
+
// 不是真正的探索计划,不能捕获为 plan steps
|
|
933
|
+
const questionCount = planLines.filter(l => /[??]\s*$/.test(l.trim())).length;
|
|
934
|
+
if (questionCount > planLines.length * 0.5) return null;
|
|
935
|
+
|
|
936
|
+
return planLines.join('\n').trim();
|
|
909
937
|
}
|
|
910
938
|
}
|
|
911
939
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* 生命周期:
|
|
11
11
|
* - Bootstrap 模式: 会话级 (orchestrator 创建, 贯穿所有维度)
|
|
12
|
-
* - User Chat 模式: 实例级 (
|
|
12
|
+
* - User Chat 模式: 实例级 (AgentRuntime 创建)
|
|
13
13
|
*
|
|
14
14
|
* @module MemoryCoordinator
|
|
15
15
|
*/
|
|
@@ -53,7 +53,7 @@ const NON_CACHEABLE_TOOLS = new Set([
|
|
|
53
53
|
'get_previous_evidence',
|
|
54
54
|
]);
|
|
55
55
|
|
|
56
|
-
// ── 写入路由: 规则匹配模式
|
|
56
|
+
// ── 写入路由: 规则匹配模式 ──
|
|
57
57
|
|
|
58
58
|
const PREFERENCE_PATTERNS = [
|
|
59
59
|
/我们(项目|团队)?(不用|不使用|禁止|避免|偏好|习惯|规范是)/,
|
|
@@ -81,7 +81,7 @@ export class MemoryCoordinator {
|
|
|
81
81
|
#budgetAllocation;
|
|
82
82
|
|
|
83
83
|
// ── Tier 3: Persistent (跨会话) ──
|
|
84
|
-
#persistentMemory; // PersistentMemory
|
|
84
|
+
#persistentMemory; // PersistentMemory
|
|
85
85
|
#conversationLog; // ConversationStore
|
|
86
86
|
|
|
87
87
|
// ── Tier 2: Session (会话级) ──
|
|
@@ -96,7 +96,7 @@ export class MemoryCoordinator {
|
|
|
96
96
|
|
|
97
97
|
/**
|
|
98
98
|
* @param {object} config
|
|
99
|
-
* @param {object} [config.persistentMemory] — PersistentMemory
|
|
99
|
+
* @param {object} [config.persistentMemory] — PersistentMemory 实例
|
|
100
100
|
* @param {object} [config.sessionStore] — SessionStore 实例 (bootstrap 模式)
|
|
101
101
|
* @param {object} [config.conversationLog] — ConversationStore 实例
|
|
102
102
|
* @param {'user'|'bootstrap'} [config.mode='bootstrap']
|
|
@@ -125,7 +125,7 @@ export class MemoryCoordinator {
|
|
|
125
125
|
// ═══════════════════════════════════════════════════════════
|
|
126
126
|
|
|
127
127
|
/**
|
|
128
|
-
* 配置总预算 (由
|
|
128
|
+
* 配置总预算 (由 AgentRuntime.execute 入口调用)
|
|
129
129
|
* @param {object} options
|
|
130
130
|
* @param {number} options.totalContextBudget — 模型总上下文 token 数
|
|
131
131
|
* @param {string} [options.model]
|
|
@@ -327,7 +327,7 @@ export class MemoryCoordinator {
|
|
|
327
327
|
}
|
|
328
328
|
|
|
329
329
|
/**
|
|
330
|
-
* 从对话中提取记忆
|
|
330
|
+
* 从对话中提取记忆
|
|
331
331
|
*
|
|
332
332
|
* 写入路由 (WriteRouter):
|
|
333
333
|
* - 规则 1: 只在 user 源触发规则匹配 (B4 fix)
|
|
@@ -520,7 +520,7 @@ export class MemoryCoordinator {
|
|
|
520
520
|
}
|
|
521
521
|
|
|
522
522
|
/**
|
|
523
|
-
* 获取 PersistentMemory
|
|
523
|
+
* 获取 PersistentMemory
|
|
524
524
|
* @returns {object|null}
|
|
525
525
|
*/
|
|
526
526
|
getPersistentMemory() {
|