@workermill/agent 0.6.2 → 0.7.0

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/config.d.ts CHANGED
@@ -17,6 +17,7 @@ export interface AgentConfig {
17
17
  gitlabToken: string;
18
18
  workerImage: string;
19
19
  teamPlanningEnabled: boolean;
20
+ analystModel: string;
20
21
  }
21
22
  export interface FileConfig {
22
23
  apiUrl: string;
@@ -32,6 +33,7 @@ export interface FileConfig {
32
33
  };
33
34
  workerImage: string;
34
35
  teamPlanningEnabled?: boolean;
36
+ analystModel?: string;
35
37
  setupCompletedAt: string;
36
38
  }
37
39
  export declare function getConfigDir(): string;
package/dist/config.js CHANGED
@@ -76,6 +76,7 @@ export function loadConfigFromFile() {
76
76
  gitlabToken: fc.tokens?.gitlab || "",
77
77
  workerImage,
78
78
  teamPlanningEnabled: fc.teamPlanningEnabled ?? true,
79
+ analystModel: fc.analystModel || "sonnet",
79
80
  };
80
81
  }
81
82
  /**
@@ -121,6 +122,7 @@ export function loadConfig() {
121
122
  gitlabToken: process.env.GITLAB_TOKEN || "",
122
123
  workerImage: process.env.WORKER_IMAGE || "workermill-worker:local",
123
124
  teamPlanningEnabled: process.env.TEAM_PLANNING_ENABLED !== "false",
125
+ analystModel: process.env.ANALYST_MODEL || "sonnet",
124
126
  };
125
127
  }
126
128
  /**
@@ -53,6 +53,14 @@ export declare function applyFileCap(plan: ExecutionPlan): {
53
53
  truncatedCount: number;
54
54
  details: string[];
55
55
  };
56
+ /**
57
+ * Apply story cap to the plan. Truncates stories beyond maxStories.
58
+ * Returns details about dropped stories for logging.
59
+ */
60
+ export declare function applyStoryCap(plan: ExecutionPlan, maxStories: number): {
61
+ droppedCount: number;
62
+ details: string[];
63
+ };
56
64
  /**
57
65
  * Re-serialize plan as a JSON code block for posting to the API.
58
66
  * The server-side parseExecutionPlan() expects ```json ... ``` blocks.
@@ -59,6 +59,28 @@ export function applyFileCap(plan) {
59
59
  return { truncatedCount, details };
60
60
  }
61
61
  // ============================================================================
62
+ // STORY CAP
63
+ // ============================================================================
64
+ /**
65
+ * Apply story cap to the plan. Truncates stories beyond maxStories.
66
+ * Returns details about dropped stories for logging.
67
+ */
68
+ export function applyStoryCap(plan, maxStories) {
69
+ if (plan.stories.length <= maxStories) {
70
+ return { droppedCount: 0, details: [] };
71
+ }
72
+ const droppedCount = plan.stories.length - maxStories;
73
+ const dropped = plan.stories.slice(maxStories);
74
+ const details = dropped.map((s) => `${s.id}: "${s.title}" (${s.persona})`);
75
+ plan.stories = plan.stories.slice(0, maxStories);
76
+ // Fix dependencies that reference dropped stories
77
+ const validIds = new Set(plan.stories.map((s) => s.id));
78
+ for (const story of plan.stories) {
79
+ story.dependencies = story.dependencies.filter((dep) => validIds.has(dep));
80
+ }
81
+ return { droppedCount, details };
82
+ }
83
+ // ============================================================================
62
84
  // PLAN SERIALIZATION
63
85
  // ============================================================================
