pi-subagents-lite 0.4.0 → 1.0.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.
package/README.md CHANGED
@@ -13,18 +13,18 @@ Every tool the LLM sees costs tokens — in the system prompt, and in every turn
13
13
 
14
14
  | Standard | Schema-first |
15
15
  |---|---|
16
- | `description: "Spawn a sub-agent"` | `description: "."` |
16
+ | `description: "Spawn a sub-agent"` | _(removed)_ |
17
17
  | `promptSnippet` with usage examples | _(none)_ |
18
18
  | `promptGuidelines` with rules | _(none)_ |
19
19
  | Parameters with `.description()` | Bare `Type.String()` |
20
20
 
21
21
  Tool names like `Agent` and `StopAgent`, and parameter names like `prompt`, `description`, `run_in_background` are self-documenting. The LLM infers usage from the schema — no verbose descriptions needed. Tool results reinforce correct usage with clear success/error messages.
22
22
 
23
- **Result:** foreground and background agents, custom agent types, per-model concurrency, cost tracking, steering, resume, model overrides — all with minimal token overhead.
23
+ **Result:** foreground and background agents, custom agent types, per-model concurrency, cost tracking, steering, model overrides — all with minimal token overhead.
24
24
 
25
25
  ## Features
26
26
 
27
- - **Two tools** — `Agent` (spawn) and `StopAgent` (kill)
27
+ - **Two tools** — `Agent` (spawn) and `StopAgent` (stop)
28
28
  - **Foreground & background** — block or fire-and-forget with auto-delivered results
29
29
  - **Custom agent types** — define via `.md` files with YAML frontmatter (tools, model, thinking, turn limits)
30
30
  - **Smart model resolution** — 6-level precedence: session → config → frontmatter → parent. Set once, forget
@@ -32,7 +32,7 @@ Tool names like `Agent` and `StopAgent`, and parameter names like `prompt`, `des
32
32
  - **Cost tracking** — input/output/cache tokens and dollar cost per agent
33
33
  - **Live widget** — persistent status bar above the editor showing running/completed agents
34
34
  - **Result viewer** — fullscreen markdown viewer with stats
35
- - **Steer & resume** — inject mid-execution guidance or continue a previous conversation
35
+ - **Steer** — inject mid-execution guidance into running agents
36
36
  - **Output logs** — human-readable, `tail -f` friendly
37
37
 
38
38
  ## Install
@@ -93,26 +93,25 @@ Stop a running agent at any time via /agents command
93
93
  |---|---|---|
94
94
  | `prompt` | ✅ | The task for the sub-agent |
95
95
  | `description` | ✅ | Brief description for the LLM caller |
96
- | `agent` | | Type name — `general-purpose`, `Explore`, or any custom type you define (see [Custom Agent Types](#custom-agent-types)). The available values are **auto-populated** from `.md` files in your agent directories — drop a file, it appears in the enum. Set `enabled: false` in frontmatter to remove a type from this list. |
96
+ | `agent` | | Type name — `general-purpose`, `Explore`, or any custom type you define (see [Custom Agent Types](#custom-agent-types)). The available values are **auto-populated** from `.md` files in your agent directories — drop a file, it appears in the enum. Set `hidden: true` in frontmatter to hide a type from this list (still callable by name). |
97
97
  | `run_in_background` | | Fire-and-forget; result delivered automatically when done |
98
- | `resume` | | Agent ID to continue a previous conversation |
99
98
 
100
- > `model`, `max_turns`, `isolated`, and `thinking` are **not visible to the LLM** through tool introspection — the extension injects them at call time from agent config and frontmatter. `model` is resolved via the [Model Resolution](#model-resolution) chain; `max_turns`/`isolated`/`thinking` come from the agent's config. See [Custom Agent Types](#custom-agent-types) to set them.
99
+ > `model`, `max_turns`, and `thinking` are **not visible to the LLM** through tool introspection — the extension injects them at call time from agent config and frontmatter. `model` is resolved via the [Model Resolution](#model-resolution) chain; `max_turns`/`thinking` come from the agent's config. See [Custom Agent Types](#custom-agent-types) to set them.
101
100
 
102
101
  ## Custom Agent Types
103
102
 
104
103
  Drop a `.md` file into `.pi/agents/` (project) or `~/.pi/agent/agents/` (global). The frontmatter configures the agent; the body is its system prompt.
105
104
 
106
- The file's `name` frontmatter field (or the filename without extension) becomes the agent type name and **automatically populates the `agent` parameter's enum** in the tool schema. No registration step needed — the extension scans these directories at session start and makes every discovered agent available to the LLM.
105
+ The file's `name` frontmatter field (or the filename without extension) becomes the agent type name and **automatically populates the `agent` parameter's enum** in the tool schema. No registration step needed — the extension scans these directories at session start and makes every discovered agent available to the LLM. Files added during a session are discovered on the next call that references them — no restart required.
107
106
 
108
- Built-in types (`general-purpose`, `Explore`) are always present. User agents override built-ins with the same name; project agents override user agents (see [Merge precedence](#merge-precedence)).
107
+ Built-in types (`general-purpose`, `Explore`) are always available. User agents override built-ins with the same name; project agents override user agents (see [Merge precedence](#merge-precedence)).
109
108
 
110
109
  ```markdown
