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,305 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Presets — 命名的 Agent 配置组合
|
|
3
|
+
*
|
|
4
|
+
* 核心思想: Agent 不分"类型",只有"配置"。
|
|
5
|
+
* Preset 是 Capability + Strategy + Policy 的命名组合。
|
|
6
|
+
*
|
|
7
|
+
* 这是统一架构的最终体现:
|
|
8
|
+
*
|
|
9
|
+
* | 使用场景 | Capabilities | Strategy | Policies |
|
|
10
|
+
* |------------------|--------------------------|--------------|---------------------|
|
|
11
|
+
* | chat | Conv + Analysis | Single | StandardBudget |
|
|
12
|
+
* | insight | Analysis + Production | FanOut+Pipe | DeepBudget+Quality |
|
|
13
|
+
* | remote-exec | Conv + Analysis + System | Single | ShortBudget+Safety |
|
|
14
|
+
*
|
|
15
|
+
* 注意:
|
|
16
|
+
* - "飞书聊天" 用 chat preset,不需要单独的 Agent
|
|
17
|
+
* - "飞书远程执行" 用 remote-exec preset,Safety 由 Policy 提供
|
|
18
|
+
* - "冷启动" 和 "扫描" 统一使用 insight preset,仅编排层不同
|
|
19
|
+
*
|
|
20
|
+
* @module presets
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { BudgetPolicy, SafetyPolicy, QualityGatePolicy } from './policies.js';
|
|
24
|
+
import { SingleStrategy, PipelineStrategy, FanOutStrategy, AdaptiveStrategy } from './strategies.js';
|
|
25
|
+
|
|
26
|
+
// v3.0: 导入 Insight 领域函数 (domain/ 模块)
|
|
27
|
+
import {
|
|
28
|
+
buildAnalystPrompt, ANALYST_SYSTEM_PROMPT, ANALYST_BUDGET,
|
|
29
|
+
} from './domain/insight-analyst.js';
|
|
30
|
+
import {
|
|
31
|
+
insightGateEvaluator, buildRetryPrompt,
|
|
32
|
+
} from './domain/insight-gate.js';
|
|
33
|
+
import {
|
|
34
|
+
buildProducerPromptV2, PRODUCER_SYSTEM_PROMPT, PRODUCER_BUDGET,
|
|
35
|
+
producerRejectionGateEvaluator,
|
|
36
|
+
} from './domain/insight-producer.js';
|
|
37
|
+
|
|
38
|
+
// ─── Preset 定义 ──────────────────────────────
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @typedef {Object} PresetConfig
|
|
42
|
+
* @property {string} name — 人类可读名称
|
|
43
|
+
* @property {string} description — 描述
|
|
44
|
+
* @property {string[]} capabilities — Capability 名称列表
|
|
45
|
+
* @property {Object} strategy — Strategy 配置 { type, ...opts }
|
|
46
|
+
* @property {Array<Object>} policies — Policy 实例或配置
|
|
47
|
+
* @property {Object} [persona] — 人格/角色配置
|
|
48
|
+
* @property {Object} [memory] — 记忆配置
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 所有内置 Preset
|
|
53
|
+
*/
|
|
54
|
+
export const PRESETS = Object.freeze({
|
|
55
|
+
|
|
56
|
+
// ─── chat: 通用对话 ──────────────────────
|
|
57
|
+
|
|
58
|
+
chat: {
|
|
59
|
+
name: '对话',
|
|
60
|
+
description: '多轮对话、知识检索、代码问答。适用于 Dashboard 和飞书的常规对话。',
|
|
61
|
+
capabilities: ['conversation', 'code_analysis'],
|
|
62
|
+
strategy: { type: 'single' },
|
|
63
|
+
policies: [
|
|
64
|
+
new BudgetPolicy({ maxIterations: 8, maxTokens: 4096, temperature: 0.7, timeoutMs: 120_000 }),
|
|
65
|
+
],
|
|
66
|
+
persona: {
|
|
67
|
+
role: 'assistant',
|
|
68
|
+
description: 'AutoSnippet 知识管理助手',
|
|
69
|
+
},
|
|
70
|
+
memory: {
|
|
71
|
+
enabled: true,
|
|
72
|
+
mode: 'user',
|
|
73
|
+
tiers: ['working', 'episodic', 'semantic'],
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
// ─── insight: 深度代码分析 + 知识产出 ────────
|
|
78
|
+
//
|
|
79
|
+
// v3.0 重设计: PipelineStrategy 增强版
|
|
80
|
+
// - 每个 stage 有 systemPrompt + promptBuilder (替代通用 Capability prompt)
|
|
81
|
+
// - Quality Gate 使用自定义 evaluator (三态: pass/retry/degrade)
|
|
82
|
+
// - Rejection Gate 监控 Producer 拒绝率
|
|
83
|
+
// - promptBuilder 通过 strategyContext 获取运行时数据 (dimConfig/sessionStore/...)
|
|
84
|
+
//
|
|
85
|
+
// orchestrator 通过 createRuntime('insight', { strategy: {...} }) 按需覆盖
|
|
86
|
+
// onToolCall 由 orchestrator 按维度注入 (闭包引用 ActiveContext)
|
|
87
|
+
|
|
88
|
+
insight: {
|
|
89
|
+
name: '洞察',
|
|
90
|
+
description: '深度代码分析 + 知识提取。增强 PipelineStrategy: Analyze→QualityGate→Produce→RejectionGate。',
|
|
91
|
+
capabilities: ['code_analysis', 'knowledge_production'],
|
|
92
|
+
strategy: {
|
|
93
|
+
type: 'pipeline',
|
|
94
|
+
maxRetries: 1,
|
|
95
|
+
stages: [
|
|
96
|
+
// ── Phase 1: Analyst ──
|
|
97
|
+
{
|
|
98
|
+
name: 'analyze',
|
|
99
|
+
capabilities: ['code_analysis'],
|
|
100
|
+
budget: { maxIterations: ANALYST_BUDGET.maxIterations, temperature: 0.4, timeoutMs: 300_000 },
|
|
101
|
+
systemPrompt: ANALYST_SYSTEM_PROMPT,
|
|
102
|
+
promptBuilder: (ctx) => buildAnalystPrompt(
|
|
103
|
+
ctx.dimConfig, ctx.projectInfo,
|
|
104
|
+
ctx.dimContext, ctx.sessionStore, ctx.semanticMemory, ctx.codeEntityGraph,
|
|
105
|
+
),
|
|
106
|
+
retryPromptBuilder: (retryCtx, _origPrompt, prev) => {
|
|
107
|
+
const prevAnalysis = prev.analyze?.reply || '';
|
|
108
|
+
const retryHint = buildRetryPrompt(retryCtx.reason);
|
|
109
|
+
return `${prevAnalysis}\n\n⚠️ 上述分析未通过质量检查: ${retryCtx.reason}\n\n${retryHint}`;
|
|
110
|
+
},
|
|
111
|
+
// onToolCall: 由 orchestrator 按维度注入
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
// ── Phase 2: Quality Gate ──
|
|
115
|
+
{
|
|
116
|
+
name: 'quality_gate',
|
|
117
|
+
gate: {
|
|
118
|
+
evaluator: insightGateEvaluator,
|
|
119
|
+
maxRetries: 1,
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
// ── Phase 3: Producer ──
|
|
124
|
+
{
|
|
125
|
+
name: 'produce',
|
|
126
|
+
capabilities: ['knowledge_production'],
|
|
127
|
+
// 透传完整 PRODUCER_BUDGET (searchBudget/maxSubmits/softSubmitLimit/idleRoundsToExit)
|
|
128
|
+
// 供 ExplorationTracker 精确控制 PRODUCE→SUMMARIZE 转换时机
|
|
129
|
+
budget: { ...PRODUCER_BUDGET, temperature: 0.3, timeoutMs: 180_000 },
|
|
130
|
+
systemPrompt: PRODUCER_SYSTEM_PROMPT,
|
|
131
|
+
promptBuilder: (ctx) => buildProducerPromptV2(
|
|
132
|
+
ctx.gateArtifact, // 来自 quality_gate 的 AnalysisArtifact
|
|
133
|
+
ctx.dimConfig, ctx.projectInfo,
|
|
134
|
+
),
|
|
135
|
+
// 拒绝率过高时: 缩减预算 + 特定修复 prompt (对齐旧 ProducerAgent 的 rejection retry)
|
|
136
|
+
retryBudget: { maxIterations: 5, temperature: 0.3, timeoutMs: 120_000 },
|
|
137
|
+
retryPromptBuilder: (retryCtx, _origPrompt, prev) => {
|
|
138
|
+
const prevProduce = prev.produce;
|
|
139
|
+
const submitCalls = (prevProduce?.toolCalls || []).filter(tc =>
|
|
140
|
+
['submit_knowledge', 'submit_with_check'].includes(tc.tool || tc.name));
|
|
141
|
+
const rejected = submitCalls.filter(tc => {
|
|
142
|
+
const res = tc.result;
|
|
143
|
+
if (!res) return false;
|
|
144
|
+
if (typeof res === 'string') return res.includes('rejected') || res.includes('error');
|
|
145
|
+
return res.status === 'rejected' || res.status === 'error' || res.reason === 'validation_failed';
|
|
146
|
+
}).length;
|
|
147
|
+
return `你的 ${rejected} 个提交被拒绝了。请根据拒绝原因改进后重新提交,确保:
|
|
148
|
+
1. content 必须是对象: { markdown: "...", rationale: "...", pattern: "..." }
|
|
149
|
+
2. content.markdown 字段 ≥ 200 字符,含代码块 (\`\`\`)
|
|
150
|
+
3. content.rationale 必填 — 设计原理说明(为什么这样设计)
|
|
151
|
+
4. 包含来源标注 (来源: FileName.m:行号)
|
|
152
|
+
5. 标题使用项目真实类名
|
|
153
|
+
6. 必填: trigger (@kebab-case)、kind (rule/pattern/fact)、doClause (英文祈使句)`;
|
|
154
|
+
},
|
|
155
|
+
skipOnDegrade: true,
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
// ── Phase 4: Rejection Gate ──
|
|
159
|
+
{
|
|
160
|
+
name: 'rejection_gate',
|
|
161
|
+
gate: {
|
|
162
|
+
evaluator: producerRejectionGateEvaluator,
|
|
163
|
+
maxRetries: 1,
|
|
164
|
+
},
|
|
165
|
+
skipOnDegrade: true,
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
},
|
|
169
|
+
policies: [
|
|
170
|
+
new BudgetPolicy({ maxIterations: 24, maxTokens: 4096, temperature: 0.3, timeoutMs: 600_000 }),
|
|
171
|
+
new QualityGatePolicy({ minEvidenceLength: 500, minFileRefs: 3, minToolCalls: 3 }),
|
|
172
|
+
],
|
|
173
|
+
persona: {
|
|
174
|
+
role: 'analyst',
|
|
175
|
+
description: '高级软件架构师 + 知识管理专家',
|
|
176
|
+
},
|
|
177
|
+
memory: {
|
|
178
|
+
enabled: false, // 无状态 worker
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
// ─── lark: 飞书知识管理对话 ─────────────
|
|
183
|
+
|
|
184
|
+
lark: {
|
|
185
|
+
name: '飞书对话',
|
|
186
|
+
description: '通过飞书自然语言进行知识管理、代码分析、项目理解。服务端直接处理,不转发 IDE。',
|
|
187
|
+
capabilities: ['conversation', 'code_analysis'],
|
|
188
|
+
strategy: { type: 'single' },
|
|
189
|
+
policies: [
|
|
190
|
+
new BudgetPolicy({ maxIterations: 12, maxTokens: 4096, temperature: 0.7, timeoutMs: 180_000 }),
|
|
191
|
+
new SafetyPolicy({
|
|
192
|
+
allowedSenders: process.env.ASD_LARK_ALLOWED_USERS?.split(',').filter(Boolean) || [],
|
|
193
|
+
}),
|
|
194
|
+
],
|
|
195
|
+
persona: {
|
|
196
|
+
role: 'assistant',
|
|
197
|
+
description: 'AutoSnippet 知识管理助手 (飞书)。用中文回复,简洁专业。',
|
|
198
|
+
},
|
|
199
|
+
memory: {
|
|
200
|
+
enabled: true,
|
|
201
|
+
mode: 'user',
|
|
202
|
+
tiers: ['working', 'episodic', 'semantic'],
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
// ─── remote-exec: 远程执行 ──────────────
|
|
207
|
+
|
|
208
|
+
'remote-exec': {
|
|
209
|
+
name: '远程执行',
|
|
210
|
+
description: '通过飞书/远程终端执行本地操作。搭配 SafetyPolicy 保障安全。',
|
|
211
|
+
capabilities: ['conversation', 'code_analysis', 'system_interaction'],
|
|
212
|
+
strategy: { type: 'single' },
|
|
213
|
+
policies: [
|
|
214
|
+
new BudgetPolicy({ maxIterations: 6, maxTokens: 2048, temperature: 0.5, timeoutMs: 60_000 }),
|
|
215
|
+
new SafetyPolicy({
|
|
216
|
+
// 实际部署时从环境变量读取 allowedSenders
|
|
217
|
+
allowedSenders: process.env.ASD_LARK_ALLOWED_USERS?.split(',').filter(Boolean) || [],
|
|
218
|
+
fileScope: process.env.ASD_PROJECT_ROOT || null,
|
|
219
|
+
}),
|
|
220
|
+
],
|
|
221
|
+
persona: {
|
|
222
|
+
role: 'assistant',
|
|
223
|
+
description: 'AutoSnippet 远程编程助手',
|
|
224
|
+
},
|
|
225
|
+
memory: {
|
|
226
|
+
enabled: true,
|
|
227
|
+
mode: 'user',
|
|
228
|
+
tiers: ['working', 'episodic'],
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
// ─── Preset 解析器 ────────────────────────────
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* 将 Preset 配置中的 strategy 声明式配置转换为实际 Strategy 实例
|
|
238
|
+
*
|
|
239
|
+
* @param {Object} strategyConfig — { type: 'single'|'pipeline'|'fan_out'|'adaptive', ...opts }
|
|
240
|
+
* @returns {import('./strategies.js').Strategy}
|
|
241
|
+
*/
|
|
242
|
+
export function resolveStrategy(strategyConfig) {
|
|
243
|
+
if (!strategyConfig) return new SingleStrategy();
|
|
244
|
+
|
|
245
|
+
switch (strategyConfig.type) {
|
|
246
|
+
case 'single':
|
|
247
|
+
return new SingleStrategy();
|
|
248
|
+
|
|
249
|
+
case 'pipeline':
|
|
250
|
+
return new PipelineStrategy({
|
|
251
|
+
stages: strategyConfig.stages || [],
|
|
252
|
+
maxRetries: strategyConfig.maxRetries,
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
case 'fan_out': {
|
|
256
|
+
const itemStrategy = strategyConfig.itemStrategy
|
|
257
|
+
? resolveStrategy(strategyConfig.itemStrategy)
|
|
258
|
+
: new SingleStrategy();
|
|
259
|
+
return new FanOutStrategy({
|
|
260
|
+
itemStrategy,
|
|
261
|
+
tiers: strategyConfig.tiers,
|
|
262
|
+
merge: strategyConfig.merge,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
case 'adaptive':
|
|
267
|
+
return new AdaptiveStrategy({
|
|
268
|
+
single: strategyConfig.single ? resolveStrategy(strategyConfig.single) : undefined,
|
|
269
|
+
pipeline: strategyConfig.pipeline ? resolveStrategy(strategyConfig.pipeline) : undefined,
|
|
270
|
+
fanOut: strategyConfig.fanOut ? resolveStrategy(strategyConfig.fanOut) : undefined,
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
default:
|
|
274
|
+
throw new Error(`Unknown strategy type: ${strategyConfig.type}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* 获取 Preset 并展开为可用配置
|
|
280
|
+
*
|
|
281
|
+
* @param {string} presetName
|
|
282
|
+
* @param {Object} [overrides] — 覆盖 preset 中的特定字段
|
|
283
|
+
* @returns {PresetConfig & { strategyInstance: Strategy }}
|
|
284
|
+
*/
|
|
285
|
+
export function getPreset(presetName, overrides = {}) {
|
|
286
|
+
const preset = PRESETS[presetName];
|
|
287
|
+
if (!preset) throw new Error(`Unknown preset: "${presetName}". Available: ${Object.keys(PRESETS).join(', ')}`);
|
|
288
|
+
|
|
289
|
+
const merged = {
|
|
290
|
+
...preset,
|
|
291
|
+
...overrides,
|
|
292
|
+
capabilities: overrides.capabilities || preset.capabilities,
|
|
293
|
+
policies: overrides.policies || preset.policies,
|
|
294
|
+
persona: { ...preset.persona, ...overrides.persona },
|
|
295
|
+
memory: { ...preset.memory, ...overrides.memory },
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
// 解析 strategy
|
|
299
|
+
const strategyConfig = overrides.strategy || preset.strategy;
|
|
300
|
+
merged.strategyInstance = resolveStrategy(strategyConfig);
|
|
301
|
+
|
|
302
|
+
return merged;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export default { PRESETS, resolveStrategy, getPreset };
|