autosnippet 3.0.0 → 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 +759 -243
- 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
|
@@ -108,8 +108,8 @@ export class EpisodicConsolidator {
|
|
|
108
108
|
|
|
109
109
|
this.#logger.info(
|
|
110
110
|
`[Consolidator] Extracted ${allCandidates.length} candidate memories: ` +
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
`${findingMemories.length} findings, ${insightMemories.length} insights, ` +
|
|
112
|
+
`${textFactMemories.length} text facts`
|
|
113
113
|
);
|
|
114
114
|
|
|
115
115
|
const result = this.#semanticMemory.consolidate(allCandidates, { bootstrapSession });
|
|
@@ -117,8 +117,8 @@ export class EpisodicConsolidator {
|
|
|
117
117
|
const durationMs = Date.now() - t0;
|
|
118
118
|
this.#logger.info(
|
|
119
119
|
`[Consolidator] Consolidation complete in ${durationMs}ms: ` +
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
`+${result.added} ADD, ~${result.updated} UPDATE, ⊕${result.merged} MERGE, ` +
|
|
121
|
+
`=${result.skipped} SKIP`
|
|
122
122
|
);
|
|
123
123
|
|
|
124
124
|
return {
|
|
@@ -143,15 +143,21 @@ export class EpisodicConsolidator {
|
|
|
143
143
|
|
|
144
144
|
for (const dimId of completedDims) {
|
|
145
145
|
const report = episodicMemory.getDimensionReport(dimId);
|
|
146
|
-
if (!report?.findings)
|
|
146
|
+
if (!report?.findings) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
147
149
|
|
|
148
150
|
for (const f of report.findings) {
|
|
149
151
|
// 跳过低重要性的发现
|
|
150
|
-
if ((f.importance || 5) < 4)
|
|
152
|
+
if ((f.importance || 5) < 4) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
151
155
|
|
|
152
156
|
// 跳过过短的发现
|
|
153
|
-
const content = typeof f === 'string' ? f :
|
|
154
|
-
if (content.length < 10)
|
|
157
|
+
const content = typeof f === 'string' ? f : f.finding || '';
|
|
158
|
+
if (content.length < 10) {
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
155
161
|
|
|
156
162
|
// 提取关联实体 (从 evidence 中提取文件名/类名)
|
|
157
163
|
const entities = this.#extractEntities(content, f.evidence);
|
|
@@ -160,9 +166,9 @@ export class EpisodicConsolidator {
|
|
|
160
166
|
type: 'fact',
|
|
161
167
|
content: content.substring(0, 500),
|
|
162
168
|
source: 'bootstrap',
|
|
163
|
-
importance: typeof f === 'string' ? 5 :
|
|
169
|
+
importance: typeof f === 'string' ? 5 : f.importance || 5,
|
|
164
170
|
sourceDimension: dimId,
|
|
165
|
-
sourceEvidence: typeof f === 'string' ? '' :
|
|
171
|
+
sourceEvidence: typeof f === 'string' ? '' : f.evidence || '',
|
|
166
172
|
relatedEntities: entities,
|
|
167
173
|
tags: [dimId],
|
|
168
174
|
});
|
|
@@ -186,8 +192,10 @@ export class EpisodicConsolidator {
|
|
|
186
192
|
|
|
187
193
|
for (const ref of reflections) {
|
|
188
194
|
// 跨维度模式 → insight
|
|
189
|
-
for (const pattern of
|
|
190
|
-
if (pattern.length < 10)
|
|
195
|
+
for (const pattern of ref.crossDimensionPatterns || []) {
|
|
196
|
+
if (pattern.length < 10) {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
191
199
|
memories.push({
|
|
192
200
|
type: 'insight',
|
|
193
201
|
content: pattern.substring(0, 500),
|
|
@@ -200,8 +208,10 @@ export class EpisodicConsolidator {
|
|
|
200
208
|
}
|
|
201
209
|
|
|
202
210
|
// 建议 → insight (较低优先级)
|
|
203
|
-
for (const suggestion of
|
|
204
|
-
if (suggestion.length < 10)
|
|
211
|
+
for (const suggestion of ref.suggestionsForNextTier || []) {
|
|
212
|
+
if (suggestion.length < 10) {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
205
215
|
memories.push({
|
|
206
216
|
type: 'insight',
|
|
207
217
|
content: suggestion.substring(0, 500),
|
|
@@ -213,10 +223,14 @@ export class EpisodicConsolidator {
|
|
|
213
223
|
}
|
|
214
224
|
|
|
215
225
|
// 高重要性 topFindings → fact (≥ 7 分的重要发现)
|
|
216
|
-
for (const f of
|
|
217
|
-
if ((f.importance || 5) < 7)
|
|
218
|
-
|
|
219
|
-
|
|
226
|
+
for (const f of ref.topFindings || []) {
|
|
227
|
+
if ((f.importance || 5) < 7) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
const content = typeof f === 'string' ? f : f.finding || '';
|
|
231
|
+
if (content.length < 10) {
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
220
234
|
|
|
221
235
|
memories.push({
|
|
222
236
|
type: 'fact',
|
|
@@ -246,7 +260,9 @@ export class EpisodicConsolidator {
|
|
|
246
260
|
|
|
247
261
|
for (const dimId of completedDims) {
|
|
248
262
|
const report = episodicMemory.getDimensionReport(dimId);
|
|
249
|
-
if (!report?.analysisText)
|
|
263
|
+
if (!report?.analysisText) {
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
250
266
|
|
|
251
267
|
const text = report.analysisText;
|
|
252
268
|
|
|
@@ -258,8 +274,12 @@ export class EpisodicConsolidator {
|
|
|
258
274
|
let matchCount = 0;
|
|
259
275
|
while ((match = pattern.exec(text)) !== null && matchCount < 5) {
|
|
260
276
|
const fullMatch = match[0].trim();
|
|
261
|
-
if (fullMatch.length < 10 || fullMatch.length > 120)
|
|
262
|
-
|
|
277
|
+
if (fullMatch.length < 10 || fullMatch.length > 120) {
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
if (seen.has(fullMatch)) {
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
263
283
|
seen.add(fullMatch);
|
|
264
284
|
matchCount++;
|
|
265
285
|
|
|
@@ -282,8 +302,12 @@ export class EpisodicConsolidator {
|
|
|
282
302
|
let matchCount = 0;
|
|
283
303
|
while ((match = pattern.exec(text)) !== null && matchCount < 3) {
|
|
284
304
|
const fullMatch = match[0].trim();
|
|
285
|
-
if (fullMatch.length < 10 || fullMatch.length > 120)
|
|
286
|
-
|
|
305
|
+
if (fullMatch.length < 10 || fullMatch.length > 120) {
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
if (seen.has(fullMatch)) {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
287
311
|
seen.add(fullMatch);
|
|
288
312
|
matchCount++;
|
|
289
313
|
|
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
* 这些内容如果传给 Producer,会干扰其正常工作流。
|
|
19
19
|
*/
|
|
20
20
|
function sanitizeAnalysisText(text) {
|
|
21
|
-
if (!text)
|
|
21
|
+
if (!text) {
|
|
22
|
+
return '';
|
|
23
|
+
}
|
|
22
24
|
// 移除 graceful exit nudge 及 digest 模板指令
|
|
23
25
|
const patterns = [
|
|
24
26
|
/\*{0,2}⚠️?\s*(?:你已使用|轮次即将耗尽|仅剩|请立即停止|必须立即结束)[^\n]*\n?/gi,
|
|
@@ -28,6 +30,63 @@ function sanitizeAnalysisText(text) {
|
|
|
28
30
|
/> ?⚠️ 严禁输出任何非 JSON 内容[^\n]*\n?/gi,
|
|
29
31
|
// 移除 AI 回显的 dimensionDigest JSON 块(对 Producer 无价值且会干扰)
|
|
30
32
|
/```json\s*\n\s*\{\s*"dimensionDigest"\s*:[\s\S]*?\n```/g,
|
|
33
|
+
|
|
34
|
+
// ── AI 思考伪影清理 ──
|
|
35
|
+
|
|
36
|
+
// 轮次/阶段计数器(如 "第 18/24 轮 | 验证阶段 | 剩余 6 轮")
|
|
37
|
+
/^-{2,3}\s*\n\s*第\s*\d+\/\d+\s*轮[^\n]*\n(-{2,3}\s*\n)?/gm,
|
|
38
|
+
// 独立分隔线 + 空内容
|
|
39
|
+
/^-{3}\s*$/gm,
|
|
40
|
+
|
|
41
|
+
// AI 规划/反思段落("计划偏差分析"、"最终总结阶段" 等)
|
|
42
|
+
/^#{1,3}\s*(?:计划偏差分析|最终总结阶段|执行计划|下一步计划|分析计划)\s*\n[\s\S]*?(?=\n#{1,3}\s|\n\n(?=[^#\s-]))/gm,
|
|
43
|
+
|
|
44
|
+
// 系统提示回显("(提示: ...)")
|
|
45
|
+
/^\(提示[::][^)]*\)\s*\n?/gm,
|
|
46
|
+
|
|
47
|
+
// AI 英文思考泄漏("Wait, I have enough information..."、"Let me..."、"I'll stop here...")
|
|
48
|
+
/^(?:Wait,|Let me|I'll stop here|I will stop|I need to|I should|I have enough)[^\n]*\n?/gm,
|
|
49
|
+
|
|
50
|
+
// 工具提示循环("尝试使用 `tool_name`..."、"- 尝试使用...")
|
|
51
|
+
/^[-•]\s*尝试使用\s*`[^`]+`[^\n]*\n?/gm,
|
|
52
|
+
/^💡\s*提示[::]?\s*\n?/gm,
|
|
53
|
+
|
|
54
|
+
// 请继续 / 请接续 单行(AI 被截断后的续写请求)
|
|
55
|
+
/^请(?:继续|接续)[。.]?\s*$/gm,
|
|
56
|
+
|
|
57
|
+
// 📊 中期反思块("📊 中期反思 (第 N/M 轮, X% 预算):" 及后续所有内容直到下一个 ## 或 📊)
|
|
58
|
+
/📊\s*中期反思\s*\([^)]*\):?\s*\n(?:[\s\S]*?(?=\n#{1,3}\s(?!探索计划|第\s*\d)|\n(?=📊)|$))/gm,
|
|
59
|
+
|
|
60
|
+
// AI 思考方向列表("你最近的思考方向:" + 编号列表 + 嵌套的探索计划)
|
|
61
|
+
/^你最近的思考方向:\s*\n(?:[\s\S]*?(?=\n#{1,3}\s(?!探索计划|第\s*\d)|\n(?=📊)|$))/gm,
|
|
62
|
+
|
|
63
|
+
// AI 探索计划标题("### 探索计划")— 这是 AI 内部规划,不应出现在最终输出中
|
|
64
|
+
/^#{1,3}\s*探索计划\s*\n(?:[\s\S]*?(?=\n#{1,3}\s(?!探索计划)|\n\n(?=[^#\s\d-])|\n(?=📊)|$))/gm,
|
|
65
|
+
// 编号前缀的探索计划(" 1. ### 探索计划" + 紧随的编号列表项)
|
|
66
|
+
/^\s*\d+\.\s+#{1,3}\s*探索计划[^\n]*\n(?:\d+\.\s+\*{0,2}[^\n]*\n?)*/gm,
|
|
67
|
+
|
|
68
|
+
// AI 轮次标题("### 第 N 轮:..." 开头的规划/反思段落)
|
|
69
|
+
/^#{1,3}\s*第\s*\d+\s*轮[::][^\n]*\n(?:[\s\S]*?(?=\n#{1,3}\s(?!探索计划|第\s*\d)|\n\n(?=#{1,3}\s)|\n(?=📊)|$))/gm,
|
|
70
|
+
|
|
71
|
+
// 行动效率统计行("行动效率: 最近 N 轮中 X% 获取到新信息")
|
|
72
|
+
/^行动效率[::][^\n]*\n?/gm,
|
|
73
|
+
/^累计[::]\s*\d+\s*文件[^\n]*\n?/gm,
|
|
74
|
+
|
|
75
|
+
// 计划进度("📋 计划进度: 0/1 步骤已完成")
|
|
76
|
+
/^📋\s*计划进度[::][^\n]*\n?/gm,
|
|
77
|
+
|
|
78
|
+
// 请评估提示块("请评估: 1. ...")
|
|
79
|
+
/^请评估[::]\s*\n(?:\s*\d+\.\s+[^\n]*\n?)*/gm,
|
|
80
|
+
|
|
81
|
+
// AI 对话提示回显("(请在继续调用工具前...)", "(由于当前已是第 N 轮...)", "(注意: 每一轮都必须...)")
|
|
82
|
+
/^\([请由注](?:在继续|于当前|意[::])[^)]*\)\s*\n?/gm,
|
|
83
|
+
|
|
84
|
+
// AI 步骤进度与计划更新("已经读取,未完成步骤..."、"计划更新:..."、"更新后的计划:...")
|
|
85
|
+
/^(?:\d+\.\s+)?(?:`[^`]*`\s+)?(?:已经读取|未完成步骤仅剩|计划更新|更新后的计划)[^\n]*\n?/gm,
|
|
86
|
+
/^更新后的计划[::]\s*\n(?:\s*\d+\.\s+[^\n]*\n?)*/gm,
|
|
87
|
+
|
|
88
|
+
// 纯数字编号残留行(清理被上面 pattern 删除后留下的孤立编号)
|
|
89
|
+
/^\s*\d+\.\s*$/gm,
|
|
31
90
|
];
|
|
32
91
|
let cleaned = text;
|
|
33
92
|
for (const pat of patterns) {
|
|
@@ -53,24 +112,30 @@ export function buildAnalysisReport(analystResult, dimensionId, projectGraph = n
|
|
|
53
112
|
const searchQueries = [];
|
|
54
113
|
const classesExplored = [];
|
|
55
114
|
|
|
56
|
-
for (const call of
|
|
115
|
+
for (const call of analystResult.toolCalls || []) {
|
|
57
116
|
const tool = call.tool || call.name;
|
|
58
117
|
const args = call.params || call.args || {};
|
|
59
118
|
const result = call.result;
|
|
60
119
|
|
|
61
120
|
switch (tool) {
|
|
62
121
|
case 'read_project_file':
|
|
63
|
-
if (args.filePath)
|
|
122
|
+
if (args.filePath) {
|
|
123
|
+
referencedFiles.add(args.filePath);
|
|
124
|
+
}
|
|
64
125
|
break;
|
|
65
126
|
case 'search_project_code':
|
|
66
|
-
if (args.pattern || args.query)
|
|
127
|
+
if (args.pattern || args.query) {
|
|
128
|
+
searchQueries.push(args.pattern || args.query);
|
|
129
|
+
}
|
|
67
130
|
// 从搜索结果中提取文件路径
|
|
68
131
|
if (typeof result === 'string') {
|
|
69
|
-
const fileMatches = result.match(/(?:^|\n)([\w/.-]+\.
|
|
132
|
+
const fileMatches = result.match(/(?:^|\n)([\w/.-]+\.(?:go|mod|sum|py|pyi|java|kt|kts|js|ts|jsx|tsx|mjs|cjs|swift|m|h|c|cpp|cc|hpp|cs|rb|rs|sql|json|yaml|yml|toml|xml|html|css|scss|less|sh|md|txt|gradle|properties|proto|vue|svelte|graphql|cfg|conf|ini|env|lock|rst))(?::\d+)?/gi);
|
|
70
133
|
if (fileMatches) {
|
|
71
134
|
for (const m of fileMatches) {
|
|
72
135
|
const clean = m.trim().replace(/:\d+$/, '').replace(/^\n/, '');
|
|
73
|
-
if (clean.length > 2 && clean.length < 120)
|
|
136
|
+
if (clean.length > 2 && clean.length < 120) {
|
|
137
|
+
referencedFiles.add(clean);
|
|
138
|
+
}
|
|
74
139
|
}
|
|
75
140
|
}
|
|
76
141
|
}
|
|
@@ -81,28 +146,35 @@ export function buildAnalysisReport(analystResult, dimensionId, projectGraph = n
|
|
|
81
146
|
// 从 ProjectGraph 反查文件路径
|
|
82
147
|
if (projectGraph) {
|
|
83
148
|
const info = projectGraph.getClassInfo(args.className);
|
|
84
|
-
if (info?.filePath)
|
|
149
|
+
if (info?.filePath) {
|
|
150
|
+
referencedFiles.add(info.filePath);
|
|
151
|
+
}
|
|
85
152
|
}
|
|
86
153
|
}
|
|
87
154
|
break;
|
|
88
155
|
case 'get_protocol_info':
|
|
89
156
|
if (args.protocolName && projectGraph) {
|
|
90
157
|
const info = projectGraph.getProtocolInfo(args.protocolName);
|
|
91
|
-
if (info?.filePath)
|
|
158
|
+
if (info?.filePath) {
|
|
159
|
+
referencedFiles.add(info.filePath);
|
|
160
|
+
}
|
|
92
161
|
}
|
|
93
162
|
break;
|
|
94
163
|
case 'get_file_summary':
|
|
95
|
-
if (args.filePath)
|
|
164
|
+
if (args.filePath) {
|
|
165
|
+
referencedFiles.add(args.filePath);
|
|
166
|
+
}
|
|
96
167
|
break;
|
|
97
168
|
}
|
|
98
169
|
}
|
|
99
170
|
|
|
100
|
-
//
|
|
171
|
+
// 从分析文本中提取文件路径(支持多语言项目)
|
|
101
172
|
const text = sanitizeAnalysisText(analystResult.reply || '');
|
|
102
|
-
const
|
|
173
|
+
const FILE_EXT_RE = /[\w/.-]+\.(?:go|mod|sum|py|pyi|java|kt|kts|js|ts|jsx|tsx|mjs|cjs|swift|m|h|c|cpp|cc|hpp|cs|rb|rs|sql|json|yaml|yml|toml|xml|html|css|scss|less|sh|md|txt|gradle|properties|proto|vue|svelte|graphql|cfg|conf|ini|env|lock|rst)\b/gi;
|
|
174
|
+
const textFileRefs = text.match(FILE_EXT_RE);
|
|
103
175
|
if (textFileRefs) {
|
|
104
176
|
for (const f of textFileRefs) {
|
|
105
|
-
if (f.length > 2 && f.length < 120
|
|
177
|
+
if (f.length > 2 && f.length < 120) {
|
|
106
178
|
referencedFiles.add(f);
|
|
107
179
|
}
|
|
108
180
|
}
|
|
@@ -156,19 +228,20 @@ export function analysisQualityGate(report, options = {}) {
|
|
|
156
228
|
/I cannot|I'm unable|I don't have access/i,
|
|
157
229
|
/无法分析|无法访问|没有足够/,
|
|
158
230
|
];
|
|
159
|
-
if (refusalPatterns.some(p => p.test(report.analysisText))) {
|
|
231
|
+
if (refusalPatterns.some((p) => p.test(report.analysisText))) {
|
|
160
232
|
return { pass: false, reason: 'Agent refused to analyze', action: 'degrade' };
|
|
161
233
|
}
|
|
162
234
|
|
|
163
235
|
// 规则 4: 内容实质性检查 — 有结构化内容或足够多的探索
|
|
164
236
|
// v3.1: 放宽条件 — tool calling 模式下 AI 往往不输出 markdown 格式
|
|
165
237
|
// 只要分析足够长且引用了足够多的文件,就认为有实质性内容
|
|
166
|
-
const hasStructure =
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
238
|
+
const hasStructure =
|
|
239
|
+
/#{1,3}\s/.test(report.analysisText) ||
|
|
240
|
+
/\d+\.\s/.test(report.analysisText) ||
|
|
241
|
+
/[-•]\s/.test(report.analysisText) ||
|
|
242
|
+
/[::].+\n/.test(report.analysisText) ||
|
|
243
|
+
report.analysisText.length >= 500 ||
|
|
244
|
+
(report.referencedFiles.length >= 3 && report.analysisText.length >= 200);
|
|
172
245
|
if (!hasStructure) {
|
|
173
246
|
return { pass: false, reason: 'Analysis lacks structure', action: 'retry' };
|
|
174
247
|
}
|
|
@@ -184,9 +257,12 @@ export function analysisQualityGate(report, options = {}) {
|
|
|
184
257
|
*/
|
|
185
258
|
export function buildRetryPrompt(reason) {
|
|
186
259
|
const hints = {
|
|
187
|
-
'Analysis too short':
|
|
188
|
-
|
|
189
|
-
'
|
|
260
|
+
'Analysis too short':
|
|
261
|
+
'你的分析不够深入。请使用更多工具(get_class_info、read_project_file、search_project_code)查看实际代码,输出至少 500 字的分析。',
|
|
262
|
+
'Too few file references':
|
|
263
|
+
'你的分析缺少代码引用。请使用 get_class_info 和 read_project_file 查看至少 3 个相关文件,并在分析中引用具体文件和行号。',
|
|
264
|
+
'Analysis lacks structure':
|
|
265
|
+
'请将分析组织成结构化的段落,使用编号列表或标题来区分不同的发现。每个发现应包含具体的文件路径和代码位置。',
|
|
190
266
|
};
|
|
191
267
|
|
|
192
268
|
return hints[reason] || '请更深入地分析代码,引用至少 3 个具体文件,每个发现都要有代码证据。';
|
|
@@ -51,16 +51,26 @@ export class Memory {
|
|
|
51
51
|
*/
|
|
52
52
|
load(limit = 20, { source } = {}) {
|
|
53
53
|
try {
|
|
54
|
-
if (!fs.existsSync(this.#filePath))
|
|
54
|
+
if (!fs.existsSync(this.#filePath)) {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
55
57
|
const raw = fs.readFileSync(this.#filePath, 'utf-8').trim();
|
|
56
|
-
if (!raw)
|
|
58
|
+
if (!raw) {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
57
61
|
const lines = raw.split('\n').filter(Boolean);
|
|
58
62
|
const now = Date.now();
|
|
59
63
|
return lines
|
|
60
|
-
.map(
|
|
64
|
+
.map((l) => {
|
|
65
|
+
try {
|
|
66
|
+
return JSON.parse(l);
|
|
67
|
+
} catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
})
|
|
61
71
|
.filter(Boolean)
|
|
62
|
-
.filter(m => !m.ttl ||
|
|
63
|
-
.filter(m => !source || (m.source || 'user') === source)
|
|
72
|
+
.filter((m) => !m.ttl || now - new Date(m.ts).getTime() < m.ttl * 86400000)
|
|
73
|
+
.filter((m) => !source || (m.source || 'user') === source)
|
|
64
74
|
.slice(-limit);
|
|
65
75
|
} catch {
|
|
66
76
|
return [];
|
|
@@ -77,9 +87,11 @@ export class Memory {
|
|
|
77
87
|
const existing = this.load(this.#maxEntries);
|
|
78
88
|
const normalizedContent = (entry.content || '').trim().substring(0, 200);
|
|
79
89
|
const isDuplicate = existing.some(
|
|
80
|
-
m => m.type === entry.type && m.content === normalizedContent
|
|
90
|
+
(m) => m.type === entry.type && m.content === normalizedContent
|
|
81
91
|
);
|
|
82
|
-
if (isDuplicate)
|
|
92
|
+
if (isDuplicate) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
83
95
|
|
|
84
96
|
const dir = path.dirname(this.#filePath);
|
|
85
97
|
fs.mkdirSync(dir, { recursive: true });
|
|
@@ -89,9 +101,11 @@ export class Memory {
|
|
|
89
101
|
...entry,
|
|
90
102
|
content: normalizedContent,
|
|
91
103
|
});
|
|
92
|
-
fs.appendFileSync(this.#filePath, line
|
|
104
|
+
fs.appendFileSync(this.#filePath, `${line}\n`, 'utf-8');
|
|
93
105
|
this.#compact();
|
|
94
|
-
} catch {
|
|
106
|
+
} catch {
|
|
107
|
+
/* write failure non-critical */
|
|
108
|
+
}
|
|
95
109
|
}
|
|
96
110
|
|
|
97
111
|
/**
|
|
@@ -105,8 +119,10 @@ export class Memory {
|
|
|
105
119
|
*/
|
|
106
120
|
toPromptSection({ source } = {}) {
|
|
107
121
|
const memories = this.load(20, { source });
|
|
108
|
-
if (memories.length === 0)
|
|
109
|
-
|
|
122
|
+
if (memories.length === 0) {
|
|
123
|
+
return '';
|
|
124
|
+
}
|
|
125
|
+
const lines = memories.map((m) => `- [${m.type}] ${m.content}`).join('\n');
|
|
110
126
|
return `\n## 历史记忆\n以下是之前对话中积累的项目偏好和决策,请参考:\n${lines}\n`;
|
|
111
127
|
}
|
|
112
128
|
|
|
@@ -125,12 +141,16 @@ export class Memory {
|
|
|
125
141
|
#compact() {
|
|
126
142
|
try {
|
|
127
143
|
const raw = fs.readFileSync(this.#filePath, 'utf-8').trim();
|
|
128
|
-
if (!raw)
|
|
144
|
+
if (!raw) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
129
147
|
const lines = raw.split('\n').filter(Boolean);
|
|
130
148
|
if (lines.length > this.#maxEntries) {
|
|
131
|
-
fs.writeFileSync(this.#filePath, lines.slice(-this.#maxEntries).join('\n')
|
|
149
|
+
fs.writeFileSync(this.#filePath, `${lines.slice(-this.#maxEntries).join('\n')}\n`, 'utf-8');
|
|
132
150
|
}
|
|
133
|
-
} catch {
|
|
151
|
+
} catch {
|
|
152
|
+
/* ignore */
|
|
153
|
+
}
|
|
134
154
|
}
|
|
135
155
|
}
|
|
136
156
|
|
|
@@ -55,18 +55,14 @@ const PRODUCER_SYSTEM_PROMPT = `你是知识管理专家。你会收到一段代
|
|
|
55
55
|
// Producer 可用工具白名单 — 只做格式化和提交
|
|
56
56
|
// ──────────────────────────────────────────────────────────────────
|
|
57
57
|
|
|
58
|
-
const PRODUCER_TOOLS = [
|
|
59
|
-
'submit_knowledge',
|
|
60
|
-
'submit_with_check',
|
|
61
|
-
'read_project_file',
|
|
62
|
-
];
|
|
58
|
+
const PRODUCER_TOOLS = ['submit_knowledge', 'submit_with_check', 'read_project_file'];
|
|
63
59
|
|
|
64
60
|
// ──────────────────────────────────────────────────────────────────
|
|
65
61
|
// Producer 预算 — 格式化任务,迭代更少
|
|
66
62
|
// ──────────────────────────────────────────────────────────────────
|
|
67
63
|
|
|
68
64
|
const PRODUCER_BUDGET = {
|
|
69
|
-
maxIterations: 24,
|
|
65
|
+
maxIterations: 24, // was 18 — 与 Analyst 统一
|
|
70
66
|
searchBudget: 4,
|
|
71
67
|
searchBudgetGrace: 3,
|
|
72
68
|
maxSubmits: 10,
|
|
@@ -111,7 +107,7 @@ submit_knowledge 的 content.markdown 字段必须是「项目特写」。
|
|
|
111
107
|
- dontClause: 反向约束英文描述(不以 "Don't" 开头,调用方会加前缀)。如 "use @synchronized for singleton"
|
|
112
108
|
- whenClause: 触发场景英文。如 "When implementing singleton pattern or global shared instance"
|
|
113
109
|
- topicHint: 主题分类,取值 networking / ui / data / architecture / conventions
|
|
114
|
-
- coreCode: 最典型纯代码片段 3-8 行(不含 Markdown 格式、无 # 标题、无围栏、无 >
|
|
110
|
+
- coreCode: 最典型纯代码片段 3-8 行(不含 Markdown 格式、无 # 标题、无围栏、无 > 引用;必须语法完整——括号配对、不以 } 或 ) 开头、不以 { 或 ( 结尾)
|
|
115
111
|
|
|
116
112
|
### 规范
|
|
117
113
|
1. trigger 以 @ 开头,kebab-case,不得在同一批次重复
|
|
@@ -208,7 +204,9 @@ export class ProducerAgent {
|
|
|
208
204
|
}
|
|
209
205
|
|
|
210
206
|
const prompt = buildProducerPrompt(analysisReport, dimConfig, projectInfo);
|
|
211
|
-
this.#logger.info(
|
|
207
|
+
this.#logger.info(
|
|
208
|
+
`[ProducerAgent] ▶ producing candidates for "${dimId}" — prompt ${prompt.length} chars`
|
|
209
|
+
);
|
|
212
210
|
|
|
213
211
|
const budget = options.budget
|
|
214
212
|
? { ...PRODUCER_BUDGET, ...options.budget }
|
|
@@ -233,24 +231,38 @@ export class ProducerAgent {
|
|
|
233
231
|
|
|
234
232
|
// 统计提交 (区分成功/失败)
|
|
235
233
|
const submitCalls = (result.toolCalls || []).filter(
|
|
236
|
-
|
|
234
|
+
(tc) =>
|
|
235
|
+
(tc.tool || tc.name) === 'submit_knowledge' ||
|
|
236
|
+
(tc.tool || tc.name) === 'submit_with_check'
|
|
237
237
|
);
|
|
238
|
-
const successCount = submitCalls.filter(tc => {
|
|
238
|
+
const successCount = submitCalls.filter((tc) => {
|
|
239
239
|
const res = tc.result;
|
|
240
|
-
if (!res)
|
|
241
|
-
|
|
240
|
+
if (!res) {
|
|
241
|
+
return true; // 无结果信息默认成功
|
|
242
|
+
}
|
|
243
|
+
if (typeof res === 'string') {
|
|
244
|
+
return !res.includes('rejected') && !res.includes('error');
|
|
245
|
+
}
|
|
242
246
|
return res.status !== 'rejected' && res.status !== 'error';
|
|
243
247
|
}).length;
|
|
244
248
|
const rejectedCount = submitCalls.length - successCount;
|
|
245
249
|
|
|
246
250
|
// ── 拒绝率过高时追加一轮修正尝试 ──
|
|
247
|
-
if (
|
|
248
|
-
|
|
251
|
+
if (
|
|
252
|
+
rejectedCount > successCount &&
|
|
253
|
+
rejectedCount >= 2 &&
|
|
254
|
+
options.retryOnRejection !== false
|
|
255
|
+
) {
|
|
256
|
+
this.#logger.info(
|
|
257
|
+
`[ProducerAgent] 高拒绝率 (${rejectedCount}/${submitCalls.length}) — 尝试修正`
|
|
258
|
+
);
|
|
249
259
|
try {
|
|
250
260
|
const retryPrompt = `你的 ${rejectedCount} 个提交被拒绝了。请根据拒绝原因改进后重新提交,确保:\n1. content.markdown 字段 ≥ 200 字符\n2. 包含代码块 (\`\`\`)\n3. 包含来源标注 (来源: FileName.m:行号)\n4. 标题使用项目真实类名\n5. 必填: trigger (@kebab-case)、kind (rule/pattern/fact)、doClause (英文祈使句)`;
|
|
251
261
|
const retryResult = await this.#chatAgent.execute(retryPrompt, {
|
|
252
262
|
source: 'system',
|
|
253
|
-
conversationId: options.sessionId
|
|
263
|
+
conversationId: options.sessionId
|
|
264
|
+
? `producer-retry-${options.sessionId}-${dimId}`
|
|
265
|
+
: undefined,
|
|
254
266
|
budget: { ...budget, maxIterations: 5, maxSubmits: rejectedCount },
|
|
255
267
|
systemPromptOverride: PRODUCER_SYSTEM_PROMPT,
|
|
256
268
|
allowedTools: PRODUCER_TOOLS,
|
|
@@ -265,12 +277,18 @@ export class ProducerAgent {
|
|
|
265
277
|
});
|
|
266
278
|
|
|
267
279
|
const retrySubmits = (retryResult.toolCalls || []).filter(
|
|
268
|
-
|
|
280
|
+
(tc) =>
|
|
281
|
+
(tc.tool || tc.name) === 'submit_knowledge' ||
|
|
282
|
+
(tc.tool || tc.name) === 'submit_with_check'
|
|
269
283
|
);
|
|
270
|
-
const retrySuccess = retrySubmits.filter(tc => {
|
|
284
|
+
const retrySuccess = retrySubmits.filter((tc) => {
|
|
271
285
|
const res = tc.result;
|
|
272
|
-
if (!res)
|
|
273
|
-
|
|
286
|
+
if (!res) {
|
|
287
|
+
return true;
|
|
288
|
+
}
|
|
289
|
+
if (typeof res === 'string') {
|
|
290
|
+
return !res.includes('rejected') && !res.includes('error');
|
|
291
|
+
}
|
|
274
292
|
return res.status !== 'rejected' && res.status !== 'error';
|
|
275
293
|
}).length;
|
|
276
294
|
|
|
@@ -297,7 +315,9 @@ export class ProducerAgent {
|
|
|
297
315
|
}
|
|
298
316
|
}
|
|
299
317
|
|
|
300
|
-
this.#logger.info(
|
|
318
|
+
this.#logger.info(
|
|
319
|
+
`[ProducerAgent] ✅ dimension "${dimId}" — ${successCount} candidates created (${rejectedCount} rejected), ${result.toolCalls?.length || 0} total tool calls`
|
|
320
|
+
);
|
|
301
321
|
|
|
302
322
|
return {
|
|
303
323
|
candidateCount: successCount,
|