ac-teams 0.0.14 → 0.0.15
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/docs/operations.md +9 -3
- package/package.json +1 -1
- package/src/coordinator.ts +1 -1
- package/src/index.ts +1 -1
- package/src/resources.ts +9 -9
package/docs/operations.md
CHANGED
|
@@ -35,15 +35,21 @@ Other delegation tools remain outside these limits. See [companion tools](usage.
|
|
|
35
35
|
|
|
36
36
|
`team_agent list` and `limits` include a fresh `resources` advisory. Launch and teammate resume results include the sample taken before startup.
|
|
37
37
|
|
|
38
|
-
It reports host available RAM, occupied swap, recent memory stalls, and live/starting member counts. Values are bytes; Linux pressure averages are percentages
|
|
38
|
+
It reports host available RAM, occupied swap, recent memory stalls, and live/starting member counts. Values are bytes; Linux pressure averages are percentages.
|
|
39
|
+
|
|
40
|
+
`someAvg10` and `fullAvg10` cover ten-second trends; `fullAvg60` covers a sixty-second trend. Missing or invalid metrics are `null` with a warning, not zero or an all-clear.
|
|
39
41
|
|
|
40
42
|
The check reads only `/proc/meminfo` and `/proc/pressure/memory` on demand. It adds no polling, process-tree scans, or subprocesses.
|
|
41
43
|
|
|
42
|
-
Available RAM below 10% triggers a low-headroom warning (a heuristic, not a per-member budget).
|
|
44
|
+
Available RAM below 10% triggers a low-headroom warning (a heuristic, not a per-member budget). Low headroom alone does not prescribe sequential work.
|
|
45
|
+
|
|
46
|
+
Memory contention warns when `fullAvg60 >= 5` or `fullAvg10 >= 10`. Full pressure measures time when all non-idle work is stalled on memory. Partial pressure (`someAvg10`) remains informational; occupied swap alone does not trigger a pressure warning.
|
|
47
|
+
|
|
48
|
+
These thresholds are advisory defaults, not measured limits for optimal concurrency. Consider reducing concurrency if contention is slowing progress.
|
|
43
49
|
|
|
44
50
|
Starting members reserve count slots synchronously, but may not yet consume their full memory. Concurrent launch results warn about earlier starts.
|
|
45
51
|
|
|
46
|
-
|
|
52
|
+
Choose concurrency using resource readings and observed progress. These advisories never block a launch, change the configured ceiling, reserve RAM, or stop a member. Host figures do not account for a tighter container/cgroup limit or guarantee future capacity; other teams and non-team processes also consume resources.
|
|
47
53
|
|
|
48
54
|
Idle members keep Pi and its extensions alive. Stop unneeded members to release their owned processes, then resume their saved sessions when needed.
|
|
49
55
|
|
package/package.json
CHANGED
package/src/coordinator.ts
CHANGED
|
@@ -356,7 +356,7 @@ export class Coordinator {
|
|
|
356
356
|
const live = this.live();
|
|
357
357
|
const startingMembers = live.filter(member => member.status === "starting").length;
|
|
358
358
|
const warnings = [...sample.warnings];
|
|
359
|
-
if (startingMembers) warnings.push(`${startingMembers} teammate(s) still starting; their full memory cost is not yet reflected
|
|
359
|
+
if (startingMembers) warnings.push(`${startingMembers} teammate(s) still starting; their full memory cost is not yet reflected in host headroom.`);
|
|
360
360
|
return { ...sample, liveMembers: live.length, startingMembers, warnings };
|
|
361
361
|
}
|
|
362
362
|
ack(id: string, through: number): void {
|
package/src/index.ts
CHANGED
|
@@ -280,7 +280,7 @@ export default function teams(pi: ExtensionAPI) {
|
|
|
280
280
|
if (change) report(ctx, change);
|
|
281
281
|
});
|
|
282
282
|
function output(data: unknown) { return { content: [{ type: "text" as const, text: JSON.stringify(data) }], details: data }; }
|
|
283
|
-
const guidance = "Team launches use real long-lived Pi sessions. Idle members count against the shared ceiling and retain their processes and extensions. Check team_agent list resources before adding concurrency; teammate launch/resume results include pre-launch host headroom. Resource warnings are advisory, not a memory reservation or capacity guarantee.
|
|
283
|
+
const guidance = "Team launches use real long-lived Pi sessions. Idle members count against the shared ceiling and retain their processes and extensions. Check team_agent list resources before adding concurrency; teammate launch/resume results include pre-launch host headroom. Resource warnings are advisory, not a memory reservation or capacity guarantee. Choose concurrency using resource readings and observed progress, not low headroom alone. If contention slows progress, stop unneeded idle members and resume their saved sessions later. Use teammate names for messaging and stable IDs for member control and tasks; query status and history instead of acknowledging notifications. Limits cover only ac-teams, not other launchers or shell commands.";
|
|
284
284
|
const taskTrackingGuidance = "Before delegating a deliverable through team_agent, create or reuse a team_task and include its ID in the member's brief. Use one shared task list for your own work and delegated work; do not create one task per teammate by default. Quick lookups and brief second opinions need no separate task unless their results need coordination or follow-up.";
|
|
285
285
|
pi.registerTool({
|
|
286
286
|
name: "team_agent", label: "Team agent", description: "Launch/resume Pi members, list/status, stop owned subtrees, change root limits, and explicitly clean stopped worktrees. Create or reuse team_task entries for delegated deliverables; quick lookups need no task unless results need coordination or follow-up.",
|
package/src/resources.ts
CHANGED
|
@@ -3,8 +3,8 @@ import { readFileSync } from "node:fs";
|
|
|
3
3
|
export interface HostResources {
|
|
4
4
|
scope: "host";
|
|
5
5
|
memory: { totalBytes: number; availableBytes: number; swapUsedBytes: number } | null;
|
|
6
|
-
/**
|
|
7
|
-
memoryPressure: { someAvg10: number; fullAvg10: number } | null;
|
|
6
|
+
/** Linux PSI percentages: partial ten-second pressure and full ten-/sixty-second pressure. */
|
|
7
|
+
memoryPressure: { someAvg10: number; fullAvg10: number; fullAvg60: number } | null;
|
|
8
8
|
warnings: string[];
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -22,19 +22,19 @@ export function hostResources(read: (path: string) => string = path => readFileS
|
|
|
22
22
|
const swapTotal = bytes("SwapTotal"), swapFree = bytes("SwapFree");
|
|
23
23
|
if ([totalBytes, availableBytes, swapTotal, swapFree].every(Number.isSafeInteger) && totalBytes > 0 && availableBytes <= totalBytes && swapFree <= swapTotal) {
|
|
24
24
|
result.memory = { totalBytes, availableBytes, swapUsedBytes: swapTotal - swapFree };
|
|
25
|
-
if (availableBytes < totalBytes * 0.1) result.warnings.push("Host available memory is below 10%.
|
|
25
|
+
if (availableBytes < totalBytes * 0.1) result.warnings.push("Host available memory is below 10%. This is low headroom, not a per-member capacity estimate.");
|
|
26
26
|
}
|
|
27
27
|
} catch { /* Missing or unreadable metrics remain explicitly unavailable. */ }
|
|
28
28
|
try {
|
|
29
29
|
const text = read("/proc/pressure/memory");
|
|
30
|
-
const avg = (kind: string) => {
|
|
31
|
-
const match = text.match(new RegExp(`^${kind}
|
|
30
|
+
const avg = (kind: string, window: 10 | 60) => {
|
|
31
|
+
const match = text.match(new RegExp(`^${kind} .*?\\bavg${window}=(\\d+(?:\\.\\d+)?) `, "m"));
|
|
32
32
|
return match ? Number(match[1]) : NaN;
|
|
33
33
|
};
|
|
34
|
-
const someAvg10 = avg("some"), fullAvg10 = avg("full");
|
|
35
|
-
if ([someAvg10, fullAvg10].every(value => Number.isFinite(value) && value >= 0 && value <= 100) && fullAvg10 <= someAvg10) {
|
|
36
|
-
result.memoryPressure = { someAvg10, fullAvg10 };
|
|
37
|
-
if (
|
|
34
|
+
const someAvg10 = avg("some", 10), fullAvg10 = avg("full", 10), fullAvg60 = avg("full", 60);
|
|
35
|
+
if ([someAvg10, fullAvg10, fullAvg60].every(value => Number.isFinite(value) && value >= 0 && value <= 100) && fullAvg10 <= someAvg10) {
|
|
36
|
+
result.memoryPressure = { someAvg10, fullAvg10, fullAvg60 };
|
|
37
|
+
if (fullAvg60 >= 5 || fullAvg10 >= 10) result.warnings.push(`Significant memory contention detected (full avg10: ${fullAvg10}%, full avg60: ${fullAvg60}%). Consider reducing concurrency if progress is slowing.`);
|
|
38
38
|
}
|
|
39
39
|
} catch { /* PSI is optional on older kernels. */ }
|
|
40
40
|
}
|