@ferris1225/pi-subagents 4.1.8 → 4.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +161 -476
- package/agents/cleaner.md +51 -52
- package/agents/documenter.md +39 -46
- package/agents/explorer.md +40 -50
- package/agents/reviewer.md +29 -31
- package/agents/worker.md +15 -34
- package/package.json +1 -1
- package/src/announcements.ts +8 -0
- package/src/background.ts +23 -5
- package/src/config.ts +4 -2
- package/src/dispatch.ts +645 -746
- package/src/durable.ts +336 -0
- package/src/format.ts +1 -8
- package/src/index.ts +7 -0
- package/src/monitor.ts +29 -30
- package/src/prompt.ts +22 -40
- package/src/rpc-run.ts +22 -228
- package/src/runtime.ts +71 -46
- package/src/session-fork.ts +7 -2
- package/src/setup.ts +25 -193
- package/src/spawn.ts +31 -28
- package/src/temp-hygiene.ts +194 -0
- package/src/thread-lifecycle.ts +1410 -1324
- package/src/tools.ts +21 -108
- package/src/widget.ts +3 -3
- package/src/workflow.ts +248 -0
- package/src/worktree.ts +144 -4
- package/src/fixloop.ts +0 -382
package/src/background.ts
CHANGED
|
@@ -27,15 +27,21 @@ interface PendingTask {
|
|
|
27
27
|
onError?: (error: unknown) => void | Promise<void>;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
/** How many sub-agent processes may run at once
|
|
31
|
-
*
|
|
32
|
-
* by waiting, so the knob bought nothing
|
|
30
|
+
/** How many sub-agent processes may run at once. This paces execution only —
|
|
31
|
+
* it never rejects work, so a wider parallel `subagent` call simply queues.
|
|
32
|
+
* Fixed by design: the queue sheds load by waiting, so the knob bought nothing
|
|
33
|
+
* worth its maintenance. Only manually dispatched top-level generations hold
|
|
34
|
+
* slots; runtime-initiated managed continuations (gate reviews, documentation
|
|
35
|
+
* sync) suspend their task's slot so they never starve manual dispatches. */
|
|
33
36
|
export const MAX_CONCURRENT_SUBAGENTS = 4;
|
|
34
37
|
|
|
35
38
|
export class BackgroundTaskQueue {
|
|
36
39
|
private concurrency: number;
|
|
37
40
|
private readonly pending: PendingTask[] = [];
|
|
38
41
|
private readonly active = new Set<AbortController>();
|
|
42
|
+
/** Active tasks that no longer count toward the concurrency limit. They keep
|
|
43
|
+
* every other guarantee: abortable, awaited by waitForTask/waitForIdle. */
|
|
44
|
+
private readonly suspended = new Set<AbortController>();
|
|
39
45
|
private readonly completions = new WeakMap<AbortController, Promise<void>>();
|
|
40
46
|
private readonly idleWaiters = new Set<() => void>();
|
|
41
47
|
private stopped = false;
|
|
@@ -71,6 +77,16 @@ export class BackgroundTaskQueue {
|
|
|
71
77
|
return this.completions.get(controller) ?? Promise.resolve();
|
|
72
78
|
}
|
|
73
79
|
|
|
80
|
+
/** Stop counting a running task toward the concurrency limit. Its body keeps
|
|
81
|
+
* running under the same abort signal; completion still releases everything
|
|
82
|
+
* waitForTask/waitForIdle promise. Frees a slot for queued work immediately. */
|
|
83
|
+
suspend(controller: AbortController | undefined): void {
|
|
84
|
+
if (!controller || this.stopped) return;
|
|
85
|
+
if (!this.active.delete(controller)) return;
|
|
86
|
+
this.suspended.add(controller);
|
|
87
|
+
this.drain();
|
|
88
|
+
}
|
|
89
|
+
|
|
74
90
|
/** Cancel one queued/running task. Queued entries are removed immediately;
|
|
75
91
|
* active entries resolve waitForTask only after their body and error handler
|
|
76
92
|
* have quiesced and the concurrency slot has been released. */
|
|
@@ -89,7 +105,7 @@ export class BackgroundTaskQueue {
|
|
|
89
105
|
|
|
90
106
|
/** Resolve once no queued or running task remains. */
|
|
91
107
|
waitForIdle(): Promise<void> {
|
|
92
|
-
if (this.pending.length === 0 && this.active.size === 0) return Promise.resolve();
|
|
108
|
+
if (this.pending.length === 0 && this.active.size === 0 && this.suspended.size === 0) return Promise.resolve();
|
|
93
109
|
return new Promise<void>((resolve) => this.idleWaiters.add(resolve));
|
|
94
110
|
}
|
|
95
111
|
|
|
@@ -104,6 +120,7 @@ export class BackgroundTaskQueue {
|
|
|
104
120
|
entry.complete();
|
|
105
121
|
}
|
|
106
122
|
for (const controller of this.active) controller.abort();
|
|
123
|
+
for (const controller of this.suspended) controller.abort();
|
|
107
124
|
this.resolveIdleWaiters();
|
|
108
125
|
}
|
|
109
126
|
|
|
@@ -145,6 +162,7 @@ export class BackgroundTaskQueue {
|
|
|
145
162
|
})
|
|
146
163
|
.finally(() => {
|
|
147
164
|
this.active.delete(entry.controller);
|
|
165
|
+
this.suspended.delete(entry.controller);
|
|
148
166
|
entry.complete();
|
|
149
167
|
this.drain();
|
|
150
168
|
this.resolveIdleWaiters();
|
|
@@ -153,7 +171,7 @@ export class BackgroundTaskQueue {
|
|
|
153
171
|
}
|
|
154
172
|
|
|
155
173
|
private resolveIdleWaiters(): void {
|
|
156
|
-
if (this.pending.length > 0 || this.active.size > 0) return;
|
|
174
|
+
if (this.pending.length > 0 || this.active.size > 0 || this.suspended.size > 0) return;
|
|
157
175
|
for (const resolve of this.idleWaiters) resolve();
|
|
158
176
|
this.idleWaiters.clear();
|
|
159
177
|
}
|
package/src/config.ts
CHANGED
|
@@ -26,8 +26,10 @@ export const THINKING_LEVEL_VALUES = ["off", "minimal", "low", "medium", "high",
|
|
|
26
26
|
export type ThinkingLevel = (typeof THINKING_LEVEL_VALUES)[number];
|
|
27
27
|
export const DEFAULT_THINKING_LEVEL: ThinkingLevel = "high";
|
|
28
28
|
|
|
29
|
-
/** How many lines of a sub-agent result the completion message may carry.
|
|
30
|
-
|
|
29
|
+
/** How many lines of a sub-agent result the completion message may carry.
|
|
30
|
+
* Default: 40 — wide fan-outs multiply completion blocks, so deliveries stay
|
|
31
|
+
* compact and the full text lives in the on-disk result artifact. */
|
|
32
|
+
export const DEFAULT_MAX_RESULT_LINES = 40;
|
|
31
33
|
/** Upper bound accepted for maxResultLines (defensive clamp). */
|
|
32
34
|
export const MAX_RESULT_LINES_LIMIT = 2000;
|
|
33
35
|
|