64
86
  /**
package/dist/planner.js CHANGED
@@ -18,7 +18,7 @@ import chalk from "chalk";
18
18
  import { spawn, execSync } from "child_process";
19
19
  import { findClaudePath } from "./config.js";
20
20
  import { api } from "./api.js";
21
- import { parseExecutionPlan, applyFileCap, serializePlan, runCriticValidation, formatCriticFeedback, AUTO_APPROVAL_THRESHOLD, } from "./plan-validator.js";
21
+ import { parseExecutionPlan, applyFileCap, applyStoryCap, serializePlan, runCriticValidation, formatCriticFeedback, AUTO_APPROVAL_THRESHOLD, } from "./plan-validator.js";
22
22
  import { generateText } from "./providers.js";
23
23
  /** Max Planner-Critic iterations before giving up */
24
24
  const MAX_ITERATIONS = 3;
@@ -546,7 +546,8 @@ export async function planTask(task, config, credentials) {
546
546
  const promptResponse = await api.get("/api/agent/planning-prompt", {
547
547
  params: { taskId: task.id },
548
548
  });
549
- const { prompt: basePrompt, model, provider: planningProvider } = promptResponse.data;
549
+ const { prompt: basePrompt, model, provider: planningProvider, maxStories: apiMaxStories } = promptResponse.data;
550
+ const maxStories = typeof apiMaxStories === "number" ? apiMaxStories : 8;
550
551
  const cliModel = model || "sonnet";
551
552
  const provider = (planningProvider || "anthropic");
552
553
  const isAnthropicPlanning = provider === "anthropic";
@@ -577,7 +578,9 @@ export async function planTask(task, config, credentials) {
577
578
  console.log(`${ts()} ${taskLabel} ${chalk.yellow("⚠")} No SCM token for ${scmProvider}, skipping team planning`);
578
579
  }
579
580
  if (repoPath) {
580
- const analysisResult = await runTeamAnalysis(task, basePrompt, claudePath, cliModel, cleanEnv, repoPath, task.id, startTime);
581
+ const analystModel = config.analystModel || "sonnet";
582
+ console.log(`${ts()} ${taskLabel} Analysts using model: ${chalk.yellow(analystModel)} (planner: ${chalk.yellow(cliModel)})`);
583
+ const analysisResult = await runTeamAnalysis(task, basePrompt, claudePath, analystModel, cleanEnv, repoPath, task.id, startTime);
581
584
  if (analysisResult) {
582
585
  enhancedBasePrompt = analysisResult;
583
586
  }
@@ -656,7 +659,17 @@ export async function planTask(task, config, credentials) {
656
659
  console.log(`${ts()} ${taskLabel} ${chalk.dim(detail)}`);
657
660
  }
658
661
  }
659
- console.log(`${ts()} ${taskLabel} Plan: ${chalk.bold(plan.stories.length)} stories`);
662
+ // 2c2. Apply story cap (max stories from org calibration)
663
+ const { droppedCount: storyDropCount, details: storyDropDetails } = applyStoryCap(plan, maxStories);
664
+ if (storyDropCount > 0) {
665
+ const msg = `${PREFIX} Story cap applied: ${storyDropCount} stories dropped (max ${maxStories})`;
666
+ console.log(`${ts()} ${taskLabel} ${chalk.yellow("⚠")} ${msg}`);
667
+ await postLog(task.id, msg);
668
+ for (const detail of storyDropDetails) {
669
+ console.log(`${ts()} ${taskLabel} ${chalk.dim(detail)}`);
670
+ }
671
+ }
672
+ console.log(`${ts()} ${taskLabel} Plan: ${chalk.bold(plan.stories.length)} stories (max ${maxStories})`);
660
673
  await postLog(task.id, `${PREFIX} Plan generated: ${plan.stories.length} stories (${formatElapsed(elapsed)}). Running critic validation...`);
661
674
  // 2d. Run critic validation
662
675
  const criticResult = await runCriticValidation(claudePath, cliModel, prd, plan, cleanEnv, taskLabel, provider, providerApiKey);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workermill/agent",
3
- "version": "0.6.2",
3
+ "version": "0.7.0",
4
4
  "description": "WorkerMill Remote Agent - Run AI workers locally with your Claude Max subscription",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",