@gjczone/pi-swarm 0.4.1 → 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.
Files changed (75) hide show
  1. package/README.md +35 -89
  2. package/dist/index.d.ts +3 -10
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +4 -16
  5. package/dist/index.js.map +1 -1
  6. package/dist/shared/controller.d.ts +19 -5
  7. package/dist/shared/controller.d.ts.map +1 -1
  8. package/dist/shared/controller.js +139 -17
  9. package/dist/shared/controller.js.map +1 -1
  10. package/dist/shared/render.d.ts +1 -12
  11. package/dist/shared/render.d.ts.map +1 -1
  12. package/dist/shared/render.js +4 -37
  13. package/dist/shared/render.js.map +1 -1
  14. package/dist/shared/spawner.js +49 -5
  15. package/dist/shared/spawner.js.map +1 -1
  16. package/dist/shared/types.d.ts +38 -0
  17. package/dist/shared/types.d.ts.map +1 -1
  18. package/dist/shared/types.js.map +1 -1
  19. package/dist/shared/worktree.d.ts +2 -0
  20. package/dist/shared/worktree.d.ts.map +1 -1
  21. package/dist/shared/worktree.js +10 -3
  22. package/dist/shared/worktree.js.map +1 -1
  23. package/dist/shared/xml.d.ts +18 -0
  24. package/dist/shared/xml.d.ts.map +1 -0
  25. package/dist/shared/xml.js +31 -0
  26. package/dist/shared/xml.js.map +1 -0
  27. package/dist/state/recovery.d.ts.map +1 -1
  28. package/dist/state/recovery.js +25 -4
  29. package/dist/state/recovery.js.map +1 -1
  30. package/dist/swarm/command.d.ts +4 -5
  31. package/dist/swarm/command.d.ts.map +1 -1
  32. package/dist/swarm/command.js +26 -74
  33. package/dist/swarm/command.js.map +1 -1
  34. package/dist/swarm/mode.d.ts +1 -1
  35. package/dist/swarm/mode.js +2 -2
  36. package/dist/swarm/mode.js.map +1 -1
  37. package/dist/swarm/tool.d.ts +4 -4
  38. package/dist/swarm/tool.d.ts.map +1 -1
  39. package/dist/swarm/tool.js +115 -160
  40. package/dist/swarm/tool.js.map +1 -1
  41. package/dist/team/command.d.ts +2 -4
  42. package/dist/team/command.d.ts.map +1 -1
  43. package/dist/team/command.js +5 -13
  44. package/dist/team/command.js.map +1 -1
  45. package/dist/team/mailbox.d.ts +7 -0
  46. package/dist/team/mailbox.d.ts.map +1 -1
  47. package/dist/team/mailbox.js +99 -13
  48. package/dist/team/mailbox.js.map +1 -1
  49. package/dist/tui/progress.d.ts +26 -9
  50. package/dist/tui/progress.d.ts.map +1 -1
  51. package/dist/tui/progress.js +262 -163
  52. package/dist/tui/progress.js.map +1 -1
  53. package/dist/tui/swarm-markers.d.ts +1 -1
  54. package/dist/tui/swarm-markers.js +1 -1
  55. package/package.json +13 -2
  56. package/dist/team/supervisor.d.ts +0 -171
  57. package/dist/team/supervisor.d.ts.map +0 -1
  58. package/dist/team/supervisor.js +0 -700
  59. package/dist/team/supervisor.js.map +0 -1
  60. package/dist/team/task-graph.d.ts +0 -64
  61. package/dist/team/task-graph.d.ts.map +0 -1
  62. package/dist/team/task-graph.js +0 -216
  63. package/dist/team/task-graph.js.map +0 -1
  64. package/dist/team/tool.d.ts +0 -11
  65. package/dist/team/tool.d.ts.map +0 -1
  66. package/dist/team/tool.js +0 -455
  67. package/dist/team/tool.js.map +0 -1
  68. package/dist/tui/permission-prompt.d.ts +0 -26
  69. package/dist/tui/permission-prompt.d.ts.map +0 -1
  70. package/dist/tui/permission-prompt.js +0 -98
  71. package/dist/tui/permission-prompt.js.map +0 -1
  72. package/dist/tui/team-dashboard.d.ts +0 -48
  73. package/dist/tui/team-dashboard.d.ts.map +0 -1
  74. package/dist/tui/team-dashboard.js +0 -249
  75. package/dist/tui/team-dashboard.js.map +0 -1
package/README.md CHANGED
@@ -1,36 +1,29 @@
1
- # @gjczone/pi-swarm
1
+ # pi-swarm
2
2
 
3
- > **Early release stability not guaranteed.** This is an initial version. Expect rough edges. Bug reports, feedback, feature requests, and PRs are very welcome.
3
+ Agent Swarm & Team extension for pi-coding-agent. Run 1 to 128 parallel subagents or collaborative role-based teams no preset configuration needed.
4
4
 
