@oni.bot/core 0.8.0 → 1.0.1
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/CHANGELOG.md +15 -0
- package/README.md +59 -373
- package/dist/checkpointers/sqlite.d.ts.map +1 -1
- package/dist/checkpointers/sqlite.js +23 -8
- package/dist/checkpointers/sqlite.js.map +1 -1
- package/dist/cli/build.d.ts +11 -0
- package/dist/cli/build.d.ts.map +1 -0
- package/dist/cli/build.js +61 -0
- package/dist/cli/build.js.map +1 -0
- package/dist/cli/dev.d.ts +5 -0
- package/dist/cli/dev.d.ts.map +1 -0
- package/dist/cli/dev.js +54 -0
- package/dist/cli/dev.js.map +1 -0
- package/dist/cli/index.js +16 -27
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init.d.ts +2 -0
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +18 -1
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/inspect.d.ts +5 -0
- package/dist/cli/inspect.d.ts.map +1 -0
- package/dist/cli/inspect.js +85 -0
- package/dist/cli/inspect.js.map +1 -0
- package/dist/cli/router.d.ts +14 -0
- package/dist/cli/router.d.ts.map +1 -0
- package/dist/cli/router.js +107 -0
- package/dist/cli/router.js.map +1 -0
- package/dist/cli/run.d.ts +5 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +53 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/templates.d.ts +1 -0
- package/dist/cli/templates.d.ts.map +1 -1
- package/dist/cli/templates.js +106 -66
- package/dist/cli/templates.js.map +1 -1
- package/dist/cli/test.d.ts +3 -0
- package/dist/cli/test.d.ts.map +1 -0
- package/dist/cli/test.js +29 -0
- package/dist/cli/test.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +3 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +37 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +180 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/types.d.ts +74 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +5 -0
- package/dist/config/types.js.map +1 -0
- package/dist/coordination/pubsub.d.ts +4 -0
- package/dist/coordination/pubsub.d.ts.map +1 -1
- package/dist/coordination/pubsub.js +8 -0
- package/dist/coordination/pubsub.js.map +1 -1
- package/dist/coordination/request-reply.d.ts +3 -1
- package/dist/coordination/request-reply.d.ts.map +1 -1
- package/dist/coordination/request-reply.js +11 -2
- package/dist/coordination/request-reply.js.map +1 -1
- package/dist/errors.d.ts +7 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +18 -3
- package/dist/errors.js.map +1 -1
- package/dist/events/bridge.d.ts +17 -0
- package/dist/events/bridge.d.ts.map +1 -0
- package/dist/events/bridge.js +67 -0
- package/dist/events/bridge.js.map +1 -0
- package/dist/events/bus.d.ts +9 -0
- package/dist/events/bus.d.ts.map +1 -1
- package/dist/events/bus.js +39 -4
- package/dist/events/bus.js.map +1 -1
- package/dist/events/index.d.ts +2 -1
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +2 -0
- package/dist/events/index.js.map +1 -1
- package/dist/events/types.d.ts +123 -1
- package/dist/events/types.d.ts.map +1 -1
- package/dist/graph.d.ts.map +1 -1
- package/dist/graph.js +16 -8
- package/dist/graph.js.map +1 -1
- package/dist/guardrails/types.d.ts +1 -1
- package/dist/guardrails/types.d.ts.map +1 -1
- package/dist/harness/agent-loop.d.ts.map +1 -1
- package/dist/harness/agent-loop.js +226 -29
- package/dist/harness/agent-loop.js.map +1 -1
- package/dist/harness/context-compactor.d.ts +21 -2
- package/dist/harness/context-compactor.d.ts.map +1 -1
- package/dist/harness/context-compactor.js +45 -6
- package/dist/harness/context-compactor.js.map +1 -1
- package/dist/harness/hooks-engine.d.ts +7 -1
- package/dist/harness/hooks-engine.d.ts.map +1 -1
- package/dist/harness/hooks-engine.js.map +1 -1
- package/dist/harness/index.d.ts +3 -2
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js +2 -0
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/skill-loader.d.ts +14 -1
- package/dist/harness/skill-loader.d.ts.map +1 -1
- package/dist/harness/skill-loader.js +33 -3
- package/dist/harness/skill-loader.js.map +1 -1
- package/dist/harness/types.d.ts +24 -2
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/dist/harness/validate-args.d.ts +16 -0
- package/dist/harness/validate-args.d.ts.map +1 -0
- package/dist/harness/validate-args.js +132 -0
- package/dist/harness/validate-args.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -12
- package/dist/index.js.map +1 -1
- package/dist/internal/timeout.d.ts +2 -0
- package/dist/internal/timeout.d.ts.map +1 -0
- package/dist/internal/timeout.js +16 -0
- package/dist/internal/timeout.js.map +1 -0
- package/dist/lsp/client.d.ts +70 -0
- package/dist/lsp/client.d.ts.map +1 -0
- package/dist/lsp/client.js +421 -0
- package/dist/lsp/client.js.map +1 -0
- package/dist/lsp/index.d.ts +77 -0
- package/dist/lsp/index.d.ts.map +1 -0
- package/dist/lsp/index.js +183 -0
- package/dist/lsp/index.js.map +1 -0
- package/dist/lsp/servers.d.ts +48 -0
- package/dist/lsp/servers.d.ts.map +1 -0
- package/dist/lsp/servers.js +108 -0
- package/dist/lsp/servers.js.map +1 -0
- package/dist/lsp/types.d.ts +142 -0
- package/dist/lsp/types.d.ts.map +1 -0
- package/dist/lsp/types.js +16 -0
- package/dist/lsp/types.js.map +1 -0
- package/dist/mcp/client.d.ts +56 -0
- package/dist/mcp/client.d.ts.map +1 -0
- package/dist/mcp/client.js +170 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/mcp/convert.d.ts +26 -0
- package/dist/mcp/convert.d.ts.map +1 -0
- package/dist/mcp/convert.js +56 -0
- package/dist/mcp/convert.js.map +1 -0
- package/dist/mcp/index.d.ts +21 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +19 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/transport.d.ts +56 -0
- package/dist/mcp/transport.d.ts.map +1 -0
- package/dist/mcp/transport.js +204 -0
- package/dist/mcp/transport.js.map +1 -0
- package/dist/mcp/types.d.ts +96 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +11 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/models/anthropic.d.ts.map +1 -1
- package/dist/models/anthropic.js +78 -41
- package/dist/models/anthropic.js.map +1 -1
- package/dist/models/google.d.ts.map +1 -1
- package/dist/models/google.js +47 -46
- package/dist/models/google.js.map +1 -1
- package/dist/models/http-error.d.ts +16 -0
- package/dist/models/http-error.d.ts.map +1 -0
- package/dist/models/http-error.js +67 -0
- package/dist/models/http-error.js.map +1 -0
- package/dist/models/index.d.ts +3 -0
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/index.js +2 -0
- package/dist/models/index.js.map +1 -1
- package/dist/models/ollama.d.ts.map +1 -1
- package/dist/models/ollama.js +4 -3
- package/dist/models/ollama.js.map +1 -1
- package/dist/models/openai.d.ts.map +1 -1
- package/dist/models/openai.js +36 -44
- package/dist/models/openai.js.map +1 -1
- package/dist/models/openrouter.d.ts +13 -0
- package/dist/models/openrouter.d.ts.map +1 -1
- package/dist/models/openrouter.js +86 -47
- package/dist/models/openrouter.js.map +1 -1
- package/dist/models/sse.d.ts +9 -0
- package/dist/models/sse.d.ts.map +1 -0
- package/dist/models/sse.js +45 -0
- package/dist/models/sse.js.map +1 -0
- package/dist/models/types.d.ts +10 -0
- package/dist/models/types.d.ts.map +1 -1
- package/dist/pregel.d.ts +4 -0
- package/dist/pregel.d.ts.map +1 -1
- package/dist/pregel.js +121 -54
- package/dist/pregel.js.map +1 -1
- package/dist/retry.d.ts.map +1 -1
- package/dist/retry.js +10 -3
- package/dist/retry.js.map +1 -1
- package/dist/store/index.d.ts +3 -0
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +17 -0
- package/dist/store/index.js.map +1 -1
- package/dist/streaming.d.ts +4 -1
- package/dist/streaming.d.ts.map +1 -1
- package/dist/streaming.js +21 -7
- package/dist/streaming.js.map +1 -1
- package/dist/swarm/graph.d.ts +81 -2
- package/dist/swarm/graph.d.ts.map +1 -1
- package/dist/swarm/graph.js +517 -32
- package/dist/swarm/graph.js.map +1 -1
- package/dist/swarm/index.d.ts +10 -2
- package/dist/swarm/index.d.ts.map +1 -1
- package/dist/swarm/index.js +6 -1
- package/dist/swarm/index.js.map +1 -1
- package/dist/swarm/mermaid.d.ts +10 -0
- package/dist/swarm/mermaid.d.ts.map +1 -0
- package/dist/swarm/mermaid.js +64 -0
- package/dist/swarm/mermaid.js.map +1 -0
- package/dist/swarm/pool.d.ts +9 -1
- package/dist/swarm/pool.d.ts.map +1 -1
- package/dist/swarm/pool.js +58 -10
- package/dist/swarm/pool.js.map +1 -1
- package/dist/swarm/registry.d.ts +11 -1
- package/dist/swarm/registry.d.ts.map +1 -1
- package/dist/swarm/registry.js +17 -3
- package/dist/swarm/registry.js.map +1 -1
- package/dist/swarm/scaling.d.ts +95 -0
- package/dist/swarm/scaling.d.ts.map +1 -0
- package/dist/swarm/scaling.js +214 -0
- package/dist/swarm/scaling.js.map +1 -0
- package/dist/swarm/snapshot.d.ts +51 -0
- package/dist/swarm/snapshot.d.ts.map +1 -0
- package/dist/swarm/snapshot.js +115 -0
- package/dist/swarm/snapshot.js.map +1 -0
- package/dist/swarm/supervisor.d.ts.map +1 -1
- package/dist/swarm/supervisor.js +82 -0
- package/dist/swarm/supervisor.js.map +1 -1
- package/dist/swarm/tracer.d.ts +57 -0
- package/dist/swarm/tracer.d.ts.map +1 -0
- package/dist/swarm/tracer.js +138 -0
- package/dist/swarm/tracer.js.map +1 -0
- package/dist/swarm/types.d.ts +23 -1
- package/dist/swarm/types.d.ts.map +1 -1
- package/dist/swarm/types.js.map +1 -1
- package/dist/tools/types.d.ts +2 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/package.json +160 -141
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { SwarmTracer } from "./tracer.js";
|
|
2
|
+
export interface ScalingConfig {
|
|
3
|
+
/** Minimum number of agents to maintain (default: 1) */
|
|
4
|
+
minAgents?: number;
|
|
5
|
+
/** Maximum number of agents allowed (default: 10) */
|
|
6
|
+
maxAgents?: number;
|
|
7
|
+
/**
|
|
8
|
+
* Error rate threshold to trigger scale-up (0-1, default: 0.25 = 25%).
|
|
9
|
+
* Rationale: 25% catches systemic issues (API degradation, bad prompts)
|
|
10
|
+
* early without over-reacting to transient single-agent failures.
|
|
11
|
+
* Lower than 20% would trigger on 1-of-5 agents failing once.
|
|
12
|
+
*/
|
|
13
|
+
scaleUpErrorRate?: number;
|
|
14
|
+
/**
|
|
15
|
+
* Max latency (ms) before triggering scale-up (default: 15000).
|
|
16
|
+
* Rationale: multi-turn LLM agents (think→act→observe cycles) typically
|
|
17
|
+
* take 15-120s per full lifecycle. Opus inference alone is ~10s/call.
|
|
18
|
+
* 5s was far too aggressive — normal Opus agents would constantly trigger.
|
|
19
|
+
*/
|
|
20
|
+
scaleUpLatencyMs?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Seconds of no activity before triggering scale-down (default: 60).
|
|
23
|
+
* Rationale: agents actively running may go 30-60s between tracer events
|
|
24
|
+
* (no events emitted mid-execution). 30s caused false scale-downs while
|
|
25
|
+
* agents were still working. 60s gives a full agent lifecycle to complete.
|
|
26
|
+
*/
|
|
27
|
+
scaleDownIdleSeconds?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Minimum ms between scaling decisions (default: 10000).
|
|
30
|
+
* Rationale: 10s prevents oscillation in reactive mode where error
|
|
31
|
+
* and complete events fire in rapid succession. 5s was too short when
|
|
32
|
+
* multiple agents complete simultaneously.
|
|
33
|
+
*/
|
|
34
|
+
cooldownMs?: number;
|
|
35
|
+
}
|
|
36
|
+
export interface ScalingDecision {
|
|
37
|
+
/** What action to take */
|
|
38
|
+
action: "scale_up" | "scale_down" | "idle";
|
|
39
|
+
/** Number of agents to add (scale_up) or remove (scale_down) */
|
|
40
|
+
count: number;
|
|
41
|
+
/** Human-readable reason for the decision */
|
|
42
|
+
reason: string;
|
|
43
|
+
}
|
|
44
|
+
export interface ScalingHistoryEntry {
|
|
45
|
+
decision: ScalingDecision;
|
|
46
|
+
timestamp: number;
|
|
47
|
+
}
|
|
48
|
+
type ScalingCallback = (decision: ScalingDecision) => void;
|
|
49
|
+
export declare class DynamicScalingMonitor {
|
|
50
|
+
private readonly tracer;
|
|
51
|
+
private readonly config;
|
|
52
|
+
private currentAgentCount;
|
|
53
|
+
private lastDecision;
|
|
54
|
+
private lastDecisionTime;
|
|
55
|
+
private history;
|
|
56
|
+
private callbacks;
|
|
57
|
+
private unsubscribeTracer;
|
|
58
|
+
constructor(tracer: SwarmTracer, config?: ScalingConfig);
|
|
59
|
+
getConfig(): Readonly<Required<ScalingConfig>>;
|
|
60
|
+
setCurrentAgentCount(count: number): void;
|
|
61
|
+
getState(): {
|
|
62
|
+
currentAgentCount: number;
|
|
63
|
+
lastDecision: ScalingDecision | null;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Evaluate current tracer metrics and return a scaling decision.
|
|
67
|
+
* Call this periodically or after significant events.
|
|
68
|
+
*/
|
|
69
|
+
evaluate(): ScalingDecision;
|
|
70
|
+
private checkScaleUp;
|
|
71
|
+
private checkScaleDown;
|
|
72
|
+
/**
|
|
73
|
+
* Record a decision (for cooldown tracking and history).
|
|
74
|
+
* Call this after applying the decision from evaluate().
|
|
75
|
+
*/
|
|
76
|
+
recordDecision(decision: ScalingDecision): void;
|
|
77
|
+
getHistory(): ScalingHistoryEntry[];
|
|
78
|
+
/**
|
|
79
|
+
* Register a callback that fires on non-idle scaling decisions.
|
|
80
|
+
*/
|
|
81
|
+
onScaleDecision(callback: ScalingCallback): () => void;
|
|
82
|
+
/**
|
|
83
|
+
* Enable reactive mode: subscribe to tracer events and auto-evaluate
|
|
84
|
+
* on error events. Non-idle decisions fire registered callbacks.
|
|
85
|
+
*/
|
|
86
|
+
enableReactive(): void;
|
|
87
|
+
/**
|
|
88
|
+
* Disable reactive mode. Stops listening to tracer events.
|
|
89
|
+
*/
|
|
90
|
+
disableReactive(): void;
|
|
91
|
+
/** Clean up — disables reactive mode. */
|
|
92
|
+
dispose(): void;
|
|
93
|
+
}
|
|
94
|
+
export {};
|
|
95
|
+
//# sourceMappingURL=scaling.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaling.d.ts","sourceRoot":"","sources":["../../src/swarm/scaling.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,aAAa,CAAC;AAI3D,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,0BAA0B;IAC1B,MAAM,EAAE,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;IAC3C,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,eAAe,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,KAAK,eAAe,GAAG,CAAC,QAAQ,EAAE,eAAe,KAAK,IAAI,CAAC;AAe3D,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;IACjD,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,YAAY,CAAgC;IACpD,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,SAAS,CAAmC;IACpD,OAAO,CAAC,iBAAiB,CAA6B;gBAE1C,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,aAAa;IAcvD,SAAS,IAAI,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IAI9C,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIzC,QAAQ,IAAI;QAAE,iBAAiB,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,eAAe,GAAG,IAAI,CAAA;KAAE;IAS/E;;;OAGG;IACH,QAAQ,IAAI,eAAe;IAyC3B,OAAO,CAAC,YAAY;IA0CpB,OAAO,CAAC,cAAc;IA4BtB;;;OAGG;IACH,cAAc,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;IAQ/C,UAAU,IAAI,mBAAmB,EAAE;IAMnC;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,IAAI;IAKtD;;;OAGG;IACH,cAAc,IAAI,IAAI;IAsBtB;;OAEG;IACH,eAAe,IAAI,IAAI;IAOvB,yCAAyC;IACzC,OAAO,IAAI,IAAI;CAIhB"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// @oni.bot/core/swarm — DynamicScalingMonitor
|
|
3
|
+
// ============================================================
|
|
4
|
+
// Reactive scaling decisions based on SwarmTracer events.
|
|
5
|
+
// Monitors agent error rates, latencies, and idle periods to
|
|
6
|
+
// recommend scale-up or scale-down actions.
|
|
7
|
+
//
|
|
8
|
+
// Two modes:
|
|
9
|
+
// 1. Polling — call evaluate() periodically to get decisions
|
|
10
|
+
// 2. Reactive — enableReactive() subscribes to tracer events
|
|
11
|
+
// and fires callback on actionable decisions
|
|
12
|
+
// ============================================================
|
|
13
|
+
// ── Defaults ──────────────────────────────────────────────
|
|
14
|
+
const DEFAULT_CONFIG = {
|
|
15
|
+
minAgents: 1,
|
|
16
|
+
maxAgents: 10,
|
|
17
|
+
scaleUpErrorRate: 0.25,
|
|
18
|
+
scaleUpLatencyMs: 15000,
|
|
19
|
+
scaleDownIdleSeconds: 60,
|
|
20
|
+
cooldownMs: 10000,
|
|
21
|
+
};
|
|
22
|
+
// ── DynamicScalingMonitor ─────────────────────────────────
|
|
23
|
+
export class DynamicScalingMonitor {
|
|
24
|
+
tracer;
|
|
25
|
+
config;
|
|
26
|
+
currentAgentCount = 0;
|
|
27
|
+
lastDecision = null;
|
|
28
|
+
lastDecisionTime = 0;
|
|
29
|
+
history = [];
|
|
30
|
+
callbacks = new Set();
|
|
31
|
+
unsubscribeTracer = null;
|
|
32
|
+
constructor(tracer, config) {
|
|
33
|
+
this.tracer = tracer;
|
|
34
|
+
this.config = {
|
|
35
|
+
minAgents: config?.minAgents ?? DEFAULT_CONFIG.minAgents,
|
|
36
|
+
maxAgents: config?.maxAgents ?? DEFAULT_CONFIG.maxAgents,
|
|
37
|
+
scaleUpErrorRate: config?.scaleUpErrorRate ?? DEFAULT_CONFIG.scaleUpErrorRate,
|
|
38
|
+
scaleUpLatencyMs: config?.scaleUpLatencyMs ?? DEFAULT_CONFIG.scaleUpLatencyMs,
|
|
39
|
+
scaleDownIdleSeconds: config?.scaleDownIdleSeconds ?? DEFAULT_CONFIG.scaleDownIdleSeconds,
|
|
40
|
+
cooldownMs: config?.cooldownMs ?? DEFAULT_CONFIG.cooldownMs,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
// ── Configuration ─────────────────────────────────────
|
|
44
|
+
getConfig() {
|
|
45
|
+
return this.config;
|
|
46
|
+
}
|
|
47
|
+
setCurrentAgentCount(count) {
|
|
48
|
+
this.currentAgentCount = count;
|
|
49
|
+
}
|
|
50
|
+
getState() {
|
|
51
|
+
return {
|
|
52
|
+
currentAgentCount: this.currentAgentCount,
|
|
53
|
+
lastDecision: this.lastDecision,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// ── Core evaluation ───────────────────────────────────
|
|
57
|
+
/**
|
|
58
|
+
* Evaluate current tracer metrics and return a scaling decision.
|
|
59
|
+
* Call this periodically or after significant events.
|
|
60
|
+
*/
|
|
61
|
+
evaluate() {
|
|
62
|
+
// Check cooldown
|
|
63
|
+
if (this.lastDecisionTime > 0) {
|
|
64
|
+
const elapsed = Date.now() - this.lastDecisionTime;
|
|
65
|
+
if (elapsed < this.config.cooldownMs) {
|
|
66
|
+
return { action: "idle", count: 0, reason: "cooldown active" };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// No agents to evaluate
|
|
70
|
+
if (this.currentAgentCount === 0) {
|
|
71
|
+
return { action: "idle", count: 0, reason: "no agents registered" };
|
|
72
|
+
}
|
|
73
|
+
const timeline = this.tracer.getTimeline();
|
|
74
|
+
if (timeline.length === 0) {
|
|
75
|
+
return { action: "idle", count: 0, reason: "no events to evaluate" };
|
|
76
|
+
}
|
|
77
|
+
// Single-pass count of starts and errors (used by checkScaleUp)
|
|
78
|
+
let starts = 0;
|
|
79
|
+
let errors = 0;
|
|
80
|
+
for (const e of timeline) {
|
|
81
|
+
if (e.type === "agent_start")
|
|
82
|
+
starts++;
|
|
83
|
+
else if (e.type === "agent_error")
|
|
84
|
+
errors++;
|
|
85
|
+
}
|
|
86
|
+
// Check scale-up conditions first (more urgent than scale-down)
|
|
87
|
+
const scaleUp = this.checkScaleUp(starts, errors);
|
|
88
|
+
if (scaleUp)
|
|
89
|
+
return scaleUp;
|
|
90
|
+
// Check scale-down — last event is most recent (timeline is append-only)
|
|
91
|
+
const lastActivity = timeline[timeline.length - 1].timestamp;
|
|
92
|
+
const scaleDown = this.checkScaleDown(lastActivity);
|
|
93
|
+
if (scaleDown)
|
|
94
|
+
return scaleDown;
|
|
95
|
+
return { action: "idle", count: 0, reason: "metrics within normal range" };
|
|
96
|
+
}
|
|
97
|
+
// ── Scale-up checks ───────────────────────────────────
|
|
98
|
+
checkScaleUp(starts, errors) {
|
|
99
|
+
// Already at max
|
|
100
|
+
if (this.currentAgentCount >= this.config.maxAgents)
|
|
101
|
+
return null;
|
|
102
|
+
// Error rate check
|
|
103
|
+
if (starts > 0) {
|
|
104
|
+
const errorRate = errors / starts;
|
|
105
|
+
if (errorRate >= this.config.scaleUpErrorRate) {
|
|
106
|
+
const headroom = this.config.maxAgents - this.currentAgentCount;
|
|
107
|
+
// Scale by ceil(currentCount * 0.5), capped by headroom
|
|
108
|
+
const addCount = Math.min(Math.max(1, Math.ceil(this.currentAgentCount * 0.5)), headroom);
|
|
109
|
+
return {
|
|
110
|
+
action: "scale_up",
|
|
111
|
+
count: addCount,
|
|
112
|
+
reason: `error rate ${(errorRate * 100).toFixed(0)}% exceeds ${(this.config.scaleUpErrorRate * 100).toFixed(0)}% threshold`,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Latency check
|
|
117
|
+
const metrics = this.tracer.metrics();
|
|
118
|
+
if (metrics.maxLatencyMs > this.config.scaleUpLatencyMs) {
|
|
119
|
+
const headroom = this.config.maxAgents - this.currentAgentCount;
|
|
120
|
+
const addCount = Math.min(Math.max(1, Math.ceil(this.currentAgentCount * 0.25)), headroom);
|
|
121
|
+
return {
|
|
122
|
+
action: "scale_up",
|
|
123
|
+
count: addCount,
|
|
124
|
+
reason: `max latency ${metrics.maxLatencyMs}ms exceeds ${this.config.scaleUpLatencyMs}ms threshold`,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
// ── Scale-down checks ─────────────────────────────────
|
|
130
|
+
checkScaleDown(lastActivity) {
|
|
131
|
+
// Already at minimum
|
|
132
|
+
if (this.currentAgentCount <= this.config.minAgents)
|
|
133
|
+
return null;
|
|
134
|
+
// Check if all agents have been idle for scaleDownIdleSeconds
|
|
135
|
+
const now = Date.now();
|
|
136
|
+
const idleThresholdMs = this.config.scaleDownIdleSeconds * 1000;
|
|
137
|
+
if (lastActivity > 0 && now - lastActivity > idleThresholdMs) {
|
|
138
|
+
// All agents idle — reduce by half, respecting minAgents
|
|
139
|
+
const removeCount = Math.min(Math.max(1, Math.floor(this.currentAgentCount / 2)), this.currentAgentCount - this.config.minAgents);
|
|
140
|
+
if (removeCount > 0) {
|
|
141
|
+
return {
|
|
142
|
+
action: "scale_down",
|
|
143
|
+
count: removeCount,
|
|
144
|
+
reason: `all agents idle for ${Math.round((now - lastActivity) / 1000)}s (threshold: ${this.config.scaleDownIdleSeconds}s)`,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
// ── Decision recording ────────────────────────────────
|
|
151
|
+
/**
|
|
152
|
+
* Record a decision (for cooldown tracking and history).
|
|
153
|
+
* Call this after applying the decision from evaluate().
|
|
154
|
+
*/
|
|
155
|
+
recordDecision(decision) {
|
|
156
|
+
this.lastDecision = decision;
|
|
157
|
+
if (decision.action !== "idle") {
|
|
158
|
+
this.lastDecisionTime = Date.now();
|
|
159
|
+
}
|
|
160
|
+
this.history.push({ decision, timestamp: Date.now() });
|
|
161
|
+
}
|
|
162
|
+
getHistory() {
|
|
163
|
+
return [...this.history];
|
|
164
|
+
}
|
|
165
|
+
// ── Reactive mode ─────────────────────────────────────
|
|
166
|
+
/**
|
|
167
|
+
* Register a callback that fires on non-idle scaling decisions.
|
|
168
|
+
*/
|
|
169
|
+
onScaleDecision(callback) {
|
|
170
|
+
this.callbacks.add(callback);
|
|
171
|
+
return () => this.callbacks.delete(callback);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Enable reactive mode: subscribe to tracer events and auto-evaluate
|
|
175
|
+
* on error events. Non-idle decisions fire registered callbacks.
|
|
176
|
+
*/
|
|
177
|
+
enableReactive() {
|
|
178
|
+
if (this.unsubscribeTracer)
|
|
179
|
+
return; // already enabled
|
|
180
|
+
this.unsubscribeTracer = this.tracer.subscribe((event) => {
|
|
181
|
+
// Only react to error events (scale-up signal)
|
|
182
|
+
// and complete events (potential scale-down signal)
|
|
183
|
+
if (event.type !== "agent_error" && event.type !== "agent_complete")
|
|
184
|
+
return;
|
|
185
|
+
const decision = this.evaluate();
|
|
186
|
+
if (decision.action !== "idle") {
|
|
187
|
+
this.recordDecision(decision);
|
|
188
|
+
for (const cb of this.callbacks) {
|
|
189
|
+
try {
|
|
190
|
+
cb(decision);
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
// Callback errors must not disrupt monitoring
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Disable reactive mode. Stops listening to tracer events.
|
|
201
|
+
*/
|
|
202
|
+
disableReactive() {
|
|
203
|
+
if (this.unsubscribeTracer) {
|
|
204
|
+
this.unsubscribeTracer();
|
|
205
|
+
this.unsubscribeTracer = null;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/** Clean up — disables reactive mode. */
|
|
209
|
+
dispose() {
|
|
210
|
+
this.disableReactive();
|
|
211
|
+
this.callbacks.clear();
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=scaling.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaling.js","sourceRoot":"","sources":["../../src/swarm/scaling.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { AgentRegistry, AgentManifestEntry } from "./registry.js";
|
|
2
|
+
import type { SwarmTracer, SwarmEvent } from "./tracer.js";
|
|
3
|
+
export interface SwarmSnapshot {
|
|
4
|
+
/** Unique snapshot ID. */
|
|
5
|
+
id: string;
|
|
6
|
+
/** Capture timestamp (ms since epoch). */
|
|
7
|
+
timestamp: number;
|
|
8
|
+
/** Deep copy of swarm state at capture time. */
|
|
9
|
+
state: Record<string, unknown>;
|
|
10
|
+
/** Agent statuses from registry (if provided at capture). */
|
|
11
|
+
agents?: AgentManifestEntry[];
|
|
12
|
+
/** Tracer event timeline (if provided at capture). */
|
|
13
|
+
timeline?: SwarmEvent[];
|
|
14
|
+
/** User-provided metadata. */
|
|
15
|
+
metadata?: Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
export interface SwarmSnapshotDiff {
|
|
18
|
+
/** Keys present in snapshot B but not A. */
|
|
19
|
+
added: string[];
|
|
20
|
+
/** Keys present in both but with different values. */
|
|
21
|
+
changed: string[];
|
|
22
|
+
/** Keys present in A but not B. */
|
|
23
|
+
removed: string[];
|
|
24
|
+
/** Keys present in both with identical values. */
|
|
25
|
+
unchanged: string[];
|
|
26
|
+
}
|
|
27
|
+
export interface SnapshotCaptureOptions {
|
|
28
|
+
registry?: AgentRegistry;
|
|
29
|
+
tracer?: SwarmTracer;
|
|
30
|
+
metadata?: Record<string, unknown>;
|
|
31
|
+
}
|
|
32
|
+
export declare class SwarmSnapshotStore {
|
|
33
|
+
private snapshots;
|
|
34
|
+
/**
|
|
35
|
+
* Capture a point-in-time snapshot of the swarm state.
|
|
36
|
+
* Returns the snapshot ID for later retrieval.
|
|
37
|
+
*/
|
|
38
|
+
capture(state: Record<string, unknown>, opts?: SnapshotCaptureOptions): string;
|
|
39
|
+
/** Retrieve a snapshot by ID. Returns null if not found. */
|
|
40
|
+
restore(id: string): SwarmSnapshot | null;
|
|
41
|
+
/** List all snapshots ordered by timestamp ascending. */
|
|
42
|
+
list(): SwarmSnapshot[];
|
|
43
|
+
/**
|
|
44
|
+
* Compare state between two snapshots.
|
|
45
|
+
* Returns null if either snapshot ID is not found.
|
|
46
|
+
*/
|
|
47
|
+
diff(idA: string, idB: string): SwarmSnapshotDiff | null;
|
|
48
|
+
/** Remove all stored snapshots. */
|
|
49
|
+
clear(): void;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../src/swarm/snapshot.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAM3D,MAAM,WAAW,aAAa;IAC5B,0BAA0B;IAC1B,EAAE,EAAU,MAAM,CAAC;IACnB,0CAA0C;IAC1C,SAAS,EAAG,MAAM,CAAC;IACnB,gDAAgD;IAChD,KAAK,EAAO,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,6DAA6D;IAC7D,MAAM,CAAC,EAAK,kBAAkB,EAAE,CAAC;IACjC,sDAAsD;IACtD,QAAQ,CAAC,EAAG,UAAU,EAAE,CAAC;IACzB,8BAA8B;IAC9B,QAAQ,CAAC,EAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,iBAAiB;IAChC,4CAA4C;IAC5C,KAAK,EAAM,MAAM,EAAE,CAAC;IACpB,sDAAsD;IACtD,OAAO,EAAI,MAAM,EAAE,CAAC;IACpB,mCAAmC;IACnC,OAAO,EAAI,MAAM,EAAE,CAAC;IACpB,kDAAkD;IAClD,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAG,aAAa,CAAC;IAC1B,MAAM,CAAC,EAAK,WAAW,CAAC;IACxB,QAAQ,CAAC,EAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAQD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,SAAS,CAAoC;IAErD;;;OAGG;IACH,OAAO,CACL,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,IAAI,CAAC,EAAE,sBAAsB,GAC5B,MAAM;IAsBT,4DAA4D;IAC5D,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAIzC,yDAAyD;IACzD,IAAI,IAAI,aAAa,EAAE;IAIvB;;;OAGG;IACH,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;IAgCxD,mCAAmC;IACnC,KAAK,IAAI,IAAI;CAGd"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// @oni.bot/core/swarm — SwarmSnapshotStore
|
|
3
|
+
// ============================================================
|
|
4
|
+
// Point-in-time capture of swarm state for debugging.
|
|
5
|
+
// Captures state, agent statuses, tracer timeline, and metadata.
|
|
6
|
+
// Supports listing, restoring, diffing, and clearing snapshots.
|
|
7
|
+
// ============================================================
|
|
8
|
+
// ----------------------------------------------------------------
|
|
9
|
+
// SwarmSnapshotStore
|
|
10
|
+
// ----------------------------------------------------------------
|
|
11
|
+
let _counter = 0;
|
|
12
|
+
export class SwarmSnapshotStore {
|
|
13
|
+
snapshots = new Map();
|
|
14
|
+
/**
|
|
15
|
+
* Capture a point-in-time snapshot of the swarm state.
|
|
16
|
+
* Returns the snapshot ID for later retrieval.
|
|
17
|
+
*/
|
|
18
|
+
capture(state, opts) {
|
|
19
|
+
const id = `snap_${Date.now()}_${++_counter}`;
|
|
20
|
+
const snapshot = {
|
|
21
|
+
id,
|
|
22
|
+
timestamp: Date.now(),
|
|
23
|
+
state: structuredClone(state),
|
|
24
|
+
};
|
|
25
|
+
if (opts?.registry) {
|
|
26
|
+
snapshot.agents = opts.registry.manifest();
|
|
27
|
+
}
|
|
28
|
+
if (opts?.tracer) {
|
|
29
|
+
snapshot.timeline = opts.tracer.getTimeline();
|
|
30
|
+
}
|
|
31
|
+
if (opts?.metadata) {
|
|
32
|
+
snapshot.metadata = structuredClone(opts.metadata);
|
|
33
|
+
}
|
|
34
|
+
this.snapshots.set(id, snapshot);
|
|
35
|
+
return id;
|
|
36
|
+
}
|
|
37
|
+
/** Retrieve a snapshot by ID. Returns null if not found. */
|
|
38
|
+
restore(id) {
|
|
39
|
+
return this.snapshots.get(id) ?? null;
|
|
40
|
+
}
|
|
41
|
+
/** List all snapshots ordered by timestamp ascending. */
|
|
42
|
+
list() {
|
|
43
|
+
return [...this.snapshots.values()].sort((a, b) => a.timestamp - b.timestamp);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Compare state between two snapshots.
|
|
47
|
+
* Returns null if either snapshot ID is not found.
|
|
48
|
+
*/
|
|
49
|
+
diff(idA, idB) {
|
|
50
|
+
const a = this.snapshots.get(idA);
|
|
51
|
+
const b = this.snapshots.get(idB);
|
|
52
|
+
if (!a || !b)
|
|
53
|
+
return null;
|
|
54
|
+
const keysA = new Set(Object.keys(a.state));
|
|
55
|
+
const keysB = new Set(Object.keys(b.state));
|
|
56
|
+
const added = [];
|
|
57
|
+
const changed = [];
|
|
58
|
+
const removed = [];
|
|
59
|
+
const unchanged = [];
|
|
60
|
+
for (const k of keysB) {
|
|
61
|
+
if (!keysA.has(k)) {
|
|
62
|
+
added.push(k);
|
|
63
|
+
}
|
|
64
|
+
else if (!deepEqual(a.state[k], b.state[k])) {
|
|
65
|
+
changed.push(k);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
unchanged.push(k);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
for (const k of keysA) {
|
|
72
|
+
if (!keysB.has(k)) {
|
|
73
|
+
removed.push(k);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return { added, changed, removed, unchanged };
|
|
77
|
+
}
|
|
78
|
+
/** Remove all stored snapshots. */
|
|
79
|
+
clear() {
|
|
80
|
+
this.snapshots.clear();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// ----------------------------------------------------------------
|
|
84
|
+
// Helpers
|
|
85
|
+
// ----------------------------------------------------------------
|
|
86
|
+
function deepEqual(a, b, seen = new WeakSet()) {
|
|
87
|
+
if (a === b)
|
|
88
|
+
return true;
|
|
89
|
+
if (a === null || b === null)
|
|
90
|
+
return false;
|
|
91
|
+
if (typeof a !== typeof b)
|
|
92
|
+
return false;
|
|
93
|
+
if (typeof a !== "object")
|
|
94
|
+
return false;
|
|
95
|
+
// Cycle guard: if we've already started comparing this object, assume equal
|
|
96
|
+
// (the non-cyclic portions have already matched at earlier recursion levels)
|
|
97
|
+
if (seen.has(a))
|
|
98
|
+
return true;
|
|
99
|
+
seen.add(a);
|
|
100
|
+
if (Array.isArray(a)) {
|
|
101
|
+
if (!Array.isArray(b))
|
|
102
|
+
return false;
|
|
103
|
+
if (a.length !== b.length)
|
|
104
|
+
return false;
|
|
105
|
+
return a.every((v, i) => deepEqual(v, b[i], seen));
|
|
106
|
+
}
|
|
107
|
+
const objA = a;
|
|
108
|
+
const objB = b;
|
|
109
|
+
const keysA = Object.keys(objA);
|
|
110
|
+
const keysB = Object.keys(objB);
|
|
111
|
+
if (keysA.length !== keysB.length)
|
|
112
|
+
return false;
|
|
113
|
+
return keysA.every((k) => deepEqual(objA[k], objB[k], seen));
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/swarm/snapshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"supervisor.d.ts","sourceRoot":"","sources":["../../src/swarm/supervisor.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAE,gBAAgB,EAAa,MAAM,YAAY,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"supervisor.d.ts","sourceRoot":"","sources":["../../src/swarm/supervisor.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAE,gBAAgB,EAAa,MAAM,YAAY,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAQnD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAa,MAAM,CAAC;IACxB,OAAO,EAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAK,MAAM,GAAG,IAAI,CAAC;IAC/B,YAAY,EAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,QAAQ,EAAS,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1D,IAAI,EAAa,OAAO,CAAC;IACzB,CAAC,GAAG,EAAE,MAAM,GAAK,OAAO,CAAC;CAC1B;AAMD,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,eAAe,EAC5D,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,EAC1B,MAAM,EAAI,gBAAgB,CAAC,CAAC,CAAC,GAC5B,MAAM,CAAC,CAAC,CAAC,CA6HX"}
|
package/dist/swarm/supervisor.js
CHANGED
|
@@ -7,14 +7,40 @@
|
|
|
7
7
|
// ============================================================
|
|
8
8
|
import { END } from "../types.js";
|
|
9
9
|
import { Command } from "../types.js";
|
|
10
|
+
import { ONIError } from "../errors.js";
|
|
10
11
|
// ----------------------------------------------------------------
|
|
11
12
|
// createSupervisorNode — factory that returns a NodeFn
|
|
12
13
|
// ----------------------------------------------------------------
|
|
13
14
|
export function createSupervisorNode(registry, config) {
|
|
15
|
+
// Validate config
|
|
16
|
+
if (config.strategy === "llm" && !config.model) {
|
|
17
|
+
throw new ONIError('Strategy "llm" requires a model to be provided.', { code: "ONI_SWARM_CONFIG", category: "SWARM", recoverable: false });
|
|
18
|
+
}
|
|
14
19
|
const maxRounds = config.maxRounds ?? 10;
|
|
20
|
+
const deadlineMs = config.deadlineMs;
|
|
21
|
+
const autoRecover = config.autoRecover ?? false;
|
|
15
22
|
return async (state) => {
|
|
16
23
|
const round = state.supervisorRound ?? 0;
|
|
17
24
|
const task = String(state[config.taskField] ?? "");
|
|
25
|
+
// Deadline is computed at invoke-time: on round 0, set the absolute deadline in context.
|
|
26
|
+
// On subsequent rounds, read it from context. This ensures each invoke() gets a fresh deadline.
|
|
27
|
+
let deadlineAbsolute = null;
|
|
28
|
+
if (deadlineMs != null) {
|
|
29
|
+
const ctx = (state.context ?? {});
|
|
30
|
+
if (round === 0 || ctx.__deadlineAbsolute === undefined) {
|
|
31
|
+
deadlineAbsolute = Date.now() + deadlineMs;
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
deadlineAbsolute = ctx.__deadlineAbsolute;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Guard: deadline expired
|
|
38
|
+
if (deadlineAbsolute != null && Date.now() >= deadlineAbsolute) {
|
|
39
|
+
return new Command({
|
|
40
|
+
update: { supervisorRound: round },
|
|
41
|
+
goto: END,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
18
44
|
// Guard: max rounds
|
|
19
45
|
if (round >= maxRounds || state.done) {
|
|
20
46
|
return new Command({
|
|
@@ -29,6 +55,34 @@ export function createSupervisorNode(registry, config) {
|
|
|
29
55
|
const rawCtx = (config.contextField ? state[config.contextField] : {});
|
|
30
56
|
// Enrich context with supervisorRound so rules/LLM can inspect the current round
|
|
31
57
|
const ctx = { ...rawCtx, supervisorRound: round };
|
|
58
|
+
// Auto-recovery: if lastAgentError exists and autoRecover is enabled,
|
|
59
|
+
// find an idle agent with matching capabilities
|
|
60
|
+
if (autoRecover && ctx.lastAgentError) {
|
|
61
|
+
const errorCtx = ctx.lastAgentError;
|
|
62
|
+
const failedAgent = registry.get(errorCtx.agent);
|
|
63
|
+
if (failedAgent) {
|
|
64
|
+
const failedCaps = new Set(failedAgent.def.capabilities.map((c) => c.name.toLowerCase()));
|
|
65
|
+
if (failedCaps.size > 0) {
|
|
66
|
+
// Find an idle agent with matching capability (not the failed agent)
|
|
67
|
+
const idle = registry.findIdle().filter((a) => a.def.id !== errorCtx.agent);
|
|
68
|
+
const match = idle.find((a) => a.def.capabilities.some((c) => failedCaps.has(c.name.toLowerCase())));
|
|
69
|
+
if (match) {
|
|
70
|
+
return new Command({
|
|
71
|
+
update: {
|
|
72
|
+
supervisorRound: round + 1,
|
|
73
|
+
currentAgent: match.def.id,
|
|
74
|
+
context: { ...rawCtx, lastAgentError: undefined },
|
|
75
|
+
messages: [
|
|
76
|
+
...state.messages,
|
|
77
|
+
{ role: "system", content: `Supervisor auto-recovering to: ${match.def.role}` },
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
goto: match.def.id,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
32
86
|
// Route to next agent
|
|
33
87
|
let targetAgentId = null;
|
|
34
88
|
switch (config.strategy) {
|
|
@@ -41,6 +95,9 @@ export function createSupervisorNode(registry, config) {
|
|
|
41
95
|
case "round-robin":
|
|
42
96
|
targetAgentId = routeRoundRobin(registry, round);
|
|
43
97
|
break;
|
|
98
|
+
case "capability":
|
|
99
|
+
targetAgentId = routeViaCapability(ctx, registry);
|
|
100
|
+
break;
|
|
44
101
|
}
|
|
45
102
|
if (!targetAgentId) {
|
|
46
103
|
return new Command({ update: {}, goto: END });
|
|
@@ -53,6 +110,7 @@ export function createSupervisorNode(registry, config) {
|
|
|
53
110
|
update: {
|
|
54
111
|
supervisorRound: round + 1,
|
|
55
112
|
currentAgent: targetAgentId,
|
|
113
|
+
...(deadlineAbsolute != null ? { context: { ...rawCtx, __deadlineAbsolute: deadlineAbsolute } } : {}),
|
|
56
114
|
messages: [
|
|
57
115
|
...state.messages,
|
|
58
116
|
{ role: "system", content: `Supervisor routing to: ${agentDef.role}` },
|
|
@@ -110,4 +168,28 @@ function routeRoundRobin(registry, round) {
|
|
|
110
168
|
}
|
|
111
169
|
return agents[round % agents.length].def.id;
|
|
112
170
|
}
|
|
171
|
+
function routeViaCapability(context, registry) {
|
|
172
|
+
const required = context.requiredCapabilities;
|
|
173
|
+
if (!required || required.length === 0)
|
|
174
|
+
return null;
|
|
175
|
+
const all = registry.getAll().filter((a) => a.status !== "terminated");
|
|
176
|
+
if (!all.length)
|
|
177
|
+
return null;
|
|
178
|
+
// Score each agent by how many required capabilities it matches
|
|
179
|
+
let bestId = null;
|
|
180
|
+
let bestScore = 0;
|
|
181
|
+
for (const agent of all) {
|
|
182
|
+
const capNames = new Set(agent.def.capabilities.map((c) => c.name.toLowerCase()));
|
|
183
|
+
let score = 0;
|
|
184
|
+
for (const req of required) {
|
|
185
|
+
if (capNames.has(req.toLowerCase()))
|
|
186
|
+
score++;
|
|
187
|
+
}
|
|
188
|
+
if (score > bestScore) {
|
|
189
|
+
bestScore = score;
|
|
190
|
+
bestId = agent.def.id;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return bestScore > 0 ? bestId : null;
|
|
194
|
+
}
|
|
113
195
|
//# sourceMappingURL=supervisor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"supervisor.js","sourceRoot":"","sources":["../../src/swarm/supervisor.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,mCAAmC;AACnC,+DAA+D;AAC/D,kDAAkD;AAClD,+DAA+D;AAC/D,wDAAwD;AACxD,+DAA+D;AAE/D,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAElC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"supervisor.js","sourceRoot":"","sources":["../../src/swarm/supervisor.ts"],"names":[],"mappings":"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"}
|