@workermill/agent 0.6.0 → 0.6.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/dist/plan-validator.js +3 -3
- package/dist/planner.js +28 -13
- package/dist/poller.js +5 -1
- package/dist/spawner.js +1 -1
- package/package.json +1 -1
package/dist/plan-validator.js
CHANGED
|
@@ -183,8 +183,8 @@ export function runCriticCli(claudePath, model, prompt, env) {
|
|
|
183
183
|
});
|
|
184
184
|
const timeout = setTimeout(() => {
|
|
185
185
|
proc.kill("SIGTERM");
|
|
186
|
-
reject(new Error("Critic CLI timed out after
|
|
187
|
-
},
|
|
186
|
+
reject(new Error("Critic CLI timed out after 20 minutes"));
|
|
187
|
+
}, 1_200_000);
|
|
188
188
|
proc.on("exit", (code) => {
|
|
189
189
|
clearTimeout(timeout);
|
|
190
190
|
if (code !== 0) {
|
|
@@ -262,7 +262,7 @@ export async function runCriticValidation(claudePath, model, prd, plan, env, tas
|
|
|
262
262
|
if (!providerApiKey) {
|
|
263
263
|
throw new Error(`No API key for critic provider "${effectiveProvider}"`);
|
|
264
264
|
}
|
|
265
|
-
rawCriticOutput = await generateText(effectiveProvider, model, criticPrompt, providerApiKey, { maxTokens: 4096, temperature: 0.3, timeoutMs:
|
|
265
|
+
rawCriticOutput = await generateText(effectiveProvider, model, criticPrompt, providerApiKey, { maxTokens: 4096, temperature: 0.3, timeoutMs: 1_200_000 });
|
|
266
266
|
}
|
|
267
267
|
const result = parseCriticResponse(rawCriticOutput);
|
|
268
268
|
const statusIcon = result.score >= AUTO_APPROVAL_THRESHOLD
|
package/dist/planner.js
CHANGED
|
@@ -456,7 +456,15 @@ Keep your report under 1500 words. Only report facts you verified with tools.`;
|
|
|
456
456
|
*
|
|
457
457
|
* Falls back to single-agent planning if anything goes wrong.
|
|
458
458
|
*/
|
|
459
|
-
|
|
459
|
+
/**
|
|
460
|
+
* Run team analysis: spawn 3 parallel analyst agents once, then return
|
|
461
|
+
* an enhanced prompt with their reports appended. Returns null if all
|
|
462
|
+
* analysts fail (caller should fall back to basePrompt).
|
|
463
|
+
*
|
|
464
|
+
* This runs ONCE before the planner-critic loop — analyst prompts don't
|
|
465
|
+
* include critic feedback, so re-running them on iteration 2+ is waste.
|
|
466
|
+
*/
|
|
467
|
+
async function runTeamAnalysis(task, basePrompt, claudePath, model, env, repoPath, taskId, startTime) {
|
|
460
468
|
const taskLabel = chalk.cyan(taskId.slice(0, 8));
|
|
461
469
|
console.log(`${ts()} ${taskLabel} ${chalk.magenta("◆ Team planning")} — running 3 analysts in parallel...`);
|
|
462
470
|
await postLog(taskId, `${PREFIX} Team planning: running codebase, requirements, and risk analysts in parallel...`);
|
|
@@ -497,7 +505,7 @@ async function runTeamPlanning(task, basePrompt, claudePath, model, env, repoPat
|
|
|
497
505
|
if (attempt === MAX_TEAM_RETRIES) {
|
|
498
506
|
console.log(`${ts()} ${taskLabel} ${chalk.yellow("⚠")} All analysts failed after ${MAX_TEAM_RETRIES} attempts, falling back to single-agent planning`);
|
|
499
507
|
await postLog(taskId, `${PREFIX} All analysis agents failed after ${MAX_TEAM_RETRIES} attempts — falling back to single-agent planning`);
|
|
500
|
-
return
|
|
508
|
+
return null;
|
|
501
509
|
}
|
|
502
510
|
}
|
|
503
511
|
// Build enhanced prompt with analysis reports
|
|
@@ -511,14 +519,12 @@ async function runTeamPlanning(task, basePrompt, claudePath, model, env, repoPat
|
|
|
511
519
|
if (riskReport) {
|
|
512
520
|
sections.push(`## Risk Assessment\n\n${riskReport}`);
|
|
513
521
|
}
|
|
514
|
-
|
|
522
|
+
return (basePrompt +
|
|
515
523
|
"\n\n" +
|
|
516
524
|
sections.join("\n\n") +
|
|
517
525
|
"\n\n" +
|
|
518
526
|
"Use these analyses to produce a more accurate execution plan.\n" +
|
|
519
|
-
"Prefer actual file paths discovered in the codebase analysis over guessed paths.";
|
|
520
|
-
// Run the final synthesizer planner with the enhanced prompt
|
|
521
|
-
return runClaudeCli(claudePath, model, enhancedPrompt, env, taskId, startTime);
|
|
527
|
+
"Prefer actual file paths discovered in the codebase analysis over guessed paths.");
|
|
522
528
|
}
|
|
523
529
|
/**
|
|
524
530
|
* Run planning for a task with Planner-Critic validation loop.
|
|
@@ -552,8 +558,11 @@ export async function planTask(task, config, credentials) {
|
|
|
552
558
|
const startTime = Date.now();
|
|
553
559
|
// PRD for critic validation: use task description, fall back to summary
|
|
554
560
|
const prd = task.description || task.summary;
|
|
555
|
-
//
|
|
561
|
+
// Run team analysis ONCE before the planner-critic loop.
|
|
562
|
+
// Analyst prompts don't include critic feedback, so re-running them
|
|
563
|
+
// on iteration 2+ wastes compute (they'd produce the same reports).
|
|
556
564
|
let repoPath = null;
|
|
565
|
+
let enhancedBasePrompt = basePrompt;
|
|
557
566
|
if (isAnthropicPlanning && config.teamPlanningEnabled && task.githubRepo) {
|
|
558
567
|
const scmProvider = task.scmProvider || "github";
|
|
559
568
|
const scmToken = scmProvider === "bitbucket"
|
|
@@ -567,9 +576,18 @@ export async function planTask(task, config, credentials) {
|
|
|
567
576
|
else {
|
|
568
577
|
console.log(`${ts()} ${taskLabel} ${chalk.yellow("⚠")} No SCM token for ${scmProvider}, skipping team planning`);
|
|
569
578
|
}
|
|
579
|
+
if (repoPath) {
|
|
580
|
+
const analysisResult = await runTeamAnalysis(task, basePrompt, claudePath, cliModel, cleanEnv, repoPath, task.id, startTime);
|
|
581
|
+
if (analysisResult) {
|
|
582
|
+
enhancedBasePrompt = analysisResult;
|
|
583
|
+
}
|
|
584
|
+
// else: all analysts failed, fall back to basePrompt
|
|
585
|
+
}
|
|
570
586
|
}
|
|
571
587
|
// 2. Planner-Critic iteration loop
|
|
572
|
-
|
|
588
|
+
// Use enhancedBasePrompt (with analyst reports) as the base for all iterations.
|
|
589
|
+
// Critic feedback gets appended on re-plan, but analyst reports are fixed.
|
|
590
|
+
let currentPrompt = enhancedBasePrompt;
|
|
573
591
|
let bestPlan = null;
|
|
574
592
|
let bestScore = 0;
|
|
575
593
|
// Track critic history across iterations for analytics
|
|
@@ -590,10 +608,7 @@ export async function planTask(task, config, credentials) {
|
|
|
590
608
|
// 2a. Generate plan via Claude CLI (Anthropic) or HTTP API (other providers)
|
|
591
609
|
let rawOutput;
|
|
592
610
|
try {
|
|
593
|
-
if (isAnthropicPlanning
|
|
594
|
-
rawOutput = await runTeamPlanning(task, currentPrompt, claudePath, cliModel, cleanEnv, repoPath, task.id, startTime);
|
|
595
|
-
}
|
|
596
|
-
else if (isAnthropicPlanning) {
|
|
611
|
+
if (isAnthropicPlanning) {
|
|
597
612
|
rawOutput = await runClaudeCli(claudePath, cliModel, currentPrompt, cleanEnv, task.id, startTime);
|
|
598
613
|
}
|
|
599
614
|
else {
|
|
@@ -690,7 +705,7 @@ export async function planTask(task, config, credentials) {
|
|
|
690
705
|
// 2f. Rejected — append critic feedback for next iteration
|
|
691
706
|
if (iteration < MAX_ITERATIONS) {
|
|
692
707
|
const feedback = formatCriticFeedback(criticResult);
|
|
693
|
-
currentPrompt =
|
|
708
|
+
currentPrompt = enhancedBasePrompt + "\n\n" + feedback;
|
|
694
709
|
const msg = `${PREFIX} Critic rejected (score: ${criticResult.score}/100, threshold: ${AUTO_APPROVAL_THRESHOLD}). Re-planning with feedback...`;
|
|
695
710
|
console.log(`${ts()} ${taskLabel} ${chalk.yellow("⚠")} ${msg}`);
|
|
696
711
|
await postLog(task.id, msg);
|
package/dist/poller.js
CHANGED
|
@@ -250,7 +250,11 @@ export function startPolling(config) {
|
|
|
250
250
|
*/
|
|
251
251
|
export function startHeartbeat(config) {
|
|
252
252
|
setInterval(async () => {
|
|
253
|
-
|
|
253
|
+
// Include BOTH running containers AND tasks being planned/managed
|
|
254
|
+
const containerTaskIds = getActiveTaskIds();
|
|
255
|
+
const planningTaskIds = Array.from(planningInProgress);
|
|
256
|
+
const managerTaskIds = Array.from(managerInProgress);
|
|
257
|
+
const activeTaskIds = [...containerTaskIds, ...planningTaskIds, ...managerTaskIds];
|
|
254
258
|
try {
|
|
255
259
|
const response = await api.post("/api/agent/heartbeat", {
|
|
256
260
|
agentId: config.agentId,
|
package/dist/spawner.js
CHANGED
|
@@ -218,7 +218,7 @@ export async function spawnWorker(task, config, orgConfig, credentials) {
|
|
|
218
218
|
EXISTING_PR_URL: task.githubPrUrl || "",
|
|
219
219
|
EXISTING_PR_NUMBER: task.githubPrNumber ? String(task.githubPrNumber) : "",
|
|
220
220
|
// PRD Orchestration
|
|
221
|
-
PARENT_TASK_ID: task.parentTaskId ||
|
|
221
|
+
PARENT_TASK_ID: task.parentTaskId || task.id,
|
|
222
222
|
PARENT_JIRA_KEY: task.jiraIssueKey && /-S\d+$/.test(task.jiraIssueKey)
|
|
223
223
|
? task.jiraFields?.parentJiraKey || ""
|
|
224
224
|
: "",
|