@gotgenes/pi-subagents 6.18.4 → 6.18.6
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 +24 -0
- package/docs/architecture/architecture.md +70 -131
- package/docs/plans/0168-extract-tool-filter-config.md +173 -0
- package/docs/plans/0169-extract-run-context-from-run-options.md +194 -0
- package/docs/retro/0167-narrow-runner-io.md +28 -0
- package/docs/retro/0168-extract-tool-filter-config.md +76 -0
- package/docs/retro/0169-extract-run-context-from-run-options.md +37 -0
- package/package.json +1 -1
- package/src/lifecycle/agent-manager.ts +6 -4
- package/src/lifecycle/agent-runner.ts +34 -36
- package/src/runtime.ts +1 -1
- package/src/session/session-config.ts +19 -10
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,30 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [6.18.6](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v6.18.5...pi-subagents-v6.18.6) (2026-05-24)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Documentation
|
|
12
|
+
|
|
13
|
+
* plan extract RunContext from RunOptions ([#169](https://github.com/gotgenes/pi-packages/issues/169)) ([ca12b2e](https://github.com/gotgenes/pi-packages/commit/ca12b2ebd116cb50c6e12d2d3fe3a87ff997d6d6))
|
|
14
|
+
* **retro:** add planning stage notes for issue [#169](https://github.com/gotgenes/pi-packages/issues/169) ([05b0176](https://github.com/gotgenes/pi-packages/commit/05b01764a4aaa885efca9d061abf6bacb384057c))
|
|
15
|
+
* **retro:** add retro notes for issue [#168](https://github.com/gotgenes/pi-packages/issues/168) ([dfe46ed](https://github.com/gotgenes/pi-packages/commit/dfe46ed5b5ee62371912dbbc6227443adee8e67b))
|
|
16
|
+
* **retro:** add TDD stage notes for issue [#169](https://github.com/gotgenes/pi-packages/issues/169) ([84c0d8d](https://github.com/gotgenes/pi-packages/commit/84c0d8d5ef0a94750c470e3f10b3ab589caac794))
|
|
17
|
+
* update architecture doc for RunContext extraction ([#169](https://github.com/gotgenes/pi-packages/issues/169)) ([ea49fe1](https://github.com/gotgenes/pi-packages/commit/ea49fe1b9c316e6541814de821738d6d121c4d13))
|
|
18
|
+
* update RunOptions field references in comments ([#169](https://github.com/gotgenes/pi-packages/issues/169)) ([fd9c3ed](https://github.com/gotgenes/pi-packages/commit/fd9c3ed0e0b01c45136c8f34d8f31a89564e8061))
|
|
19
|
+
|
|
20
|
+
## [6.18.5](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v6.18.4...pi-subagents-v6.18.5) (2026-05-24)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Documentation
|
|
24
|
+
|
|
25
|
+
* mark ToolFilterConfig extraction done in architecture doc ([#168](https://github.com/gotgenes/pi-packages/issues/168)) ([686c33e](https://github.com/gotgenes/pi-packages/commit/686c33ed107e1ec1ec56c73441b1551bf59bff3f))
|
|
26
|
+
* plan extract ToolFilterConfig from SessionConfig ([#168](https://github.com/gotgenes/pi-packages/issues/168)) ([beaaeb4](https://github.com/gotgenes/pi-packages/commit/beaaeb41588bb93739b5ba6959c12202efbe7862))
|
|
27
|
+
* **retro:** add planning stage notes for issue [#168](https://github.com/gotgenes/pi-packages/issues/168) ([7086139](https://github.com/gotgenes/pi-packages/commit/70861390a6190653d499c720fc298972e03967aa))
|
|
28
|
+
* **retro:** add retro notes for issue [#167](https://github.com/gotgenes/pi-packages/issues/167) ([cc96edd](https://github.com/gotgenes/pi-packages/commit/cc96edd20994a48ee2f824ea9136fa0da83e4c23))
|
|
29
|
+
* **retro:** add TDD stage notes for issue [#168](https://github.com/gotgenes/pi-packages/issues/168) ([8a14bf7](https://github.com/gotgenes/pi-packages/commit/8a14bf766e9c38c89f31468293fdafa8c79d32ea))
|
|
30
|
+
* update architecture to reflect current layout and RunnerIO split ([#167](https://github.com/gotgenes/pi-packages/issues/167)) ([d4a98aa](https://github.com/gotgenes/pi-packages/commit/d4a98aaa1600c24c28dd1005e381588990ab74fd))
|
|
31
|
+
|
|
8
32
|
## [6.18.4](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v6.18.3...pi-subagents-v6.18.4) (2026-05-24)
|
|
9
33
|
|
|
10
34
|
|
|
@@ -220,9 +220,9 @@ sequenceDiagram
|
|
|
220
220
|
|
|
221
221
|
## Module organization
|
|
222
222
|
|
|
223
|
-
The extension has
|
|
224
|
-
All eight domains
|
|
225
|
-
Issue #164 moved the 26 previously flat root-level files into
|
|
223
|
+
The extension has 51 source files (7,338 LOC) organized into six domains plus entry-point wiring.
|
|
224
|
+
All eight domains have directories: `config/`, `session/`, `lifecycle/`, `observation/`, `service/`, `tools/`, `ui/`, and `handlers/`.
|
|
225
|
+
Issue #164 moved the 26 previously flat root-level files into five new domain directories, reducing the root to 5 files + 8 directories.
|
|
226
226
|
|
|
227
227
|
### Current layout
|
|
228
228
|
|
|
@@ -234,44 +234,43 @@ src/
|
|
|
234
234
|
├── settings.ts SettingsManager (persistent operational settings)
|
|
235
235
|
├── debug.ts debug logging utility
|
|
236
236
|
│
|
|
237
|
-
|
|
238
|
-
├── agent-types.ts
|
|
239
|
-
├── default-agents.ts
|
|
240
|
-
├── custom-agents.ts
|
|
241
|
-
|
|
237
|
+
├── config/ agent type definitions and resolution
|
|
238
|
+
│ ├── agent-types.ts AgentTypeRegistry class
|
|
239
|
+
│ ├── default-agents.ts built-in agent configs (general-purpose, Explore, Plan)
|
|
240
|
+
│ ├── custom-agents.ts user-defined agent .md file loader
|
|
241
|
+
│ └── invocation-config.ts per-call config merge
|
|
242
242
|
│
|
|
243
|
-
|
|
244
|
-
├── session-config.ts
|
|
245
|
-
├── prompts.ts
|
|
246
|
-
├── context.ts
|
|
247
|
-
├── memory.ts
|
|
248
|
-
├── skill-loader.ts
|
|
249
|
-
├── env.ts
|
|
250
|
-
├── model-resolver.ts
|
|
251
|
-
|
|
243
|
+
├── session/ session assembly and preparation
|
|
244
|
+
│ ├── session-config.ts pure assembler (main entry)
|
|
245
|
+
│ ├── prompts.ts system prompt building
|
|
246
|
+
│ ├── context.ts parent conversation extraction
|
|
247
|
+
│ ├── memory.ts persistent MEMORY.md per agent
|
|
248
|
+
│ ├── skill-loader.ts skill preloading
|
|
249
|
+
│ ├── env.ts git/platform detection
|
|
250
|
+
│ ├── model-resolver.ts fuzzy model name resolution
|
|
251
|
+
│ └── session-dir.ts session directory derivation
|
|
252
252
|
│
|
|
253
|
-
|
|
254
|
-
├── agent-manager.ts
|
|
255
|
-
├── agent-runner.ts
|
|
256
|
-
├── agent-record.ts
|
|
257
|
-
├── parent-snapshot.ts
|
|
258
|
-
├── execution-state.ts
|
|
259
|
-
├── worktree.ts
|
|
260
|
-
├── worktree-state.ts
|
|
261
|
-
|
|
253
|
+
├── lifecycle/ agent execution and state tracking
|
|
254
|
+
│ ├── agent-manager.ts spawn, queue, abort, resume, concurrency
|
|
255
|
+
│ ├── agent-runner.ts session creation, turn loop, tool filtering
|
|
256
|
+
│ ├── agent-record.ts status state machine
|
|
257
|
+
│ ├── parent-snapshot.ts immutable spawn-time parent state
|
|
258
|
+
│ ├── execution-state.ts session/output phase state
|
|
259
|
+
│ ├── worktree.ts git worktree isolation
|
|
260
|
+
│ ├── worktree-state.ts worktree phase state
|
|
261
|
+
│ └── usage.ts token usage tracking
|
|
262
262
|
│
|
|
263
|
-
|
|
264
|
-
├── record-observer.ts
|
|
265
|
-
├── notification.ts
|
|
266
|
-
├── notification-state.ts
|
|
267
|
-
|
|
263
|
+
├── observation/ progress tracking and notification
|
|
264
|
+
│ ├── record-observer.ts session-event stats observer
|
|
265
|
+
│ ├── notification.ts completion nudges
|
|
266
|
+
│ ├── notification-state.ts per-agent notification tracking
|
|
267
|
+
│ └── renderer.ts notification TUI component
|
|
268
268
|
│
|
|
269
|
-
|
|
270
|
-
├── service.ts
|
|
271
|
-
|
|
269
|
+
├── service/ cross-extension API boundary
|
|
270
|
+
│ ├── service.ts SubagentsService interface + Symbol.for() accessors
|
|
271
|
+
│ └── service-adapter.ts SubagentsService wrapper around AgentManager
|
|
272
272
|
│
|
|
273
|
-
|
|
274
|
-
├── tools/
|
|
273
|
+
├── tools/ LLM-facing tool implementations
|
|
275
274
|
│ ├── agent-tool.ts Agent tool definition, validation, dispatch
|
|
276
275
|
│ ├── spawn-config.ts pure config resolution
|
|
277
276
|
│ ├── foreground-runner.ts foreground execution loop
|
|
@@ -280,8 +279,7 @@ src/
|
|
|
280
279
|
│ ├── steer-tool.ts steer_subagent tool
|
|
281
280
|
│ └── helpers.ts shared tool utilities
|
|
282
281
|
│
|
|
283
|
-
|
|
284
|
-
├── ui/
|
|
282
|
+
├── ui/ user-facing presentation
|
|
285
283
|
│ ├── agent-widget.ts above-editor live status widget
|
|
286
284
|
│ ├── widget-renderer.ts pure rendering for widget
|
|
287
285
|
│ ├── agent-menu.ts /agents slash command menu
|
|
@@ -293,68 +291,12 @@ src/
|
|
|
293
291
|
│ ├── ui-observer.ts session-event observer for streaming
|
|
294
292
|
│ └── display.ts pure formatters and shared types
|
|
295
293
|
│
|
|
296
|
-
|
|
297
|
-
|
|
294
|
+
└── handlers/ event handlers
|
|
295
|
+
├── index.ts barrel re-export
|
|
298
296
|
├── lifecycle.ts session_start, session_before_switch, session_shutdown
|
|
299
297
|
└── tool-start.ts tool_execution_start handler
|
|
300
298
|
```
|
|
301
299
|
|
|
302
|
-
### Proposed directory restructuring
|
|
303
|
-
|
|
304
|
-
Move the four ungrouped domains into subdirectories so the filesystem mirrors the domain model.
|
|
305
|
-
Root-level files stay: `index.ts` (entry point), `runtime.ts` (wiring), `types.ts` (shared), `settings.ts`, `debug.ts`.
|
|
306
|
-
|
|
307
|
-
```text
|
|
308
|
-
src/
|
|
309
|
-
├── index.ts
|
|
310
|
-
├── runtime.ts
|
|
311
|
-
├── types.ts
|
|
312
|
-
├── settings.ts
|
|
313
|
-
├── debug.ts
|
|
314
|
-
│
|
|
315
|
-
├── config/ agent type definitions and resolution
|
|
316
|
-
│ ├── agent-types.ts
|
|
317
|
-
│ ├── default-agents.ts
|
|
318
|
-
│ ├── custom-agents.ts
|
|
319
|
-
│ └── invocation-config.ts
|
|
320
|
-
│
|
|
321
|
-
├── session/ session assembly and preparation
|
|
322
|
-
│ ├── session-config.ts
|
|
323
|
-
│ ├── prompts.ts
|
|
324
|
-
│ ├── context.ts
|
|
325
|
-
│ ├── memory.ts
|
|
326
|
-
│ ├── skill-loader.ts
|
|
327
|
-
│ ├── env.ts
|
|
328
|
-
│ ├── model-resolver.ts
|
|
329
|
-
│ └── session-dir.ts
|
|
330
|
-
│
|
|
331
|
-
├── lifecycle/ agent execution and state tracking
|
|
332
|
-
│ ├── agent-manager.ts
|
|
333
|
-
│ ├── agent-runner.ts
|
|
334
|
-
│ ├── agent-record.ts
|
|
335
|
-
│ ├── parent-snapshot.ts
|
|
336
|
-
│ ├── execution-state.ts
|
|
337
|
-
│ ├── worktree.ts
|
|
338
|
-
│ ├── worktree-state.ts
|
|
339
|
-
│ └── usage.ts
|
|
340
|
-
│
|
|
341
|
-
├── observation/ progress tracking and notification
|
|
342
|
-
│ ├── record-observer.ts
|
|
343
|
-
│ ├── notification.ts
|
|
344
|
-
│ ├── notification-state.ts
|
|
345
|
-
│ └── renderer.ts
|
|
346
|
-
│
|
|
347
|
-
├── service/ cross-extension API boundary
|
|
348
|
-
│ ├── service.ts
|
|
349
|
-
│ └── service-adapter.ts
|
|
350
|
-
│
|
|
351
|
-
├── tools/ (existing)
|
|
352
|
-
├── ui/ (existing)
|
|
353
|
-
└── handlers/ (existing)
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
Root goes from 31 files to 5 files + 8 directories — each directory name tells you what domain it belongs to.
|
|
357
|
-
|
|
358
300
|
### Observation model
|
|
359
301
|
|
|
360
302
|
Record statistics (tool uses, token usage, compaction counts) are updated by `record-observer.ts`, which subscribes directly to session events.
|
|
@@ -504,8 +446,8 @@ Bags with 10+ fields are the highest priority for decomposition.
|
|
|
504
446
|
| --------------------------- | ------------------------------------------------------ | ------------------------------------------------- | -------- |
|
|
505
447
|
| `ResolvedSpawnConfig` | 3 nested | foreground-runner, background-spawner, agent-tool | ✓ done |
|
|
506
448
|
| `AgentSpawnConfig` | 13 → 13 (ParentSessionInfo nested) | agent-manager (internal) | ✓ done |
|
|
507
|
-
| `RunOptions` |
|
|
508
|
-
| `SessionConfig` |
|
|
449
|
+
| `RunOptions` | 9 (`RunContext` nested) | agent-runner | ✓ done |
|
|
450
|
+
| `SessionConfig` | 8 (ToolFilterConfig nested) | agent-runner (output of assembler) | ✓ done |
|
|
509
451
|
| `NotificationDetails` | 10 | notification | Medium |
|
|
510
452
|
| `ResourceLoaderOptions` | 10 | agent-runner (SDK bridge) | Medium |
|
|
511
453
|
| `RunnerIO` | split → `EnvironmentIO` (3) + `SessionFactoryIO` (5+1) | agent-runner | ✓ done |
|
|
@@ -601,61 +543,57 @@ export interface ParentSessionInfo {
|
|
|
601
543
|
|
|
602
544
|
`AgentSpawnConfig` now carries `parentSession?: ParentSessionInfo` instead of three flat optional fields.
|
|
603
545
|
|
|
604
|
-
#### RunOptions (12 fields → extract RunContext)
|
|
546
|
+
#### RunOptions (12 fields → extract RunContext) — done ([#169][169])
|
|
605
547
|
|
|
606
|
-
The `RunOptions` bag mixes execution parameters with context information
|
|
548
|
+
The `RunOptions` bag mixes execution parameters with context information.
|
|
549
|
+
`RunContext` was extracted and nested as `RunOptions.context`:
|
|
607
550
|
|
|
608
551
|
```typescript
|
|
609
|
-
/** Parent context
|
|
610
|
-
interface RunContext {
|
|
611
|
-
cwd?: string;
|
|
612
|
-
parentSessionFile?: string;
|
|
613
|
-
parentSessionId?: string;
|
|
552
|
+
/** Parent execution context — where/who is running. */
|
|
553
|
+
export interface RunContext {
|
|
614
554
|
exec: ShellExec;
|
|
615
555
|
registry: AgentConfigLookup;
|
|
556
|
+
cwd?: string;
|
|
557
|
+
parentSession?: ParentSessionInfo;
|
|
616
558
|
}
|
|
617
559
|
```
|
|
618
560
|
|
|
619
561
|
The remaining `RunOptions` fields (`model`, `maxTurns`, `signal`, `isolated`, `thinkingLevel`, `defaultMaxTurns`, `graceTurns`, `onSessionCreated`) are genuine execution parameters.
|
|
562
|
+
`RunOptions` now has 9 fields: 1 nested `context: RunContext` plus 8 flat execution fields.
|
|
620
563
|
|
|
621
|
-
#### SessionConfig (11 fields → extract ToolFilterConfig)
|
|
622
|
-
|
|
623
|
-
Three fields form a cohesive tool-filtering cluster:
|
|
624
|
-
|
|
625
|
-
```typescript
|
|
626
|
-
/** Tool filtering configuration — used by filterActiveTools. */
|
|
627
|
-
interface ToolFilterConfig {
|
|
628
|
-
toolNames: string[];
|
|
629
|
-
disallowedSet: Set<string> | undefined;
|
|
630
|
-
extensions: boolean | string[];
|
|
631
|
-
}
|
|
632
|
-
```
|
|
564
|
+
#### SessionConfig (11 fields → extract ToolFilterConfig) — done ([#168][168])
|
|
633
565
|
|
|
634
|
-
|
|
566
|
+
The tool-filtering cluster (`toolNames`, `disallowedSet`, `extensions`) was extracted into `ToolFilterConfig` and nested as `SessionConfig.toolFilter`.
|
|
567
|
+
`filterActiveTools` now accepts a single `ToolFilterConfig` argument instead of three positional parameters.
|
|
568
|
+
`SessionConfig` reduced from 10 to 8 top-level fields.
|
|
635
569
|
|
|
636
|
-
#### RunnerIO (9 methods → 2 focused interfaces)
|
|
570
|
+
#### RunnerIO (9 methods → 2 focused interfaces) — done ([#167][167])
|
|
637
571
|
|
|
638
|
-
The IO boundary
|
|
572
|
+
The IO boundary was split into two focused interfaces:
|
|
639
573
|
|
|
640
574
|
```typescript
|
|
641
|
-
/** Environment discovery —
|
|
642
|
-
interface EnvironmentIO {
|
|
575
|
+
/** Environment discovery — detect runtime context and resolve directories. */
|
|
576
|
+
export interface EnvironmentIO {
|
|
643
577
|
detectEnv: (exec: ShellExec, cwd: string) => Promise<EnvInfo>;
|
|
644
578
|
getAgentDir: () => string;
|
|
645
579
|
deriveSessionDir: (parentSessionFile: string | undefined, effectiveCwd: string) => string;
|
|
646
580
|
}
|
|
647
581
|
|
|
648
|
-
/** Session factory —
|
|
649
|
-
interface SessionFactoryIO {
|
|
582
|
+
/** Session factory — create SDK objects for a child agent session. */
|
|
583
|
+
export interface SessionFactoryIO {
|
|
650
584
|
createResourceLoader: (opts: ResourceLoaderOptions) => ResourceLoaderLike;
|
|
651
585
|
createSessionManager: (cwd: string, sessionDir: string) => SessionManagerLike;
|
|
652
586
|
createSettingsManager: (cwd: string, agentDir: string) => SettingsManager;
|
|
653
587
|
createSession: (opts: CreateSessionOptions) => Promise<{ session: AgentSession }>;
|
|
654
588
|
assemblerIO: AssemblerIO;
|
|
655
589
|
}
|
|
590
|
+
|
|
591
|
+
/** Backward-compatible intersection of the two focused interfaces. */
|
|
592
|
+
export type RunnerIO = EnvironmentIO & SessionFactoryIO;
|
|
656
593
|
```
|
|
657
594
|
|
|
658
|
-
|
|
595
|
+
`RunnerIO` is kept as a type alias for the intersection.
|
|
596
|
+
All existing consumers satisfy both sub-interfaces via structural typing with no call-site changes.
|
|
659
597
|
|
|
660
598
|
## Improvement roadmap (Phase 10)
|
|
661
599
|
|
|
@@ -687,15 +625,16 @@ Extracted `parentSessionFile`, `parentSessionId`, `toolCallId` into `ParentSessi
|
|
|
687
625
|
`RunnerIO` kept as a backward-compatible type alias for the intersection.
|
|
688
626
|
All existing consumers satisfy both sub-interfaces via structural typing with no call-site changes.
|
|
689
627
|
|
|
690
|
-
### Step 5: Extract ToolFilterConfig from SessionConfig ([#168][168])
|
|
628
|
+
### Step 5: Extract ToolFilterConfig from SessionConfig ([#168][168]) ✓ Done
|
|
691
629
|
|
|
692
|
-
|
|
693
|
-
|
|
630
|
+
`ToolFilterConfig` extracted from `SessionConfig`, grouping `toolNames`, `disallowedSet`, and `extensions`.
|
|
631
|
+
`filterActiveTools` now accepts a single `ToolFilterConfig` argument.
|
|
632
|
+
`SessionConfig` reduced from 10 to 8 top-level fields.
|
|
694
633
|
|
|
695
|
-
### Step 6: Extract RunContext from RunOptions ([#169][169])
|
|
634
|
+
### Step 6: Extract RunContext from RunOptions ([#169][169]) ✓ Done
|
|
696
635
|
|
|
697
|
-
|
|
698
|
-
|
|
636
|
+
Extracted `exec`, `registry`, `cwd`, and `parentSession` into `RunContext`, nested as `RunOptions.context`.
|
|
637
|
+
`RunOptions` reduced from 12 to 9 fields (1 nested `context` + 8 flat execution fields).
|
|
699
638
|
|
|
700
639
|
### Step 7: Reduce buildContentLines complexity ([#170][170])
|
|
701
640
|
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
---
|
|
2
|
+
issue: 168
|
|
3
|
+
issue_title: "refactor(pi-subagents): extract ToolFilterConfig from SessionConfig (11 fields)"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Extract ToolFilterConfig from SessionConfig
|
|
7
|
+
|
|
8
|
+
## Problem Statement
|
|
9
|
+
|
|
10
|
+
`SessionConfig` in `session-config.ts` has 10 top-level fields.
|
|
11
|
+
Three of those fields — `toolNames`, `disallowedSet`, and `extensions` — form a cohesive tool-filtering cluster consumed together by `filterActiveTools` in `agent-runner.ts`.
|
|
12
|
+
Today `filterActiveTools` accepts these as three separate positional parameters, and the guard condition `cfg.extensions !== false || cfg.disallowedSet` is duplicated at both call sites.
|
|
13
|
+
Extracting the cluster into a named `ToolFilterConfig` type makes the relationship explicit and gives `filterActiveTools` a single named input.
|
|
14
|
+
|
|
15
|
+
## Goals
|
|
16
|
+
|
|
17
|
+
- Define a `ToolFilterConfig` interface grouping `toolNames`, `disallowedSet`, and `extensions`.
|
|
18
|
+
- Nest `ToolFilterConfig` inside `SessionConfig`, replacing the three flat fields.
|
|
19
|
+
- Change `filterActiveTools` to accept `ToolFilterConfig` instead of three positional parameters.
|
|
20
|
+
- Update `runAgent` to destructure `cfg.toolFilter` at both filter call sites.
|
|
21
|
+
- Update all test assertions that read the three flat fields to use the nested path.
|
|
22
|
+
|
|
23
|
+
## Non-Goals
|
|
24
|
+
|
|
25
|
+
- Extracting `ToolFilterConfig` into its own file — the type is small (3 fields) and co-located with its producer (`assembleSessionConfig`).
|
|
26
|
+
- Adding a `needsFiltering()` predicate or encapsulating the guard condition — follow-up if the duplication grows.
|
|
27
|
+
- Changing the `extensions` field on `AgentConfig` — that lives in the config domain and is unrelated.
|
|
28
|
+
|
|
29
|
+
## Background
|
|
30
|
+
|
|
31
|
+
### Affected modules
|
|
32
|
+
|
|
33
|
+
| Module | Role |
|
|
34
|
+
| ------------------------------- | -------------------------------------------------------------------- |
|
|
35
|
+
| `src/session/session-config.ts` | Defines `SessionConfig`, produces it in `assembleSessionConfig` |
|
|
36
|
+
| `src/lifecycle/agent-runner.ts` | Consumes `SessionConfig` in `runAgent`, contains `filterActiveTools` |
|
|
37
|
+
|
|
38
|
+
### Consumer analysis
|
|
39
|
+
|
|
40
|
+
`runAgent` accesses the three tool-filter fields in four places:
|
|
41
|
+
|
|
42
|
+
1. `tools: cfg.toolNames` — passed to `io.createSession` (session-creation tool list).
|
|
43
|
+
2. `noExtensions: cfg.extensions === false` — resource-loader option.
|
|
44
|
+
3. Two identical guard-plus-filter blocks passing all three fields to `filterActiveTools`.
|
|
45
|
+
|
|
46
|
+
After extraction, sites 1 and 2 will read from `cfg.toolFilter.toolNames` and `cfg.toolFilter.extensions`.
|
|
47
|
+
Site 3 (both occurrences) will pass `cfg.toolFilter` as a single argument.
|
|
48
|
+
|
|
49
|
+
### Test files affected
|
|
50
|
+
|
|
51
|
+
| Test file | What changes |
|
|
52
|
+
| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
53
|
+
| `test/session/session-config.test.ts` | Assertions on `result.toolNames`, `result.extensions`, `result.disallowedSet` move to `result.toolFilter.*` |
|
|
54
|
+
| `test/lifecycle/agent-runner-extension-tools.test.ts` | No direct `SessionConfig` assertions — exercises tool filtering via `runAgent` end-to-end; no changes needed |
|
|
55
|
+
|
|
56
|
+
### Dependency
|
|
57
|
+
|
|
58
|
+
Issue #164 (reorganize into domain directories) — closed ✓.
|
|
59
|
+
|
|
60
|
+
## Design Overview
|
|
61
|
+
|
|
62
|
+
### ToolFilterConfig shape
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
/** Tool filtering configuration — consumed by filterActiveTools. */
|
|
66
|
+
export interface ToolFilterConfig {
|
|
67
|
+
/** Built-in tool name allowlist for this agent type. */
|
|
68
|
+
toolNames: string[];
|
|
69
|
+
/** Disallowed tool set from agentConfig. undefined when empty. */
|
|
70
|
+
disallowedSet: Set<string> | undefined;
|
|
71
|
+
/** Resolved extensions setting: false | true | string[] allowlist. */
|
|
72
|
+
extensions: boolean | string[];
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### SessionConfig after extraction
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
export interface SessionConfig {
|
|
80
|
+
effectiveCwd: string;
|
|
81
|
+
systemPrompt: string;
|
|
82
|
+
toolFilter: ToolFilterConfig;
|
|
83
|
+
model: unknown;
|
|
84
|
+
thinkingLevel: ThinkingLevel | undefined;
|
|
85
|
+
noSkills: boolean;
|
|
86
|
+
extras: PromptExtras;
|
|
87
|
+
agentMaxTurns: number | undefined;
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Field count drops from 10 top-level fields to 8 (7 remaining + 1 `toolFilter`).
|
|
92
|
+
|
|
93
|
+
### filterActiveTools after extraction
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
function filterActiveTools(
|
|
97
|
+
activeTools: string[],
|
|
98
|
+
config: ToolFilterConfig,
|
|
99
|
+
): string[] {
|
|
100
|
+
const { toolNames, extensions, disallowedSet } = config;
|
|
101
|
+
// ... body unchanged
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Consumer call site (runAgent)
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
// Resource loader
|
|
109
|
+
noExtensions: cfg.toolFilter.extensions === false,
|
|
110
|
+
|
|
111
|
+
// Session creation
|
|
112
|
+
tools: cfg.toolFilter.toolNames,
|
|
113
|
+
|
|
114
|
+
// Guard + filter (two sites)
|
|
115
|
+
if (cfg.toolFilter.extensions !== false || cfg.toolFilter.disallowedSet) {
|
|
116
|
+
const filtered = filterActiveTools(session.getActiveToolNames(), cfg.toolFilter);
|
|
117
|
+
session.setActiveToolsByName(filtered);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Module-Level Changes
|
|
122
|
+
|
|
123
|
+
### `src/session/session-config.ts`
|
|
124
|
+
|
|
125
|
+
1. Add `ToolFilterConfig` interface (exported — consumed by `agent-runner.ts`).
|
|
126
|
+
2. Replace `toolNames`, `disallowedSet`, and `extensions` fields on `SessionConfig` with a single `toolFilter: ToolFilterConfig` field.
|
|
127
|
+
3. Update `assembleSessionConfig` return statement to nest the three values under `toolFilter`.
|
|
128
|
+
|
|
129
|
+
### `src/lifecycle/agent-runner.ts`
|
|
130
|
+
|
|
131
|
+
1. Import `ToolFilterConfig` from `session-config.ts`.
|
|
132
|
+
2. Change `filterActiveTools` signature from `(activeTools, toolNames, extensions, disallowedSet)` to `(activeTools, config: ToolFilterConfig)`.
|
|
133
|
+
3. Destructure `config` inside `filterActiveTools` body.
|
|
134
|
+
4. Update both filter call sites to pass `cfg.toolFilter` instead of three separate arguments.
|
|
135
|
+
5. Update `noExtensions:` and `tools:` references to use `cfg.toolFilter.*`.
|
|
136
|
+
|
|
137
|
+
### `test/session/session-config.test.ts`
|
|
138
|
+
|
|
139
|
+
1. Update all assertions reading `result.toolNames` → `result.toolFilter.toolNames`.
|
|
140
|
+
2. Update all assertions reading `result.extensions` → `result.toolFilter.extensions`.
|
|
141
|
+
3. Update all assertions reading `result.disallowedSet` → `result.toolFilter.disallowedSet`.
|
|
142
|
+
|
|
143
|
+
## Test Impact Analysis
|
|
144
|
+
|
|
145
|
+
1. No new unit tests are needed — the extraction does not introduce new behavior or branching.
|
|
146
|
+
2. No existing tests become redundant — the assembler tests verify field population, and the extension-tools integration tests verify end-to-end filtering.
|
|
147
|
+
Both remain valuable at their respective layers.
|
|
148
|
+
3. The `agent-runner-extension-tools.test.ts` tests exercise tool filtering via `runAgent` and do not reference `SessionConfig` fields directly, so they require no changes and serve as regression canaries for the refactoring.
|
|
149
|
+
|
|
150
|
+
## TDD Order
|
|
151
|
+
|
|
152
|
+
This is a pure refactoring with no new behavior, so the steps are refactor→verify rather than red→green.
|
|
153
|
+
|
|
154
|
+
1. **Add `ToolFilterConfig` interface and nest it in `SessionConfig`; update assembler return.**
|
|
155
|
+
Update `session-config.test.ts` assertions to read from `result.toolFilter.*`.
|
|
156
|
+
Run `pnpm run check` + tests.
|
|
157
|
+
Commit: `refactor(pi-subagents): extract ToolFilterConfig from SessionConfig`
|
|
158
|
+
|
|
159
|
+
2. **Change `filterActiveTools` signature to accept `ToolFilterConfig`; update `runAgent` call sites.**
|
|
160
|
+
Import `ToolFilterConfig`, destructure inside `filterActiveTools`, update all `cfg.*` references in `runAgent`.
|
|
161
|
+
Run `pnpm run check` + full test suite.
|
|
162
|
+
Commit: `refactor(pi-subagents): pass ToolFilterConfig to filterActiveTools`
|
|
163
|
+
|
|
164
|
+
## Risks and Mitigations
|
|
165
|
+
|
|
166
|
+
| Risk | Mitigation |
|
|
167
|
+
| ------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- |
|
|
168
|
+
| `cfg.toolNames` is also used for `tools:` in `createSession` — nesting it might confuse readers about intent | The field name `toolFilter.toolNames` is still descriptive; add a brief inline comment at the `tools:` site if needed |
|
|
169
|
+
| Test assertions reference flat fields — missing one causes a silent pass on `undefined` | grep for all three field names across `test/` before committing step 1 |
|
|
170
|
+
|
|
171
|
+
## Open Questions
|
|
172
|
+
|
|
173
|
+
None — the issue's proposed shape matches the architecture doc exactly and the change is internal to the package.
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
---
|
|
2
|
+
issue: 169
|
|
3
|
+
issue_title: "refactor(pi-subagents): extract RunContext from RunOptions (12 fields)"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Extract RunContext from RunOptions
|
|
7
|
+
|
|
8
|
+
## Problem Statement
|
|
9
|
+
|
|
10
|
+
`RunOptions` in `agent-runner.ts` has 12 fields mixing two distinct concerns: parent execution context ("where/who is running") and per-call execution parameters ("how to run").
|
|
11
|
+
Extracting the context cluster into a named `RunContext` interface makes the separation explicit and reduces the flat field count from 12 to 9 (8 execution fields + 1 nested context).
|
|
12
|
+
|
|
13
|
+
## Goals
|
|
14
|
+
|
|
15
|
+
- Define a `RunContext` interface grouping the 4 parent-context fields: `exec`, `registry`, `cwd`, and `parentSession`.
|
|
16
|
+
- Nest `RunContext` inside `RunOptions` as `context: RunContext`, replacing the 4 flat fields.
|
|
17
|
+
- Update `runAgent()` to read context fields from `options.context.*`.
|
|
18
|
+
- Update `AgentManager.startAgent()` to construct the nested `context` object when building `RunOptions`.
|
|
19
|
+
- Update all test files that construct or assert on `RunOptions` fields.
|
|
20
|
+
- Non-breaking refactor — `RunOptions` is not part of the public API (`service.ts` export boundary).
|
|
21
|
+
|
|
22
|
+
## Non-Goals
|
|
23
|
+
|
|
24
|
+
- Changing the `AgentRunner` interface signature — `run()` keeps its 4 positional parameters; `RunContext` is nested inside `RunOptions`, not a separate parameter.
|
|
25
|
+
- Extracting `RunContext` into its own file — the interface is small (4 fields) and co-located with its consumer (`runAgent`).
|
|
26
|
+
- Further splitting the remaining 8 execution fields — they form a coherent "how to run" cluster.
|
|
27
|
+
- Hoisting `RunContext` construction to `AgentManager` instance level — two of the four fields (`cwd`, `parentSession`) vary per spawn, so a per-spawn construction is appropriate.
|
|
28
|
+
|
|
29
|
+
## Background
|
|
30
|
+
|
|
31
|
+
Issue #164 (closed) reorganized source into domain directories; the runner now lives at `src/lifecycle/agent-runner.ts`.
|
|
32
|
+
Issue #166 (closed) extracted `ParentSessionInfo` and nested it inside `RunOptions.parentSession`.
|
|
33
|
+
Issue #167 (closed) split `RunnerIO` into `EnvironmentIO` and `SessionFactoryIO`.
|
|
34
|
+
Issue #168 (closed) extracted `ToolFilterConfig` from `SessionConfig`.
|
|
35
|
+
|
|
36
|
+
This issue continues the structural improvement by separating the two concerns mixed in `RunOptions`.
|
|
37
|
+
|
|
38
|
+
### Field analysis
|
|
39
|
+
|
|
40
|
+
| Field | Concern | Usage in `runAgent()` |
|
|
41
|
+
| ------------------ | --------- | ------------------------------------------ |
|
|
42
|
+
| `exec` | Context | `io.detectEnv(options.exec, effectiveCwd)` |
|
|
43
|
+
| `registry` | Context | Passed to `assembleSessionConfig` |
|
|
44
|
+
| `cwd` | Context | Override working directory (worktree) |
|
|
45
|
+
| `parentSession` | Context | Session dir derivation + session linking |
|
|
46
|
+
| `model` | Execution | Per-call model override |
|
|
47
|
+
| `maxTurns` | Execution | Turn limit |
|
|
48
|
+
| `signal` | Execution | Abort forwarding |
|
|
49
|
+
| `isolated` | Execution | Extension isolation flag |
|
|
50
|
+
| `thinkingLevel` | Execution | Thinking level override |
|
|
51
|
+
| `onSessionCreated` | Execution | Session delivery callback |
|
|
52
|
+
| `defaultMaxTurns` | Execution | Fallback turn limit from runtime config |
|
|
53
|
+
| `graceTurns` | Execution | Grace window after soft limit |
|
|
54
|
+
|
|
55
|
+
### Consumer analysis
|
|
56
|
+
|
|
57
|
+
`AgentManager.startAgent()` is the sole constructor of `RunOptions`.
|
|
58
|
+
The context fields come from two sources:
|
|
59
|
+
|
|
60
|
+
- Manager instance fields: `this.exec`, `this.registry`
|
|
61
|
+
- Per-spawn values: `worktreeCwd` (computed locally), `options.parentSession` (from `AgentSpawnConfig`)
|
|
62
|
+
|
|
63
|
+
## Design Overview
|
|
64
|
+
|
|
65
|
+
### `RunContext` interface
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
export interface RunContext {
|
|
69
|
+
/** Shell-exec callback for detectEnv — injected from pi.exec(). */
|
|
70
|
+
exec: ShellExec;
|
|
71
|
+
/** Agent config lookup — provides resolveAgentConfig and getToolNamesForType. */
|
|
72
|
+
registry: AgentConfigLookup;
|
|
73
|
+
/** Override working directory (e.g. for worktree isolation). */
|
|
74
|
+
cwd?: string;
|
|
75
|
+
/** Parent session identity (file path + session ID). */
|
|
76
|
+
parentSession?: ParentSessionInfo;
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Updated `RunOptions`
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
export interface RunOptions {
|
|
84
|
+
/** Parent execution context — where/who is running. */
|
|
85
|
+
context: RunContext;
|
|
86
|
+
model?: Model<any>;
|
|
87
|
+
maxTurns?: number;
|
|
88
|
+
signal?: AbortSignal;
|
|
89
|
+
isolated?: boolean;
|
|
90
|
+
thinkingLevel?: ThinkingLevel;
|
|
91
|
+
onSessionCreated?: (session: AgentSession) => void;
|
|
92
|
+
defaultMaxTurns?: number;
|
|
93
|
+
graceTurns?: number;
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Call-site sketch — `AgentManager.startAgent`
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
const promise = this.runner.run(snapshot, type, prompt, {
|
|
101
|
+
context: {
|
|
102
|
+
exec: this.exec,
|
|
103
|
+
registry: this.registry,
|
|
104
|
+
cwd: worktreeCwd,
|
|
105
|
+
parentSession: options.parentSession,
|
|
106
|
+
},
|
|
107
|
+
model: options.model,
|
|
108
|
+
maxTurns: options.maxTurns,
|
|
109
|
+
// ... remaining execution fields
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Access pattern in `runAgent`
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
const effectiveCwd = options.context.cwd ?? snapshot.cwd;
|
|
117
|
+
const env = await io.detectEnv(options.context.exec, effectiveCwd);
|
|
118
|
+
// ...
|
|
119
|
+
const sessionDir = io.deriveSessionDir(
|
|
120
|
+
options.context.parentSession?.parentSessionFile,
|
|
121
|
+
cfg.effectiveCwd,
|
|
122
|
+
);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Module-Level Changes
|
|
126
|
+
|
|
127
|
+
### `src/lifecycle/agent-runner.ts`
|
|
128
|
+
|
|
129
|
+
1. Add `RunContext` interface (4 fields, exported) before `RunOptions`.
|
|
130
|
+
2. Replace the 4 flat context fields on `RunOptions` with `context: RunContext`.
|
|
131
|
+
3. Update all `options.*` reads in `runAgent()`:
|
|
132
|
+
- `options.exec` → `options.context.exec`
|
|
133
|
+
- `options.cwd` → `options.context.cwd`
|
|
134
|
+
- `options.parentSession` → `options.context.parentSession`
|
|
135
|
+
- `options.registry` → `options.context.registry`
|
|
136
|
+
4. Move JSDoc from the removed flat fields to `RunContext` interface members.
|
|
137
|
+
5. Export `RunContext`.
|
|
138
|
+
|
|
139
|
+
### `src/lifecycle/agent-manager.ts`
|
|
140
|
+
|
|
141
|
+
1. Update the `RunOptions` object literal in `startAgent()` to nest the four context fields under `context: { ... }`.
|
|
142
|
+
2. No import changes needed — `RunOptions` is consumed via the `AgentRunner` interface, not imported directly.
|
|
143
|
+
|
|
144
|
+
### No changes needed
|
|
145
|
+
|
|
146
|
+
- `src/lifecycle/agent-runner.ts` — `AgentRunner` interface signature unchanged (`options: RunOptions`).
|
|
147
|
+
- `src/lifecycle/agent-runner.ts` — `createAgentRunner()` unchanged.
|
|
148
|
+
- `src/index.ts` — no changes (doesn't import `RunOptions`).
|
|
149
|
+
- `src/runtime.ts` — comment-only reference to `RunOptions`; update comment if desired.
|
|
150
|
+
- `src/session/session-config.ts` — comment-only reference; update comment if desired.
|
|
151
|
+
|
|
152
|
+
## Test Impact Analysis
|
|
153
|
+
|
|
154
|
+
### New unit tests enabled
|
|
155
|
+
|
|
156
|
+
The extraction does not enable new test surfaces — `RunContext` is a plain data carrier with no behavior.
|
|
157
|
+
A type-check verification (`pnpm run check`) confirms the structural compatibility.
|
|
158
|
+
|
|
159
|
+
### Existing tests that need updates
|
|
160
|
+
|
|
161
|
+
1. `test/lifecycle/agent-runner.test.ts` — 9 `runAgent()` call sites: wrap `exec`, `registry`, `cwd`, and `parentSession` fields in `context: { ... }`.
|
|
162
|
+
2. `test/lifecycle/agent-runner-extension-tools.test.ts` — 7 `runAgent()` call sites: same wrapping.
|
|
163
|
+
3. `test/lifecycle/agent-manager.test.ts` — 3 assertion sites: update `runOpts.parentSession` → `runOpts.context.parentSession`, `runOpts.defaultMaxTurns` stays flat (execution field).
|
|
164
|
+
|
|
165
|
+
### Tests that stay as-is
|
|
166
|
+
|
|
167
|
+
- `test/lifecycle/agent-runner-settings.test.ts` — tests `normalizeMaxTurns` (pure function, no `RunOptions` involvement).
|
|
168
|
+
- All other test files — no `RunOptions` construction or assertion.
|
|
169
|
+
|
|
170
|
+
## TDD Order
|
|
171
|
+
|
|
172
|
+
1. **Define `RunContext` and update `RunOptions`** — add `RunContext` interface, replace 4 flat fields with `context: RunContext` on `RunOptions`.
|
|
173
|
+
Update all `options.*` reads in `runAgent()` to `options.context.*`.
|
|
174
|
+
Update `agent-manager.ts` `startAgent()` to construct nested context.
|
|
175
|
+
Update `agent-runner.test.ts` (9 call sites) and `agent-runner-extension-tools.test.ts` (7 call sites) to nest context fields.
|
|
176
|
+
Update `agent-manager.test.ts` assertions (3 sites) to read from `runOpts.context.*`.
|
|
177
|
+
Run `pnpm run check` and `pnpm vitest run` to verify.
|
|
178
|
+
Commit: `refactor: extract RunContext from RunOptions (#169)`
|
|
179
|
+
|
|
180
|
+
2. **Update comments** — update comment references in `runtime.ts` and `session-config.ts` that mention `RunOptions` field names.
|
|
181
|
+
Commit: `docs: update RunOptions field references in comments (#169)`
|
|
182
|
+
|
|
183
|
+
## Risks and Mitigations
|
|
184
|
+
|
|
185
|
+
| Risk | Mitigation |
|
|
186
|
+
| ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
|
187
|
+
| Test factories using spread patterns lose context fields silently | No test factory returns `Partial<RunOptions>` — all call sites construct the options inline, so TypeScript will reject missing `context` |
|
|
188
|
+
| `agent-manager.test.ts` assertions on execution fields break | Only context-field assertions change; execution-field assertions (`defaultMaxTurns`, `graceTurns`) remain on `runOpts.*` |
|
|
189
|
+
| Nested access adds verbosity to `runAgent()` | Only 6 access sites gain the `.context` prefix; readability trade-off is minimal for the structural clarity gained |
|
|
190
|
+
|
|
191
|
+
## Open Questions
|
|
192
|
+
|
|
193
|
+
None — the extraction follows the natural "where/who vs. how" seam identified in the issue body.
|
|
194
|
+
The issue's proposed flat `parentSessionFile`/`parentSessionId` fields have been superseded by the already-implemented `parentSession?: ParentSessionInfo` grouping from #166.
|
|
@@ -33,3 +33,31 @@ Test count held steady at 805/805 (50 files) — no behavioral changes.
|
|
|
33
33
|
- `RunnerIO` JSDoc was split: `EnvironmentIO` got the environment-discovery description, `SessionFactoryIO` got the original "decouples from Pi SDK imports" description, and `RunnerIO` itself got a short backward-compatibility note.
|
|
34
34
|
- Architecture doc updated: wide-interface table row and Step 4 roadmap entry both marked done.
|
|
35
35
|
- No deviations from the plan.
|
|
36
|
+
|
|
37
|
+
## Stage: Final Retrospective (2026-05-24T21:30:00Z)
|
|
38
|
+
|
|
39
|
+
### Session summary
|
|
40
|
+
|
|
41
|
+
Issue #167 completed across three sessions: planning, TDD implementation, and ship.
|
|
42
|
+
The `RunnerIO` interface was split into `EnvironmentIO` and `SessionFactoryIO` with a backward-compatible type alias.
|
|
43
|
+
Released as `pi-subagents-v6.18.4`.
|
|
44
|
+
|
|
45
|
+
### Observations
|
|
46
|
+
|
|
47
|
+
#### What went well
|
|
48
|
+
|
|
49
|
+
- The plan correctly identified that structural typing would make this zero-friction — no call-site changes were needed in `index.ts` or either test factory.
|
|
50
|
+
- The two-step TDD plan was right-sized for a pure refactoring: step 1 for the interface split, step 2 for comment updates.
|
|
51
|
+
No new tests were needed, and the existing 805 tests validated the change without modification.
|
|
52
|
+
- Ship session was clean: CI passed first try, release-please PR merged, issue closed.
|
|
53
|
+
|
|
54
|
+
#### What caused friction (agent side)
|
|
55
|
+
|
|
56
|
+
- `missing-context` — The TDD session's architecture doc update (`824fd72`) only touched the `RunnerIO`-specific table row and Step 4 roadmap entry.
|
|
57
|
+
It missed that the same file's "Current layout" section still showed the pre-#164 flat file structure and retained a redundant "Proposed directory restructuring" section.
|
|
58
|
+
The user had to request a follow-up update (`d4a98aa`) in the ship session.
|
|
59
|
+
Impact: one extra commit and user prompt; no rework of prior commits.
|
|
60
|
+
|
|
61
|
+
#### What caused friction (user side)
|
|
62
|
+
|
|
63
|
+
- No friction observed.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
issue: 168
|
|
3
|
+
issue_title: "refactor(pi-subagents): extract ToolFilterConfig from SessionConfig (11 fields)"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Retro: #168 — extract ToolFilterConfig from SessionConfig
|
|
7
|
+
|
|
8
|
+
## Stage: Planning (2026-05-24T19:00:00Z)
|
|
9
|
+
|
|
10
|
+
### Session summary
|
|
11
|
+
|
|
12
|
+
Produced a 2-step plan to extract `ToolFilterConfig` (grouping `toolNames`, `disallowedSet`, `extensions`) from `SessionConfig` and update `filterActiveTools` to accept the named type.
|
|
13
|
+
The change is a pure internal refactoring — `SessionConfig` is not exported from the package.
|
|
14
|
+
|
|
15
|
+
### Observations
|
|
16
|
+
|
|
17
|
+
- The issue says "11 fields" but `SessionConfig` currently has 10 — likely a minor count discrepancy from when the issue was filed.
|
|
18
|
+
The extraction still reduces top-level fields from 10 to 8.
|
|
19
|
+
- `toolNames` serves dual duty: it's both the session-creation tool list and the `filterActiveTools` allowlist reference.
|
|
20
|
+
Nesting it under `toolFilter` is still correct since both uses originate from the same assembled config.
|
|
21
|
+
- `agent-runner-extension-tools.test.ts` exercises tool filtering end-to-end via `runAgent` and never references `SessionConfig` fields directly — it serves as a zero-change regression canary for this refactoring.
|
|
22
|
+
- The plan has only 2 TDD steps because the refactoring is mechanical and behavior-preserving.
|
|
23
|
+
Step 1 handles the interface change + assembler + tests; step 2 handles the consumer (`filterActiveTools` + `runAgent`).
|
|
24
|
+
|
|
25
|
+
## Stage: Implementation — TDD (2026-05-24T19:30:00Z)
|
|
26
|
+
|
|
27
|
+
### Session summary
|
|
28
|
+
|
|
29
|
+
Completed both refactoring steps cleanly.
|
|
30
|
+
`ToolFilterConfig` is now exported from `session-config.ts`, nested as `SessionConfig.toolFilter`, and consumed by `filterActiveTools` as a single named argument.
|
|
31
|
+
All 805 tests continue to pass; no new tests were added (pure structural refactoring with no behavior change).
|
|
32
|
+
|
|
33
|
+
### Observations
|
|
34
|
+
|
|
35
|
+
- Step 1 left intentional type errors in `agent-runner.ts` (expected: the consumer hadn't been updated yet); committing mid-step-1 was correct because the session-config tests were green in isolation.
|
|
36
|
+
- The autoformatter ran on `agent-runner.ts` after the Step 2 edits (Biome reformatted the two condensed filter-call lines); the committed diff was already formatted.
|
|
37
|
+
- All 9 flat-field assertions in `session-config.test.ts` (`result.toolNames`, `result.extensions`, `result.disallowedSet`) were correctly migrated to `result.toolFilter.*` — grep confirmed no stragglers.
|
|
38
|
+
- `agent-runner-extension-tools.test.ts` required zero changes, confirming its role as a regression canary.
|
|
39
|
+
- Architecture doc updated: `SessionConfig` row in the wide-interface table marked `✓ done`; Step 5 narrative updated to reflect actual field count (10 → 8, not 11 → 8 as the issue stated).
|
|
40
|
+
|
|
41
|
+
## Stage: Final Retrospective (2026-05-24T20:00:00Z)
|
|
42
|
+
|
|
43
|
+
### Session summary
|
|
44
|
+
|
|
45
|
+
Issue #168 completed across three sessions (Planning → TDD → Ship) with zero friction, rework, or plan deviations.
|
|
46
|
+
Total diff: 3 files changed, 37 insertions, 41 deletions (net reduction).
|
|
47
|
+
Released as `pi-subagents-v6.18.5`.
|
|
48
|
+
|
|
49
|
+
### Observations
|
|
50
|
+
|
|
51
|
+
#### What went well
|
|
52
|
+
|
|
53
|
+
- **Grep-before-commit safety net.**
|
|
54
|
+
The planning session identified 9 flat-field assertions in `session-config.test.ts` that would silently pass as `undefined` if missed during migration.
|
|
55
|
+
The TDD session grepped for all three field names before committing step 1, catching all 9 in one pass.
|
|
56
|
+
This is the testing skill’s "grep for all test files" rule applied to assertion migration.
|
|
57
|
+
- **Regression canary identification during planning.**
|
|
58
|
+
The planning session called out `agent-runner-extension-tools.test.ts` as a zero-change regression canary.
|
|
59
|
+
The TDD session confirmed this prediction — no changes needed, all existing tests green.
|
|
60
|
+
Identifying canary tests during planning gave confidence that the two refactoring steps were correctly scoped.
|
|
61
|
+
- **2-step granularity was right.**
|
|
62
|
+
Step 1 (interface + assembler + tests) left intentional type errors in the consumer.
|
|
63
|
+
Step 2 (consumer update) resolved them.
|
|
64
|
+
This kept each commit reviewable and type-check-green at the session-config boundary.
|
|
65
|
+
|
|
66
|
+
#### What caused friction (agent side)
|
|
67
|
+
|
|
68
|
+
None.
|
|
69
|
+
|
|
70
|
+
#### What caused friction (user side)
|
|
71
|
+
|
|
72
|
+
None.
|
|
73
|
+
|
|
74
|
+
### Changes made
|
|
75
|
+
|
|
76
|
+
No process changes — clean execution with no proposals warranted.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
issue: 169
|
|
3
|
+
issue_title: "refactor(pi-subagents): extract RunContext from RunOptions (12 fields)"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Retro: #169 — extract RunContext from RunOptions
|
|
7
|
+
|
|
8
|
+
## Stage: Planning (2026-05-24T17:07:10Z)
|
|
9
|
+
|
|
10
|
+
### Session summary
|
|
11
|
+
|
|
12
|
+
Produced a plan to extract 4 parent-context fields (`exec`, `registry`, `cwd`, `parentSession`) from `RunOptions` into a nested `RunContext` interface.
|
|
13
|
+
The plan is a single-step refactor (all changes in one commit) plus a comment-update commit, affecting 3 source files and 3 test files.
|
|
14
|
+
|
|
15
|
+
### Observations
|
|
16
|
+
|
|
17
|
+
- The issue body proposed flat `parentSessionFile`/`parentSessionId` fields on `RunContext`, but #166 already grouped these into `ParentSessionInfo`.
|
|
18
|
+
The plan uses `parentSession?: ParentSessionInfo` instead, preserving the existing grouping.
|
|
19
|
+
- `RunOptions` is purely internal — not exported via `service.ts` — so the refactor is non-breaking.
|
|
20
|
+
- All test call sites construct `RunOptions` inline (no `Partial<RunOptions>` spread patterns), so TypeScript will catch any missing `context` field at compile time.
|
|
21
|
+
- The change is small enough to land in a single TDD step — no lift-and-shift needed.
|
|
22
|
+
- Prerequisite #164 (directory reorganization) is already implemented.
|
|
23
|
+
|
|
24
|
+
## Stage: Implementation — TDD (2026-05-24T17:14:32Z)
|
|
25
|
+
|
|
26
|
+
### Session summary
|
|
27
|
+
|
|
28
|
+
Completed both TDD steps in one session.
|
|
29
|
+
Step 1 defined `RunContext`, updated `RunOptions`, migrated `runAgent()` reads to `options.context.*`, restructured `AgentManager.startAgent()`, and updated all 16 test call sites across 3 test files.
|
|
30
|
+
Step 2 updated comment references in `runtime.ts` and `session-config.ts`.
|
|
31
|
+
Test count unchanged (50 files, 805 tests — pure refactor with no behavior change).
|
|
32
|
+
|
|
33
|
+
### Observations
|
|
34
|
+
|
|
35
|
+
- The `agent-manager.test.ts` update also added two new assertions (`context.exec` and `context.registry` are defined) to each existing `getRunConfig` threading test, confirming the context object is wired correctly; these were not in the plan but add useful coverage.
|
|
36
|
+
- All 16 `runAgent()` call sites in tests used inline option literals (no spread patterns), so TypeScript caught any missed site at compile time — the plan's risk mitigation held.
|
|
37
|
+
- No deviations from the plan otherwise; the comment-only step was trivial.
|
package/package.json
CHANGED
|
@@ -225,17 +225,19 @@ export class AgentManager {
|
|
|
225
225
|
|
|
226
226
|
const runConfig = this.getRunConfig?.();
|
|
227
227
|
const promise = this.runner.run(snapshot, type, prompt, {
|
|
228
|
-
|
|
228
|
+
context: {
|
|
229
|
+
exec: this.exec,
|
|
230
|
+
registry: this.registry,
|
|
231
|
+
cwd: worktreeCwd,
|
|
232
|
+
parentSession: options.parentSession,
|
|
233
|
+
},
|
|
229
234
|
model: options.model,
|
|
230
235
|
maxTurns: options.maxTurns,
|
|
231
236
|
defaultMaxTurns: runConfig?.defaultMaxTurns,
|
|
232
237
|
graceTurns: runConfig?.graceTurns,
|
|
233
238
|
isolated: options.isolated,
|
|
234
239
|
thinkingLevel: options.thinkingLevel,
|
|
235
|
-
cwd: worktreeCwd,
|
|
236
|
-
parentSession: options.parentSession,
|
|
237
240
|
signal: record.abortController!.signal,
|
|
238
|
-
registry: this.registry,
|
|
239
241
|
onSessionCreated: (session) => {
|
|
240
242
|
// Capture the session file path early so it's available for display
|
|
241
243
|
// before the run completes (e.g. in background agent status messages).
|
|
@@ -13,7 +13,7 @@ import type { ParentSessionInfo } from "#src/lifecycle/agent-manager";
|
|
|
13
13
|
import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
|
|
14
14
|
import { extractText } from "#src/session/context";
|
|
15
15
|
import type { EnvInfo } from "#src/session/env";
|
|
16
|
-
import { type AssemblerIO, assembleSessionConfig } from "#src/session/session-config";
|
|
16
|
+
import { type AssemblerIO, assembleSessionConfig, type ToolFilterConfig } from "#src/session/session-config";
|
|
17
17
|
import type { ShellExec, SubagentType, ThinkingLevel } from "#src/types";
|
|
18
18
|
|
|
19
19
|
/** Names of tools registered by this extension that subagents must NOT inherit. */
|
|
@@ -45,16 +45,13 @@ function getToolCallName(c: { type: string }): string {
|
|
|
45
45
|
* the post-bind re-filter trivial.
|
|
46
46
|
*
|
|
47
47
|
* @param activeTools Names currently active on the session.
|
|
48
|
-
* @param
|
|
49
|
-
* @param extensions Agent config `extensions` field: false | true | string[] (allowlist).
|
|
50
|
-
* @param disallowedSet Optional denylist from agent config.
|
|
48
|
+
* @param config Tool filtering configuration from the assembled session config.
|
|
51
49
|
*/
|
|
52
50
|
function filterActiveTools(
|
|
53
51
|
activeTools: string[],
|
|
54
|
-
|
|
55
|
-
extensions: boolean | string[],
|
|
56
|
-
disallowedSet: Set<string> | undefined,
|
|
52
|
+
config: ToolFilterConfig,
|
|
57
53
|
): string[] {
|
|
54
|
+
const { toolNames, extensions, disallowedSet } = config;
|
|
58
55
|
if (extensions === false) {
|
|
59
56
|
// Extensions disabled: only apply the denylist to built-in tools.
|
|
60
57
|
if (!disallowedSet) return activeTools;
|
|
@@ -155,18 +152,31 @@ export type RunnerIO = EnvironmentIO & SessionFactoryIO;
|
|
|
155
152
|
|
|
156
153
|
// ── Public interfaces ─────────────────────────────────────────────────────────
|
|
157
154
|
|
|
158
|
-
|
|
155
|
+
/**
|
|
156
|
+
* Parent execution context — where/who is running.
|
|
157
|
+
*
|
|
158
|
+
* Groups the four fields that describe the parent environment and identity,
|
|
159
|
+
* separating them from the per-call execution parameters in RunOptions.
|
|
160
|
+
*/
|
|
161
|
+
export interface RunContext {
|
|
159
162
|
/** Shell-exec callback for detectEnv — injected from pi.exec(). */
|
|
160
163
|
exec: ShellExec;
|
|
164
|
+
/** Agent config lookup — provides resolveAgentConfig and getToolNamesForType. */
|
|
165
|
+
registry: AgentConfigLookup;
|
|
166
|
+
/** Override working directory (e.g. for worktree isolation). */
|
|
167
|
+
cwd?: string;
|
|
168
|
+
/** Parent session identity (file path + session ID). */
|
|
169
|
+
parentSession?: ParentSessionInfo;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface RunOptions {
|
|
173
|
+
/** Parent execution context — where/who is running. */
|
|
174
|
+
context: RunContext;
|
|
161
175
|
model?: Model<any>;
|
|
162
176
|
maxTurns?: number;
|
|
163
177
|
signal?: AbortSignal;
|
|
164
178
|
isolated?: boolean;
|
|
165
179
|
thinkingLevel?: ThinkingLevel;
|
|
166
|
-
/** Override working directory (e.g. for worktree isolation). */
|
|
167
|
-
cwd?: string;
|
|
168
|
-
/** Parent session identity (file path + session ID). */
|
|
169
|
-
parentSession?: ParentSessionInfo;
|
|
170
180
|
/** Called once after session creation — session delivery mechanism. */
|
|
171
181
|
onSessionCreated?: (session: AgentSession) => void;
|
|
172
182
|
/**
|
|
@@ -180,8 +190,6 @@ export interface RunOptions {
|
|
|
180
190
|
* module-scope `graceTurns` during migration.
|
|
181
191
|
*/
|
|
182
192
|
graceTurns?: number;
|
|
183
|
-
/** Agent config lookup — provides resolveAgentConfig and getToolNamesForType. */
|
|
184
|
-
registry: AgentConfigLookup;
|
|
185
193
|
}
|
|
186
194
|
|
|
187
195
|
export interface RunResult {
|
|
@@ -278,8 +286,8 @@ export async function runAgent(
|
|
|
278
286
|
io: RunnerIO,
|
|
279
287
|
): Promise<RunResult> {
|
|
280
288
|
// Resolve working directory upfront — needed for detectEnv before assembly.
|
|
281
|
-
const effectiveCwd = options.cwd ?? snapshot.cwd;
|
|
282
|
-
const env = await io.detectEnv(options.exec, effectiveCwd);
|
|
289
|
+
const effectiveCwd = options.context.cwd ?? snapshot.cwd;
|
|
290
|
+
const env = await io.detectEnv(options.context.exec, effectiveCwd);
|
|
283
291
|
|
|
284
292
|
// Assemble session configuration (synchronous, no SDK objects).
|
|
285
293
|
const cfg = assembleSessionConfig(
|
|
@@ -291,13 +299,13 @@ export async function runAgent(
|
|
|
291
299
|
modelRegistry: snapshot.modelRegistry,
|
|
292
300
|
},
|
|
293
301
|
{
|
|
294
|
-
cwd: options.cwd,
|
|
302
|
+
cwd: options.context.cwd,
|
|
295
303
|
isolated: options.isolated,
|
|
296
304
|
model: options.model,
|
|
297
305
|
thinkingLevel: options.thinkingLevel,
|
|
298
306
|
},
|
|
299
307
|
env,
|
|
300
|
-
options.registry,
|
|
308
|
+
options.context.registry,
|
|
301
309
|
io.assemblerIO,
|
|
302
310
|
);
|
|
303
311
|
|
|
@@ -312,7 +320,7 @@ export async function runAgent(
|
|
|
312
320
|
const loader = io.createResourceLoader({
|
|
313
321
|
cwd: cfg.effectiveCwd,
|
|
314
322
|
agentDir,
|
|
315
|
-
noExtensions: cfg.extensions === false,
|
|
323
|
+
noExtensions: cfg.toolFilter.extensions === false,
|
|
316
324
|
noSkills: cfg.noSkills,
|
|
317
325
|
noPromptTemplates: true,
|
|
318
326
|
noThemes: true,
|
|
@@ -325,9 +333,9 @@ export async function runAgent(
|
|
|
325
333
|
// Create a persisted SessionManager so transcripts are written in Pi's
|
|
326
334
|
// official JSONL format. Falls back to a temp directory when the parent
|
|
327
335
|
// session is not persisted (e.g. headless/API mode).
|
|
328
|
-
const sessionDir = io.deriveSessionDir(options.parentSession?.parentSessionFile, cfg.effectiveCwd);
|
|
336
|
+
const sessionDir = io.deriveSessionDir(options.context.parentSession?.parentSessionFile, cfg.effectiveCwd);
|
|
329
337
|
const sessionManager = io.createSessionManager(cfg.effectiveCwd, sessionDir);
|
|
330
|
-
sessionManager.newSession({ parentSession: options.parentSession?.parentSessionId });
|
|
338
|
+
sessionManager.newSession({ parentSession: options.context.parentSession?.parentSessionId });
|
|
331
339
|
|
|
332
340
|
const { session } = await io.createSession({
|
|
333
341
|
cwd: cfg.effectiveCwd,
|
|
@@ -336,7 +344,7 @@ export async function runAgent(
|
|
|
336
344
|
settingsManager: io.createSettingsManager(cfg.effectiveCwd, agentDir),
|
|
337
345
|
modelRegistry: snapshot.modelRegistry,
|
|
338
346
|
model: cfg.model,
|
|
339
|
-
tools: cfg.toolNames,
|
|
347
|
+
tools: cfg.toolFilter.toolNames,
|
|
340
348
|
resourceLoader: loader,
|
|
341
349
|
thinkingLevel: cfg.thinkingLevel,
|
|
342
350
|
});
|
|
@@ -344,13 +352,8 @@ export async function runAgent(
|
|
|
344
352
|
// Filter active tools: remove our own tools to prevent nesting,
|
|
345
353
|
// apply extension allowlist if specified, and apply disallowedTools denylist.
|
|
346
354
|
// First pass — over built-in tools, before bindExtensions registers extension tools.
|
|
347
|
-
if (cfg.extensions !== false || cfg.disallowedSet) {
|
|
348
|
-
const filtered = filterActiveTools(
|
|
349
|
-
session.getActiveToolNames(),
|
|
350
|
-
cfg.toolNames,
|
|
351
|
-
cfg.extensions,
|
|
352
|
-
cfg.disallowedSet,
|
|
353
|
-
);
|
|
355
|
+
if (cfg.toolFilter.extensions !== false || cfg.toolFilter.disallowedSet) {
|
|
356
|
+
const filtered = filterActiveTools(session.getActiveToolNames(), cfg.toolFilter);
|
|
354
357
|
session.setActiveToolsByName(filtered);
|
|
355
358
|
}
|
|
356
359
|
|
|
@@ -366,13 +369,8 @@ export async function runAgent(
|
|
|
366
369
|
// re-filter, the `extensions: string[]` allowlist branch never matches any
|
|
367
370
|
// extension tools and `extensions: true` lets non-allowlisted denylist
|
|
368
371
|
// entries slip in. Run the same filter against the post-bind active set.
|
|
369
|
-
if (cfg.extensions !== false || cfg.disallowedSet) {
|
|
370
|
-
const refiltered = filterActiveTools(
|
|
371
|
-
session.getActiveToolNames(),
|
|
372
|
-
cfg.toolNames,
|
|
373
|
-
cfg.extensions,
|
|
374
|
-
cfg.disallowedSet,
|
|
375
|
-
);
|
|
372
|
+
if (cfg.toolFilter.extensions !== false || cfg.toolFilter.disallowedSet) {
|
|
373
|
+
const refiltered = filterActiveTools(session.getActiveToolNames(), cfg.toolFilter);
|
|
376
374
|
session.setActiveToolsByName(refiltered);
|
|
377
375
|
}
|
|
378
376
|
|
package/src/runtime.ts
CHANGED
|
@@ -22,7 +22,7 @@ export interface WidgetLike {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
* Narrow config subset read by AgentManager when constructing RunOptions.
|
|
25
|
+
* Narrow config subset read by AgentManager when constructing RunOptions execution fields.
|
|
26
26
|
* Kept separate so callers can satisfy it without depending on the full runtime.
|
|
27
27
|
*/
|
|
28
28
|
export interface RunConfig {
|
|
@@ -27,6 +27,21 @@ import type {
|
|
|
27
27
|
|
|
28
28
|
// ── Public interfaces ────────────────────────────────────────────────────────
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Tool filtering configuration — consumed by `filterActiveTools` in `agent-runner.ts`.
|
|
32
|
+
*
|
|
33
|
+
* Groups the three fields that travel together through the assembly→runner boundary:
|
|
34
|
+
* the built-in tool allowlist, the optional denylist, and the extensions setting.
|
|
35
|
+
*/
|
|
36
|
+
export interface ToolFilterConfig {
|
|
37
|
+
/** Built-in tool name allowlist for this agent type. */
|
|
38
|
+
toolNames: string[];
|
|
39
|
+
/** Disallowed tool set from agentConfig. undefined when empty. */
|
|
40
|
+
disallowedSet: Set<string> | undefined;
|
|
41
|
+
/** Resolved extensions setting: false | true | string[] allowlist. */
|
|
42
|
+
extensions: boolean | string[];
|
|
43
|
+
}
|
|
44
|
+
|
|
30
45
|
/**
|
|
31
46
|
* IO collaborators injected into `assembleSessionConfig`.
|
|
32
47
|
*
|
|
@@ -76,7 +91,7 @@ export interface AssemblerContext {
|
|
|
76
91
|
}
|
|
77
92
|
|
|
78
93
|
/**
|
|
79
|
-
* Narrow slice of RunOptions consumed by the assembler.
|
|
94
|
+
* Narrow slice of RunOptions execution fields consumed by the assembler.
|
|
80
95
|
* All fields are optional — callers pass only what they have.
|
|
81
96
|
*/
|
|
82
97
|
export interface AssemblerOptions {
|
|
@@ -100,12 +115,8 @@ export interface SessionConfig {
|
|
|
100
115
|
effectiveCwd: string;
|
|
101
116
|
/** Fully-assembled system prompt string (ready for `systemPromptOverride`). */
|
|
102
117
|
systemPrompt: string;
|
|
103
|
-
/**
|
|
104
|
-
|
|
105
|
-
/** Disallowed tool set from agentConfig (for `filterActiveTools`). undefined when empty. */
|
|
106
|
-
disallowedSet: Set<string> | undefined;
|
|
107
|
-
/** Resolved extensions setting for resource loader and tool filtering. */
|
|
108
|
-
extensions: boolean | string[];
|
|
118
|
+
/** Tool filtering cluster — tool allowlist, denylist, and extensions setting. */
|
|
119
|
+
toolFilter: ToolFilterConfig;
|
|
109
120
|
/**
|
|
110
121
|
* Resolved model instance (undefined → use parent model as passed to SDK).
|
|
111
122
|
* Opaque handle — the assembler passes it through without inspection.
|
|
@@ -264,9 +275,7 @@ export function assembleSessionConfig(
|
|
|
264
275
|
return {
|
|
265
276
|
effectiveCwd,
|
|
266
277
|
systemPrompt,
|
|
267
|
-
toolNames,
|
|
268
|
-
disallowedSet,
|
|
269
|
-
extensions,
|
|
278
|
+
toolFilter: { toolNames, disallowedSet, extensions },
|
|
270
279
|
model,
|
|
271
280
|
thinkingLevel,
|
|
272
281
|
noSkills,
|