attocode 0.2.1 → 0.2.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/CHANGELOG.md +91 -1
- package/README.md +7 -0
- package/dist/src/adapters.d.ts +6 -1
- package/dist/src/adapters.d.ts.map +1 -1
- package/dist/src/adapters.js +8 -1
- package/dist/src/adapters.js.map +1 -1
- package/dist/src/agent.d.ts +35 -4
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +361 -45
- package/dist/src/agent.js.map +1 -1
- package/dist/src/defaults.d.ts +1 -1
- package/dist/src/defaults.d.ts.map +1 -1
- package/dist/src/defaults.js +2 -0
- package/dist/src/defaults.js.map +1 -1
- package/dist/src/integrations/agent-registry.d.ts +2 -0
- package/dist/src/integrations/agent-registry.d.ts.map +1 -1
- package/dist/src/integrations/agent-registry.js.map +1 -1
- package/dist/src/integrations/async-subagent.d.ts +135 -0
- package/dist/src/integrations/async-subagent.d.ts.map +1 -0
- package/dist/src/integrations/async-subagent.js +213 -0
- package/dist/src/integrations/async-subagent.js.map +1 -0
- package/dist/src/integrations/auto-checkpoint.d.ts +98 -0
- package/dist/src/integrations/auto-checkpoint.d.ts.map +1 -0
- package/dist/src/integrations/auto-checkpoint.js +252 -0
- package/dist/src/integrations/auto-checkpoint.js.map +1 -0
- package/dist/src/integrations/complexity-classifier.d.ts +86 -0
- package/dist/src/integrations/complexity-classifier.d.ts.map +1 -0
- package/dist/src/integrations/complexity-classifier.js +233 -0
- package/dist/src/integrations/complexity-classifier.js.map +1 -0
- package/dist/src/integrations/delegation-protocol.d.ts +86 -0
- package/dist/src/integrations/delegation-protocol.d.ts.map +1 -0
- package/dist/src/integrations/delegation-protocol.js +127 -0
- package/dist/src/integrations/delegation-protocol.js.map +1 -0
- package/dist/src/integrations/dynamic-budget.d.ts +81 -0
- package/dist/src/integrations/dynamic-budget.d.ts.map +1 -0
- package/dist/src/integrations/dynamic-budget.js +151 -0
- package/dist/src/integrations/dynamic-budget.js.map +1 -0
- package/dist/src/integrations/economics.d.ts +44 -1
- package/dist/src/integrations/economics.d.ts.map +1 -1
- package/dist/src/integrations/economics.js +182 -3
- package/dist/src/integrations/economics.js.map +1 -1
- package/dist/src/integrations/environment-facts.d.ts +52 -0
- package/dist/src/integrations/environment-facts.d.ts.map +1 -0
- package/dist/src/integrations/environment-facts.js +84 -0
- package/dist/src/integrations/environment-facts.js.map +1 -0
- package/dist/src/integrations/index.d.ts +16 -1
- package/dist/src/integrations/index.d.ts.map +1 -1
- package/dist/src/integrations/index.js +31 -1
- package/dist/src/integrations/index.js.map +1 -1
- package/dist/src/integrations/injection-budget.d.ts +71 -0
- package/dist/src/integrations/injection-budget.d.ts.map +1 -0
- package/dist/src/integrations/injection-budget.js +136 -0
- package/dist/src/integrations/injection-budget.js.map +1 -0
- package/dist/src/integrations/mcp-client.d.ts.map +1 -1
- package/dist/src/integrations/mcp-client.js +14 -0
- package/dist/src/integrations/mcp-client.js.map +1 -1
- package/dist/src/integrations/mcp-custom-tools.d.ts +102 -0
- package/dist/src/integrations/mcp-custom-tools.d.ts.map +1 -0
- package/dist/src/integrations/mcp-custom-tools.js +232 -0
- package/dist/src/integrations/mcp-custom-tools.js.map +1 -0
- package/dist/src/integrations/mcp-tool-validator.d.ts +60 -0
- package/dist/src/integrations/mcp-tool-validator.d.ts.map +1 -0
- package/dist/src/integrations/mcp-tool-validator.js +141 -0
- package/dist/src/integrations/mcp-tool-validator.js.map +1 -0
- package/dist/src/integrations/self-improvement.d.ts +90 -0
- package/dist/src/integrations/self-improvement.d.ts.map +1 -0
- package/dist/src/integrations/self-improvement.js +217 -0
- package/dist/src/integrations/self-improvement.js.map +1 -0
- package/dist/src/integrations/smart-decomposer.d.ts +4 -0
- package/dist/src/integrations/smart-decomposer.d.ts.map +1 -1
- package/dist/src/integrations/smart-decomposer.js +55 -28
- package/dist/src/integrations/smart-decomposer.js.map +1 -1
- package/dist/src/integrations/subagent-output-store.d.ts +91 -0
- package/dist/src/integrations/subagent-output-store.d.ts.map +1 -0
- package/dist/src/integrations/subagent-output-store.js +257 -0
- package/dist/src/integrations/subagent-output-store.js.map +1 -0
- package/dist/src/integrations/swarm/index.d.ts +1 -1
- package/dist/src/integrations/swarm/index.d.ts.map +1 -1
- package/dist/src/integrations/swarm/index.js +1 -1
- package/dist/src/integrations/swarm/index.js.map +1 -1
- package/dist/src/integrations/swarm/model-selector.d.ts +1 -0
- package/dist/src/integrations/swarm/model-selector.d.ts.map +1 -1
- package/dist/src/integrations/swarm/model-selector.js +37 -3
- package/dist/src/integrations/swarm/model-selector.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-config-loader.d.ts +10 -1
- package/dist/src/integrations/swarm/swarm-config-loader.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-config-loader.js +72 -6
- package/dist/src/integrations/swarm/swarm-config-loader.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-event-bridge.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-event-bridge.js +26 -4
- package/dist/src/integrations/swarm/swarm-event-bridge.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-events.d.ts +11 -0
- package/dist/src/integrations/swarm/swarm-events.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-events.js +4 -0
- package/dist/src/integrations/swarm/swarm-events.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-orchestrator.d.ts +11 -0
- package/dist/src/integrations/swarm/swarm-orchestrator.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-orchestrator.js +233 -10
- package/dist/src/integrations/swarm/swarm-orchestrator.js.map +1 -1
- package/dist/src/integrations/swarm/swarm-quality-gate.d.ts +9 -2
- package/dist/src/integrations/swarm/swarm-quality-gate.d.ts.map +1 -1
- package/dist/src/integrations/swarm/swarm-quality-gate.js +128 -11
- package/dist/src/integrations/swarm/swarm-quality-gate.js.map +1 -1
- package/dist/src/integrations/swarm/task-queue.d.ts +11 -1
- package/dist/src/integrations/swarm/task-queue.d.ts.map +1 -1
- package/dist/src/integrations/swarm/task-queue.js +125 -15
- package/dist/src/integrations/swarm/task-queue.js.map +1 -1
- package/dist/src/integrations/swarm/types.d.ts +40 -1
- package/dist/src/integrations/swarm/types.d.ts.map +1 -1
- package/dist/src/integrations/swarm/types.js +6 -1
- package/dist/src/integrations/swarm/types.js.map +1 -1
- package/dist/src/integrations/swarm/worker-pool.d.ts +9 -3
- package/dist/src/integrations/swarm/worker-pool.d.ts.map +1 -1
- package/dist/src/integrations/swarm/worker-pool.js +89 -17
- package/dist/src/integrations/swarm/worker-pool.js.map +1 -1
- package/dist/src/integrations/thinking-strategy.d.ts +52 -0
- package/dist/src/integrations/thinking-strategy.d.ts.map +1 -0
- package/dist/src/integrations/thinking-strategy.js +129 -0
- package/dist/src/integrations/thinking-strategy.js.map +1 -0
- package/dist/src/integrations/tool-recommendation.d.ts +58 -0
- package/dist/src/integrations/tool-recommendation.d.ts.map +1 -0
- package/dist/src/integrations/tool-recommendation.js +215 -0
- package/dist/src/integrations/tool-recommendation.js.map +1 -0
- package/dist/src/integrations/verification-gate.d.ts +80 -0
- package/dist/src/integrations/verification-gate.d.ts.map +1 -0
- package/dist/src/integrations/verification-gate.js +146 -0
- package/dist/src/integrations/verification-gate.js.map +1 -0
- package/dist/src/integrations/work-log.d.ts +87 -0
- package/dist/src/integrations/work-log.d.ts.map +1 -0
- package/dist/src/integrations/work-log.js +275 -0
- package/dist/src/integrations/work-log.js.map +1 -0
- package/dist/src/main.js +5 -4
- package/dist/src/main.js.map +1 -1
- package/dist/src/modes.d.ts +6 -0
- package/dist/src/modes.d.ts.map +1 -1
- package/dist/src/modes.js +73 -2
- package/dist/src/modes.js.map +1 -1
- package/dist/src/tools/bash.d.ts +6 -0
- package/dist/src/tools/bash.d.ts.map +1 -1
- package/dist/src/tools/bash.js +12 -0
- package/dist/src/tools/bash.js.map +1 -1
- package/dist/src/tools/standard.d.ts +17 -1
- package/dist/src/tools/standard.d.ts.map +1 -1
- package/dist/src/tools/standard.js +64 -11
- package/dist/src/tools/standard.js.map +1 -1
- package/dist/src/types.d.ts +18 -0
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +6 -2
package/dist/src/agent.js
CHANGED
|
@@ -21,7 +21,11 @@
|
|
|
21
21
|
import { buildConfig, isFeatureEnabled, getEnabledFeatures, getSubagentTimeout, getSubagentMaxIterations, } from './defaults.js';
|
|
22
22
|
import { createModeManager, formatModeList, parseMode, calculateTaskSimilarity, SUBAGENT_PLAN_MODE_ADDITION, } from './modes.js';
|
|
23
23
|
import { createLSPFileTools, } from './agent-tools/index.js';
|
|
24
|
-
import { HookManager, MemoryManager, PlanningManager, ObservabilityManager, SafetyManager, RoutingManager, MultiAgentManager, ReActManager, ExecutionPolicyManager, ThreadManager, RulesManager, DEFAULT_RULE_SOURCES, ExecutionEconomicsManager, STANDARD_BUDGET, SUBAGENT_BUDGET, TIMEOUT_WRAPUP_PROMPT, AgentRegistry, filterToolsForAgent, formatAgentList, createCancellationManager, isCancellationError, createLinkedToken, createGracefulTimeout, race, createResourceManager, createLSPManager, createSemanticCacheManager, createSkillManager, formatSkillList, createContextEngineering, stableStringify, createCodebaseContext, buildContextFromChunks, createSharedFileCache, createBudgetPool, createPendingPlanManager, createInteractivePlanner, createRecursiveContext, createLearningStore, createCompactor, createAutoCompactionManager, createFileChangeTracker, createCapabilitiesRegistry, createSharedBlackboard, createTaskManager, createSwarmOrchestrator, createThrottledProvider, FREE_TIER_THROTTLE, PAID_TIER_THROTTLE,
|
|
24
|
+
import { HookManager, MemoryManager, PlanningManager, ObservabilityManager, SafetyManager, RoutingManager, MultiAgentManager, ReActManager, ExecutionPolicyManager, ThreadManager, RulesManager, DEFAULT_RULE_SOURCES, ExecutionEconomicsManager, STANDARD_BUDGET, SUBAGENT_BUDGET, TIMEOUT_WRAPUP_PROMPT, AgentRegistry, filterToolsForAgent, formatAgentList, createCancellationManager, isCancellationError, createLinkedToken, createGracefulTimeout, race, createResourceManager, createLSPManager, createSemanticCacheManager, createSkillManager, formatSkillList, createContextEngineering, stableStringify, createCodebaseContext, buildContextFromChunks, createSharedFileCache, createBudgetPool, createDynamicBudgetPool, createPendingPlanManager, createInteractivePlanner, createRecursiveContext, createLearningStore, createCompactor, createAutoCompactionManager, createFileChangeTracker, createCapabilitiesRegistry, createSharedBlackboard, createTaskManager, createSwarmOrchestrator, createThrottledProvider, FREE_TIER_THROTTLE, PAID_TIER_THROTTLE, createWorkLog, createVerificationGate,
|
|
25
|
+
// Phase 2: Orchestration
|
|
26
|
+
classifyComplexity, getScalingGuidance, buildDelegationPrompt, createMinimalDelegationSpec, getSubagentQualityPrompt, ToolRecommendationEngine, createToolRecommendationEngine, createInjectionBudgetManager,
|
|
27
|
+
// Phase 3: Advanced
|
|
28
|
+
getThinkingSystemPrompt, createSelfImprovementProtocol, createSubagentOutputStore, createSerperSearchTool, getEnvironmentFacts, formatFactsBlock, createAutoCheckpointManager, createSubagentSupervisor, createSubagentHandle, } from './integrations/index.js';
|
|
25
29
|
// Lesson 26: Tracing & Evaluation integration
|
|
26
30
|
import { createTraceCollector } from './tracing/trace-collector.js';
|
|
27
31
|
// Model registry for context window limits
|
|
@@ -43,31 +47,107 @@ export const PARALLELIZABLE_TOOLS = new Set([
|
|
|
43
47
|
'search_code', 'get_file_info',
|
|
44
48
|
]);
|
|
45
49
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* Non-parallelizable tools break the sequence, starting a new batch.
|
|
50
|
+
* Tools that can run in parallel IF they target different files.
|
|
51
|
+
* write_file and edit_file on different paths are safe to parallelize.
|
|
49
52
|
*/
|
|
50
|
-
export
|
|
53
|
+
export const CONDITIONALLY_PARALLEL_TOOLS = new Set([
|
|
54
|
+
'write_file', 'edit_file',
|
|
55
|
+
]);
|
|
56
|
+
/**
|
|
57
|
+
* Extract the target file path from a tool call's arguments.
|
|
58
|
+
* Returns null if no file path can be determined.
|
|
59
|
+
*/
|
|
60
|
+
export function extractToolFilePath(toolCall) {
|
|
61
|
+
// Check common argument patterns
|
|
62
|
+
const args = toolCall;
|
|
63
|
+
for (const key of ['path', 'file_path', 'filename', 'file']) {
|
|
64
|
+
if (typeof args[key] === 'string')
|
|
65
|
+
return args[key];
|
|
66
|
+
}
|
|
67
|
+
// Check nested args object
|
|
68
|
+
if (args.args && typeof args.args === 'object') {
|
|
69
|
+
const nested = args.args;
|
|
70
|
+
for (const key of ['path', 'file_path', 'filename', 'file']) {
|
|
71
|
+
if (typeof nested[key] === 'string')
|
|
72
|
+
return nested[key];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Check input object (common in structured tool calls)
|
|
76
|
+
if (args.input && typeof args.input === 'object') {
|
|
77
|
+
const input = args.input;
|
|
78
|
+
for (const key of ['path', 'file_path', 'filename', 'file']) {
|
|
79
|
+
if (typeof input[key] === 'string')
|
|
80
|
+
return input[key];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check if a conditionally-parallel tool call conflicts with any tool
|
|
87
|
+
* in the current accumulator (same file path).
|
|
88
|
+
*/
|
|
89
|
+
function hasFileConflict(toolCall, accumulator) {
|
|
90
|
+
const path = extractToolFilePath(toolCall);
|
|
91
|
+
if (!path)
|
|
92
|
+
return true; // Can't determine path → assume conflict
|
|
93
|
+
for (const existing of accumulator) {
|
|
94
|
+
const existingPath = extractToolFilePath(existing);
|
|
95
|
+
if (existingPath === path)
|
|
96
|
+
return true; // Same file → conflict
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Groups tool calls into batches for parallel/sequential execution.
|
|
102
|
+
* Uses accumulate-and-flush: parallelizable tools accumulate until a
|
|
103
|
+
* non-parallelizable tool flushes them as a batch. This produces optimal
|
|
104
|
+
* batching even for non-consecutive parallelizable tools.
|
|
105
|
+
*
|
|
106
|
+
* Enhanced with conditional parallelism: write_file/edit_file on
|
|
107
|
+
* DIFFERENT files can be batched together for parallel execution.
|
|
108
|
+
*
|
|
109
|
+
* Example: [read1, read2, write, read3, grep] → [[read1, read2], [write], [read3, grep]]
|
|
110
|
+
* (Previous algorithm produced 4 batches; this produces 3)
|
|
111
|
+
*
|
|
112
|
+
* Enhanced: [write_a, write_b, write_a] → [[write_a, write_b], [write_a]]
|
|
113
|
+
* (Different files parallelized, same file sequential)
|
|
114
|
+
*/
|
|
115
|
+
export function groupToolCallsIntoBatches(toolCalls, isParallelizable = (tc) => PARALLELIZABLE_TOOLS.has(tc.name), isConditionallyParallel = (tc) => CONDITIONALLY_PARALLEL_TOOLS.has(tc.name)) {
|
|
116
|
+
if (toolCalls.length === 0)
|
|
117
|
+
return [];
|
|
51
118
|
const batches = [];
|
|
52
|
-
let
|
|
53
|
-
let currentIsParallel = false;
|
|
119
|
+
let parallelAccum = [];
|
|
54
120
|
for (const toolCall of toolCalls) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
currentBatch.push(toolCall);
|
|
58
|
-
currentIsParallel = isParallel;
|
|
121
|
+
if (isParallelizable(toolCall)) {
|
|
122
|
+
parallelAccum.push(toolCall);
|
|
59
123
|
}
|
|
60
|
-
else if (
|
|
61
|
-
|
|
124
|
+
else if (isConditionallyParallel(toolCall)) {
|
|
125
|
+
// Can parallelize if no file conflict with existing accumulator
|
|
126
|
+
if (!hasFileConflict(toolCall, parallelAccum)) {
|
|
127
|
+
parallelAccum.push(toolCall);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
// Conflict: flush current batch, start new one with this tool
|
|
131
|
+
if (parallelAccum.length > 0) {
|
|
132
|
+
batches.push(parallelAccum);
|
|
133
|
+
parallelAccum = [];
|
|
134
|
+
}
|
|
135
|
+
parallelAccum.push(toolCall);
|
|
136
|
+
}
|
|
62
137
|
}
|
|
63
138
|
else {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
139
|
+
// Flush any accumulated parallel tools as a single batch
|
|
140
|
+
if (parallelAccum.length > 0) {
|
|
141
|
+
batches.push(parallelAccum);
|
|
142
|
+
parallelAccum = [];
|
|
143
|
+
}
|
|
144
|
+
// Non-parallelizable tool gets its own batch
|
|
145
|
+
batches.push([toolCall]);
|
|
67
146
|
}
|
|
68
147
|
}
|
|
69
|
-
|
|
70
|
-
|
|
148
|
+
// Flush remaining parallel tools
|
|
149
|
+
if (parallelAccum.length > 0) {
|
|
150
|
+
batches.push(parallelAccum);
|
|
71
151
|
}
|
|
72
152
|
return batches;
|
|
73
153
|
}
|
|
@@ -117,6 +197,15 @@ export class ProductionAgent {
|
|
|
117
197
|
taskManager = null;
|
|
118
198
|
store = null;
|
|
119
199
|
swarmOrchestrator = null;
|
|
200
|
+
workLog = null;
|
|
201
|
+
verificationGate = null;
|
|
202
|
+
// Phase 2-4 integration modules
|
|
203
|
+
injectionBudget = null;
|
|
204
|
+
selfImprovement = null;
|
|
205
|
+
subagentOutputStore = null;
|
|
206
|
+
autoCheckpointManager = null;
|
|
207
|
+
toolRecommendation = null;
|
|
208
|
+
lastComplexityAssessment = null;
|
|
120
209
|
// Duplicate spawn prevention - tracks recently spawned tasks to prevent doom loops
|
|
121
210
|
// Map<taskKey, { timestamp: number; result: string; queuedChanges: number }>
|
|
122
211
|
spawnedTasks = new Map();
|
|
@@ -311,6 +400,19 @@ export class ProductionAgent {
|
|
|
311
400
|
maxIterations: this.config.maxIterations,
|
|
312
401
|
targetIterations: Math.min(baseBudget.targetIterations ?? 20, this.config.maxIterations),
|
|
313
402
|
});
|
|
403
|
+
// Work Log - compaction-resilient summary of agent work
|
|
404
|
+
// Always enabled - minimal overhead and critical for long-running tasks
|
|
405
|
+
this.workLog = createWorkLog();
|
|
406
|
+
// Verification Gate - opt-in completion verification
|
|
407
|
+
if (this.config.verificationCriteria) {
|
|
408
|
+
this.verificationGate = createVerificationGate(this.config.verificationCriteria);
|
|
409
|
+
}
|
|
410
|
+
// Phase 2-4: Orchestration & Advanced modules (always enabled, lightweight)
|
|
411
|
+
this.injectionBudget = createInjectionBudgetManager();
|
|
412
|
+
this.selfImprovement = createSelfImprovementProtocol(undefined, this.learningStore ?? undefined);
|
|
413
|
+
this.subagentOutputStore = createSubagentOutputStore({ persistToFile: false });
|
|
414
|
+
this.autoCheckpointManager = createAutoCheckpointManager({ enabled: true });
|
|
415
|
+
this.toolRecommendation = createToolRecommendationEngine();
|
|
314
416
|
// Agent Registry - always enabled for subagent support
|
|
315
417
|
this.agentRegistry = new AgentRegistry();
|
|
316
418
|
// Load user agents asynchronously - tracked for ensureReady()
|
|
@@ -341,6 +443,15 @@ export class ProductionAgent {
|
|
|
341
443
|
for (const tool of taskTools) {
|
|
342
444
|
this.tools.set(tool.name, tool);
|
|
343
445
|
}
|
|
446
|
+
// Built-in web search (Serper API) — gracefully handles missing API key
|
|
447
|
+
const serperCustomTool = createSerperSearchTool();
|
|
448
|
+
this.tools.set('web_search', {
|
|
449
|
+
name: serperCustomTool.name,
|
|
450
|
+
description: serperCustomTool.description,
|
|
451
|
+
parameters: serperCustomTool.inputSchema,
|
|
452
|
+
execute: serperCustomTool.execute,
|
|
453
|
+
dangerLevel: 'safe',
|
|
454
|
+
});
|
|
344
455
|
// Swarm Mode (experimental)
|
|
345
456
|
if (this.config.swarm) {
|
|
346
457
|
const swarmConfig = this.config.swarm;
|
|
@@ -837,6 +948,10 @@ export class ProductionAgent {
|
|
|
837
948
|
try {
|
|
838
949
|
// Check for cancellation before starting
|
|
839
950
|
cancellationToken?.throwIfCancellationRequested();
|
|
951
|
+
// Classify task complexity for scaling guidance
|
|
952
|
+
this.lastComplexityAssessment = classifyComplexity(task, {
|
|
953
|
+
hasActivePlan: !!this.state.plan,
|
|
954
|
+
});
|
|
840
955
|
// Check if swarm mode should handle this task
|
|
841
956
|
if (this.swarmOrchestrator) {
|
|
842
957
|
const swarmResult = await this.runSwarm(task);
|
|
@@ -1119,6 +1234,14 @@ export class ProductionAgent {
|
|
|
1119
1234
|
content: `[CONTEXT REDUCED: Earlier messages were removed to stay within budget. Conversation continues from recent context.]`,
|
|
1120
1235
|
});
|
|
1121
1236
|
messages.push(...recentMessages);
|
|
1237
|
+
// Inject work log after emergency truncation to prevent amnesia
|
|
1238
|
+
if (this.workLog?.hasContent()) {
|
|
1239
|
+
const workLogMessage = {
|
|
1240
|
+
role: 'user',
|
|
1241
|
+
content: this.workLog.toCompactString(),
|
|
1242
|
+
};
|
|
1243
|
+
messages.push(workLogMessage);
|
|
1244
|
+
}
|
|
1122
1245
|
// Update state messages too
|
|
1123
1246
|
this.state.messages.length = 0;
|
|
1124
1247
|
this.state.messages.push(...messages);
|
|
@@ -1299,6 +1422,35 @@ export class ProductionAgent {
|
|
|
1299
1422
|
}
|
|
1300
1423
|
}
|
|
1301
1424
|
// =====================================================================
|
|
1425
|
+
// INJECTION BUDGET ANALYSIS (Phase 2 - monitoring mode)
|
|
1426
|
+
// Collects stats on context injections without gating; logs when
|
|
1427
|
+
// budget would have dropped items. Validates system before enabling gating.
|
|
1428
|
+
// =====================================================================
|
|
1429
|
+
if (this.injectionBudget) {
|
|
1430
|
+
const proposals = [];
|
|
1431
|
+
if (budgetInjectedPrompt) {
|
|
1432
|
+
proposals.push({ name: 'budget_warning', priority: 0, maxTokens: 500, content: budgetInjectedPrompt });
|
|
1433
|
+
}
|
|
1434
|
+
// Approximate recitation content (actual injection handled above)
|
|
1435
|
+
if (this.contextEngineering) {
|
|
1436
|
+
const failureCtx = this.contextEngineering.getFailureContext(5);
|
|
1437
|
+
if (failureCtx) {
|
|
1438
|
+
proposals.push({ name: 'failure_context', priority: 2, maxTokens: 300, content: failureCtx });
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
if (proposals.length > 0) {
|
|
1442
|
+
const accepted = this.injectionBudget.allocate(proposals);
|
|
1443
|
+
const stats = this.injectionBudget.getLastStats();
|
|
1444
|
+
if (stats && stats.droppedNames.length > 0 && process.env.DEBUG) {
|
|
1445
|
+
console.log(`[injection-budget] Would drop: ${stats.droppedNames.join(', ')} (${stats.proposedTokens} proposed, ${stats.acceptedTokens} accepted)`);
|
|
1446
|
+
}
|
|
1447
|
+
// Log total injection overhead for observability
|
|
1448
|
+
if (stats && process.env.DEBUG_LLM) {
|
|
1449
|
+
console.log(`[injection-budget] Iteration ${this.state.iteration}: ${accepted.length}/${proposals.length} injections, ~${stats.acceptedTokens} tokens`);
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
// =====================================================================
|
|
1302
1454
|
// RESILIENT LLM CALL: Empty response retries + max_tokens continuation
|
|
1303
1455
|
// =====================================================================
|
|
1304
1456
|
// Get resilience config
|
|
@@ -1594,6 +1746,24 @@ export class ProductionAgent {
|
|
|
1594
1746
|
});
|
|
1595
1747
|
incompleteActionRetries = 0;
|
|
1596
1748
|
}
|
|
1749
|
+
// Verification gate: if criteria not met, nudge agent to verify before completing
|
|
1750
|
+
if (this.verificationGate && !forceTextOnly) {
|
|
1751
|
+
const vResult = this.verificationGate.check();
|
|
1752
|
+
if (!vResult.satisfied && !vResult.forceAllow && vResult.nudge) {
|
|
1753
|
+
// Inject nudge and continue the loop
|
|
1754
|
+
const nudgeMessage = {
|
|
1755
|
+
role: 'user',
|
|
1756
|
+
content: vResult.nudge,
|
|
1757
|
+
};
|
|
1758
|
+
messages.push(nudgeMessage);
|
|
1759
|
+
this.state.messages.push(nudgeMessage);
|
|
1760
|
+
this.observability?.logger?.info('Verification gate nudge', {
|
|
1761
|
+
missing: vResult.missing,
|
|
1762
|
+
nudgeCount: this.verificationGate.getState().nudgeCount,
|
|
1763
|
+
});
|
|
1764
|
+
continue;
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1597
1767
|
// No tool calls (or forced to ignore), agent is done - compact tool outputs to save context
|
|
1598
1768
|
// The model has "consumed" the tool outputs and produced a response,
|
|
1599
1769
|
// so we can replace verbose outputs with compact summaries
|
|
@@ -1630,12 +1800,33 @@ export class ProductionAgent {
|
|
|
1630
1800
|
// Execute tool calls (we know toolCalls is defined here due to the check above)
|
|
1631
1801
|
const toolCalls = response.toolCalls;
|
|
1632
1802
|
const toolResults = await this.executeToolCalls(toolCalls);
|
|
1633
|
-
// Record tool calls for economics/progress tracking
|
|
1803
|
+
// Record tool calls for economics/progress tracking + work log
|
|
1634
1804
|
for (let i = 0; i < toolCalls.length; i++) {
|
|
1635
1805
|
const toolCall = toolCalls[i];
|
|
1636
1806
|
const result = toolResults[i];
|
|
1637
1807
|
executedToolNames.add(toolCall.name);
|
|
1638
1808
|
this.economics?.recordToolCall(toolCall.name, toolCall.arguments, result?.result);
|
|
1809
|
+
// Record in work log for compaction resilience
|
|
1810
|
+
const toolOutput = result?.result && typeof result.result === 'object' && 'output' in result.result
|
|
1811
|
+
? String(result.result.output)
|
|
1812
|
+
: typeof result?.result === 'string' ? result.result : undefined;
|
|
1813
|
+
this.workLog?.recordToolExecution(toolCall.name, toolCall.arguments, toolOutput);
|
|
1814
|
+
// Record in verification gate
|
|
1815
|
+
if (this.verificationGate) {
|
|
1816
|
+
if (toolCall.name === 'bash') {
|
|
1817
|
+
const toolRes = result?.result;
|
|
1818
|
+
const output = toolRes && typeof toolRes === 'object' && 'output' in toolRes
|
|
1819
|
+
? String(toolRes.output)
|
|
1820
|
+
: typeof toolRes === 'string' ? toolRes : '';
|
|
1821
|
+
const exitCode = toolRes && typeof toolRes === 'object' && toolRes.metadata
|
|
1822
|
+
? toolRes.metadata.exitCode ?? null
|
|
1823
|
+
: null;
|
|
1824
|
+
this.verificationGate.recordBashExecution(String(toolCall.arguments.command || ''), output, exitCode);
|
|
1825
|
+
}
|
|
1826
|
+
if (['write_file', 'edit_file'].includes(toolCall.name)) {
|
|
1827
|
+
this.verificationGate.recordFileChange();
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1639
1830
|
}
|
|
1640
1831
|
// Add tool results to messages (with truncation and proactive budget management)
|
|
1641
1832
|
const MAX_TOOL_OUTPUT_CHARS = 8000; // ~2000 tokens max per tool output
|
|
@@ -1657,6 +1848,15 @@ export class ProductionAgent {
|
|
|
1657
1848
|
messages.push(...compactionResult.compactedMessages);
|
|
1658
1849
|
this.state.messages.length = 0;
|
|
1659
1850
|
this.state.messages.push(...compactionResult.compactedMessages);
|
|
1851
|
+
// Inject work log after compaction to prevent amnesia
|
|
1852
|
+
if (this.workLog?.hasContent()) {
|
|
1853
|
+
const workLogMessage = {
|
|
1854
|
+
role: 'user',
|
|
1855
|
+
content: this.workLog.toCompactString(),
|
|
1856
|
+
};
|
|
1857
|
+
messages.push(workLogMessage);
|
|
1858
|
+
this.state.messages.push(workLogMessage);
|
|
1859
|
+
}
|
|
1660
1860
|
}
|
|
1661
1861
|
else if (compactionResult.status === 'hard_limit') {
|
|
1662
1862
|
// Hard limit reached - this is serious, emit error
|
|
@@ -1851,12 +2051,25 @@ export class ProductionAgent {
|
|
|
1851
2051
|
}
|
|
1852
2052
|
}
|
|
1853
2053
|
// Build system prompt using cache-aware builder if available (Trick P)
|
|
1854
|
-
// Combine memory, learnings, and
|
|
1855
|
-
const
|
|
2054
|
+
// Combine memory, learnings, codebase context, and environment facts
|
|
2055
|
+
const combinedContextParts = [
|
|
2056
|
+
// Environment facts — temporal/platform grounding (prevents stale date hallucinations)
|
|
2057
|
+
formatFactsBlock(getEnvironmentFacts()),
|
|
1856
2058
|
...(memoryContext.length > 0 ? memoryContext : []),
|
|
1857
2059
|
...(learningsContext ? [learningsContext] : []),
|
|
1858
2060
|
...(codebaseContextStr ? [`\n## Relevant Code\n${codebaseContextStr}`] : []),
|
|
1859
|
-
]
|
|
2061
|
+
];
|
|
2062
|
+
// Inject thinking directives and scaling guidance for non-simple tasks
|
|
2063
|
+
if (this.lastComplexityAssessment) {
|
|
2064
|
+
const thinkingPrompt = getThinkingSystemPrompt(this.lastComplexityAssessment.tier);
|
|
2065
|
+
if (thinkingPrompt) {
|
|
2066
|
+
combinedContextParts.push(thinkingPrompt);
|
|
2067
|
+
}
|
|
2068
|
+
if (this.lastComplexityAssessment.tier !== 'simple') {
|
|
2069
|
+
combinedContextParts.push(getScalingGuidance(this.lastComplexityAssessment));
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
const combinedContext = combinedContextParts.join('\n');
|
|
1860
2073
|
const promptOptions = {
|
|
1861
2074
|
rules: rulesContent + (skillsPrompt ? '\n\n' + skillsPrompt : ''),
|
|
1862
2075
|
tools: toolDescriptions,
|
|
@@ -1996,6 +2209,8 @@ export class ProductionAgent {
|
|
|
1996
2209
|
},
|
|
1997
2210
|
},
|
|
1998
2211
|
});
|
|
2212
|
+
// Pause duration budget during LLM call - network time shouldn't count against agent
|
|
2213
|
+
this.economics?.pauseDuration();
|
|
1999
2214
|
try {
|
|
2000
2215
|
let response;
|
|
2001
2216
|
let actualModel = model;
|
|
@@ -2135,6 +2350,10 @@ export class ProductionAgent {
|
|
|
2135
2350
|
this.observability?.tracer?.endSpan(spanId);
|
|
2136
2351
|
throw error;
|
|
2137
2352
|
}
|
|
2353
|
+
finally {
|
|
2354
|
+
// Resume duration budget after LLM call completes (success or failure)
|
|
2355
|
+
this.economics?.resumeDuration();
|
|
2356
|
+
}
|
|
2138
2357
|
}
|
|
2139
2358
|
/**
|
|
2140
2359
|
* Execute an async callback while excluding wall-clock wait time from duration budgeting.
|
|
@@ -2467,6 +2686,8 @@ export class ProductionAgent {
|
|
|
2467
2686
|
this.blackboard.release(filePath, agentId);
|
|
2468
2687
|
}
|
|
2469
2688
|
}
|
|
2689
|
+
// Self-improvement: record success pattern
|
|
2690
|
+
this.selfImprovement?.recordSuccess(toolCall.name, toolCall.arguments, typeof result === 'string' ? result.slice(0, 200) : JSON.stringify(result).slice(0, 200));
|
|
2470
2691
|
this.observability?.tracer?.endSpan(spanId);
|
|
2471
2692
|
return { callId: toolCall.id, result };
|
|
2472
2693
|
}
|
|
@@ -2494,6 +2715,12 @@ export class ProductionAgent {
|
|
|
2494
2715
|
error,
|
|
2495
2716
|
intent: `Execute tool ${toolCall.name}`,
|
|
2496
2717
|
});
|
|
2718
|
+
// Self-improvement: enhance error message with diagnosis for better LLM recovery
|
|
2719
|
+
if (this.selfImprovement) {
|
|
2720
|
+
const enhanced = this.selfImprovement.enhanceErrorMessage(toolCall.name, error.message, toolCall.arguments);
|
|
2721
|
+
this.emit({ type: 'tool.blocked', tool: toolCall.name, reason: enhanced });
|
|
2722
|
+
return { callId: toolCall.id, result: `Error: ${enhanced}`, error: enhanced };
|
|
2723
|
+
}
|
|
2497
2724
|
this.emit({ type: 'tool.blocked', tool: toolCall.name, reason: error.message });
|
|
2498
2725
|
return { callId: toolCall.id, result: `Error: ${error.message}`, error: error.message };
|
|
2499
2726
|
}
|
|
@@ -3522,6 +3749,19 @@ export class ProductionAgent {
|
|
|
3522
3749
|
}
|
|
3523
3750
|
// Create the checkpoint
|
|
3524
3751
|
const label = `auto-iter-${this.state.iteration}`;
|
|
3752
|
+
// Supplementary: also save to AutoCheckpointManager (file-based)
|
|
3753
|
+
if (this.autoCheckpointManager) {
|
|
3754
|
+
try {
|
|
3755
|
+
this.autoCheckpointManager.save({
|
|
3756
|
+
label,
|
|
3757
|
+
sessionId: this.agentId,
|
|
3758
|
+
iteration: this.state.iteration,
|
|
3759
|
+
});
|
|
3760
|
+
}
|
|
3761
|
+
catch {
|
|
3762
|
+
// Non-critical — don't fail the main checkpoint path
|
|
3763
|
+
}
|
|
3764
|
+
}
|
|
3525
3765
|
return this.createCheckpoint(label);
|
|
3526
3766
|
}
|
|
3527
3767
|
// =========================================================================
|
|
@@ -3675,7 +3915,18 @@ export class ProductionAgent {
|
|
|
3675
3915
|
let workerResultId;
|
|
3676
3916
|
try {
|
|
3677
3917
|
// Filter tools for this agent
|
|
3678
|
-
|
|
3918
|
+
let agentTools = filterToolsForAgent(agentDef, Array.from(this.tools.values()));
|
|
3919
|
+
// Apply tool recommendations to improve subagent focus (only for large tool sets)
|
|
3920
|
+
if (this.toolRecommendation && agentTools.length > 15) {
|
|
3921
|
+
const taskType = ToolRecommendationEngine.inferTaskType(agentName);
|
|
3922
|
+
const recommendations = this.toolRecommendation.recommendTools(task, taskType, agentTools.map(t => t.name));
|
|
3923
|
+
if (recommendations.length > 0) {
|
|
3924
|
+
const recommendedNames = new Set(recommendations.map(r => r.toolName));
|
|
3925
|
+
// Always keep spawn tools even if not recommended
|
|
3926
|
+
const alwaysKeep = new Set(['spawn_agent', 'spawn_agents_parallel']);
|
|
3927
|
+
agentTools = agentTools.filter(t => recommendedNames.has(t.name) || alwaysKeep.has(t.name));
|
|
3928
|
+
}
|
|
3929
|
+
}
|
|
3679
3930
|
// Resolve model - abstract tiers (fast/balanced/quality) should use parent's model
|
|
3680
3931
|
// Only use agentDef.model if it's an actual model ID (contains '/')
|
|
3681
3932
|
const resolvedModel = (agentDef.model && agentDef.model.includes('/'))
|
|
@@ -3767,14 +4018,30 @@ export class ProductionAgent {
|
|
|
3767
4018
|
// BUDGET AWARENESS: Always inject so subagent understands its limits
|
|
3768
4019
|
const subagentBudgetTokens = constraints?.maxTokens ?? SUBAGENT_BUDGET.maxTokens ?? 100000;
|
|
3769
4020
|
const subagentBudgetMinutes = Math.round((SUBAGENT_BUDGET.maxDuration ?? 240000) / 60000);
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
4021
|
+
if (isSwarmWorker) {
|
|
4022
|
+
// V6: Calmer resource awareness for swarm workers — prevents weaker models
|
|
4023
|
+
// from confabulating budget warnings and wrapping up without doing work
|
|
4024
|
+
constraintParts.push(`**Resource Info:**\n` +
|
|
4025
|
+
`- Token budget: ~${(subagentBudgetTokens / 1000).toFixed(0)}k tokens (you have plenty)\n` +
|
|
4026
|
+
`- Time limit: ~${subagentBudgetMinutes} minutes\n` +
|
|
4027
|
+
`- Focus on completing your task. Do NOT wrap up prematurely.\n` +
|
|
4028
|
+
`- You will receive a system warning IF you approach budget limits. Until then, work normally.\n` +
|
|
4029
|
+
`- **IMPORTANT:** Budget warnings come from the SYSTEM, not from your own assessment. ` +
|
|
4030
|
+
`Do not preemptively claim budget issues.\n` +
|
|
4031
|
+
`- **STRUCTURED WRAPUP:** When told to wrap up, respond with ONLY this JSON (no tool calls):\n` +
|
|
4032
|
+
` {"findings":[...], "actionsTaken":[...], "failures":[...], "remainingWork":[...], "suggestedNextSteps":[...]}`);
|
|
4033
|
+
}
|
|
4034
|
+
else {
|
|
4035
|
+
// Original RESOURCE AWARENESS text for regular subagents
|
|
4036
|
+
constraintParts.push(`**RESOURCE AWARENESS (CRITICAL):**\n` +
|
|
4037
|
+
`- Token budget: ~${(subagentBudgetTokens / 1000).toFixed(0)}k tokens\n` +
|
|
4038
|
+
`- Time limit: ~${subagentBudgetMinutes} minutes\n` +
|
|
4039
|
+
`- You will receive warnings at 70% usage. When warned, WRAP UP immediately.\n` +
|
|
4040
|
+
`- Do not explore indefinitely - be focused and efficient.\n` +
|
|
4041
|
+
`- If approaching limits, summarize findings and return.\n` +
|
|
4042
|
+
`- **STRUCTURED WRAPUP:** When told to wrap up, respond with ONLY this JSON (no tool calls):\n` +
|
|
4043
|
+
` {"findings":[...], "actionsTaken":[...], "failures":[...], "remainingWork":[...], "suggestedNextSteps":[...]}`);
|
|
4044
|
+
}
|
|
3778
4045
|
if (constraints) {
|
|
3779
4046
|
if (constraints.focusAreas && constraints.focusAreas.length > 0) {
|
|
3780
4047
|
constraintParts.push(`**FOCUS AREAS (limit exploration to these paths):**\n${constraints.focusAreas.map(a => ` - ${a}`).join('\n')}`);
|
|
@@ -3790,11 +4057,19 @@ export class ProductionAgent {
|
|
|
3790
4057
|
}
|
|
3791
4058
|
}
|
|
3792
4059
|
const constraintContext = `\n\n**EXECUTION CONSTRAINTS:**\n${constraintParts.join('\n\n')}\n`;
|
|
4060
|
+
// Build delegation-enhanced system prompt
|
|
4061
|
+
let delegationContext = '';
|
|
4062
|
+
if (this.lastComplexityAssessment && this.lastComplexityAssessment.tier !== 'simple') {
|
|
4063
|
+
const spec = createMinimalDelegationSpec(task, agentName);
|
|
4064
|
+
delegationContext = '\n\n' + buildDelegationPrompt(spec);
|
|
4065
|
+
}
|
|
4066
|
+
// Quality self-assessment prompt for subagent
|
|
4067
|
+
const qualityPrompt = '\n\n' + getSubagentQualityPrompt();
|
|
3793
4068
|
// Build subagent system prompt with subagent-specific plan mode addition
|
|
3794
4069
|
const parentMode = this.getMode();
|
|
3795
4070
|
const subagentSystemPrompt = parentMode === 'plan'
|
|
3796
|
-
? `${agentDef.systemPrompt}\n\n${SUBAGENT_PLAN_MODE_ADDITION}${blackboardContext}${constraintContext}`
|
|
3797
|
-
: `${agentDef.systemPrompt}${blackboardContext}${constraintContext}`;
|
|
4071
|
+
? `${agentDef.systemPrompt}\n\n${SUBAGENT_PLAN_MODE_ADDITION}${blackboardContext}${constraintContext}${delegationContext}${qualityPrompt}`
|
|
4072
|
+
: `${agentDef.systemPrompt}${blackboardContext}${constraintContext}${delegationContext}${qualityPrompt}`;
|
|
3798
4073
|
// Allocate budget from pool (or use default) — track allocation ID for release later
|
|
3799
4074
|
const pooledBudget = this.getSubagentBudget(agentName, constraints);
|
|
3800
4075
|
const poolAllocationId = pooledBudget.allocationId;
|
|
@@ -4006,6 +4281,25 @@ export class ProductionAgent {
|
|
|
4006
4281
|
},
|
|
4007
4282
|
structured,
|
|
4008
4283
|
};
|
|
4284
|
+
// Save full output to subagent output store (avoids telephone problem)
|
|
4285
|
+
if (this.subagentOutputStore) {
|
|
4286
|
+
const outputEntry = {
|
|
4287
|
+
id: agentId,
|
|
4288
|
+
agentId,
|
|
4289
|
+
agentName,
|
|
4290
|
+
task,
|
|
4291
|
+
fullOutput: finalOutput,
|
|
4292
|
+
structured,
|
|
4293
|
+
filesModified: [],
|
|
4294
|
+
filesCreated: [],
|
|
4295
|
+
timestamp: new Date(),
|
|
4296
|
+
tokensUsed: result.metrics.totalTokens,
|
|
4297
|
+
durationMs: duration,
|
|
4298
|
+
};
|
|
4299
|
+
const storeId = this.subagentOutputStore.save(outputEntry);
|
|
4300
|
+
// Attach reference so downstream consumers can retrieve full output
|
|
4301
|
+
spawnResultFinal.outputStoreId = storeId;
|
|
4302
|
+
}
|
|
4009
4303
|
if (workerResultId && this.store?.hasWorkerResultsFeature()) {
|
|
4010
4304
|
try {
|
|
4011
4305
|
this.store.completeWorkerResult(workerResultId, {
|
|
@@ -4310,23 +4604,34 @@ export class ProductionAgent {
|
|
|
4310
4604
|
count: tasks.length,
|
|
4311
4605
|
agents: tasks.map(t => t.agent),
|
|
4312
4606
|
});
|
|
4313
|
-
//
|
|
4314
|
-
//
|
|
4315
|
-
// gets an equal share instead of racing for the full maxPerChild allocation.
|
|
4607
|
+
// Use DynamicBudgetPool for parallel spawns (prevents child starvation,
|
|
4608
|
+
// enables priority-based allocation). Falls back to regular pool for single tasks.
|
|
4316
4609
|
let settled;
|
|
4610
|
+
const originalPool = this.budgetPool;
|
|
4611
|
+
// SubagentSupervisor for unified monitoring of concurrent subagents
|
|
4612
|
+
const supervisor = tasks.length > 1 ? createSubagentSupervisor() : null;
|
|
4317
4613
|
if (this.budgetPool && tasks.length > 1) {
|
|
4614
|
+
// Swap to DynamicBudgetPool for this parallel batch
|
|
4318
4615
|
const poolStats = this.budgetPool.getStats();
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
// so
|
|
4322
|
-
|
|
4323
|
-
this.budgetPool.setMaxPerChild(equalShare);
|
|
4616
|
+
const dynamicPool = createDynamicBudgetPool(poolStats.tokensRemaining, 0.1);
|
|
4617
|
+
dynamicPool.setExpectedChildren(tasks.length);
|
|
4618
|
+
// Temporarily replace the budget pool so spawnAgent's reserve() uses the dynamic one
|
|
4619
|
+
this.budgetPool = dynamicPool;
|
|
4324
4620
|
try {
|
|
4325
|
-
const promises = tasks.map(({ agent, task }) =>
|
|
4621
|
+
const promises = tasks.map(({ agent, task }) => {
|
|
4622
|
+
const spawnPromise = this.spawnAgent(agent, task);
|
|
4623
|
+
// Register with supervisor for monitoring
|
|
4624
|
+
if (supervisor) {
|
|
4625
|
+
const handle = createSubagentHandle(`parallel-${agent}-${Date.now()}`, agent, task, spawnPromise, {});
|
|
4626
|
+
supervisor.add(handle);
|
|
4627
|
+
}
|
|
4628
|
+
return spawnPromise;
|
|
4629
|
+
});
|
|
4326
4630
|
settled = await Promise.allSettled(promises);
|
|
4327
4631
|
}
|
|
4328
4632
|
finally {
|
|
4329
|
-
this.budgetPool
|
|
4633
|
+
this.budgetPool = originalPool;
|
|
4634
|
+
supervisor?.stop();
|
|
4330
4635
|
}
|
|
4331
4636
|
}
|
|
4332
4637
|
else {
|
|
@@ -5041,8 +5346,19 @@ If the task is a simple question or doesn't need specialized handling, set bestA
|
|
|
5041
5346
|
this.unsubscribers = [];
|
|
5042
5347
|
// Flush trace collector before cleanup
|
|
5043
5348
|
await this.traceCollector?.flush();
|
|
5044
|
-
//
|
|
5045
|
-
|
|
5349
|
+
// Per-agent blackboard cleanup: release only this agent's claims and subscriptions
|
|
5350
|
+
// so parallel siblings don't lose their data. Only root agent clears everything.
|
|
5351
|
+
if (this.blackboard) {
|
|
5352
|
+
if (this.parentIterations > 0 && this.agentId) {
|
|
5353
|
+
// Subagent: release only our claims and subscriptions
|
|
5354
|
+
this.blackboard.releaseAll(this.agentId);
|
|
5355
|
+
this.blackboard.unsubscribeAgent(this.agentId);
|
|
5356
|
+
}
|
|
5357
|
+
else {
|
|
5358
|
+
// Root agent: full clear
|
|
5359
|
+
this.blackboard.clear();
|
|
5360
|
+
}
|
|
5361
|
+
}
|
|
5046
5362
|
// Wait for any pending init before cleanup
|
|
5047
5363
|
if (this.initPromises.length > 0) {
|
|
5048
5364
|
try {
|