5
- Think of it as **kimi-code's AgentSwarm + Claude Code's agent teams** — inside pi. Parallel swarm agents and collaborative role-based teams, all dynamically spawned with no preset configuration.
6
-
7
- ## What It Does
8
-
9
- **Swarm** — 1 to 128 parallel agents. Like kimi-code's AgentSwarm: one template, many items, running simultaneously. Also works for single subagent delegation. Each agent is an isolated `pi --print` child process with its own context window.
10
-
11
- **Team** — collaborative agents. Like Claude Code's agent teams or pi-crew: role-based agents (explorer, planner, coder, reviewer, tester) working in sequence. Each phase agent receives context from previous phases via a shared mailbox. Every agent runs as an independent child process. Optional per-role model tier routing: use a cheaper/faster model for exploration while keeping reasoning-heavy roles on the default model.
12
-
13
- **Worktree Isolation** — each subagent runs in a temporary git worktree by default, so parallel agents cannot interfere with each other's file changes. On completion, changes are committed to a named branch for safe merging. Non-git repos fall back to regular directory mode.
14
-
15
- **Real-time Mailbox** — team agents can send and receive messages during execution, not just between phases. Messages are delivered in near-real-time via file polling.
16
-
17
- All agents are created on-the-fly. No `agents/*.md` files. The main agent decides what to spawn based on the task.
18
-
19
- ## Install
5
+ ## Installation
20
6
 
21
7
  ```bash
22
8
  pi install npm:@gjczone/pi-swarm@latest
23
9
  ```
24
10
 
25
- ## How to Use
11
+ ## Core Features
26
12
 
27
- ### Swarm "Do this to all of these" (or just one)
13
+ | Feature | When to Use | What It Does |
14
+ |---------|-------------|--------------|
15
+ | **Swarm** | Run the same task across many items in parallel | Spawns 1-20 subagents from an item template. Optional mailbox mode for inter-agent communication. |
16
+ | **/swarm** | Trigger a swarm from chat | Shortcut for the Swarm tool. Usage: `/swarm <task>` |
17
+ | **/swarm-team** | Trigger a collaborative swarm | Shortcut for Swarm with mailbox enabled. Usage: `/swarm-team <goal>` |
18
+ | **Mailbox Mode** | Need agents to share findings | When `mailbox: true`, agents get inbox/outbox and can exchange messages during execution. |
19
+ | **Worktree Isolation** | Parallel agents modifying the same repo | Each subagent runs in a temporary git worktree. Changes commit to named branches for safe merging. Non-git repos fall back to regular directories. |
20
+ | **Live TUI Progress** | Monitor running swarms | Braille progress bars, grid layout, scrolling model output. Single-agent compact mode. |
21
+ | **Rate-Limit Retry** | Avoid API quota exhaustion | Auto-suspends on rate-limit errors and retries with exponential backoff (3s, 6s, 12s...). |
22
+ | **Crash Recovery** | Survive unexpected termination | Durable file-based state. Resume incomplete runs automatically. Completed runs auto-clean after 7 days. |
28
23
 
29
- Use for 1 to 128 items — same interface, same isolation.
24
+ ## Usage Examples
30
25
 
31
- ```
32
- Audit src/auth.ts for security issues — use a subagent
33
- ```
26
+ ### Swarm — parallel or collaborative
34
27
 
35
28
  ```
36
29
  Review every file in src/ for bugs — use a swarm
@@ -40,73 +33,21 @@ Review every file in src/ for bugs — use a swarm
40
33
  Run a security audit on these five packages in parallel: auth, api, db, cache, middleware
41
34
  ```
42
35
 
43
- Or the slash command:
44
-
45
- ```
46
- /swarm Find deprecated API usage across the codebase
47
- ```
48
-
49
- ### Team — "Plan this, build it, review it"
50
-
51
- ```
52
- Implement user login with JWT — use a team with planner, coder, and reviewer
53
- ```
54
-
55
- ```
56
- Add Redis caching — explore the codebase first, then plan, implement, review, test
57
- ```
58
-
59
- Or:
60
-
61
36
  ```
62
- /swarm-team Refactor the auth module end-to-end
37
+ Implement user login with JWT — use a swarm with mailbox so agents can collaborate
63
38
  ```
64
39
 
65
- ### Resume Failed Work
66
-
67
- If agents fail, the LLM gets `resume_agent_ids` and can retry:
68
-
69
40
  ```
70
- Two of the five swarm reviews failed retry those
41
+ Add Redis caching explore first, then implement based on findings
71
42
  ```
72
43
 
