@ifi/oh-pi-ant-colony 0.2.8 → 0.2.10

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 CHANGED
@@ -25,6 +25,20 @@ Goal → Scouting → Task Pool → Workers Execute in Parallel → Soldiers Rev
25
25
  └───────────────────────────┘
26
26
  ```
27
27
 
28
+ ## Workspace Isolation (Default)
29
+
30
+ By default, each colony runs in an **isolated git worktree** on its own branch (`ant-colony/...`).
31
+ This keeps your current branch untouched while the swarm edits code.
32
+
33
+ If worktree creation is unavailable (e.g. not a git repo), the colony automatically falls back to the shared cwd and
34
+ reports the reason in the final report/status output.
35
+
36
+ You can disable worktree isolation with:
37
+
38
+ ```bash
39
+ PI_ANT_COLONY_WORKTREE=0
40
+ ```
41
+
28
42
  ## Adaptive Concurrency
29
43
 
30
44
  Models real ant colony dynamic recruitment:
@@ -44,7 +58,11 @@ The LLM automatically invokes the `ant_colony` tool when task complexity warrant
44
58
  ### Commands
45
59
 
46
60
  ```
47
- /colony-stop Cancel a running colony
61
+ /colony <goal> Start a new colony for the given goal
62
+ /colony-count Show number of currently running colonies
63
+ /colony-status [id] Show running colonies (runtime cN or stable colony-... ID)
64
+ /colony-stop [id|all] Cancel one running colony (runtime/stable ID) or all
65
+ /colony-resume [colonyId] Resume a specific stable colony ID, or all resumable by default
48
66
  Ctrl+Shift+A Open colony details panel
49
67
  ```
50
68
 
@@ -58,6 +76,11 @@ Ctrl+Shift+A Open colony details panel
58
76
  /colony Refactor auth system from session-based to JWT, maintaining API compatibility
59
77
  ```
60
78
 
79
+ ## Usage Tracking Integration
80
+
81
+ Ant inference usage (tokens + cost) is streamed to the `usage-tracker` extension via `pi.events` (`usage:record`).
82
+ So `/usage`, `usage_report`, and session cost totals now include background colony inference, making colony spend visible.
83
+
61
84
  ## Pheromone System
62
85
 
63
86
  Ants communicate indirectly through pheromones (stigmergy), not direct messages:
@@ -94,13 +117,17 @@ Each task declares the files it operates on. The queen guarantees:
94
117
  ## Installation
95
118
 
96
119
  ```bash
97
- # Option 1: Symlink to pi extensions directory
98
- mkdir -p ~/.pi/agent/extensions/ant-colony
99
- ln -sf "$(pwd)/pi-package/extensions/ant-colony/index.ts" ~/.pi/agent/extensions/ant-colony/index.ts
100
- # ... (symlink all .ts files)
120
+ # Install just ant-colony
121
+ pi install npm:@ifi/oh-pi-ant-colony
122
+
123
+ # Or install the full oh-pi bundle (includes ant-colony)
124
+ pi install npm:@ifi/oh-pi
125
+ ```
126
+
127
+ Then enable/configure extensions with:
101
128
 
102
- # Option 2: Install via oh-pi
103
- npx oh-pi # Select "Full Power" preset
129
+ ```bash
130
+ npx @ifi/oh-pi-cli
104
131
  ```
105
132
 
106
133
  ## Module Reference
@@ -110,9 +137,10 @@ npx oh-pi # Select "Full Power" preset
110
137
  | `types.ts` | ~150 | Type system: ants, tasks, pheromones, colony state |
111
138
  | `nest.ts` | ~500 | Nest: file-system shared state, atomic R/W, pheromone decay |
112
139
  | `concurrency.ts` | ~120 | Adaptive concurrency: system sampling, exploration/steady-state adjustment |
113
- | `spawner.ts` | ~370 | Ant spawning: session management, prompt construction, output parsing |
114
- | `queen.ts` | ~1000 | Queen scheduling: lifecycle, task waves, multi-round iteration |
115
- | `index.ts` | ~900 | Extension entry: tool/shortcut registration, TUI rendering |
140
+ | `spawner.ts` | ~420 | Ant spawning: session lifecycle, usage streaming, prompt/output handling |
141
+ | `queen.ts` | ~1020 | Queen scheduling: lifecycle, task waves, multi-round iteration |
142
+ | `worktree.ts` | ~180 | Git worktree isolation and resume workspace recovery helpers |
143
+ | `index.ts` | ~1050 | Extension entry: tool/shortcut registration, TUI rendering, status signals |
116
144
  | `deps.ts` | ~140 | Lightweight import graph for dependency-aware scheduling |
117
145
  | `parser.ts` | ~180 | Sub-task and pheromone extraction from ant output |