111
110
  ---
112
111
  name: security-review
113
112
  display_name: Security Review
114
113
  description: Review code for security issues
115
- tools: [read, bash, grep, find, ls]
114
+ tools: [read, bash, grep]
116
115
  extensions: false
117
116
  skills: false
118
117
  model: anthropic/claude-sonnet-4-5-20250514
@@ -124,22 +123,107 @@ You are a security review specialist. Analyze code for vulnerabilities,
124
123
  focusing on injection flaws, auth bypasses, and insecure defaults.
125
124
  ```
126
125
 
127
- **Frontmatter quick reference:**
126
+ **Minimal agent — just name and description:**
128
127
 
129
- | Field | Type | Description |
128
+ ```markdown
129
+ ---
130
+ name: my-agent
131
+ description: Does something
132
+ ---
133
+
134
+ System prompt here.
135
+ ```
136
+
137
+ This agent gets everything: all tools, all extensions, all skills. Same as `general-purpose`. No boilerplate needed — set restrictions only when you want them.
138
+
139
+ **Frontmatter reference:**
140
+
141
+ | Field | Type | Default | Description |
142
+ |---|---|---|---|
143
+ | `name` | string | filename | Agent type name. Used as the enum value in the `agent` parameter. Must be unique across all agent types. |
144
+ | `display_name` | string | `name` | Human-readable label shown in the UI widget, `/agents` menu, and result viewer. |
145
+ | `description` | string | `""` | Short description displayed in the `/agents` type list and tool rendering. Keep it one sentence. |
146
+ | `tools` | `true` \| `string[]` \| `false` | `true` | **Tool whitelist.** Controls which tool schemas the LLM sees. Accepts built-in names and extension tool references (see below). `true` = all tools visible; `false` = no tools; `string[]` = only listed tools visible. Mutually exclusive with `exclude_tools`. |
147
+ | `exclude_tools` | `string[]` | none | **Tool blacklist.** All tools except these are visible. Mutually exclusive with `tools` (when `tools` is `string[]`). |
148
+ | `extensions` | `true` \| `string[]` \| `false` | `true` | **Extension loader.** Controls which extensions load (hooks + commands fire). Does NOT control tool visibility. `true` = load all; `false` = load none; `string[]` = load only listed extensions. Mutually exclusive with `exclude_extensions`. |
149
+ | `exclude_extensions` | `string[]` | none | **Extension blacklist.** All extensions except these load. Mutually exclusive with `extensions` (when `extensions` is `string[]`). |
150
+ | `skills` | `true` \| `string[]` \| `false` | `true` | **Skill whitelist.** Controls which skills are available (metadata injected into system prompt). `true` = all skills; `false` = no skills; `string[]` = only listed skills. |
151
+ | `preload_skills` | `string[]` \| `false` | `false` | **Full skill injection.** Dumps complete SKILL.md content into system prompt instead of metadata-only. `string[]` = list of skills to preload; `false` = none. |
152
+ | `model` | string | inherit parent | Default model as `"provider/model-id"`. Override via `/agents` or `subagents-lite.json`. See [Model Resolution](#model-resolution). |
153
+ | `thinking` | string | inherit parent | Default thinking level. One of: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`. |
154
+ | `max_turns` | number | unlimited | Soft turn limit. Agent gets a steer message at the limit, then `max_turns + 5` grace turns before hard abort. |
155
+ | `hidden` | `true` \| `false` | `false` | `true` hides the agent type from the tool schema's enum (LLM can't see or invoke it). Agent is still callable by name. Running agents unaffected. |
156
+
157
+ #### `tools` field values
158
+
159
+ The `tools` field accepts built-in tool names and extension tool references:
160
+
161
+ | Value | Meaning | Example |
162
+ |---|---|---|
163
+ | `true` | All tools visible (default) | `tools: true` or omit the field |
164
+ | `false` | No tools visible | `tools: false` |
165
+ | `[read, bash, grep]` | Only listed built-in tools | `tools: [read, bash]` |
166
+ | `[web_search]` | Extension tool by name | `tools: [read, web_search]` |
167
+ | `[tavily/*]` | All tools from an extension | `tools: [read, tavily/*]` |
168
+ | `[tavily/web_search]` | Specific tool from extension | `tools: [read, tavily/web_search]` |
169
+ | Mixed | Combine the above | `tools: [read, bash, tavily/*, exa_search]` |
170
+
171
+ Built-in tool names: `read`, `bash`, `edit`, `write`, `grep`.
172
+
173
+ #### Blacklist mode (`exclude_tools` and `exclude_extensions`)
174
+
175
+ When you have many tools or extensions and want to disable a few, use the blacklist fields:
176
+
177
+ ```yaml
178
+ ---
179
+ name: restricted-agent
180
+ description: Agent with write disabled
181
+ exclude_tools: [write] # all tools except write
182
+ exclude_extensions: [quality-monitor] # all extensions except quality-monitor
183
+ ---
184
+ ```
185
+
186
+ `exclude_tools` supports the same `ext/*` syntax as `tools`:
187
+
188
+ ```yaml
189
+ exclude_tools: [tavily/*] # hide all tavily tools (extension still loads)
190
+ exclude_tools: [write, tavily/*] # hide write + all tavily tools
191
+ exclude_tools: [tavily/web_search] # hide only web_search from tavily
192
+ ```
193
+
194
+ | Field | Mutually exclusive with | Behavior |
195
+ |---|---|---|
196
+ | `exclude_tools` | `tools` (when `tools` is `string[]`) | All tools except listed ones visible. Supports `ext/*` syntax. |
197
+ | `exclude_extensions` | `extensions` (when `extensions` is `string[]`) | All extensions except listed ones load. |
198
+
199
+ **Constraint:** You can use EITHER `tools` OR `exclude_tools`, not both. Same for `extensions`/`exclude_extensions`. If both are set, the whitelist (`tools`/`extensions`) wins.
200
+
201
+ **Note:** `exclude_tools: [tavily/*]` hides tavily's tools but the extension still loads (hooks fire). Use `exclude_extensions: [tavily]` to prevent the extension from loading entirely.
202
+
203
+ #### `extensions` field values
204
+
205
+ The `extensions` field controls which extensions load. It does NOT affect tool visibility.
206
+
207
+ | Value | Meaning | Example |
130
208
  |---|---|---|