73
- ### Cancel Mid-Run
74
-
75
- Press `Ctrl+C` during a swarm or team run. Completed agents are preserved and results are final (no post-cancellation mutation). In-progress agents are cancelled gracefully and their partial work discarded. For teams, completed phases are saved and returned as partial results. Timeout errors are correctly surfaced instead of being lost in abort/exit races.
76
-
77
- ## Runtime Files
78
-
79
- State is stored under `.pi/swarm/state/`. The extension auto-creates `.pi/` if it doesn't exist, and auto-appends `.pi/swarm/state/` to the project's `.gitignore`.
80
-
81
- ```
82
- .pi/swarm/state/runs/{runId}/
83
- manifest.json # Run metadata, agent IDs, timestamps
84
- tasks.json # Task graph, per-phase status
85
- events.jsonl # Append-only event log
86
- agents/{agentId}/
87
- status.json # Per-agent status snapshot
88
- output.log # Full agent session output (header, raw stdout, footer)
89
- mailbox/ # Team inter-agent messages
90
- inbox.jsonl
91
- outbox.jsonl
92
- delivery.json
93
- tasks/{roleName}/
94
- inbox.jsonl # Per-role real-time inbox
95
- outbox.jsonl # Per-role real-time outbox
96
- ```
44
+ ### Cancel mid-run
97
45
 
98
- Worktree branches (`pi-agent-{agentId}`) are created in the local git repo when agents make changes. Merge them with `git merge pi-agent-{agentId}` or let the tool handle it automatically.
99
-
100
- Runs auto-clean: completed runs deleted after 7 days, stale runs (30min no heartbeat) marked abandoned.
46
+ Press `Ctrl+C` during a swarm run. Completed agents are preserved, in-progress agents are cancelled gracefully.
101
47
 
102
48
  ## Settings
103
49
 
104
- Default max concurrency is **5**. Recommended: **3-10**. Can be set to any positive integer.
105
-
106
- | Settings file | Scope |
107
- | --------------------------- | --------------------------- |
108
- | `.pi/settings.json` | Project (current directory) |
109
- | `~/.pi/agent/settings.json` | Global (all projects) |
50
+ Default max concurrency is **5**. Adjust in `.pi/settings.json` (project) or `~/.pi/agent/settings.json` (global):
110
51
 
111
52
  ```json
112
53
  {
@@ -116,13 +57,7 @@ Default max concurrency is **5**. Recommended: **3-10**. Can be set to any posit
116
57
  }
117
58
  ```
118
59
 
119
- Priority: project settings > global settings > `PI_SWARM_MAX_CONCURRENCY` env var.
120
-
121
- Lower values (3-5) are safer for API rate limits. Values above 10 work if your provider allows high concurrent requests. No hard upper limit.
122
-
123
- ## Team Model Tier
124
-
125
- When using `SwarmTeam`, you can configure a lightweight model for exploration roles to reduce costs:
60
+ Configure a lightweight model for simple/exploratory subagent tasks. The LLM reads this setting and passes `model` explicitly when appropriate:
126
61
 
127
62
  ```json
128
63
  {
@@ -132,12 +67,23 @@ When using `SwarmTeam`, you can configure a lightweight model for exploration ro
132
67
  }
133
68
  ```
134
69
 
135
- The `explorer` and `tester` roles (when assigned to a phase) automatically use the small model. Other roles (`planner`, `coder`, `reviewer`, `fixer`) use the default model unless overridden. No preset agents — you define phases and assign roles via the tool schema. Per-phase overrides are available via `modelTier` and `model` fields.
70
+ When to use small model: exploration, straightforward execution, tasks with clear instructions.
71
+ When NOT to use: review, planning, complex analysis, architecture decisions.
72
+
73
+ ## Supported Platforms
74
+
75
+ | Platform | Status |
76
+ |----------|--------|
77
+ | pi-coding-agent | Required runtime |
78
+ | Node.js >= 18 | Required |
79
+ | Linux / macOS / Windows | Supported |
136
80
 
137
81
  ## Credits
138
82
 
