@lloyal-labs/lloyal-agents 1.0.0 → 1.2.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 (48) hide show
  1. package/README.md +28 -50
  2. package/dist/Tool.d.ts +13 -3
  3. package/dist/Tool.d.ts.map +1 -1
  4. package/dist/Tool.js +7 -2
  5. package/dist/Tool.js.map +1 -1
  6. package/dist/agent-pool.d.ts +9 -11
  7. package/dist/agent-pool.d.ts.map +1 -1
  8. package/dist/agent-pool.js +156 -101
  9. package/dist/agent-pool.js.map +1 -1
  10. package/dist/context.d.ts +32 -1
  11. package/dist/context.d.ts.map +1 -1
  12. package/dist/context.js +31 -1
  13. package/dist/context.js.map +1 -1
  14. package/dist/generate.d.ts +20 -5
  15. package/dist/generate.d.ts.map +1 -1
  16. package/dist/generate.js +80 -9
  17. package/dist/generate.js.map +1 -1
  18. package/dist/index.d.ts +6 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +11 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/init.d.ts +4 -1
  23. package/dist/init.d.ts.map +1 -1
  24. package/dist/init.js +5 -1
  25. package/dist/init.js.map +1 -1
  26. package/dist/shared-root.d.ts +3 -3
  27. package/dist/shared-root.d.ts.map +1 -1
  28. package/dist/shared-root.js +66 -5
  29. package/dist/shared-root.js.map +1 -1
  30. package/dist/source.d.ts +27 -0
  31. package/dist/source.d.ts.map +1 -0
  32. package/dist/source.js +25 -0
  33. package/dist/source.js.map +1 -0
  34. package/dist/trace-scope.d.ts +25 -0
  35. package/dist/trace-scope.d.ts.map +1 -0
  36. package/dist/trace-scope.js +41 -0
  37. package/dist/trace-scope.js.map +1 -0
  38. package/dist/trace-types.d.ts +178 -0
  39. package/dist/trace-types.d.ts.map +1 -0
  40. package/dist/trace-types.js +3 -0
  41. package/dist/trace-types.js.map +1 -0
  42. package/dist/trace-writer.d.ts +58 -0
  43. package/dist/trace-writer.d.ts.map +1 -0
  44. package/dist/trace-writer.js +56 -0
  45. package/dist/trace-writer.js.map +1 -0
  46. package/dist/types.d.ts +8 -6
  47. package/dist/types.d.ts.map +1 -1
  48. package/package.json +1 -1
package/README.md CHANGED
@@ -1,20 +1,21 @@
1
1
  # @lloyal-labs/lloyal-agents
2
2
 
3
- Structured concurrency agent runtime for the lloyal inference platform.
3
+ Continuous Context agent runtime.
4
4
 
5
- `lloyal-agents` runs multi-agent inference inside the decode loop. Agents are branches of a single running process — forked from shared KV cache state, advancing through one GPU forward pass per tick, spawning sub-agents from their own live branches at arbitrary depth. Orchestration is not a layer above inference. It is inference.
5
+ `lloyal-agents` runs multi-agent inference inside the decode loop. Instead of N independent model calls rebuilding the prompt each step, all agents advance inside one continuous decode process — forked from shared KV cache state, driven through a single GPU forward pass per tick, spawning sub-agents from their own live branches at arbitrary depth.
6
6
 
