autosnippet 3.0.1 → 3.0.2
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 +230 -324
- package/bin/api-server.js +1 -1
- package/bin/cli.js +204 -244
- package/bin/mcp-server.js +5 -3
- package/config/knowledge-base.config.js +132 -132
- package/dashboard/dist/assets/{icons-CEfgGaZi.js → icons-Cdq22n2i.js} +95 -100
- package/dashboard/dist/assets/index-ClkyPkDX.js +133 -0
- package/dashboard/dist/assets/index-t4QrJwv1.css +1 -0
- package/dashboard/dist/index.html +3 -3
- package/lib/bootstrap.js +8 -8
- package/lib/cli/AiScanService.js +86 -40
- package/lib/cli/KnowledgeSyncService.js +113 -74
- package/lib/cli/SetupService.js +439 -277
- package/lib/cli/UpgradeService.js +63 -100
- package/lib/core/AstAnalyzer.js +276 -597
- package/lib/core/ast/ProjectGraph.js +101 -40
- package/lib/core/ast/ensure-grammars.js +232 -0
- package/lib/core/ast/index.js +115 -0
- package/lib/core/ast/lang-dart.js +661 -0
- package/lib/core/ast/lang-go.js +530 -0
- package/lib/core/ast/lang-java.js +435 -0
- package/lib/core/ast/lang-javascript.js +272 -0
- package/lib/core/ast/lang-kotlin.js +423 -0
- package/lib/core/ast/lang-objc.js +388 -0
- package/lib/core/ast/lang-python.js +371 -0
- package/lib/core/ast/lang-swift.js +337 -0
- package/lib/core/ast/lang-typescript.js +503 -0
- package/lib/core/capability/CapabilityProbe.js +18 -9
- package/lib/core/constitution/Constitution.js +2 -3
- package/lib/core/constitution/ConstitutionValidator.js +65 -24
- package/lib/core/discovery/DartDiscoverer.js +534 -0
- package/lib/core/discovery/DiscovererRegistry.js +83 -0
- package/lib/core/discovery/GenericDiscoverer.js +225 -0
- package/lib/core/discovery/GoDiscoverer.js +541 -0
- package/lib/core/discovery/JvmDiscoverer.js +506 -0
- package/lib/core/discovery/NodeDiscoverer.js +466 -0
- package/lib/core/discovery/ProjectDiscoverer.js +93 -0
- package/lib/core/discovery/PythonDiscoverer.js +338 -0
- package/lib/core/discovery/SpmDiscoverer.js +5 -0
- package/lib/core/discovery/index.js +53 -0
- package/lib/core/enhancement/EnhancementPack.js +71 -0
- package/lib/core/enhancement/EnhancementRegistry.js +47 -0
- package/lib/core/enhancement/android-enhancement.js +102 -0
- package/lib/core/enhancement/django-enhancement.js +70 -0
- package/lib/core/enhancement/fastapi-enhancement.js +63 -0
- package/lib/core/enhancement/go-grpc-enhancement.js +152 -0
- package/lib/core/enhancement/go-web-enhancement.js +201 -0
- package/lib/core/enhancement/index.js +65 -0
- package/lib/core/enhancement/node-server-enhancement.js +88 -0
- package/lib/core/enhancement/react-enhancement.js +86 -0
- package/lib/core/enhancement/spring-enhancement.js +112 -0
- package/lib/core/enhancement/vue-enhancement.js +96 -0
- package/lib/core/gateway/Gateway.js +8 -9
- package/lib/core/gateway/GatewayActionRegistry.js +1 -1
- package/lib/core/permission/PermissionManager.js +12 -8
- package/lib/domain/index.js +13 -9
- package/lib/domain/knowledge/KnowledgeEntry.js +111 -101
- package/lib/domain/knowledge/KnowledgeRepository.js +0 -1
- package/lib/domain/knowledge/Lifecycle.js +22 -22
- package/lib/domain/knowledge/index.js +9 -12
- package/lib/domain/knowledge/values/Constraints.js +31 -21
- package/lib/domain/knowledge/values/Content.js +21 -13
- package/lib/domain/knowledge/values/Quality.js +31 -18
- package/lib/domain/knowledge/values/Reasoning.js +20 -12
- package/lib/domain/knowledge/values/Relations.js +37 -25
- package/lib/domain/knowledge/values/Stats.js +18 -12
- package/lib/domain/knowledge/values/index.js +4 -3
- package/lib/domain/snippet/Snippet.js +35 -10
- package/lib/external/ai/AiFactory.js +48 -16
- package/lib/external/ai/AiProvider.js +184 -90
- package/lib/external/ai/providers/ClaudeProvider.js +25 -12
- package/lib/external/ai/providers/GoogleGeminiProvider.js +59 -30
- package/lib/external/ai/providers/MockProvider.js +9 -3
- package/lib/external/ai/providers/OpenAiProvider.js +51 -29
- package/lib/external/mcp/McpServer.js +66 -36
- package/lib/external/mcp/errorHandler.js +23 -11
- package/lib/external/mcp/handlers/LanguageExtensions.js +138 -53
- package/lib/external/mcp/handlers/TargetClassifier.js +52 -16
- package/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.js +81 -20
- package/lib/external/mcp/handlers/bootstrap/pipeline/EpisodicMemory.js +71 -42
- package/lib/external/mcp/handlers/bootstrap/pipeline/IncrementalBootstrap.js +9 -17
- package/lib/external/mcp/handlers/bootstrap/pipeline/ToolResultCache.js +14 -9
- package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.js +15 -7
- package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +352 -153
- package/lib/external/mcp/handlers/bootstrap/pipeline/tier-scheduler.js +52 -12
- package/lib/external/mcp/handlers/bootstrap/skills.js +143 -39
- package/lib/external/mcp/handlers/bootstrap.js +691 -168
- package/lib/external/mcp/handlers/browse.js +66 -22
- package/lib/external/mcp/handlers/candidate.js +118 -35
- package/lib/external/mcp/handlers/consolidated.js +49 -17
- package/lib/external/mcp/handlers/guard.js +104 -39
- package/lib/external/mcp/handlers/knowledge.js +60 -36
- package/lib/external/mcp/handlers/search.js +43 -14
- package/lib/external/mcp/handlers/skill.js +120 -45
- package/lib/external/mcp/handlers/structure.js +240 -86
- package/lib/external/mcp/handlers/system.js +42 -12
- package/lib/external/mcp/handlers/wiki.js +58 -33
- package/lib/external/mcp/tools.js +306 -123
- package/lib/http/HttpServer.js +72 -47
- package/lib/http/middleware/RateLimiter.js +5 -3
- package/lib/http/middleware/errorHandler.js +6 -1
- package/lib/http/middleware/requestLogger.js +14 -3
- package/lib/http/middleware/roleResolver.js +30 -23
- package/lib/http/routes/ai.js +387 -265
- package/lib/http/routes/auth.js +81 -61
- package/lib/http/routes/candidates.js +430 -320
- package/lib/http/routes/commands.js +289 -189
- package/lib/http/routes/extract.js +158 -125
- package/lib/http/routes/guardRules.js +309 -217
- package/lib/http/routes/knowledge.js +213 -154
- package/lib/http/routes/modules.js +578 -0
- package/lib/http/routes/monitoring.js +6 -6
- package/lib/http/routes/recipes.js +104 -93
- package/lib/http/routes/search.js +361 -305
- package/lib/http/routes/skills.js +145 -98
- package/lib/http/routes/snippets.js +42 -30
- package/lib/http/routes/spm.js +3 -405
- package/lib/http/routes/violations.js +113 -93
- package/lib/http/routes/wiki.js +211 -170
- package/lib/http/utils/routeHelpers.js +3 -1
- package/lib/http/utils/sse-sessions.js +16 -6
- package/lib/http/utils/sse.js +15 -5
- package/lib/infrastructure/audit/AuditLogger.js +5 -2
- package/lib/infrastructure/audit/AuditStore.js +10 -7
- package/lib/infrastructure/cache/CacheService.js +3 -1
- package/lib/infrastructure/cache/GraphCache.js +8 -4
- package/lib/infrastructure/cache/UnifiedCacheAdapter.js +1 -1
- package/lib/infrastructure/config/ConfigLoader.js +9 -5
- package/lib/infrastructure/config/Defaults.js +30 -10
- package/lib/infrastructure/config/Paths.js +28 -8
- package/lib/infrastructure/config/TriggerSymbol.js +22 -10
- package/lib/infrastructure/database/DatabaseConnection.js +15 -10
- package/lib/infrastructure/database/migrations/001_initial_schema.js +0 -1
- package/lib/infrastructure/external/ClipboardManager.js +6 -2
- package/lib/infrastructure/external/NativeUi.js +50 -43
- package/lib/infrastructure/external/OpenBrowser.js +14 -17
- package/lib/infrastructure/external/XcodeAutomation.js +14 -258
- package/lib/infrastructure/logging/Logger.js +46 -30
- package/lib/infrastructure/monitoring/ErrorTracker.js +7 -5
- package/lib/infrastructure/monitoring/PerformanceMonitor.js +12 -4
- package/lib/infrastructure/paths/HeaderResolver.js +25 -9
- package/lib/infrastructure/paths/PathFinder.js +34 -12
- package/lib/infrastructure/plugin/PluginManager.js +26 -8
- package/lib/infrastructure/realtime/RealtimeService.js +2 -2
- package/lib/infrastructure/vector/Chunker.js +22 -7
- package/lib/infrastructure/vector/IndexingPipeline.js +46 -22
- package/lib/infrastructure/vector/JsonVectorAdapter.js +90 -53
- package/lib/infrastructure/vector/VectorStore.js +28 -10
- package/lib/injection/ServiceContainer.js +247 -93
- package/lib/platform/ios/index.js +63 -0
- package/lib/platform/ios/routes/spm.js +437 -0
- package/lib/platform/ios/snippet/PlaceholderConverter.js +55 -0
- package/lib/platform/ios/snippet/XcodeCodec.js +112 -0
- package/lib/{service → platform/ios}/spm/DependencyGraph.js +41 -17
- package/lib/{service → platform/ios}/spm/PackageSwiftParser.js +41 -14
- package/lib/{service → platform/ios}/spm/PolicyEngine.js +9 -4
- package/lib/platform/ios/spm/SpmDiscoverer.js +122 -0
- package/lib/{service → platform/ios}/spm/SpmService.js +385 -127
- package/lib/{service/automation → platform/ios/xcode}/SaveEventFilter.js +8 -7
- package/lib/platform/ios/xcode/XcodeAutomation.js +350 -0
- package/lib/{service/automation → platform/ios/xcode}/XcodeIntegration.js +325 -145
- package/lib/repository/base/BaseRepository.js +7 -9
- package/lib/repository/knowledge/KnowledgeRepository.impl.js +98 -75
- package/lib/repository/token/TokenUsageStore.js +4 -2
- package/lib/service/automation/ActionPipeline.js +1 -1
- package/lib/service/automation/AutomationOrchestrator.js +8 -4
- package/lib/service/automation/ContextCollector.js +7 -5
- package/lib/service/automation/DirectiveDetector.js +23 -16
- package/lib/service/automation/FileWatcher.js +112 -56
- package/lib/service/automation/TriggerResolver.js +6 -4
- package/lib/service/automation/handlers/AlinkHandler.js +24 -12
- package/lib/service/automation/handlers/CreateHandler.js +19 -20
- package/lib/service/automation/handlers/DraftHandler.js +14 -8
- package/lib/service/automation/handlers/GuardHandler.js +93 -63
- package/lib/service/automation/handlers/HeaderHandler.js +1 -6
- package/lib/service/automation/handlers/SearchHandler.js +155 -88
- package/lib/service/bootstrap/BootstrapTaskManager.js +77 -35
- package/lib/service/candidate/SimilarityService.js +25 -9
- package/lib/service/chat/AnalystAgent.js +50 -24
- package/lib/service/chat/CandidateGuardrail.js +143 -17
- package/lib/service/chat/ChatAgent.js +655 -260
- package/lib/service/chat/ContextWindow.js +116 -71
- package/lib/service/chat/ConversationStore.js +77 -36
- package/lib/service/chat/EpisodicConsolidator.js +47 -23
- package/lib/service/chat/HandoffProtocol.js +98 -22
- package/lib/service/chat/Memory.js +34 -14
- package/lib/service/chat/ProducerAgent.js +40 -20
- package/lib/service/chat/ProjectSemanticMemory.js +109 -78
- package/lib/service/chat/ReasoningLayer.js +148 -70
- package/lib/service/chat/ReasoningTrace.js +44 -32
- package/lib/service/chat/TaskPipeline.js +39 -19
- package/lib/service/chat/ToolRegistry.js +48 -29
- package/lib/service/chat/WorkingMemory.js +44 -18
- package/lib/service/chat/tools.js +1096 -494
- package/lib/service/context/RecipeExtractor.js +132 -51
- package/lib/service/cursor/CursorDeliveryPipeline.js +82 -37
- package/lib/service/cursor/KnowledgeCompressor.js +25 -22
- package/lib/service/cursor/RulesGenerator.js +13 -7
- package/lib/service/cursor/SkillsSyncer.js +77 -27
- package/lib/service/cursor/TokenBudget.js +2 -2
- package/lib/service/cursor/TopicClassifier.js +54 -20
- package/lib/service/guard/ComplianceReporter.js +55 -43
- package/lib/service/guard/ExclusionManager.js +67 -29
- package/lib/service/guard/GuardCheckEngine.js +381 -86
- package/lib/service/guard/GuardFeedbackLoop.js +22 -10
- package/lib/service/guard/GuardService.js +29 -19
- package/lib/service/guard/RuleLearner.js +55 -23
- package/lib/service/guard/SourceFileCollector.js +27 -20
- package/lib/service/guard/ViolationsStore.js +43 -38
- package/lib/service/knowledge/CodeEntityGraph.js +147 -82
- package/lib/service/knowledge/ConfidenceRouter.js +12 -10
- package/lib/service/knowledge/KnowledgeFileWriter.js +147 -56
- package/lib/service/knowledge/KnowledgeGraphService.js +81 -34
- package/lib/service/knowledge/KnowledgeService.js +222 -112
- package/lib/service/module/ModuleService.js +969 -0
- package/lib/service/quality/FeedbackCollector.js +27 -15
- package/lib/service/quality/QualityScorer.js +78 -24
- package/lib/service/recipe/RecipeCandidateValidator.js +110 -44
- package/lib/service/recipe/RecipeParser.js +78 -45
- package/lib/service/search/CoarseRanker.js +43 -28
- package/lib/service/search/CrossEncoderReranker.js +32 -21
- package/lib/service/search/InvertedIndex.js +21 -7
- package/lib/service/search/MultiSignalRanker.js +90 -28
- package/lib/service/search/RetrievalFunnel.js +45 -24
- package/lib/service/search/SearchEngine.js +255 -103
- package/lib/service/skills/EventAggregator.js +32 -15
- package/lib/service/skills/SignalCollector.js +140 -64
- package/lib/service/skills/SkillAdvisor.js +79 -42
- package/lib/service/skills/SkillHooks.js +16 -14
- package/lib/service/snippet/PlaceholderConverter.js +5 -0
- package/lib/service/snippet/SnippetFactory.js +116 -99
- package/lib/service/snippet/SnippetInstaller.js +234 -62
- package/lib/service/snippet/codecs/SnippetCodec.js +67 -0
- package/lib/service/snippet/codecs/VSCodeCodec.js +102 -0
- package/lib/service/snippet/codecs/XcodeCodec.js +5 -0
- package/lib/service/wiki/WikiGenerator.js +637 -263
- package/lib/shared/DimensionCopyRegistry.js +472 -0
- package/lib/shared/LanguageService.js +399 -0
- package/lib/shared/PathGuard.js +45 -28
- package/lib/shared/RecipeReadinessChecker.js +72 -12
- package/lib/shared/constants.js +41 -41
- package/lib/shared/errors/BaseError.js +2 -2
- package/lib/shared/errors/index.js +4 -4
- package/lib/shared/similarity.js +25 -8
- package/lib/shared/token-utils.js +6 -2
- package/lib/shared/utils/common.js +12 -4
- package/package.json +49 -13
- package/scripts/bench-real-projects.mjs +256 -0
- package/scripts/build-native-ui.js +30 -30
- package/scripts/clear-old-vector-index.js +5 -35
- package/scripts/clear-vector-cache.js +7 -37
- package/scripts/collect-test-project-stats.mjs +160 -0
- package/scripts/diagnose-mcp.js +41 -32
- package/scripts/ensure-parse-package.js +6 -9
- package/scripts/generate-recipe-drafts.js +116 -77
- package/scripts/init-db.js +3 -20
- package/scripts/init-snippets.js +305 -0
- package/scripts/init-vector-db.js +173 -170
- package/scripts/install-cursor-skill.js +148 -104
- package/scripts/install-full.js +8 -21
- package/scripts/install-vscode-copilot.js +146 -145
- package/scripts/migrate-md-to-knowledge.mjs +139 -151
- package/scripts/postinstall-safe.js +5 -17
- package/scripts/recipe-audit.js +106 -82
- package/scripts/release.js +283 -323
- package/scripts/setup-mcp-config.js +60 -52
- package/scripts/verify-context-api.js +20 -20
- package/skills/autosnippet-analysis/SKILL.md +10 -6
- package/skills/autosnippet-candidates/SKILL.md +27 -26
- package/skills/autosnippet-coldstart/SKILL.md +555 -38
- package/skills/autosnippet-concepts/SKILL.md +349 -337
- package/skills/autosnippet-create/SKILL.md +5 -5
- package/skills/autosnippet-reference-dart/SKILL.md +543 -0
- package/skills/autosnippet-reference-go/SKILL.md +539 -0
- package/skills/autosnippet-reference-java/SKILL.md +534 -0
- package/skills/autosnippet-reference-jsts/SKILL.md +41 -9
- package/skills/autosnippet-reference-kotlin/SKILL.md +526 -0
- package/skills/autosnippet-reference-objc/SKILL.md +29 -6
- package/skills/autosnippet-reference-python/SKILL.md +800 -0
- package/skills/autosnippet-reference-swift/SKILL.md +70 -14
- package/skills/autosnippet-structure/SKILL.md +4 -4
- package/templates/cursor-rules/autosnippet-conventions.mdc +2 -2
- package/templates/recipes-setup/README.md +2 -2
- package/templates/recipes-setup/_template.md +1 -1
- package/dashboard/dist/assets/index-Bun3ld_J.css +0 -1
- package/dashboard/dist/assets/index-_Sk_Dmg3.js +0 -143
- package/resources/asd-entry/main.swift +0 -159
- package/scripts/build-asd-entry.js +0 -51
- package/scripts/init-xcode-snippets.js +0 -311
- package/template.json +0 -39
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
* @module ReasoningLayer
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
import { ReasoningTrace } from './ReasoningTrace.js';
|
|
30
29
|
import Logger from '../../infrastructure/logging/Logger.js';
|
|
30
|
+
import { ReasoningTrace } from './ReasoningTrace.js';
|
|
31
31
|
|
|
32
32
|
/** 反思间隔(每 N 轮触发一次) */
|
|
33
33
|
const DEFAULT_REFLECTION_INTERVAL = 5;
|
|
@@ -109,7 +109,9 @@ export class ReasoningLayer {
|
|
|
109
109
|
* @returns {string|null} — 反思/规划提示(null = 不触发)
|
|
110
110
|
*/
|
|
111
111
|
beforeAICall(iteration, { explorationMetrics, budget, phase } = {}) {
|
|
112
|
-
if (!this.#config.enabled)
|
|
112
|
+
if (!this.#config.enabled) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
113
115
|
|
|
114
116
|
this.#trace.startRound(iteration);
|
|
115
117
|
|
|
@@ -133,7 +135,7 @@ export class ReasoningLayer {
|
|
|
133
135
|
// ── 合并 replan + reflection ──
|
|
134
136
|
if (replanNudge && reflectionNudge) {
|
|
135
137
|
// 两者同时触发 → 合并,避免两条独立 nudge
|
|
136
|
-
return replanNudge
|
|
138
|
+
return `${replanNudge}\n\n${reflectionNudge}`;
|
|
137
139
|
}
|
|
138
140
|
return replanNudge || reflectionNudge || null;
|
|
139
141
|
}
|
|
@@ -146,7 +148,9 @@ export class ReasoningLayer {
|
|
|
146
148
|
* @param {object} aiResult — AI 返回结果 (native tool calling)
|
|
147
149
|
*/
|
|
148
150
|
afterAICall(aiResult) {
|
|
149
|
-
if (!this.#config.enabled)
|
|
151
|
+
if (!this.#config.enabled) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
150
154
|
|
|
151
155
|
let extractedText = null;
|
|
152
156
|
|
|
@@ -154,7 +158,9 @@ export class ReasoningLayer {
|
|
|
154
158
|
if (aiResult?.text && aiResult?.functionCalls?.length > 0) {
|
|
155
159
|
this.#trace.setThought(aiResult.text);
|
|
156
160
|
extractedText = aiResult.text;
|
|
157
|
-
this.#logger.info(
|
|
161
|
+
this.#logger.info(
|
|
162
|
+
`[ReasoningLayer] 💭 thought: ${aiResult.text.substring(0, 150).replace(/\n/g, '↵')}…`
|
|
163
|
+
);
|
|
158
164
|
} else if (aiResult?.text) {
|
|
159
165
|
extractedText = aiResult.text;
|
|
160
166
|
}
|
|
@@ -179,7 +185,7 @@ export class ReasoningLayer {
|
|
|
179
185
|
this.#trace.updatePlan(replanText, iteration);
|
|
180
186
|
const plan = this.#trace.getPlan();
|
|
181
187
|
// 重置进度追踪
|
|
182
|
-
this.#planProgress.coveredSteps = plan.steps.filter(s => s.status === 'done').length;
|
|
188
|
+
this.#planProgress.coveredSteps = plan.steps.filter((s) => s.status === 'done').length;
|
|
183
189
|
this.#planProgress.totalSteps = plan.steps.length;
|
|
184
190
|
this.#planProgress.unplannedActions = 0;
|
|
185
191
|
this.#planProgress.consecutiveOffPlan = 0;
|
|
@@ -201,7 +207,9 @@ export class ReasoningLayer {
|
|
|
201
207
|
* @param {object} [explorationMetrics] — 探索指标(用于判断是否新信息)
|
|
202
208
|
*/
|
|
203
209
|
afterToolExec(toolName, args, result, explorationMetrics) {
|
|
204
|
-
if (!this.#config.enabled)
|
|
210
|
+
if (!this.#config.enabled) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
205
213
|
|
|
206
214
|
this.#trace.addAction(toolName, args);
|
|
207
215
|
|
|
@@ -222,7 +230,9 @@ export class ReasoningLayer {
|
|
|
222
230
|
* @param {object} [roundResults.explorationMetrics] — 探索指标
|
|
223
231
|
*/
|
|
224
232
|
afterRound({ newInfoCount, totalCalls, submitCount, explorationMetrics } = {}) {
|
|
225
|
-
if (!this.#config.enabled)
|
|
233
|
+
if (!this.#config.enabled) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
226
236
|
|
|
227
237
|
this.#trace.setRoundSummary({
|
|
228
238
|
newInfoCount: newInfoCount || 0,
|
|
@@ -269,26 +279,29 @@ export class ReasoningLayer {
|
|
|
269
279
|
const hasPlan = plan && plan.steps.length > 0;
|
|
270
280
|
let planScore = 0;
|
|
271
281
|
if (hasPlan) {
|
|
272
|
-
const completionRate =
|
|
273
|
-
|
|
274
|
-
|
|
282
|
+
const completionRate =
|
|
283
|
+
this.#planProgress.totalSteps > 0
|
|
284
|
+
? this.#planProgress.coveredSteps / this.#planProgress.totalSteps
|
|
285
|
+
: 0;
|
|
275
286
|
const adherenceRate = 1 - (this.#planProgress.deviationScore || 0);
|
|
276
287
|
planScore = completionRate * 0.6 + adherenceRate * 0.4;
|
|
277
288
|
}
|
|
278
289
|
|
|
279
290
|
const score = hasPlan
|
|
280
291
|
? Math.round(
|
|
281
|
-
(thoughtRatio * 0.
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
292
|
+
(thoughtRatio * 0.3 +
|
|
293
|
+
reflectionRatio * 0.15 +
|
|
294
|
+
actionEfficiency * 0.15 +
|
|
295
|
+
observationCoverage * 0.15 +
|
|
296
|
+
planScore * 0.25) *
|
|
297
|
+
100
|
|
286
298
|
)
|
|
287
299
|
: Math.round(
|
|
288
300
|
(thoughtRatio * 0.4 +
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
301
|
+
reflectionRatio * 0.2 +
|
|
302
|
+
actionEfficiency * 0.2 +
|
|
303
|
+
observationCoverage * 0.2) *
|
|
304
|
+
100
|
|
292
305
|
);
|
|
293
306
|
|
|
294
307
|
const breakdown = {
|
|
@@ -339,13 +352,18 @@ export class ReasoningLayer {
|
|
|
339
352
|
|
|
340
353
|
// 触发条件
|
|
341
354
|
const periodicTrigger = iteration > 1 && interval > 0 && iteration % interval === 0;
|
|
342
|
-
const staleTrigger =
|
|
343
|
-
|
|
355
|
+
const staleTrigger =
|
|
356
|
+
explorationMetrics?.staleRounds >= staleThreshold &&
|
|
357
|
+
iteration >= MIN_ITERS_FOR_STALE_REFLECTION;
|
|
344
358
|
|
|
345
|
-
if (!periodicTrigger && !staleTrigger)
|
|
359
|
+
if (!periodicTrigger && !staleTrigger) {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
346
362
|
|
|
347
363
|
const summary = this.#trace.getRecentSummary(interval || 3);
|
|
348
|
-
if (!summary)
|
|
364
|
+
if (!summary) {
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
349
367
|
|
|
350
368
|
const stats = this.#trace.getStats();
|
|
351
369
|
const maxIter = budget?.maxIterations || 30;
|
|
@@ -356,34 +374,44 @@ export class ReasoningLayer {
|
|
|
356
374
|
const parts = [];
|
|
357
375
|
|
|
358
376
|
if (staleTrigger) {
|
|
359
|
-
parts.push(
|
|
377
|
+
parts.push(
|
|
378
|
+
`📊 停滞反思 (第 ${iteration}/${maxIter} 轮, 连续 ${explorationMetrics.staleRounds} 轮无新信息):`
|
|
379
|
+
);
|
|
360
380
|
} else {
|
|
361
381
|
parts.push(`📊 中期反思 (第 ${iteration}/${maxIter} 轮, ${progressPct}% 预算):`);
|
|
362
382
|
}
|
|
363
383
|
|
|
364
384
|
// 过去推理回顾
|
|
365
385
|
if (summary.thoughts.length > 0) {
|
|
366
|
-
parts.push(
|
|
386
|
+
parts.push(
|
|
387
|
+
`\n你最近的思考方向:\n${summary.thoughts.map((t, i) => ` ${i + 1}. ${t}`).join('\n')}`
|
|
388
|
+
);
|
|
367
389
|
}
|
|
368
390
|
|
|
369
391
|
// 行动效率统计
|
|
370
|
-
parts.push(
|
|
392
|
+
parts.push(
|
|
393
|
+
`\n行动效率: 最近 ${summary.roundCount} 轮中 ${Math.round(summary.newInfoRatio * 100)}% 获取到新信息`
|
|
394
|
+
);
|
|
371
395
|
|
|
372
396
|
// 累计进度
|
|
373
|
-
parts.push(
|
|
397
|
+
parts.push(
|
|
398
|
+
`累计: ${explorationMetrics?.uniqueFiles?.size || 0} 文件, ${explorationMetrics?.uniquePatterns?.size || 0} 搜索模式, ${stats.totalActions} 次工具调用`
|
|
399
|
+
);
|
|
374
400
|
|
|
375
401
|
// ── Planning 进度附加 ──
|
|
376
402
|
if (this.#config.planningEnabled) {
|
|
377
403
|
const plan = this.#trace.getPlan();
|
|
378
404
|
if (plan && plan.steps.length > 0) {
|
|
379
|
-
const doneCount = plan.steps.filter(s => s.status === 'done').length;
|
|
405
|
+
const doneCount = plan.steps.filter((s) => s.status === 'done').length;
|
|
380
406
|
parts.push(`\n📋 计划进度: ${doneCount}/${plan.steps.length} 步骤已完成`);
|
|
381
407
|
}
|
|
382
408
|
}
|
|
383
409
|
|
|
384
410
|
// 阶段化评估问题
|
|
385
411
|
if (phase === 'EXPLORE' || !phase) {
|
|
386
|
-
parts.push(
|
|
412
|
+
parts.push(
|
|
413
|
+
`\n请评估:\n1. 到目前为止最重要的发现是什么?\n2. 还有哪些关键方面未覆盖?\n3. 剩余 ${remaining} 轮,最有价值的下一步是什么?`
|
|
414
|
+
);
|
|
387
415
|
} else if (phase === 'PRODUCE') {
|
|
388
416
|
parts.push(`\n请评估:\n1. 已提交的候选是否覆盖了核心发现?\n2. 是否有高价值知识点被遗漏?`);
|
|
389
417
|
}
|
|
@@ -393,7 +421,9 @@ export class ReasoningLayer {
|
|
|
393
421
|
// 记录到 trace
|
|
394
422
|
this.#trace.setReflection(reflectionText);
|
|
395
423
|
|
|
396
|
-
this.#logger.info(
|
|
424
|
+
this.#logger.info(
|
|
425
|
+
`[ReasoningLayer] 💭 reflection triggered at iteration ${iteration} (${staleTrigger ? 'stale' : 'periodic'})`
|
|
426
|
+
);
|
|
397
427
|
|
|
398
428
|
return reflectionText;
|
|
399
429
|
}
|
|
@@ -434,18 +464,24 @@ export class ReasoningLayer {
|
|
|
434
464
|
if (metrics?.uniqueFiles) {
|
|
435
465
|
const allFiles = [];
|
|
436
466
|
for (const m of matches) {
|
|
437
|
-
if (m.file)
|
|
467
|
+
if (m.file) {
|
|
468
|
+
allFiles.push(m.file);
|
|
469
|
+
}
|
|
438
470
|
}
|
|
439
471
|
if (batchResults) {
|
|
440
472
|
for (const sub of Object.values(batchResults)) {
|
|
441
|
-
for (const m of
|
|
442
|
-
if (m.file)
|
|
473
|
+
for (const m of sub.matches || []) {
|
|
474
|
+
if (m.file) {
|
|
475
|
+
allFiles.push(m.file);
|
|
476
|
+
}
|
|
443
477
|
}
|
|
444
478
|
}
|
|
445
479
|
}
|
|
446
|
-
const newFiles = allFiles.filter(f => !metrics.uniqueFiles.has(f));
|
|
480
|
+
const newFiles = allFiles.filter((f) => !metrics.uniqueFiles.has(f));
|
|
447
481
|
meta.gotNewInfo = newFiles.length > 0;
|
|
448
|
-
if (newFiles.length > 0)
|
|
482
|
+
if (newFiles.length > 0) {
|
|
483
|
+
meta.keyFacts.push(`${newFiles.length} new files`);
|
|
484
|
+
}
|
|
449
485
|
} else {
|
|
450
486
|
meta.gotNewInfo = totalMatches > 0;
|
|
451
487
|
}
|
|
@@ -458,7 +494,7 @@ export class ReasoningLayer {
|
|
|
458
494
|
const fps = args?.filePaths || [];
|
|
459
495
|
const allPaths = fp ? [fp, ...fps] : fps;
|
|
460
496
|
if (metrics?.uniqueFiles) {
|
|
461
|
-
const newPaths = allPaths.filter(p => !metrics.uniqueFiles.has(p));
|
|
497
|
+
const newPaths = allPaths.filter((p) => !metrics.uniqueFiles.has(p));
|
|
462
498
|
meta.gotNewInfo = newPaths.length > 0;
|
|
463
499
|
} else {
|
|
464
500
|
meta.gotNewInfo = allPaths.length > 0;
|
|
@@ -471,7 +507,7 @@ export class ReasoningLayer {
|
|
|
471
507
|
case 'submit_with_check': {
|
|
472
508
|
meta.resultType = 'submit';
|
|
473
509
|
meta.gotNewInfo = true; // submit 本身就是进展
|
|
474
|
-
const status = typeof result === 'object' ?
|
|
510
|
+
const status = typeof result === 'object' ? result?.status || 'ok' : 'ok';
|
|
475
511
|
const title = args?.title || '(untitled)';
|
|
476
512
|
meta.keyFacts.push(`submit "${title}": ${status}`);
|
|
477
513
|
break;
|
|
@@ -582,7 +618,9 @@ export class ReasoningLayer {
|
|
|
582
618
|
*/
|
|
583
619
|
#checkReplan(iteration, explorationMetrics, budget, phase) {
|
|
584
620
|
const plan = this.#trace.getPlan();
|
|
585
|
-
if (!plan)
|
|
621
|
+
if (!plan) {
|
|
622
|
+
return null;
|
|
623
|
+
}
|
|
586
624
|
|
|
587
625
|
const progress = this.#planProgress;
|
|
588
626
|
const interval = this.#config.replanInterval;
|
|
@@ -590,12 +628,14 @@ export class ReasoningLayer {
|
|
|
590
628
|
|
|
591
629
|
// 触发条件
|
|
592
630
|
const baseIteration = progress.lastReplanIteration || plan.createdAtIteration;
|
|
593
|
-
const periodicTrigger = interval > 0 && iteration > 1
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
631
|
+
const periodicTrigger = interval > 0 && iteration > 1 && iteration - baseIteration >= interval;
|
|
632
|
+
const deviationTrigger =
|
|
633
|
+
progress.consecutiveOffPlan >= 3 ||
|
|
634
|
+
(progress.totalSteps > 0 && progress.deviationScore > deviationThreshold);
|
|
597
635
|
|
|
598
|
-
if (!periodicTrigger && !deviationTrigger)
|
|
636
|
+
if (!periodicTrigger && !deviationTrigger) {
|
|
637
|
+
return null;
|
|
638
|
+
}
|
|
599
639
|
|
|
600
640
|
// 构建 replan nudge
|
|
601
641
|
const maxIter = budget?.maxIterations || 30;
|
|
@@ -613,8 +653,8 @@ export class ReasoningLayer {
|
|
|
613
653
|
}
|
|
614
654
|
|
|
615
655
|
// 步骤完成情况
|
|
616
|
-
const doneSteps = plan.steps.filter(s => s.status === 'done');
|
|
617
|
-
const pendingSteps = plan.steps.filter(s => s.status === 'pending');
|
|
656
|
+
const doneSteps = plan.steps.filter((s) => s.status === 'done');
|
|
657
|
+
const pendingSteps = plan.steps.filter((s) => s.status === 'pending');
|
|
618
658
|
|
|
619
659
|
if (doneSteps.length > 0) {
|
|
620
660
|
parts.push(`\n✅ 已完成 (${doneSteps.length}/${plan.steps.length}):`);
|
|
@@ -640,7 +680,9 @@ export class ReasoningLayer {
|
|
|
640
680
|
progress.lastReplanIteration = iteration;
|
|
641
681
|
this.#pendingReplan = true;
|
|
642
682
|
|
|
643
|
-
this.#logger.info(
|
|
683
|
+
this.#logger.info(
|
|
684
|
+
`[ReasoningLayer] 📋 replan triggered at iteration ${iteration} (${deviationTrigger ? 'deviation' : 'periodic'})`
|
|
685
|
+
);
|
|
644
686
|
|
|
645
687
|
return parts.join('\n');
|
|
646
688
|
}
|
|
@@ -653,10 +695,14 @@ export class ReasoningLayer {
|
|
|
653
695
|
*/
|
|
654
696
|
#updatePlanProgress() {
|
|
655
697
|
const steps = this.#trace.getPlanStepsMutable();
|
|
656
|
-
if (steps.length === 0)
|
|
698
|
+
if (steps.length === 0) {
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
657
701
|
|
|
658
702
|
const actions = this.#trace.getCurrentRoundActions();
|
|
659
|
-
if (actions.length === 0)
|
|
703
|
+
if (actions.length === 0) {
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
660
706
|
|
|
661
707
|
let matchedThisRound = false;
|
|
662
708
|
|
|
@@ -678,11 +724,10 @@ export class ReasoningLayer {
|
|
|
678
724
|
}
|
|
679
725
|
|
|
680
726
|
// 重新计算进度
|
|
681
|
-
this.#planProgress.coveredSteps = steps.filter(s => s.status === 'done').length;
|
|
727
|
+
this.#planProgress.coveredSteps = steps.filter((s) => s.status === 'done').length;
|
|
682
728
|
this.#planProgress.totalSteps = steps.length;
|
|
683
|
-
this.#planProgress.deviationScore =
|
|
684
|
-
? 1 -
|
|
685
|
-
: 0;
|
|
729
|
+
this.#planProgress.deviationScore =
|
|
730
|
+
steps.length > 0 ? 1 - this.#planProgress.coveredSteps / steps.length : 0;
|
|
686
731
|
}
|
|
687
732
|
|
|
688
733
|
/**
|
|
@@ -702,35 +747,62 @@ export class ReasoningLayer {
|
|
|
702
747
|
const argsStr = JSON.stringify(action.params || {}).toLowerCase();
|
|
703
748
|
|
|
704
749
|
for (const step of steps) {
|
|
705
|
-
if (step.status === 'done')
|
|
750
|
+
if (step.status === 'done') {
|
|
751
|
+
continue;
|
|
752
|
+
}
|
|
706
753
|
|
|
707
754
|
// 策略 1: 关键词匹配
|
|
708
755
|
if (step.keywords?.length > 0) {
|
|
709
|
-
const matched = step.keywords.some(kw => argsStr.includes(kw.toLowerCase()));
|
|
710
|
-
if (matched)
|
|
756
|
+
const matched = step.keywords.some((kw) => argsStr.includes(kw.toLowerCase()));
|
|
757
|
+
if (matched) {
|
|
758
|
+
return step;
|
|
759
|
+
}
|
|
711
760
|
}
|
|
712
761
|
|
|
713
762
|
// 策略 2: 工具类型 → 步骤描述的语义匹配
|
|
714
763
|
const desc = step.description.toLowerCase();
|
|
715
|
-
if (
|
|
716
|
-
|
|
764
|
+
if (
|
|
765
|
+
toolName === 'get_project_overview' &&
|
|
766
|
+
(desc.includes('概览') ||
|
|
767
|
+
desc.includes('overview') ||
|
|
768
|
+
desc.includes('结构') ||
|
|
769
|
+
desc.includes('项目'))
|
|
770
|
+
) {
|
|
717
771
|
return step;
|
|
718
772
|
}
|
|
719
|
-
if (
|
|
720
|
-
|
|
773
|
+
if (
|
|
774
|
+
toolName === 'list_project_structure' &&
|
|
775
|
+
(desc.includes('目录') || desc.includes('结构') || desc.includes('structure'))
|
|
776
|
+
) {
|
|
721
777
|
return step;
|
|
722
778
|
}
|
|
723
|
-
if (
|
|
724
|
-
|
|
779
|
+
if (
|
|
780
|
+
(toolName === 'get_class_info' || toolName === 'get_class_hierarchy') &&
|
|
781
|
+
(desc.includes('继承') ||
|
|
782
|
+
desc.includes('类') ||
|
|
783
|
+
desc.includes('hierarchy') ||
|
|
784
|
+
desc.includes('class'))
|
|
785
|
+
) {
|
|
725
786
|
return step;
|
|
726
787
|
}
|
|
727
|
-
if (
|
|
728
|
-
|
|
788
|
+
if (
|
|
789
|
+
toolName === 'read_project_file' &&
|
|
790
|
+
(desc.includes('阅读') ||
|
|
791
|
+
desc.includes('read') ||
|
|
792
|
+
desc.includes('深入') ||
|
|
793
|
+
desc.includes('查看') ||
|
|
794
|
+
desc.includes('文件'))
|
|
795
|
+
) {
|
|
729
796
|
return step;
|
|
730
797
|
}
|
|
731
798
|
// search_project_code 匹配更宽松:任何含"搜索/查找/search"的待处理步骤
|
|
732
|
-
if (
|
|
733
|
-
|
|
799
|
+
if (
|
|
800
|
+
toolName === 'search_project_code' &&
|
|
801
|
+
(desc.includes('搜索') ||
|
|
802
|
+
desc.includes('search') ||
|
|
803
|
+
desc.includes('查找') ||
|
|
804
|
+
desc.includes('分析'))
|
|
805
|
+
) {
|
|
734
806
|
return step;
|
|
735
807
|
}
|
|
736
808
|
}
|
|
@@ -750,7 +822,9 @@ export class ReasoningLayer {
|
|
|
750
822
|
* @private
|
|
751
823
|
*/
|
|
752
824
|
#extractPlanFromText(text) {
|
|
753
|
-
if (!text || text.length < 30)
|
|
825
|
+
if (!text || text.length < 30) {
|
|
826
|
+
return null;
|
|
827
|
+
}
|
|
754
828
|
|
|
755
829
|
// 在文本的前 2000 字符中搜索计划
|
|
756
830
|
const searchArea = text.substring(0, 2000);
|
|
@@ -774,13 +848,15 @@ export class ReasoningLayer {
|
|
|
774
848
|
|
|
775
849
|
// 策略 2: 如果没有标记,查找第一个编号列表的起始位置
|
|
776
850
|
if (planStart === -1) {
|
|
777
|
-
const listMatch = searchArea.match(/\n\s*1[
|
|
851
|
+
const listMatch = searchArea.match(/\n\s*1[.)]\s+/);
|
|
778
852
|
if (listMatch) {
|
|
779
853
|
planStart = listMatch.index;
|
|
780
854
|
}
|
|
781
855
|
}
|
|
782
856
|
|
|
783
|
-
if (planStart === -1)
|
|
857
|
+
if (planStart === -1) {
|
|
858
|
+
return null;
|
|
859
|
+
}
|
|
784
860
|
|
|
785
861
|
// 从 planStart 开始提取到列表结束
|
|
786
862
|
const remaining = searchArea.substring(planStart);
|
|
@@ -789,7 +865,7 @@ export class ReasoningLayer {
|
|
|
789
865
|
let inList = false;
|
|
790
866
|
|
|
791
867
|
for (const line of lines) {
|
|
792
|
-
if (/^\s*(?:\d+[
|
|
868
|
+
if (/^\s*(?:\d+[.)]\s+|[-*]\s+)/.test(line)) {
|
|
793
869
|
inList = true;
|
|
794
870
|
planLines.push(line);
|
|
795
871
|
} else if (inList && line.trim() === '') {
|
|
@@ -801,7 +877,9 @@ export class ReasoningLayer {
|
|
|
801
877
|
}
|
|
802
878
|
}
|
|
803
879
|
|
|
804
|
-
if (planLines.length < 2)
|
|
880
|
+
if (planLines.length < 2) {
|
|
881
|
+
return null;
|
|
882
|
+
}
|
|
805
883
|
|
|
806
884
|
return planLines.join('\n').trim();
|
|
807
885
|
}
|
|
@@ -57,7 +57,9 @@ export class ReasoningTrace {
|
|
|
57
57
|
* @param {number} iteration — 轮次编号
|
|
58
58
|
*/
|
|
59
59
|
startRound(iteration) {
|
|
60
|
-
if (this.#currentRound)
|
|
60
|
+
if (this.#currentRound) {
|
|
61
|
+
this.endRound(); // 安全关闭上一轮
|
|
62
|
+
}
|
|
61
63
|
this.#currentRound = {
|
|
62
64
|
iteration,
|
|
63
65
|
thought: null,
|
|
@@ -137,8 +139,8 @@ export class ReasoningTrace {
|
|
|
137
139
|
*/
|
|
138
140
|
getThoughts() {
|
|
139
141
|
return this.#rounds
|
|
140
|
-
.filter(r => r.thought)
|
|
141
|
-
.map(r => ({ iteration: r.iteration, thought: r.thought }));
|
|
142
|
+
.filter((r) => r.thought)
|
|
143
|
+
.map((r) => ({ iteration: r.iteration, thought: r.thought }));
|
|
142
144
|
}
|
|
143
145
|
|
|
144
146
|
/**
|
|
@@ -148,16 +150,19 @@ export class ReasoningTrace {
|
|
|
148
150
|
*/
|
|
149
151
|
getRecentSummary(n = 3) {
|
|
150
152
|
const recent = this.#rounds.slice(-n);
|
|
151
|
-
if (recent.length === 0)
|
|
153
|
+
if (recent.length === 0) {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
152
156
|
|
|
153
157
|
const thoughts = recent
|
|
154
|
-
.filter(r => r.thought)
|
|
155
|
-
.map(r => r.thought.length > 100 ? r.thought.substring(0, 100)
|
|
158
|
+
.filter((r) => r.thought)
|
|
159
|
+
.map((r) => (r.thought.length > 100 ? `${r.thought.substring(0, 100)}…` : r.thought));
|
|
156
160
|
|
|
157
|
-
const tools = recent.flatMap(r => r.actions.map(a => a.tool));
|
|
161
|
+
const tools = recent.flatMap((r) => r.actions.map((a) => a.tool));
|
|
158
162
|
|
|
159
|
-
const newInfoCount = recent.reduce(
|
|
160
|
-
c + r.observations.filter(o => o.gotNewInfo).length,
|
|
163
|
+
const newInfoCount = recent.reduce(
|
|
164
|
+
(c, r) => c + r.observations.filter((o) => o.gotNewInfo).length,
|
|
165
|
+
0
|
|
161
166
|
);
|
|
162
167
|
const totalObs = recent.reduce((c, r) => c + r.observations.length, 0);
|
|
163
168
|
|
|
@@ -177,12 +182,13 @@ export class ReasoningTrace {
|
|
|
177
182
|
getStats() {
|
|
178
183
|
return {
|
|
179
184
|
totalRounds: this.#rounds.length,
|
|
180
|
-
thoughtCount: this.#rounds.filter(r => r.thought).length,
|
|
185
|
+
thoughtCount: this.#rounds.filter((r) => r.thought).length,
|
|
181
186
|
totalActions: this.#rounds.reduce((c, r) => c + r.actions.length, 0),
|
|
182
187
|
totalObservations: this.#rounds.reduce((c, r) => c + r.observations.length, 0),
|
|
183
|
-
reflectionCount: this.#rounds.filter(r => r.reflection).length,
|
|
184
|
-
totalDurationMs: this.#rounds.reduce(
|
|
185
|
-
d + ((r.endTime || Date.now()) - r.startTime),
|
|
188
|
+
reflectionCount: this.#rounds.filter((r) => r.reflection).length,
|
|
189
|
+
totalDurationMs: this.#rounds.reduce(
|
|
190
|
+
(d, r) => d + ((r.endTime || Date.now()) - r.startTime),
|
|
191
|
+
0
|
|
186
192
|
),
|
|
187
193
|
};
|
|
188
194
|
}
|
|
@@ -213,7 +219,7 @@ export class ReasoningTrace {
|
|
|
213
219
|
this.setPlan(replanText, iteration);
|
|
214
220
|
return;
|
|
215
221
|
}
|
|
216
|
-
this.#planHistory.push({ ...this.#plan, steps: this.#plan.steps.map(s => ({ ...s })) });
|
|
222
|
+
this.#planHistory.push({ ...this.#plan, steps: this.#plan.steps.map((s) => ({ ...s })) });
|
|
217
223
|
this.#plan.text = replanText;
|
|
218
224
|
this.#plan.steps = this.#parsePlanSteps(replanText);
|
|
219
225
|
this.#plan.lastUpdatedAtIteration = iteration;
|
|
@@ -224,10 +230,12 @@ export class ReasoningTrace {
|
|
|
224
230
|
* @returns {Plan|null}
|
|
225
231
|
*/
|
|
226
232
|
getPlan() {
|
|
227
|
-
if (!this.#plan)
|
|
233
|
+
if (!this.#plan) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
228
236
|
return {
|
|
229
237
|
...this.#plan,
|
|
230
|
-
steps: this.#plan.steps.map(s => ({ ...s })),
|
|
238
|
+
steps: this.#plan.steps.map((s) => ({ ...s })),
|
|
231
239
|
};
|
|
232
240
|
}
|
|
233
241
|
|
|
@@ -244,7 +252,7 @@ export class ReasoningTrace {
|
|
|
244
252
|
* @returns {Array<Plan>}
|
|
245
253
|
*/
|
|
246
254
|
getPlanHistory() {
|
|
247
|
-
return this.#planHistory.map(p => ({ ...p, steps: p.steps.map(s => ({ ...s })) }));
|
|
255
|
+
return this.#planHistory.map((p) => ({ ...p, steps: p.steps.map((s) => ({ ...s })) }));
|
|
248
256
|
}
|
|
249
257
|
|
|
250
258
|
/**
|
|
@@ -272,12 +280,14 @@ export class ReasoningTrace {
|
|
|
272
280
|
* @private
|
|
273
281
|
*/
|
|
274
282
|
#parsePlanSteps(text) {
|
|
275
|
-
if (!text)
|
|
283
|
+
if (!text) {
|
|
284
|
+
return [];
|
|
285
|
+
}
|
|
276
286
|
const lines = text.split('\n');
|
|
277
287
|
const steps = [];
|
|
278
288
|
for (const line of lines) {
|
|
279
289
|
// 匹配: 1. xxx / - xxx / * xxx / 1) xxx
|
|
280
|
-
const m = line.match(/^\s*(?:\d+[
|
|
290
|
+
const m = line.match(/^\s*(?:\d+[.)]\s*|[-*]\s+)(.+)/);
|
|
281
291
|
if (m && m[1].trim().length > 5) {
|
|
282
292
|
steps.push({
|
|
283
293
|
description: m[1].trim(),
|
|
@@ -297,11 +307,11 @@ export class ReasoningTrace {
|
|
|
297
307
|
*/
|
|
298
308
|
#extractKeywords(text) {
|
|
299
309
|
// 提取反引号/引号内的标识符
|
|
300
|
-
const quoted = [...text.matchAll(/[`"']([A-Za-z_]\w{2,})[`"']/g)].map(m => m[1]);
|
|
310
|
+
const quoted = [...text.matchAll(/[`"']([A-Za-z_]\w{2,})[`"']/g)].map((m) => m[1]);
|
|
301
311
|
// 提取 CamelCase 词
|
|
302
|
-
const camelCase = [...text.matchAll(/\b([A-Z][a-z]+(?:[A-Z][a-z]+)+)\b/g)].map(m => m[0]);
|
|
312
|
+
const camelCase = [...text.matchAll(/\b([A-Z][a-z]+(?:[A-Z][a-z]+)+)\b/g)].map((m) => m[0]);
|
|
303
313
|
// 提取全大写缩写 (如 API, HTTP, URL)
|
|
304
|
-
const acronyms = [...text.matchAll(/\b([A-Z]{2,}[a-z]\w+)\b/g)].map(m => m[0]);
|
|
314
|
+
const acronyms = [...text.matchAll(/\b([A-Z]{2,}[a-z]\w+)\b/g)].map((m) => m[0]);
|
|
305
315
|
return [...new Set([...quoted, ...camelCase, ...acronyms])];
|
|
306
316
|
}
|
|
307
317
|
|
|
@@ -311,17 +321,19 @@ export class ReasoningTrace {
|
|
|
311
321
|
*/
|
|
312
322
|
toJSON() {
|
|
313
323
|
return {
|
|
314
|
-
rounds: this.#rounds.map(r => ({ ...r })),
|
|
324
|
+
rounds: this.#rounds.map((r) => ({ ...r })),
|
|
315
325
|
stats: this.getStats(),
|
|
316
|
-
...(this.#plan
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
326
|
+
...(this.#plan
|
|
327
|
+
? {
|
|
328
|
+
plan: {
|
|
329
|
+
text: this.#plan.text,
|
|
330
|
+
steps: this.#plan.steps.map((s) => ({ ...s })),
|
|
331
|
+
createdAtIteration: this.#plan.createdAtIteration,
|
|
332
|
+
lastUpdatedAtIteration: this.#plan.lastUpdatedAtIteration,
|
|
333
|
+
},
|
|
334
|
+
planHistory: this.#planHistory.length,
|
|
335
|
+
}
|
|
336
|
+
: {}),
|
|
325
337
|
};
|
|
326
338
|
}
|
|
327
339
|
}
|