118
146
  | `prompts.ts` | ~90 | Per-caste system prompts and prompt builder |
@@ -68,6 +68,18 @@ export interface CasteBudget {
68
68
  }
69
69
 
70
70
  /** Full budget plan for a colony run. */
71
+ export interface RoutingTelemetrySnapshot {
72
+ totalRoutes: number;
73
+ avgLatencyMs: number;
74
+ outcomeCounts: {
75
+ claimed: number;
76
+ completed: number;
77
+ failed: number;
78
+ escalated: number;
79
+ };
80
+ escalationReasonCounts: Record<string, number>;
81
+ }
82
+
71
83
  export interface BudgetPlan {
72
84
  /** Per-caste allocations. */
73
85
  castes: Record<AntCaste, CasteBudget>;
@@ -79,6 +91,8 @@ export interface BudgetPlan {
79
91
  lowestRateLimitPct: number;
80
92
  /** Human-readable summary for prompt injection. */
81
93
  summary: string;
94
+ /** Aggregated routing telemetry used for reporting and debugging. */
95
+ routingTelemetry: RoutingTelemetrySnapshot;
82
96
  }
83
97
 
84
98
  // ═══ Constants ═══
@@ -210,6 +224,7 @@ export function buildBudgetSummary(
210
224
  maxCost: number | null,
211
225
  tasksDone: number,
212
226
  tasksTotal: number,
227
+ routingTelemetry?: RoutingTelemetrySnapshot,
213
228
  ): string {
214
229
  const parts: string[] = [];
215
230
 
@@ -233,6 +248,16 @@ export function buildBudgetSummary(
233
248
  parts.push(`Progress: ${tasksDone}/${tasksTotal} tasks completed.`);
234
249
  }
235
250
 
251
+ if (routingTelemetry && routingTelemetry.totalRoutes > 0) {
252
+ parts.push(
253
+ `Routing: ${routingTelemetry.totalRoutes} outcomes, avg latency ${routingTelemetry.avgLatencyMs}ms, escalations ${routingTelemetry.outcomeCounts.escalated}.`,
254
+ );
255
+ const topEscalation = Object.entries(routingTelemetry.escalationReasonCounts).sort((a, b) => b[1] - a[1])[0];
256
+ if (topEscalation) {
257
+ parts.push(`Top escalation reason: ${topEscalation[0]} (${topEscalation[1]}).`);
258
+ }
259
+ }
260
+
236
261
  // Severity-specific guidance
237
262
  switch (severity) {
238
263
  case "critical":
@@ -265,6 +290,33 @@ export function buildBudgetSummary(
265
290
  * @param concurrency - Current concurrency config for max bounds.
266
291
  * @returns A complete budget plan with per-caste allocations.
267
292
  */
293
+ export function buildRoutingTelemetrySnapshot(metrics: ColonyMetrics): RoutingTelemetrySnapshot {
294
+ const entries = metrics.routingTelemetry ?? [];
295
+ const outcomeCounts = {
296
+ claimed: 0,
297
+ completed: 0,
298
+ failed: 0,
299
+ escalated: 0,
300
+ };
301
+ const escalationReasonCounts: Record<string, number> = {};
302
+ let latencyTotal = 0;
303
+
304
+ for (const entry of entries) {
305
+ outcomeCounts[entry.outcome] += 1;
306
+ latencyTotal += entry.latencyMs;
307
+ for (const reason of entry.escalationReasons) {
308
+ escalationReasonCounts[reason] = (escalationReasonCounts[reason] ?? 0) + 1;
309
+ }
310
+ }
311
+
312
+ return {
313
+ totalRoutes: entries.length,
314
+ avgLatencyMs: entries.length > 0 ? Math.round(latencyTotal / entries.length) : 0,
315
+ outcomeCounts,
316
+ escalationReasonCounts,
317
+ };
318
+ }
319
+
268
320
  export function planBudget(
269
321
  usageLimits: UsageLimitsEvent | null,
270
322
  metrics: ColonyMetrics,
@@ -311,6 +363,7 @@ export function planBudget(
311
363
  };
312
364
  }
313
365
 
366
+ const routingTelemetry = buildRoutingTelemetrySnapshot(metrics);
314
367
  const summary = buildBudgetSummary(
315
368
  severity,
316
369
  lowestRateLimitPct,
@@ -318,6 +371,7 @@ export function planBudget(
318
371
  maxCost,
319
372
  metrics.tasksDone,
320
373
  metrics.tasksTotal,
374
+ routingTelemetry,
321
375
  );
322
376
 
323
377
  return {
@@ -326,6 +380,7 @@ export function planBudget(
326
380
  severity,
327
381
  lowestRateLimitPct,
328
382
  summary,
383
+ routingTelemetry,
329
384
  };
330
385
  }
331
386