7
- ```bash
8
- npm i @lloyal-labs/lloyal-agents
9
- ```
10
-
11
- **Backends:** [lloyal.node](https://github.com/lloyal-ai/lloyal.node) — prebuilt binaries for macOS (Metal, CPU), Linux (CPU, CUDA, Vulkan), and Windows (CPU, CUDA, Vulkan). GPU selection at runtime.
7
+ Built on [lloyal.node](https://github.com/lloyal-ai/lloyal.node), which provides forkable decode state and continuous tree batching over llama.cpp. `lloyal-agents` adds structured concurrency, tool dispatch, and a four-phase tick loop. Orchestration is not a layer above inference. It is inference.
12
8
 
13
- ## Generation as the Primitive
9
+ <picture>
10
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/lloyal-ai/sdk/main/assets/continuous-context-dark.svg">
11
+ <img src="https://raw.githubusercontent.com/lloyal-ai/sdk/main/assets/continuous-context.svg" alt="Traditional Agents vs Continuous Context Agents — shared KV prefix, tool prefill, sub-agent spawning" width="100%">
12
+ </picture>
14
13
 
15
- The core architectural decision: generation is the primitive, not the API call. Agents are not processes that exchange messages. They are branches of a running inference process — forked from shared KV cache state, generating independently, their outputs comparable because they share a computational origin.
14
+ ```bash
15
+ npm i @lloyal-labs/lloyal-agents @lloyal-labs/lloyal.node
16
+ ```
16
17
 
17
- This is built on [lloyal.node](https://github.com/lloyal-ai/lloyal.node), which provides forkable decode state and continuous tree batching over llama.cpp. `lloyal-agents` adds structured concurrency, tool dispatch, and a three-phase tick loop that drives N branches through a single GPU forward pass per step.
18
+ `lloyal-agents` provides the agent runtime. [`lloyal.node`](https://github.com/lloyal-ai/lloyal.node) provides the native inference backend prebuilt binaries for macOS (Metal, CPU), Linux (CPU, CUDA, Vulkan), and Windows (CPU, CUDA, Vulkan). Both are required. GPU selection at runtime.
18
19
 
19
20
  The public API surface:
20
21
 
@@ -91,7 +92,7 @@ yield *
91
92
 
92
93
  ## In-Loop Orchestration
93
94
 
94
- All active agents advance together in a three-phase tick loop:
95
+ All active agents advance together in a four-phase tick loop:
95
96
 
96
97
  **PRODUCE.** Every generating agent calls `produceSync()` — synchronous sampling with no async gap between agents. This matters because it means the entire produce phase is a single uninterrupted pass over the active set.
97
98
 
@@ -99,6 +100,8 @@ All active agents advance together in a three-phase tick loop:
99
100
 
100
101
  **SETTLE.** Tool results that resolved during COMMIT are drained from a buffer. Each result is tokenized into a delta, budget-checked against a fresh `ContextPressure` snapshot, and batch-prefilled into the agent's branch. Grammar state resets. The agent transitions back to `generating`.
101
102
 
103
+ **DISPATCH.** Tool calls collected during PRODUCE are executed sequentially via `scoped()` + `call()`. Each tool runs to completion before the next begins — no concurrent `llama_decode` during dispatch. Tools return `Operation<unknown>`, so they can `yield*` into framework primitives like `useAgentPool` or `runAgents`, spawning recursive sub-agents within the calling agent's scope.
104
+
102
105
  ```typescript
103
106
  // From the tick loop — Phase 1
104
107
  const entries: [Branch, number][] = [];
@@ -122,7 +125,7 @@ if (entries.length > 0) {
122
125
  }
123
126
  ```
124
127
 
125
- When no agent is generating and tools are still pending, the loop parks itself via `action()` — an Effection primitive that suspends the generator until a tool resolves and calls `wakeIdle()`. No polling. No sleep loops.
128
+ When no agent is generating and tools are still pending, the loop yields control until the next tool resolves. No polling. No sleep loops.
126
129
 
127
130
  ## Structured Concurrency DAG
128
131
 
@@ -140,40 +143,15 @@ function* setupAgent(parent, task, ctx) {
140
143
  }
141
144
  ```
142
145
 
143
- If the scope exits — error, cancellation, normal completion — the branch is pruned. Orphaned branches are structurally impossible. Tool dispatch uses `scope.run()` for eager start inside the agent pool scope; if the scope tears down, pending tools are cancelled. The DAG is not imposed on the orchestration. It is intrinsic to the Effection task tree.
146
+ If the scope exits — error, cancellation, normal completion — the branch is pruned. Orphaned branches are structurally impossible. Tool dispatch uses `scoped()` + `call()` each tool executes inside a scoped error boundary within the agent pool scope. If the scope tears down, pending tools are cancelled. The DAG is not imposed on the orchestration. It is intrinsic to the Effection task tree.
144
147
 
145
148
  `useAgentPool` is an Effection `resource()` — it suspends via `provide()` after all agents complete, but keeps their branches alive. The caller can fork sub-agents from any completed agent's branch. Those sub-agents inherit the parent agent's full KV state — everything it generated, every tool result it consumed, every reasoning step it took. No summarization. No context window management. The sub-agent continues from the parent's frontier.
146
149
 
147
- The deep-research harness ships a concrete example: `reportPass`. Research agents run through the tick loop with tools search, grep, read_file, report. Some agents get hard-cut by context pressure before they can submit findings. Rather than losing their work, the harness forks a sub-agent from each hard-cut agent's branch with a constrained tool set (report only):
150
+ Recursive agents work at two levels. At the **harness level**, a completed pool's branches can be forked into follow-up pools — sub-agents inherit the parent's full KV state and continue from the fork point. At the **model level**, a tool's `execute()` method returns `Operation<unknown>`, so it can `yield*` directly into `useAgentPool` or `runAgents`. An agent that calls such a tool spawns sub-agents mid-generation inside its own scope, inheriting its KV state, with cleanup guaranteed by structured concurrency.
148
151
 
149
- ```typescript
150
- function* reportPass(pool: AgentPoolResult, opts: WorkflowOpts) {
151
- const hardCut = pool.agents.filter((a) => !a.findings && !a.branch.disposed);
152
- if (hardCut.length === 0) return;
153
-
154
- const reporters = yield* runAgents({
155
- tasks: hardCut.map((a) => ({
156
- systemPrompt: REPORT_PROMPT,
157
- content: "Report your findings.",
158
- tools: reportOnlyTools,
159
- parent: a.branch, // fork from the parent agent's branch
160
- })),
161
- tools: new Map([["report", reportTool]]),
162
- terminalTool: "report",
163
- });
152
+ In both cases, the sub-agent sees everything the parent saw — system prompt, tool calls, partial reasoning — because that state is already in the KV cache at the fork point. No summarization. No context reconstruction. The sub-agent just continues from the parent's frontier.
164
153
 
165
- hardCut.forEach((a, i) => {
166
- if (reporters.agents[i]?.findings)
167
- a.findings = reporters.agents[i].findings;
168
- });
169
- }
170
- ```
171
-
172
- The sub-agent sees everything the parent saw — its system prompt, its tool calls, its partial reasoning — because that state is already in the KV cache at the fork point. The sub-agent just continues from where the parent was cut off, with a tighter mandate.
173
-
174
- This is the DAG in practice: parent agents form the first level, reporter sub-agents form the second. `runAgents` wraps `useAgentPool` in `scoped()`, so the reporter branches are pruned when it returns. The parent branches are still alive in the outer scope. When that outer scope exits, every `ensure()` callback fires and prunes the parents. Teardown propagates top-down. Cleanup is guaranteed bottom-up.
175
-
176
- There is nothing in the framework that limits this to two levels. Agents can spawn sub-agents that spawn sub-agents. An agent pool can run inside another agent pool's scope. The structured concurrency guarantees compose at every depth.
154
+ There is nothing in the framework that limits depth. Agents can spawn sub-agents that spawn sub-agents. An agent pool can run inside another agent pool's scope. The structured concurrency guarantees compose at every level.
177
155
 
178
156
  ## Hallucination Detection
179
157
 
@@ -198,19 +176,15 @@ const result =
198
176
  // Losers already pruned. Winner's branch is caller's responsibility.
199
177
  ```
200
178
 
201
- The harness decides how to compare. The deep-research example measures semantic equivalence across diverge outputs using bigram Jaccard similarity where branches agree, the model is confident; where they diverge, hallucination risk is high. No model call required for the comparison itself. Other harnesses can use different equivalence measures over the same `diverge()` primitive.
179
+ The harness decides how to compare. `diverge()` returns all outputs with their perplexity scores the harness can apply any equivalence measure: bigram overlap, embedding similarity, or model-based evaluation. Where branches agree, the model is confident; where they diverge, hallucination risk is high.
202
180
 
203
181
  This directly operationalizes the semantic entropy work from Farquhar et al. ([Nature, 2024](https://www.nature.com/articles/s41586-024-07421-0)) — but as a runtime primitive, not a post-hoc metric. The key constraint: divergence from a common computational ancestor is signal. Divergence from independently-constructed contexts is sampling variance. This measurement is only meaningful because agents share a frontier.
204
182
 
205
183
  ## Session Accumulation
206
184
 
207
- When agents converge when the entropy gate passes — the winning branch is not returned as output. It is promoted. It becomes the new trunk of the session. The next query starts from ground that was computationally earned by the previous convergence check.
208
-
209
- This is the cold/warm session distinction. A cold query runs the full pipeline: plan the decomposition, dispatch research agents, synthesize via `diverge`, evaluate convergence, promote. A warm query — one where a trusted trunk already exists — skips verification entirely. The frontier is already established. Agents fork from it, research, and the session responds directly from findings.
210
-
211
- Each promote is an epistemic commitment: this branch survived N-way comparison and convergence evaluation, so it becomes the basis for future reasoning. The session doesn't just carry forward text — it carries forward the KV state of a branch that survived verification. Future agents fork from this state. Their shared frontier is not an empty system prompt. It is the accumulated, verified reasoning of every previous cycle.
185
+ `Session.promote(branch)` retains only that branch and makes it the session trunk. Future queries fork from this trunk its KV cache already contains everything the promoted branch generated, every tool result it consumed, every verification it passed.
212
186
 
213
- Over multiple queries, the session compounds. Early queries establish the foundation. Later queries branch from it, research further, verify further, promote further. The trunk grows. The frontier advances. The model's effective context is not what you put in the prompt it is what was earned by convergence.
187
+ A cold query starts from position 0. A warm query starts from an existing trunk. Over multiple queries, the session compounds each promote advances the frontier, and future agents inherit the accumulated state.
214
188
 
215
189
  ## Context Pressure
216
190
 
@@ -237,6 +211,8 @@ Tools are class-based with OpenAI-compatible function schemas:
237
211
 
238
212
  ```typescript
239
213
  import { Tool } from "@lloyal-labs/lloyal-agents";
214
+ import { call } from "effection";
215
+ import type { Operation } from "effection";
240
216
  import type { ToolContext } from "@lloyal-labs/lloyal-agents";
241
217
 
242
218
  class SearchTool extends Tool<{ query: string }> {
@@ -248,8 +224,10 @@ class SearchTool extends Tool<{ query: string }> {
248
224
  required: ["query"],
249
225
  };
250
226
 
251
- async execute(args: { query: string }, context?: ToolContext) {
252
- const results = await this.reranker.rank(args.query, this.chunks);
227
+ *execute(args: { query: string }, context?: ToolContext): Operation<unknown> {
228
+ const results = yield* call(() =>
229
+ this.reranker.rank(args.query, this.chunks),
230
+ );
253
231
  context?.onProgress?.({
254
232
  filled: results.length,
255
233
  total: this.chunks.length,
package/dist/Tool.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { Operation } from 'effection';
1
2
  import type { JsonSchema, ToolSchema, ToolContext } from './types';
2
3
  /**
3
4
  * Abstract base class for tools usable by agents in the runtime
@@ -11,6 +12,11 @@ import type { JsonSchema, ToolSchema, ToolContext } from './types';
11
12
  * and `toolsJson` pair consumed by {@link useAgentPool} and
12
13
  * {@link runAgents}.
13
14
  *
15
+ * `execute()` returns an Effection `Operation`, enabling tools to
16
+ * spawn sub-agents via {@link runAgents} or {@link withSharedRoot}.
17
+ * For async work, wrap in `call()`. For synchronous tools, return
18
+ * directly from the generator body.
19
+ *
14
20
  * @example Search tool
15
21
  * ```typescript
16
22
  * class SearchTool extends Tool<{ query: string; topK?: number }> {
@@ -25,8 +31,8 @@ import type { JsonSchema, ToolSchema, ToolContext } from './types';
25
31
  * required: ['query'],
26
32
  * };
27
33
  *
28
- * async execute(args: { query: string; topK?: number }, ctx?: ToolContext) {
29
- * const results = await this.reranker.rank(args.query, args.topK ?? 5);
34
+ * *execute(args: { query: string; topK?: number }, ctx?: ToolContext): Operation<unknown> {
35
+ * const results = yield* call(() => this.reranker.rank(args.query, args.topK ?? 5));
30
36
  * return { results };
31
37
  * }
32
38
  * }
@@ -48,11 +54,15 @@ export declare abstract class Tool<TArgs = Record<string, unknown>> {
48
54
  * this tool's name. The return value is JSON-serialized and prefilled
49
55
  * back into the agent's context as a tool result.
50
56
  *
57
+ * Returns an Effection Operation — implement as a generator method.
58
+ * The operation runs inside the agent pool's scope, so it has access
59
+ * to Ctx, Store, and Events contexts for nested agent spawning.
60
+ *
51
61
  * @param args - Parsed arguments from the model's tool call
52
62
  * @param context - Execution context with progress reporting callback
53
63
  * @returns Tool result (will be JSON-serialized)
54
64
  */
55
- abstract execute(args: TArgs, context?: ToolContext): Promise<unknown>;
65
+ abstract execute(args: TArgs, context?: ToolContext): Operation<unknown>;
56
66
  /**
57
67
  * OpenAI-compatible function tool schema
58
68
  *
@@ -1 +1 @@
1
- {"version":3,"file":"Tool.d.ts","sourceRoot":"","sources":["../src/Tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,8BAAsB,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACxD,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAC/B,oDAAoD;IACpD,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IACtC,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAEzC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAEtE;;;;;;OAMG;IACH,IAAI,MAAM,IAAI,UAAU,CASvB;CACF"}
1
+ {"version":3,"file":"Tool.d.ts","sourceRoot":"","sources":["../src/Tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,8BAAsB,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACxD,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAC/B,oDAAoD;IACpD,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IACtC,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAEzC;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC,OAAO,CAAC;IAExE;;;;;;OAMG;IACH,IAAI,MAAM,IAAI,UAAU,CASvB;CACF"}
package/dist/Tool.js CHANGED
@@ -13,6 +13,11 @@ exports.Tool = void 0;
13
13
  * and `toolsJson` pair consumed by {@link useAgentPool} and
14
14
  * {@link runAgents}.
15
15
  *
16
+ * `execute()` returns an Effection `Operation`, enabling tools to
17
+ * spawn sub-agents via {@link runAgents} or {@link withSharedRoot}.
18
+ * For async work, wrap in `call()`. For synchronous tools, return
19
+ * directly from the generator body.
20
+ *
16
21
  * @example Search tool
17
22
  * ```typescript
18
23
  * class SearchTool extends Tool<{ query: string; topK?: number }> {
@@ -27,8 +32,8 @@ exports.Tool = void 0;
27
32
  * required: ['query'],
28
33
  * };
29
34
  *
30
- * async execute(args: { query: string; topK?: number }, ctx?: ToolContext) {
31
- * const results = await this.reranker.rank(args.query, args.topK ?? 5);
35
+ * *execute(args: { query: string; topK?: number }, ctx?: ToolContext): Operation<unknown> {
36
+ * const results = yield* call(() => this.reranker.rank(args.query, args.topK ?? 5));
32
37
  * return { results };
33
38
  * }
34
39
  * }
package/dist/Tool.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Tool.js","sourceRoot":"","sources":["../src/Tool.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAsB,IAAI;IAqBxB;;;;;;OAMG;IACH,IAAI,MAAM;QACR,OAAO;YACL,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE;gBACR,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;aAC5B;SACF,CAAC;IACJ,CAAC;CACF;AAtCD,oBAsCC"}
1
+ {"version":3,"file":"Tool.js","sourceRoot":"","sources":["../src/Tool.ts"],"names":[],"mappings":";;;AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAsB,IAAI;IAyBxB;;;;;;OAMG;IACH,IAAI,MAAM;QACR,OAAO;YACL,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE;gBACR,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;aAC5B;SACF,CAAC;IACJ,CAAC;CACF;AA1CD,oBA0CC"}
@@ -6,11 +6,10 @@ import type { PressureThresholds, AgentPoolOptions, AgentPoolResult } from './ty
6
6
  *
7
7
  * Created from `SessionContext._storeKvPressure()` which returns
8
8
  * `{ nCtx, cellsUsed, remaining }` where `remaining = nCtx - cellsUsed`.
9
- * `cellsUsed` is a monotonic counter in `BranchStore`it increments on
10
- * every `decode_each` / `decode_scatter` but does **not** decrement on
11
- * individual branch prune (only resets on bulk ops like `retainOnly` and
12
- * `drain`). This means `remaining` is a conservative lower bound that
13
- * becomes increasingly pessimistic as branches are pruned mid-run.
9
+ * `cellsUsed` tracks unique KV cells per branchincremented on
10
+ * `decode_each` / `decode_scatter`, decremented on release by
11
+ * `position - fork_head` (unique cells above the fork point), reset on
12
+ * bulk ops like `retainOnly` and `drain`.
14
13
  *
15
14
  * Two thresholds partition `remaining` into three zones:
16
15
  *
@@ -44,8 +43,6 @@ export declare class ContextPressure {
44
43
  /**
45
44
  * KV slots remaining (`nCtx - cellsUsed`).
46
45
  * Infinity when nCtx ≤ 0 (no context limit).
47
- * Conservative: may undercount actual free space when branches have been
48
- * pruned, since `cellsUsed` is monotonic.
49
46
  */
50
47
  readonly remaining: number;
51
48
  /** Remaining KV floor — tokens reserved for downstream work */
@@ -67,17 +64,18 @@ export declare class ContextPressure {
67
64
  /**
68
65
  * Concurrent agent generation loop as an Effection resource
69
66
  *
70
- * Runs N agents in parallel using a three-phase tick loop over shared
67
+ * Runs N agents in parallel using a four-phase tick loop over shared
71
68
  * {@link BranchStore} infrastructure. Each agent forks from a parent
72
69
  * branch, generates tokens, invokes tools, and reports findings.
73
70
  *
74
- * **Three-phase tick loop:**
71
+ * **Four-phase tick loop:**
75
72
  * 1. **PRODUCE** — sample all active agents via `produceSync()` (no async gap)
76
73
  * 2. **COMMIT** — single GPU call via `store.commit()` for all produced tokens
77
74
  * 3. **SETTLE** — drain settled tool results, batch prefill, reset grammars
75
+ * 4. **DISPATCH** — execute collected tool calls sequentially via `scoped()` + `call()`
78
76
  *
79
- * Tool dispatch uses `scope.run()` for eager start — tool executions run as
80
- * children of the agent pool scope and are cancelled if the scope exits.
77
+ * Tool dispatch uses `scoped()` + `call()`each tool executes to completion
78
+ * before the next tick, ensuring exclusive `llama_context` access (no concurrent decode).
81
79
  *
82
80
  * **Resource semantics:** `provide()` suspends after all agents complete,
83
81
  * keeping branches alive so the caller can fork from them (e.g. for
@@ -1 +1 @@
1
- {"version":3,"file":"agent-pool.d.ts","sourceRoot":"","sources":["../src/agent-pool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAkB,MAAM,WAAW,CAAC;AAE3D,OAAO,EAA+G,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAIpK,OAAO,KAAK,EAEV,kBAAkB,EAElB,gBAAgB,EAChB,eAAe,EAEhB,MAAM,SAAS,CAAC;AAqCjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,eAAe;IAC1B,kEAAkE;IAClE,MAAM,CAAC,QAAQ,CAAC,kBAAkB,QAAQ;IAC1C,2DAA2D;IAC3D,MAAM,CAAC,QAAQ,CAAC,kBAAkB,OAAO;IAEzC;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,+DAA+D;IAC/D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,wEAAwE;IACxE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,GAAG,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,kBAAkB;IAO1D;;;;OAIG;IACH,IAAI,QAAQ,IAAI,MAAM,CAA4C;IAElE,qEAAqE;IACrE,IAAI,QAAQ,IAAI,OAAO,CAA4C;IAEnE,iEAAiE;IACjE,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;CACpC;AAwDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,SAAS,CAAC,eAAe,CAAC,CAwW/E"}
1
+ {"version":3,"file":"agent-pool.d.ts","sourceRoot":"","sources":["../src/agent-pool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAW,MAAM,WAAW,CAAC;AAEpD,OAAO,EAA+G,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAKpK,OAAO,KAAK,EAEV,kBAAkB,EAElB,gBAAgB,EAChB,eAAe,EAEhB,MAAM,SAAS,CAAC;AAqCjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBAAa,eAAe;IAC1B,kEAAkE;IAClE,MAAM,CAAC,QAAQ,CAAC,kBAAkB,QAAQ;IAC1C,2DAA2D;IAC3D,MAAM,CAAC,QAAQ,CAAC,kBAAkB,OAAO;IAEzC;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,+DAA+D;IAC/D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,wEAAwE;IACxE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,GAAG,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE,kBAAkB;IAO1D;;;;OAIG;IACH,IAAI,QAAQ,IAAI,MAAM,CAA4C;IAElE,qEAAqE;IACrE,IAAI,QAAQ,IAAI,OAAO,CAA4C;IAEnE,iEAAiE;IACjE,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;CACpC;AA0DD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,SAAS,CAAC,eAAe,CAAC,CAsa/E"}