131
- | `name` | string | Agent type name. Used as the enum value in the `agent` parameter (defaults to filename). |
132
- | `display_name` | string | Human-readable label shown in the UI. |
133
- | `description` | string | Short description displayed in the `/agents` type list and tool rendering. |
134
- | `tools` | string[] | Built-in tool allowlist: `read`, `bash`, `edit`, `write`, `grep`, `find`, `ls`. If omitted, inherits all. |
135
- | `disallowed_tools` | string[] | Tool denylist — removes these from the agent's toolset even if allowlisted by `tools` or extensions. |
136
- | `extensions` | bool \| string[] | `false` = no extension tools; `true` = inherit all; `["ext-a"]` = allowlist. |
137
- | `skills` | bool \| string[] | `false` = no skill prompts; `true` = inherit all; `["skill-a"]` = only these. |
138
- | `model` | string | Default model as `"provider/model-id"`. Override via `/agents` or `subagents-lite.json`. |
139
- | `thinking` | string | Default thinking level: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`. |
140
- | `max_turns` | number | Turn limit (soft stop with steer). |
141
- | `enabled` | bool | `false` removes the agent type from the tool schema's enum (LLM can't see or invoke it). Running agents unaffected. Default: `true`. |
142
- | `isolated` | bool | Shorthand for `extensions: false` + `skills: false`. Reduces token footprint per turn. |
209
+ | `true` | Load all extensions (default) | `extensions: true` or omit the field |
210
+ | `false` | Load no extensions | `extensions: false` |
211
+ | `[tavily]` | Load only listed extensions | `extensions: [tavily, pi-tokf]` |
212
+ | `[tavily/web_search]` | Load extension (tool part ignored) | `extensions: [tavily/web_search]` loads all of tavily |
213
+
214
+ #### `skills` and `preload_skills` field values
215
+
216
+ Skills have two injection modes:
217
+
218
+ | Field | Value | Effect |
219
+ |---|---|---|
220
+ | `skills` | `true` | All skills available (metadata-only in system prompt) |
221
+ | `skills` | `false` | No skills |
222
+ | `skills` | `[debug, tdd]` | Only listed skills (metadata-only) |
223
+ | `preload_skills` | `[debug]` | Dump full SKILL.md content into system prompt |
224
+ | `preload_skills` | `false` | No preloading (default) |
225
+
226
+ Metadata-only means the agent sees skill name, description, and file path. It reads the full content on-demand via the `read` tool. Preloading injects the full content upfront — higher token cost but no read latency.
143
227
 
144
228
  ### Token-Saving Frontmatter Settings
145
229
 
@@ -147,18 +231,35 @@ Every tool schema and every skill snippet you inject costs tokens — in every t
147
231
 
148
232
  | Setting | What it controls | Token impact |
149
233
  |---|---|---|
150
- | `tools: [a, b, c]` | Which built-in tools the LLM sees | High — each tool has a schema (name, params, description) injected every turn. Fewer tools = fewer tokens. |
151
- | `extensions: false` | Disables all extension-provided tools | Medium — extensions can register many tools (linters, browsers, etc.). Each adds schema tokens. |
152
- | `extensions: ["my-ext"]` | Allowlist only specific extensions | Medium — pick only what the agent needs. |
153
- | `skills: false` | Prevents skill content from being injected into the system prompt | **Highest**skill prompts are prose, not schemas. A verbose skill can be 10-50x the token cost of a tool schema. |
154
- | `skills: ["skill-a"]` | Inject only listed skills (preloaded inline) | Mediumyou control exactly which skills appear. |
155
- | `isolated: true` | Shorthand for `extensions: false` + `skills: false` | High — zero extension tools, zero skill prompts. Useful for fast, focused agents. |
234
+ | `tools: [a, b, c]` | Which tool schemas the LLM sees (built-in + extension tools) | High — each tool has a schema (name, params, description) injected every turn. Fewer tools = fewer tokens. |
235
+ | `tools: [ext-name/*]` | All tools from a specific extension | Medium — lazy shorthand for listing each tool individually. |
236
+ | `extensions: false` | Disables all extensions (no hooks, no commands) | Medium — extensions can register hooks that fire every turn. |
237
+ | `extensions: ["my-ext"]` | Load only specific extensions | Mediumpick only what the agent needs. |
238
+ | `skills: ["skill-a"]` | Whitelist skills injects metadata only (name, description, location) | Lowagent reads full content on-demand via `read` tool. No prose in system prompt. |
239
+ | `skills: false` | Disables all skills | Zero skill tokens. |
240
+ | `preload_skills: ["skill-a"]` | Dump full SKILL.md content into system prompt | **Highest** — skill prompts are prose, not schemas. A verbose skill can be 10-50x the token cost of a tool schema. |
241
+ | `exclude_tools: [write]` | Disable specific tools (blacklist mode) | High — same as whitelist but without listing everything. |
242
+ | `exclude_extensions: [ext]` | Disable specific extensions (blacklist mode) | Medium — same as whitelist but without listing everything. |
243
+
244
+ **Practical examples:**
245
+
246
+ ```yaml
247
+ # Read-only agent: whitelist approach
248
+ tools: [read, bash, grep]
249
+ extensions: false
250
+ skills: false
156
251
 
157
- **Practical example:** An `Explore` agent that only reads files doesn't need write tools, browser extensions, or git skills. Setting `tools: [read, bash, grep, find, ls]` + `extensions: false` + `skills: false` saves thousands of tokens per turn compared to inheriting everything.
252
+ # Read-only agent: blacklist approach (same result, easier to maintain)
253
+ exclude_tools: [edit, write]
254
+
255
+ # Agent that uses all tools except write, and all extensions except quality-monitor
256
+ exclude_tools: [write]
257
+ exclude_extensions: [quality-monitor]
258
+ ```
158
259
 
159
260
  ### Merge precedence
160
261
 
161
- Project agents override user agents, which override built-ins (`general-purpose`, `Explore`). Agent types discovered from `.md` files automatically appear in the `agent` parameter's dropdown — no registration required.
262
+ Project agents override user agents, which override built-ins (`general-purpose`, `Explore`). Agent types discovered from `.md` files automatically appear in the `agent` parameter's enum — no registration required. Files added during a session are discovered on the next call that references them.
162
263
 
163
264
  ## Model Resolution
164
265
 
@@ -171,7 +272,7 @@ The extension picks the right model automatically. Precedence (highest first):
171
272
  5. **Agent frontmatter** — `model` in `.md` file
172
273
  6. **Parent model** — inherit from the calling agent
173
274
 
174
- The LLM never passes `model` — it's injected at call time. Set it once in config or frontmatter and forget about it.
275
+ The LLM never passes `model` — it's injected at call time via the `tool_call` listener. Set it once in config or frontmatter and forget about it.
175
276
 
176
277
  ## Commands
177
278
 
package/package.json CHANGED
@@ -1,13 +1,16 @@
1
1
  {
2
2
  "name": "pi-subagents-lite",
3
- "version": "0.4.0",
3
+ "version": "1.0.0",
4
4
  "description": "Lightweight sub-agents for pi — spawn specialized agents with isolated sessions, tools, and models.",
5
5
  "keywords": [
6
6
  "pi-package",
7
7
  "pi",
8
+ "pi-agent",
9
+ "pi-coding-agent",
8
10
  "pi-extension",
9
- "subagent",
10
- "agent"
11
+ "subagents",
12
+ "ai",
13
+ "agents"
11
14
  ],
12
15
  "author": "AlexParamonov",
13
16
  "license": "MIT",
@@ -1,8 +1,6 @@
1
1
  /**
2
2
  * agent-discovery.ts — Agent file discovery, parsing, and config merging.
3
3
  *
4
- * Extended from subagent-lazy/agent-discovery.ts with full frontmatter support.
5
- *
6
4
  * Scans:
7
5
  * ~/.pi/agent/agents/*.md (user agents)
8
6
  * <project>/.pi/agents/*.md (project agents)
@@ -26,15 +24,15 @@ export interface AgentConfigFromMd {
26
24
  display_name?: string;
27
25
  description?: string;
28
26
  tools?: string[];
27
+ exclude_tools?: string[];
29
28
  extensions?: boolean | string[];
29
+ exclude_extensions?: string[];
30
30
  skills?: boolean | string[];
31
31
  preload_skills?: string[] | false;
32
32
  model?: string;
33
33
  thinking?: ThinkingLevel;
34
34
  max_turns?: number;
35
- disallowed_tools?: string[];
36
- enabled?: boolean;
37
- isolated?: boolean;
35
+ hidden?: boolean;
38
36
  systemPrompt: string;
39
37
  source: "user" | "project";
40
38
  }
@@ -254,11 +252,6 @@ function compactDefined<T extends Record<string, unknown>>(obj: T): Partial<T> {
254
252
 
255
253
  /**
256
254
  * Parse a single agent .md file into AgentConfigFromMd.
257
- *
258
- * @param content - Raw file content
259
- * @param filename - Filename (for context, currently unused)
260
- * @param source - Source designation ("user" or "project")
261
- * @returns Parsed agent config with frontmatter and body
262
255
  */
263
256
  export function parseAgentFile(
264
257
  content: string,
@@ -272,15 +265,15 @@ export function parseAgentFile(
272
265
  display_name: parseString(frontmatter, "display_name"),
273
266
  description: parseString(frontmatter, "description"),
274
267
  tools: parseStringArray(frontmatter, "tools"),
268
+ exclude_tools: parseStringArray(frontmatter, "exclude_tools"),
275
269
  extensions: parseExtensions(frontmatter.extensions),
270
+ exclude_extensions: parseStringArray(frontmatter, "exclude_extensions"),
276
271
  skills: parseExtensions(frontmatter.skills),
277
272
  preload_skills: parsePreloadSkills(frontmatter.preload_skills),
278
273
  model: parseString(frontmatter, "model"),
279
274
  thinking: parseThinkingLevel(parseString(frontmatter, "thinking")),
280
275
  max_turns: parseNumber(frontmatter, "max_turns"),
281
- disallowed_tools: parseStringArray(frontmatter, "disallowed_tools"),
282
- enabled: parseBoolean(frontmatter, "enabled"),
283
- isolated: parseBoolean(frontmatter, "isolated"),
276
+ hidden: parseBoolean(frontmatter, "hidden"),
284
277
  systemPrompt: body,
285
278
  source: source,
286
279
  };
@@ -396,16 +389,17 @@ function fromMd(md: AgentConfigFromMd): Partial<AgentConfig> {
396
389
  name: md.name,
397
390
  displayName: md.display_name,
398
391
  description: md.description,
399
- builtinToolNames: md.tools,
392
+ registeredTools: md.tools,
393
+ tools: md.tools,
394
+ excludeTools: md.exclude_tools,
400
395
  extensions: md.extensions,
396
+ excludeExtensions: md.exclude_extensions,
401
397
  skills: md.skills,
402
398
  preloadSkills: md.preload_skills,
403
399
  model: md.model,
404
400
  thinking: md.thinking,
405
401
  maxTurns: md.max_turns,
406
- disallowedTools: md.disallowed_tools,
407
- enabled: md.enabled,
408
- isolated: md.isolated,
402
+ hidden: md.hidden,
409
403
  systemPrompt: md.systemPrompt,
410
404
  source: md.source === "project" ? "project" : "global",
411
405
  };
@@ -1,15 +1,7 @@
1
1
  /**
2
2
  * agent-manager.ts — Tracks agents, per-model concurrency, background execution.
3
3
  *
4
- * Forked from upstream pi-subagents. Key modifications:
5
- * - Per-model concurrency (Map<string, { limit, running }>) replaces
6
- * single maxConcurrent counter
7
- * - No worktree isolation (all worktree imports and code paths removed)
8
- * - Exposes steer(id, message) for /steer command
9
- * - SpawnOptions.modelKey for concurrency pool lookup
10
- * - ConcurrencyConfig with default + models map
11
- * - No IsolationMode references
12
- * - AgentRecord: removed worktree, worktreeResult, groupId, joinMode
4
+ * Supports per-model and per-provider concurrency limits with queuing.
13
5
  */
14
6
 
15
7
  import { randomUUID } from "node:crypto";
@@ -99,7 +91,6 @@ export interface SpawnOptions {
99
91
  description: string;
100
92
  model?: Model<any>;
101
93
  maxTurns?: number;
102
- isolated?: boolean;
103
94
  thinkingLevel?: ThinkingLevel;
104
95
  isBackground?: boolean;
105
96
  /**
@@ -312,7 +303,6 @@ export class AgentManager {
312
303
  agentId: id,
313
304
  model: options.model,
314
305
  maxTurns: options.maxTurns,
315
- isolated: options.isolated,
316
306
  thinkingLevel: options.thinkingLevel,
317
307
  signal: record.abortController!.signal,
318
308
  ...this.createRecordCallbacks(record, options),
@@ -498,13 +488,9 @@ export class AgentManager {
498
488
  return true;
499
489
  }
500
490
 
501
- private disposeSession(session: AgentSession | undefined): void {
502
- session?.dispose();
503
- }
504
-
505
491
  /** Dispose a record's session and remove it from the map. */
506
492
  private removeRecord(id: string, record: AgentRecord): void {
507
- this.disposeSession(record.session);
493
+ record.session?.dispose();
508
494
  record.session = undefined;
509
495
  this.agents.delete(id);
510
496
  }
@@ -522,7 +508,7 @@ export class AgentManager {
522
508
  clearInterval(this.cleanupInterval);
523
509
  this.queue = [];
524
510
  for (const record of this.agents.values()) {
525
- this.disposeSession(record.session);
511
+ record.session?.dispose();
526
512
  }
527
513
  this.agents.clear();
528
514
  }