139
- 100% vibe-coded with deepseek-v4-pro, doubao-seed-2.1-pro, and doubao-seed-2.1-turbo. Architecture ported from [MoonshotAI/kimi-code](https://github.com/MoonshotAI/kimi-code). Code implementation patterns inspired by [pi-crew](https://github.com/baphuongna/pi-crew). Agent team workflow approach inspired by Claude Code. Thank you to all these projects for their excellent work.
83
+ Architecture references [MoonshotAI/kimi-code](https://github.com/MoonshotAI/kimi-code). Team communication patterns inspired by [pi-crew](https://github.com/baphuongna/pi-crew). Agent team workflow approach inspired by Claude Code.
140
84
 
141
85
  ## License
142
86
 
143
87
  [MIT](LICENSE)
88
+
89
+
package/dist/index.d.ts CHANGED
@@ -5,20 +5,13 @@
5
5
  * the AgentSwarm tool, /swarm command, swarm-mode state machine,
6
6
  * and TUI progress components.
7
7
  *
8
- * Credit: AgentSwarm architecture ported from MoonshotAI/kimi-code.
8
+ * Credit: AgentSwarm architecture references MoonshotAI/kimi-code.
9
9
  * Team/mailbox patterns inspired by pi-crew.
10
10
  */
11
11
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
12
12
  /**
13
- * Resolve which swarm mode (if any) should be activated based on user input keywords.
14
- *
15
- * Priority: "swarm-team" / "swarm team" > "swarm" alone.
16
- * Returns null when no keyword matches.
17
- *
18
- * 业务说明:根据用户输入中的关键词判断应该激活 AgentSwarm 还是 SwarmTeam。
19
- * "swarm-team" 或 "swarm team" 激活 team 模式,单独的 "swarm" 激活 swarm 模式。
20
- * "swarm-team" 中包含 "swarm" 子串,因此 team 检查必须在 swarm 之前。
13
+ * Return "swarm" when the input contains the word "swarm", otherwise null.
21
14
  */
22
- export declare function resolveKeywordMode(text: string): "swarm" | "team" | null;
15
+ export declare function resolveKeywordMode(text: string): "swarm" | null;
23
16
  export default function (pi: ExtensionAPI): void;
24
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AA6FpE;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,CAKxE;AAED,MAAM,CAAC,OAAO,WAAW,EAAE,EAAE,YAAY,GAAG,IAAI,CAuH/C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AA2FpE;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAI/D;AAED,MAAM,CAAC,OAAO,WAAW,EAAE,EAAE,YAAY,GAAG,IAAI,CAwH/C"}
package/dist/index.js CHANGED
@@ -5,13 +5,11 @@
5
5
  * the AgentSwarm tool, /swarm command, swarm-mode state machine,
6
6
  * and TUI progress components.
7
7
  *
8
- * Credit: AgentSwarm architecture ported from MoonshotAI/kimi-code.
8
+ * Credit: AgentSwarm architecture references MoonshotAI/kimi-code.
9
9
  * Team/mailbox patterns inspired by pi-crew.
10
10
  */
11
11
  import { registerAgentSwarmTool } from "./swarm/tool.js";
12
12
  import { registerSwarmCommand, } from "./swarm/command.js";
13
- import { registerSwarmTeamTool } from "./team/tool.js";
14
- import { registerTeamCommand } from "./team/command.js";
15
13
  import { recoverRuns } from "./state/recovery.js";
16
14
  import { SwarmModeMarkerComponent, } from "./tui/swarm-markers.js";
17
15
  import { pruneWorktrees } from "./shared/worktree.js";
@@ -81,19 +79,10 @@ function findGitignore(cwd) {
81
79
  // Keyword mode resolver (exported for testing)
82
80
  // ---------------------------------------------------------------------------
83
81
  /**
84
- * Resolve which swarm mode (if any) should be activated based on user input keywords.
85
- *
86
- * Priority: "swarm-team" / "swarm team" > "swarm" alone.
87
- * Returns null when no keyword matches.
88
- *
89
- * 业务说明:根据用户输入中的关键词判断应该激活 AgentSwarm 还是 SwarmTeam。
90
- * "swarm-team" 或 "swarm team" 激活 team 模式,单独的 "swarm" 激活 swarm 模式。
91
- * "swarm-team" 中包含 "swarm" 子串,因此 team 检查必须在 swarm 之前。
82
+ * Return "swarm" when the input contains the word "swarm", otherwise null.
92
83
  */
93
84
  export function resolveKeywordMode(text) {
94
85
  const t = text.toLowerCase();
95
- if (t.includes("swarm-team") || t.includes("swarm team"))
96
- return "team";
97
86
  if (t.includes("swarm"))
98
87
  return "swarm";
99
88
  return null;
@@ -133,7 +122,8 @@ export default function (pi) {
133
122
  return tools !== undefined && tools.length > 0;
134
123
  }
135
124
  catch {
136
- return true;
125
+ console.error("[pi-swarm] Failed to check active model availability, assuming no model.");
126
+ return false;
137
127
  }
138
128
  },
139
129
  };
@@ -202,8 +192,6 @@ export default function (pi) {
202
192
  });
203
193
  registerAgentSwarmTool(pi);
204
194
  registerSwarmCommand(pi, commandHost);
205
- registerSwarmTeamTool(pi);
206
- registerTeamCommand(pi, commandHost);
207
195
  }
208
196
  // ---------------------------------------------------------------------------
209
197
  // Marker helpers
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * controller — concurrency controller for subagent batches.
3
3
  *
4
- * Ported from MoonshotAI/kimi-code's SubagentBatch.
4
+ * Architecture reference: AgentSwarm pattern.
5
5
  *
6
6
  * Two-phase scheduling:
7
7
  * Normal phase: ramp-up (5 initial, +1 every 700ms).
@@ -38,6 +38,9 @@ export declare class SubagentBatchController<T> {
38
38
  private startedAt;
39
39
  private startedSuccessCount;
40
40
  private readonly onProgress?;
41
+ private eventLog;
42
+ private nextEventId;
43
+ private completionTimesMs;
41
44
  constructor(launcher: SubagentBatchLauncher, tasks: readonly QueuedSubagentTask<T>[], options?: SubagentBatchOptions);
42
45
  /**
43
46
  * Run the batch. Returns a promise that resolves when all tasks
@@ -60,6 +63,8 @@ export declare class SubagentBatchController<T> {
60
63
  private recoverRateLimitCapacity;
61
64
  private finishIfComplete;
62
65
  private emitProgress;
66
+ /** Add an event to the event log, keeping it bounded. */
67
+ private addEvent;
63
68
  private finish;
64
69
  private finishWithUserCancellation;
65
70
  private fail;
@@ -82,9 +87,18 @@ export declare class SubagentBatchController<T> {
82
87
  * 2. `~/.pi/agent/settings.json` → `pi-swarm.maxConcurrency` (global)
83
88
  * 3. `PI_SWARM_MAX_CONCURRENCY` env var
84
89
  *
85
- * Returns `undefined` when unset. A present value must be a positive
86
- * integer; invalid input throws so a misconfigured cap never silently
87
- * reverts to uncapped.
90
+ * Falls back to DEFAULT_MAX_CONCURRENCY (5) when unset. A present
91
+ * value must be a positive integer; invalid input throws so a
92
+ * misconfigured cap never silently reverts to uncapped.
88
93
  */
89
- export declare function resolveSwarmMaxConcurrency(cwd?: string): number | undefined;
94
+ export declare function resolveSwarmMaxConcurrency(cwd?: string): number;
95
+ /**
96
+ * Resolve the optional small model from pi settings.
97
+ * Used as the default model for simple subagent tasks.
98
+ *
99
+ * Priority:
100
+ * 1. `.pi/settings.json` → `pi-swarm.smallModel`
101
+ * 2. `~/.pi/agent/settings.json` → `pi-swarm.smallModel`
102
+ */
103
+ export declare function resolveSwarmSmallModel(cwd?: string): string | undefined;
90
104
  //# sourceMappingURL=controller.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/shared/controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,kBAAkB,EAClB,cAAc,EACd,oBAAoB,EACpB,qBAAqB,EAStB,MAAM,YAAY,CAAC;AA0FpB,qBAAa,uBAAuB,CAAC,CAAC;IAkClC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAjC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+B;IACtD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;IACpD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAC7C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAqB;IACpD,OAAO,CAAC,YAAY,CAAS;IAG7B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,iBAAiB,CAA4C;IAGrE,OAAO,CAAC,oBAAoB,CAA4C;IACxE,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,oBAAoB,CAAqB;IACjD,OAAO,CAAC,sBAAsB,CAAqB;IACnD,OAAO,CAAC,qBAAqB,CAA4B;IACzD,OAAO,CAAC,qBAAqB,CAAK;IAGlC,OAAO,CAAC,OAAO,CAA4D;IAC3E,OAAO,CAAC,MAAM,CAAyC;IACvD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAA4C;gBAGrD,QAAQ,EAAE,qBAAqB,EAChD,KAAK,EAAE,SAAS,kBAAkB,CAAC,CAAC,CAAC,EAAE,EACvC,OAAO,GAAE,oBAAyB;IAqCpC;;;OAGG;IACH,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC;IAoCxC,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,QAAQ;IAYhB,OAAO,CAAC,oBAAoB;IAwC5B,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,uBAAuB;IA2C/B,OAAO,CAAC,YAAY;YA0BN,UAAU;IAgGxB,OAAO,CAAC,oBAAoB;IAoB5B,OAAO,CAAC,kBAAkB;IAwB1B,OAAO,CAAC,eAAe;IA6BvB,OAAO,CAAC,oBAAoB;IAoC5B,OAAO,CAAC,mBAAmB;IAS3B,OAAO,CAAC,uBAAuB;IAe/B,OAAO,CAAC,wBAAwB;IAiBhC,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,YAAY;IA2EpB,OAAO,CAAC,MAAM;IAUd,OAAO,CAAC,0BAA0B;IAoClC,OAAO,CAAC,IAAI;IAsBZ,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,uBAAuB;IAQ/B,OAAO,CAAC,2BAA2B;IAkBnC,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,+BAA+B;IAQvC,OAAO,CAAC,kBAAkB;CAsC3B;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CA4B3E"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/shared/controller.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * controller — concurrency controller for subagent batches.
3
3
  *
4
- * Ported from MoonshotAI/kimi-code's SubagentBatch.
4
+ * Architecture reference: AgentSwarm pattern.
5
5
  *
6
6
  * Two-phase scheduling:
7
7
  * Normal phase: ramp-up (5 initial, +1 every 700ms).
@@ -13,7 +13,7 @@
13
13
  import * as fs from "node:fs";
14
14
  import * as path from "node:path";
15
15
  // ---------------------------------------------------------------------------
16
- // Constants (from kimi-code)
16
+ // Constants
17
17
  // ---------------------------------------------------------------------------
18
18
  const INITIAL_LAUNCH_LIMIT = 5;
19
19
  const INITIAL_LAUNCH_INTERVAL_MS = 700;
@@ -23,6 +23,7 @@ const RATE_LIMIT_CAPACITY_SHRINK_INTERVAL_MS = 2000;
23
23
  const RATE_LIMIT_CAPACITY_RECOVERY_INTERVAL_MS = 3 * 60 * 1000; // 3 minutes
24
24
  const AGENT_SWARM_MAX_CONCURRENCY_ENV = "PI_SWARM_MAX_CONCURRENCY";
25
25
  const DEFAULT_MAX_CONCURRENCY = 5;
26
+ const RATE_LIMIT_SUSPENDED_REASON = "Rate limit reached — agent suspended";
26
27
  // ---------------------------------------------------------------------------
27
28
  // Abort helpers
28
29
  // ---------------------------------------------------------------------------
@@ -36,10 +37,7 @@ function isUserCancellation(reason) {
36
37
  const msg = reason instanceof Error
37
38
  ? reason.message.toLowerCase()
38
39
  : String(reason).toLowerCase();
39
- return (msg.includes("user") ||
40
- msg.includes("cancel") ||
41
- msg.includes("interrupt") ||
42
- msg.includes("abort"));
40
+ return (msg.includes("user") || msg.includes("cancel") || msg.includes("interrupt"));
43
41
  }
44
42
  function userCancellationReason() {
45
43
  return new Error("User cancelled");
@@ -91,6 +89,11 @@ export class SubagentBatchController {
91
89
  startedAt = 0;
92
90
  startedSuccessCount = 0;
93
91
  onProgress;
92
+ // Event log
93
+ eventLog = [];
94
+ nextEventId = 1;
95
+ // ETA tracking: track completion timestamps for average calculation
96
+ completionTimesMs = [];
94
97
  constructor(launcher, tasks, options = {}) {
95
98
  this.launcher = launcher;
96
99
  this.maxConcurrency = options.maxConcurrency;
@@ -108,6 +111,7 @@ export class SubagentBatchController {
108
111
  cacheWrite: 0,
109
112
  totalTokens: 0,
110
113
  },
114
+ progressTick: 0,
111
115
  }));
112
116
  this.pending = [...this.states];
113
117
  this.results = Array.from({
@@ -235,7 +239,9 @@ export class SubagentBatchController {
235
239
  return;
236
240
  const now = Date.now();
237
241
  this.recoverRateLimitCapacity(now);
238
- if (this.active.size >= this.rateLimitCapacity) {
242
+ if (this.active.size >= this.rateLimitCapacity ||
243
+ (this.maxConcurrency !== undefined &&
244
+ this.active.size >= this.maxConcurrency)) {
239
245
  this.scheduleRateLimitWakeup(this.nextRateLimitCapacityRecoveryAt(), now);
240
246
  return;
241
247
  }
@@ -271,6 +277,21 @@ export class SubagentBatchController {
271
277
  attempt.cleanup = this.linkAttemptSignals(attempt, state.task);
272
278
  this.active.add(attempt);
273
279
  attempt.state.started = true;
280
+ attempt.state.startedAt = Date.now();
281
+ // Add event to log
282
+ this.addEvent({
283
+ id: this.nextEventId++,
284
+ agentId: undefined,
285
+ timestamp: Date.now(),
286
+ type: "started",
287
+ detail: state.task.swarmItem
288
+ ? `Started: ${state.task.swarmItem.slice(0, 60)}`
289
+ : `Started task ${state.index + 1}`,
290
+ });
291
+ // Trim event log to last 50 entries
292
+ if (this.eventLog.length > 50) {
293
+ this.eventLog = this.eventLog.slice(-50);
294
+ }
274
295
  // A task transitioned from queued to working
275
296
  this.emitProgress();
276
297
  this.runAttempt(attempt).then((outcome) => {
@@ -295,6 +316,16 @@ export class SubagentBatchController {
295
316
  onUsage: (usage) => {
296
317
  attempt.state.usage = { ...usage };
297
318
  this.emitProgress();
319
+ // Forward to task-level callback (used by team mode to update supervisor phase usage)
320
+ task.onUsage?.(usage);
321
+ },
322
+ onActivity: (tool, activity) => {
323
+ attempt.state.currentTool = tool;
324
+ attempt.state.activity = activity;
325
+ attempt.state.progressTick += 1;
326
+ this.emitProgress();
327
+ // Forward to task-level callback (used by team mode to update phase activity)
328
+ task.onActivity?.(tool, activity);
298
329
  },
299
330
  onMessage: task.onMessage,
300
331
  suppressRateLimitFailureEvent: true,
@@ -343,6 +374,21 @@ export class SubagentBatchController {
343
374
  if (completion.usage) {
344
375
  attempt.state.usage = { ...completion.usage };
345
376
  }
377
+ const completedAt = Date.now();
378
+ attempt.state.completedAt = completedAt;
379
+ if (attempt.state.startedAt) {
380
+ this.completionTimesMs.push(completedAt - attempt.state.startedAt);
381
+ }
382
+ // Add event to log
383
+ this.addEvent({
384
+ id: this.nextEventId++,
385
+ agentId: handle.agentId,
386
+ timestamp: completedAt,
387
+ type: "completed",
388
+ detail: attempt.state.task.swarmItem
389
+ ? `Agent completed: ${attempt.state.task.swarmItem.slice(0, 60)}`
390
+ : `Agent completed`,
391
+ });
346
392
  return {
347
393
  task,
348
394
  agentId: handle.agentId,
@@ -408,6 +454,13 @@ export class SubagentBatchController {
408
454
  // Save agent id for retry and requeue at front
409
455
  state.retryAgentId = state.agentId ?? state.retryAgentId;
410
456
  state.retryCount += 1;
457
+ // Notify external listeners that this agent was suspended
458
+ if (state.agentId) {
459
+ this.launcher.suspended?.({
460
+ agentId: state.agentId,
461
+ reason: RATE_LIMIT_SUSPENDED_REASON,
462
+ });
463
+ }
411
464
  // Exponential backoff
412
465
  const delay = RATE_LIMIT_RETRY_BASE_MS *
413
466
  Math.pow(RATE_LIMIT_RETRY_FACTOR, state.retryCount - 1);
@@ -424,10 +477,7 @@ export class SubagentBatchController {
424
477
  }
425
478
  failedAttemptOutcome(attempt, error) {
426
479
  const task = attempt.state.task;
427
- const isAbort = error instanceof Error &&
428
- (error.message.includes("abort") ||
429
- error.message.includes("cancel") ||
430
- error.name === "AbortError");
480
+ const isAbort = isUserCancellation(error);
431
481
  const status = isAbort ? "aborted" : "failed";
432
482
  let errorMessage;
433
483
  if (attempt.timedOut && task.timeout !== undefined) {
@@ -454,7 +504,12 @@ export class SubagentBatchController {
454
504
  enterRateLimitPhase() {
455
505
  this.rateLimitMode = true;
456
506
  this.clearNormalTimer();
457
- this.rateLimitCapacity = Math.max(1, this.countReadyActive());
507
+ // Use startedSuccessCount (count of agents that fully booted during
508
+ // the normal phase) so capacity reflects true past throughput rather
509
+ // than only currently-active attempts (which may already be finishing).
510
+ this.rateLimitCapacity = Math.max(1, this.maxConcurrency !== undefined
511
+ ? Math.min(this.maxConcurrency, this.startedSuccessCount)
512
+ : this.startedSuccessCount);
458
513
  this.lastRateLimitAt = Date.now();
459
514
  this.globalRetryIntervalMs = RATE_LIMIT_RETRY_BASE_MS;
460
515
  this.nextRateLimitLaunchAt = Date.now() + RATE_LIMIT_RETRY_BASE_MS;
@@ -479,6 +534,10 @@ export class SubagentBatchController {
479
534
  return;
480
535
  this.lastCapacityRecoveryAt = now;
481
536
  this.rateLimitCapacity += 1;
537
+ if (this.maxConcurrency !== undefined &&
538
+ this.rateLimitCapacity > this.maxConcurrency) {
539
+ this.rateLimitCapacity = this.maxConcurrency;
540
+ }
482
541
  }
483
542
  // -----------------------------------------------------------------------
484
543
  // Completion
@@ -544,9 +603,25 @@ export class SubagentBatchController {
544
603
  item: state.task.swarmItem,
545
604
  error,
546
605
  usage: memberUsage,
606
+ currentTool: state.currentTool,
607
+ activity: state.activity,
608
+ progressTick: state.progressTick,
547
609
  });
548
610
  }
549
611
  const queued = this.states.length - completed - failed - active;
612
+ // Calculate ETA based on average completion time
613
+ let estimatedRemainingMs;
614
+ const totalFinished = completed + failed;
615
+ const totalRemaining = queued + active;
616
+ if (totalFinished > 0 && totalRemaining > 0) {
617
+ const avgTimeMs = this.completionTimesMs.length > 0
618
+ ? this.completionTimesMs.reduce((a, b) => a + b, 0) /
619
+ this.completionTimesMs.length
620
+ : 0;
621
+ if (avgTimeMs > 0) {
622
+ estimatedRemainingMs = avgTimeMs * totalRemaining;
623
+ }
624
+ }
550
625
  this.onProgress({
551
626
  total: this.states.length,
552
627
  completed,
@@ -556,8 +631,18 @@ export class SubagentBatchController {
556
631
  members,
557
632
  totalUsage,
558
633
  startedAt: this.startedAt,
634
+ estimatedRemainingMs,
635
+ eventLog: [...this.eventLog],
559
636
  });
560
637
  }
638
+ /** Add an event to the event log, keeping it bounded. */
639
+ addEvent(event) {
640
+ this.eventLog.push(event);
641
+ // Keep max 100 events
642
+ if (this.eventLog.length > 100) {
643
+ this.eventLog = this.eventLog.slice(-100);
644
+ }
645
+ }
561
646
  finish(results) {
562
647
  if (this.finished)
563
648
  return;
@@ -655,6 +740,17 @@ export class SubagentBatchController {
655
740
  return;
656
741
  attempt.ready = true;
657
742
  this.startedSuccessCount += 1;
743
+ // If we are in rate-limit mode, reset the global retry interval
744
+ // so the next launch uses the base delay rather than an accumulated
745
+ // exponential backoff, and re-arm the scheduler immediately.
746
+ if (this.rateLimitMode) {
747
+ this.globalRetryIntervalMs = RATE_LIMIT_RETRY_BASE_MS;
748
+ this.nextRateLimitLaunchAt = Date.now() + this.globalRetryIntervalMs;
749
+ // Clear any pending rate-limit timer so schedule() re-computes
750
+ // the next wakeup from the new (shorter) interval.
751
+ this.clearRateLimitTimer();
752
+ this.schedule();
753
+ }
658
754
  }
659
755
  countReadyActive() {
660
756
  let count = 0;
@@ -728,9 +824,9 @@ export class SubagentBatchController {
728
824
  * 2. `~/.pi/agent/settings.json` → `pi-swarm.maxConcurrency` (global)
729
825
  * 3. `PI_SWARM_MAX_CONCURRENCY` env var
730
826
  *
731
- * Returns `undefined` when unset. A present value must be a positive
732
- * integer; invalid input throws so a misconfigured cap never silently
733
- * reverts to uncapped.
827
+ * Falls back to DEFAULT_MAX_CONCURRENCY (5) when unset. A present
828
+ * value must be a positive integer; invalid input throws so a
829
+ * misconfigured cap never silently reverts to uncapped.
734
830
  */
735
831
  export function resolveSwarmMaxConcurrency(cwd) {
736
832
  // 1. Project-local settings
@@ -751,12 +847,12 @@ export function resolveSwarmMaxConcurrency(cwd) {
751
847
  if (raw !== undefined && raw.trim() !== "") {
752
848
  return validateConcurrency(Number(raw), AGENT_SWARM_MAX_CONCURRENCY_ENV);
753
849
  }
754
- // 4. Default
850
+ // 4. Default (always reached — value guaranteed)
755
851
  return DEFAULT_MAX_CONCURRENCY;
756
852
  }
757
853
  function validateConcurrency(value, source) {
758
854
  if (value === undefined || value === null)
759
- return undefined;
855
+ return DEFAULT_MAX_CONCURRENCY;
760
856
  const num = Number(value);
761
857
  if (!Number.isInteger(num) || num <= 0) {
762
858
  throw new Error(`pi-swarm.maxConcurrency in ${source} must be a positive integer, got ${JSON.stringify(value)}.`);
@@ -780,4 +876,30 @@ function getSettingsMaxConcurrency(settings) {
780
876
  const swarm = settings["pi-swarm"];
781
877
  return swarm?.maxConcurrency;
782
878
  }
879
+ /**
880
+ * Resolve the optional small model from pi settings.
881
+ * Used as the default model for simple subagent tasks.
882
+ *
883
+ * Priority:
884
+ * 1. `.pi/settings.json` → `pi-swarm.smallModel`
885
+ * 2. `~/.pi/agent/settings.json` → `pi-swarm.smallModel`
886
+ */
887
+ export function resolveSwarmSmallModel(cwd) {
888
+ const projectSettings = readPiSettings(path.join(cwd ?? process.cwd(), ".pi", "settings.json"));
889
+ const projectValue = getSettingsSmallModel(projectSettings);
890
+ if (projectValue !== undefined)
891
+ return projectValue;
892
+ const home = process.env.HOME ?? process.env.USERPROFILE ?? "~";
893
+ const globalSettings = readPiSettings(path.join(home, ".pi", "agent", "settings.json"));
894
+ return getSettingsSmallModel(globalSettings);
895
+ }
896
+ function getSettingsSmallModel(settings) {
897
+ if (!settings)
898
+ return undefined;
899
+ const swarm = settings["pi-swarm"];
900
+ const val = swarm?.smallModel;
901
+ return typeof val === "string" && val.trim().length > 0
902
+ ? val.trim()
903
+ : undefined;
904
+ }
783
905
  //# sourceMappingURL=controller.js.map