@gotgenes/pi-subagents 18.0.1 → 18.0.2
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 +7 -0
- package/docs/architecture/architecture.md +157 -204
- package/docs/architecture/history/phase-19-implement-ui-decisions.md +282 -0
- package/package.json +5 -6
- package/src/lifecycle/subagent.ts +5 -9
- package/src/observation/notification.ts +23 -10
- package/src/observation/subagent-events-observer.ts +1 -3
- package/src/tools/get-result-report.ts +60 -0
- package/src/tools/get-result-tool.ts +25 -40
- package/src/types.ts +1 -1
- package/src/ui/session-navigator.ts +0 -2
- package/.prettierignore +0 -5
- package/AGENTS.md +0 -7
- package/docs/plans/0048-implement-subagents-api.md +0 -304
- package/docs/plans/0049-remove-group-join-output-file-rpc.md +0 -180
- package/docs/plans/0051-update-adr-0001-hard-fork.md +0 -77
- package/docs/plans/0052-remove-scheduled-subagents.md +0 -133
- package/docs/plans/0053-extract-model-resolution-from-execute.md +0 -181
- package/docs/plans/0054-decompose-index-into-modules.md +0 -302
- package/docs/plans/0057-structured-debug-logging.md +0 -154
- package/docs/plans/0061-session-format-transcript.md +0 -284
- package/docs/plans/0066-replace-as-any-with-sdk-types.md +0 -215
- package/docs/plans/0069-create-subagent-runtime.md +0 -345
- package/docs/plans/0070-extract-event-handlers.md +0 -306
- package/docs/plans/0071-extract-session-config-assembler.md +0 -362
- package/docs/plans/0072-inject-agent-manager-collaborators.md +0 -329
- package/docs/plans/0076-inject-cwd-into-agent-manager.md +0 -102
- package/docs/plans/0077-inject-project-agents-dir.md +0 -115
- package/docs/plans/0080-consolidate-agent-config-lookup.md +0 -247
- package/docs/plans/0084-extract-git-worktree-manager.md +0 -142
- package/docs/plans/0087-evolve-subagent-runtime-methods.md +0 -240
- package/docs/plans/0098-extract-agent-record-state-machine.md +0 -435
- package/docs/plans/0099-replace-ctx-with-parent-snapshot.md +0 -488
- package/docs/plans/0100-replace-callback-threading-with-session-subscription.md +0 -454
- package/docs/plans/0102-consolidate-test-record-factory.md +0 -176
- package/docs/plans/0108-extract-agent-type-registry.md +0 -322
- package/docs/plans/0109-extract-settings-manager.md +0 -276
- package/docs/plans/0110-agent-activity-tracker.md +0 -297
- package/docs/plans/0111-split-agent-record-lifecycle.md +0 -582
- package/docs/plans/0112-replace-agent-manager-callbacks.md +0 -241
- package/docs/plans/0113-disambiguate-spawn-options.md +0 -155
- package/docs/plans/0114-narrow-agent-tool-menu-deps.md +0 -279
- package/docs/plans/0115-decompose-agent-tool.md +0 -337
- package/docs/plans/0116-type-housekeeping.md +0 -351
- package/docs/plans/0118-settings-manager-apply-methods.md +0 -271
- package/docs/plans/0123-remove-vi-fn-cast-smell.md +0 -179
- package/docs/plans/0131-consolidate-shared-test-fixtures.md +0 -207
- package/docs/plans/0132-inject-io-into-session-config.md +0 -219
- package/docs/plans/0133-inject-sdk-boundary-into-agent-runner.md +0 -373
- package/docs/plans/0134-reduce-as-any-casts.md +0 -366
- package/docs/plans/0135-extract-display-helpers.md +0 -182
- package/docs/plans/0136-decompose-agent-menu.md +0 -300
- package/docs/plans/0144-consolidate-observation-model.md +0 -263
- package/docs/plans/0145-decompose-execute-push-ctx-to-boundary.md +0 -290
- package/docs/plans/0146-narrow-ui-context.md +0 -319
- package/docs/plans/0147-inject-wrap-text-into-conversation-viewer.md +0 -166
- package/docs/plans/0148-split-agent-widget-rendering.md +0 -255
- package/docs/plans/0152-add-prompt-snippet.md +0 -91
- package/docs/plans/0164-reorganize-into-domain-directories.md +0 -409
- package/docs/plans/0165-decompose-resolved-spawn-config.md +0 -157
- package/docs/plans/0166-extract-parent-session-info.md +0 -231
- package/docs/plans/0167-narrow-runner-io.md +0 -150
- package/docs/plans/0168-extract-tool-filter-config.md +0 -173
- package/docs/plans/0169-extract-run-context-from-run-options.md +0 -194
- package/docs/plans/0170-reduce-build-content-lines-complexity.md +0 -225
- package/docs/plans/0171-reduce-render-result-complexity.md +0 -200
- package/docs/plans/0172-extract-turn-formatting.md +0 -206
- package/docs/plans/0180-reorder-append-prompt-for-kv-cache.md +0 -100
- package/docs/plans/0185-remove-persistent-agent-memory.md +0 -161
- package/docs/plans/0188-replace-any-casts-with-sdk-types.md +0 -162
- package/docs/plans/0192-define-session-context-interface.md +0 -107
- package/docs/plans/0193-runtime-owns-context-queries.md +0 -245
- package/docs/plans/0194-align-tool-interfaces-for-structural-typing.md +0 -139
- package/docs/plans/0195-convert-tool-factories-to-classes.md +0 -264
- package/docs/plans/0196-convert-runner-menu-to-classes.md +0 -268
- package/docs/plans/0205-decompose-render-widget-lines.md +0 -140
- package/docs/plans/0206-decompose-show-agent-detail.md +0 -211
- package/docs/plans/0207-decompose-agent-widget-update.md +0 -242
- package/docs/plans/0208-extract-shared-test-fixtures.md +0 -298
- package/docs/plans/0214-convert-remaining-closure-factories-to-classes.md +0 -261
- package/docs/plans/0215-decompose-build-parent-context.md +0 -166
- package/docs/plans/0216-decompose-start-agent.md +0 -255
- package/docs/plans/0217-extract-overwrite-guard.md +0 -176
- package/docs/plans/0218-push-sdk-boundary-in-settings.md +0 -172
- package/docs/plans/0219-reduce-test-duplication-top-3-clone-families.md +0 -162
- package/docs/plans/0227-evolve-agent-record-into-agent.md +0 -322
- package/docs/plans/0228-async-start-agent-dissolve-run-handle.md +0 -288
- package/docs/plans/0229-agent-born-complete.md +0 -564
- package/docs/plans/0230-extract-concurrency-queue.md +0 -265
- package/docs/plans/0231-push-exec-registry-to-runner.md +0 -245
- package/docs/plans/0232-agent-resume-internal-observer-lifecycle.md +0 -180
- package/docs/plans/0237-remove-disallowed-tools.md +0 -180
- package/docs/plans/0238-remove-extensions-filtering.md +0 -191
- package/docs/plans/0239-collapse-filter-active-tools.md +0 -217
- package/docs/plans/0242-rename-agent-tool-to-subagent.md +0 -165
- package/docs/plans/0256-extract-worktree-isolation.md +0 -256
- package/docs/plans/0257-extract-child-session-factory.md +0 -285
- package/docs/plans/0262-add-workspace-provider-seam.md +0 -264
- package/docs/plans/0264-remove-extension-lifecycle-control.md +0 -277
- package/docs/plans/0265-born-complete-subagent-session.md +0 -333
- package/docs/plans/0270-type-consumable-public-surface.md +0 -204
- package/docs/plans/0272-export-workspace-collaborator-types.md +0 -147
- package/docs/plans/0277-encapsulate-agent-session.md +0 -304
- package/docs/plans/0280-rename-agent-to-subagent.md +0 -197
- package/docs/plans/0360-custom-agents-default-append.md +0 -132
- package/docs/plans/0373-extract-subagent-state.md +0 -250
- package/docs/plans/0374-encapsulate-subagent-start-notification.md +0 -268
- package/docs/plans/0375-extract-run-listener-workspace-bracket.md +0 -300
- package/docs/plans/0376-extract-manager-observer.md +0 -232
- package/docs/plans/0377-split-widget-delegation-from-runtime.md +0 -254
- package/docs/plans/0378-consolidate-lifecycle-test-fixtures.md +0 -243
- package/docs/plans/0379-consolidate-ui-tools-test-fixtures.md +0 -335
- package/docs/plans/0380-extract-layered-settings-loader.md +0 -223
- package/docs/plans/0381-replace-concurrency-queue-with-limiter.md +0 -267
- package/docs/plans/0400-include-parent-prompt-in-replace-mode.md +0 -199
- package/docs/plans/0403-abort-subagents-on-interrupt.md +0 -180
- package/docs/plans/0412-unify-session-mock-builders.md +0 -146
- package/docs/plans/0420-fold-run-metrics-live-activity-onto-record.md +0 -228
- package/docs/plans/0421-migrate-activity-readers-to-record-getters.md +0 -309
- package/docs/plans/0422-delete-activity-tracker-ui-observer.md +0 -204
- package/docs/plans/0423-widget-self-drive-from-lifecycle.md +0 -264
- package/docs/plans/0424-drop-widget-dep-from-subagent-tool.md +0 -166
- package/docs/plans/0425-reconcile-subagent-events-contract.md +0 -144
- package/docs/plans/0426-consolidate-residual-test-clone-families.md +0 -235
- package/docs/plans/0427-reconsider-ui-direction.md +0 -212
- package/docs/plans/0441-remove-agent-definition-management-subtree.md +0 -180
- package/docs/plans/0442-dissolve-agents-conversation-viewer.md +0 -195
- package/docs/plans/0443-consolidate-remaining-test-clone-families.md +0 -268
- package/docs/plans/0444-shrink-widget-to-background-agents.md +0 -156
- package/docs/plans/0445-native-session-navigation.md +0 -365
- package/docs/plans/0446-spike-session-navigation-entry-criteria.md +0 -171
- package/docs/plans/0447-extract-subagents-settings-command.md +0 -220
- package/docs/plans/0448-block-disabled-agent-spawn.md +0 -207
- package/docs/plans/0462-navigation-renderer-tui-components.md +0 -338
- package/docs/plans/0463-file-snapshot-source-evicted-agents.md +0 -306
- package/docs/plans/0470-refresh-readme-command-surface.md +0 -159
- package/docs/retro/0048-implement-subagents-api.md +0 -44
- package/docs/retro/0049-remove-group-join-output-file-rpc.md +0 -49
- package/docs/retro/0051-update-adr-0001-hard-fork.md +0 -39
- package/docs/retro/0053-extract-model-resolution-from-execute.md +0 -40
- package/docs/retro/0054-decompose-index-into-modules.md +0 -53
- package/docs/retro/0057-structured-debug-logging.md +0 -77
- package/docs/retro/0061-session-format-transcript.md +0 -41
- package/docs/retro/0066-replace-as-any-with-sdk-types.md +0 -44
- package/docs/retro/0069-create-subagent-runtime.md +0 -43
- package/docs/retro/0070-extract-event-handlers.md +0 -49
- package/docs/retro/0071-extract-session-config-assembler.md +0 -60
- package/docs/retro/0072-inject-agent-manager-collaborators.md +0 -46
- package/docs/retro/0076-inject-cwd-into-agent-manager.md +0 -35
- package/docs/retro/0077-inject-project-agents-dir.md +0 -33
- package/docs/retro/0080-consolidate-agent-config-lookup.md +0 -35
- package/docs/retro/0084-extract-git-worktree-manager.md +0 -37
- package/docs/retro/0087-evolve-subagent-runtime-methods.md +0 -42
- package/docs/retro/0098-extract-agent-record-state-machine.md +0 -46
- package/docs/retro/0099-replace-ctx-with-parent-snapshot.md +0 -37
- package/docs/retro/0100-replace-callback-threading-with-session-subscription.md +0 -36
- package/docs/retro/0102-consolidate-test-record-factory.md +0 -30
- package/docs/retro/0108-extract-agent-type-registry.md +0 -41
- package/docs/retro/0109-extract-settings-manager.md +0 -55
- package/docs/retro/0110-agent-activity-tracker.md +0 -44
- package/docs/retro/0111-split-agent-record-lifecycle.md +0 -61
- package/docs/retro/0112-replace-agent-manager-callbacks.md +0 -35
- package/docs/retro/0113-disambiguate-spawn-options.md +0 -29
- package/docs/retro/0114-narrow-agent-tool-menu-deps.md +0 -38
- package/docs/retro/0115-decompose-agent-tool.md +0 -51
- package/docs/retro/0116-type-housekeeping.md +0 -42
- package/docs/retro/0118-settings-manager-apply-methods.md +0 -40
- package/docs/retro/0123-remove-vi-fn-cast-smell.md +0 -49
- package/docs/retro/0131-consolidate-shared-test-fixtures.md +0 -46
- package/docs/retro/0132-inject-io-into-session-config.md +0 -33
- package/docs/retro/0133-inject-sdk-boundary-into-agent-runner.md +0 -45
- package/docs/retro/0134-reduce-as-any-casts.md +0 -56
- package/docs/retro/0135-extract-display-helpers.md +0 -38
- package/docs/retro/0136-decompose-agent-menu.md +0 -43
- package/docs/retro/0144-consolidate-observation-model.md +0 -39
- package/docs/retro/0145-decompose-execute-push-ctx-to-boundary.md +0 -56
- package/docs/retro/0146-narrow-ui-context.md +0 -70
- package/docs/retro/0147-inject-wrap-text-into-conversation-viewer.md +0 -90
- package/docs/retro/0148-split-agent-widget-rendering.md +0 -39
- package/docs/retro/0152-add-prompt-snippet.md +0 -34
- package/docs/retro/0164-reorganize-into-domain-directories.md +0 -82
- package/docs/retro/0165-decompose-resolved-spawn-config.md +0 -78
- package/docs/retro/0166-extract-parent-session-info.md +0 -66
- package/docs/retro/0167-narrow-runner-io.md +0 -63
- package/docs/retro/0168-extract-tool-filter-config.md +0 -76
- package/docs/retro/0169-extract-run-context-from-run-options.md +0 -68
- package/docs/retro/0170-reduce-build-content-lines-complexity.md +0 -72
- package/docs/retro/0171-reduce-render-result-complexity.md +0 -77
- package/docs/retro/0172-extract-turn-formatting.md +0 -80
- package/docs/retro/0180-reorder-append-prompt-for-kv-cache.md +0 -62
- package/docs/retro/0185-remove-persistent-agent-memory.md +0 -73
- package/docs/retro/0188-replace-any-casts-with-sdk-types.md +0 -69
- package/docs/retro/0192-define-session-context-interface.md +0 -59
- package/docs/retro/0193-runtime-owns-context-queries.md +0 -75
- package/docs/retro/0194-align-tool-interfaces-for-structural-typing.md +0 -62
- package/docs/retro/0195-convert-tool-factories-to-classes.md +0 -84
- package/docs/retro/0196-convert-runner-menu-to-classes.md +0 -73
- package/docs/retro/0205-decompose-render-widget-lines.md +0 -64
- package/docs/retro/0206-decompose-show-agent-detail.md +0 -67
- package/docs/retro/0207-decompose-agent-widget-update.md +0 -92
- package/docs/retro/0208-extract-shared-test-fixtures.md +0 -102
- package/docs/retro/0214-convert-remaining-closure-factories-to-classes.md +0 -66
- package/docs/retro/0215-decompose-build-parent-context.md +0 -61
- package/docs/retro/0216-decompose-start-agent.md +0 -80
- package/docs/retro/0217-extract-overwrite-guard.md +0 -63
- package/docs/retro/0218-push-sdk-boundary-in-settings.md +0 -72
- package/docs/retro/0219-reduce-test-duplication-top-3-clone-families.md +0 -64
- package/docs/retro/0227-evolve-agent-record-into-agent.md +0 -80
- package/docs/retro/0228-async-start-agent-dissolve-run-handle.md +0 -80
- package/docs/retro/0229-agent-born-complete.md +0 -89
- package/docs/retro/0230-extract-concurrency-queue.md +0 -38
- package/docs/retro/0231-push-exec-registry-to-runner.md +0 -71
- package/docs/retro/0232-agent-resume-internal-observer-lifecycle.md +0 -109
- package/docs/retro/0237-remove-disallowed-tools.md +0 -78
- package/docs/retro/0238-remove-extensions-filtering.md +0 -72
- package/docs/retro/0239-collapse-filter-active-tools.md +0 -70
- package/docs/retro/0242-rename-agent-tool-to-subagent.md +0 -82
- package/docs/retro/0256-extract-worktree-isolation.md +0 -89
- package/docs/retro/0257-extract-child-session-factory.md +0 -33
- package/docs/retro/0262-add-workspace-provider-seam.md +0 -89
- package/docs/retro/0264-remove-extension-lifecycle-control.md +0 -91
- package/docs/retro/0265-born-complete-subagent-session.md +0 -97
- package/docs/retro/0270-type-consumable-public-surface.md +0 -108
- package/docs/retro/0272-export-workspace-collaborator-types.md +0 -38
- package/docs/retro/0277-encapsulate-agent-session.md +0 -80
- package/docs/retro/0280-rename-agent-to-subagent.md +0 -96
- package/docs/retro/0360-custom-agents-default-append.md +0 -81
- package/docs/retro/0373-extract-subagent-state.md +0 -94
- package/docs/retro/0374-encapsulate-subagent-start-notification.md +0 -171
- package/docs/retro/0375-extract-run-listener-workspace-bracket.md +0 -104
- package/docs/retro/0376-extract-manager-observer.md +0 -81
- package/docs/retro/0377-split-widget-delegation-from-runtime.md +0 -105
- package/docs/retro/0378-consolidate-lifecycle-test-fixtures.md +0 -100
- package/docs/retro/0379-consolidate-ui-tools-test-fixtures.md +0 -52
- package/docs/retro/0380-extract-layered-settings-loader.md +0 -97
- package/docs/retro/0381-replace-concurrency-queue-with-limiter.md +0 -95
- package/docs/retro/0400-include-parent-prompt-in-replace-mode.md +0 -84
- package/docs/retro/0403-abort-subagents-on-interrupt.md +0 -90
- package/docs/retro/0412-unify-session-mock-builders.md +0 -80
- package/docs/retro/0420-fold-run-metrics-live-activity-onto-record.md +0 -90
- package/docs/retro/0421-migrate-activity-readers-to-record-getters.md +0 -105
- package/docs/retro/0422-delete-activity-tracker-ui-observer.md +0 -97
- package/docs/retro/0423-widget-self-drive-from-lifecycle.md +0 -112
- package/docs/retro/0424-drop-widget-dep-from-subagent-tool.md +0 -89
- package/docs/retro/0425-reconcile-subagent-events-contract.md +0 -101
- package/docs/retro/0426-consolidate-residual-test-clone-families.md +0 -100
- package/docs/retro/0427-reconsider-ui-direction.md +0 -102
- package/docs/retro/0441-remove-agent-definition-management-subtree.md +0 -97
- package/docs/retro/0442-dissolve-agents-conversation-viewer.md +0 -108
- package/docs/retro/0443-consolidate-remaining-test-clone-families.md +0 -28
- package/docs/retro/0444-shrink-widget-to-background-agents.md +0 -81
- package/docs/retro/0445-native-session-navigation.md +0 -122
- package/docs/retro/0446-spike-session-navigation-entry-criteria.md +0 -99
- package/docs/retro/0447-extract-subagents-settings-command.md +0 -91
- package/docs/retro/0448-block-disabled-agent-spawn.md +0 -75
- package/docs/retro/0462-navigation-renderer-tui-components.md +0 -105
- package/docs/retro/0463-file-snapshot-source-evicted-agents.md +0 -103
- package/docs/retro/0470-refresh-readme-command-surface.md +0 -40
- package/src/observation/notification-state.ts +0 -27
- package/vitest.config.ts +0 -14
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
issue: 123
|
|
3
|
-
issue_title: "refactor(pi-subagents): remove vi.fn() cast smell from test helpers"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Remove vi.fn() cast smell from test helpers
|
|
7
|
-
|
|
8
|
-
## Problem Statement
|
|
9
|
-
|
|
10
|
-
Several test files construct mock objects typed to narrow interfaces (`AgentManagerLike`, `LifecycleRuntime`, `LifecycleManager`, `ToolStartRuntime`).
|
|
11
|
-
Because the returned objects are typed to the interface — not to Vitest's mock types — tests that need to configure individual method stubs are forced to cast:
|
|
12
|
-
|
|
13
|
-
```typescript
|
|
14
|
-
(deps.manager.abort as ReturnType<typeof vi.fn>).mockReturnValue(false);
|
|
15
|
-
(deps.manager.getRecord as ReturnType<typeof vi.fn>).mockReturnValue(record);
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
This silences TypeScript without constraining the call's return type — if `getRecord`'s return type changes, the cast won't catch it.
|
|
19
|
-
Nine occurrences exist across three test files.
|
|
20
|
-
|
|
21
|
-
## Goals
|
|
22
|
-
|
|
23
|
-
- Eliminate all `as ReturnType<typeof vi.fn>` casts from the test suite.
|
|
24
|
-
- Preserve type safety: mock configuration calls should be checked against the real method signatures.
|
|
25
|
-
- Keep the change minimal — this is a test hygiene fix, not a structural redesign.
|
|
26
|
-
|
|
27
|
-
## Non-Goals
|
|
28
|
-
|
|
29
|
-
- Changing `AgentManagerLike`, `LifecycleRuntime`, `LifecycleManager`, `ToolStartRuntime`, or any production code.
|
|
30
|
-
- Restructuring test layout or merging describe blocks.
|
|
31
|
-
|
|
32
|
-
## Background
|
|
33
|
-
|
|
34
|
-
The cast pattern was noted during #111 implementation and preserved to keep scope tight.
|
|
35
|
-
Issue #111 (split `AgentRecord` lifecycle state) is now closed and implemented.
|
|
36
|
-
|
|
37
|
-
### Affected files
|
|
38
|
-
|
|
39
|
-
| File | Occurrences | Interface |
|
|
40
|
-
| ---------------------------------- | ----------- | -------------------------------------- |
|
|
41
|
-
| `test/service-adapter.test.ts` | 5 | `AgentManagerLike` |
|
|
42
|
-
| `test/handlers/lifecycle.test.ts` | 2 | `LifecycleRuntime`, `LifecycleManager` |
|
|
43
|
-
| `test/handlers/tool-start.test.ts` | 2 | `ToolStartRuntime` |
|
|
44
|
-
|
|
45
|
-
### Cast sites by file
|
|
46
|
-
|
|
47
|
-
`service-adapter.test.ts` — the "steer, abort, waitForAll, hasRunning" block's `createDeps` returns `AdapterDeps` directly.
|
|
48
|
-
Five casts reconfigure `getRecord`, `abort`, or `queueSteer` after construction:
|
|
49
|
-
|
|
50
|
-
1. `(deps.manager.abort as ReturnType<typeof vi.fn>).mockReturnValue(false)`
|
|
51
|
-
2. `(deps.manager.getRecord as ReturnType<typeof vi.fn>).mockReturnValue({...})` (×4)
|
|
52
|
-
|
|
53
|
-
`lifecycle.test.ts` — mock objects are assigned to `let` variables in `beforeEach`, typed to `LifecycleRuntime` and `LifecycleManager`.
|
|
54
|
-
Two casts reconfigure methods to track call order:
|
|
55
|
-
|
|
56
|
-
1. `(runtime.setSessionContext as ReturnType<typeof vi.fn>).mockImplementation(...)`
|
|
57
|
-
2. `(manager.clearCompleted as ReturnType<typeof vi.fn>).mockImplementation(...)`
|
|
58
|
-
|
|
59
|
-
Note: the same file already uses `vi.mocked()` in the shutdown-order test — both patterns coexist, which is itself a consistency smell.
|
|
60
|
-
|
|
61
|
-
`tool-start.test.ts` — mock object assigned to a `let` variable typed to `ToolStartRuntime`.
|
|
62
|
-
Two casts reconfigure methods to track call order:
|
|
63
|
-
|
|
64
|
-
1. `(runtime.setUICtx as ReturnType<typeof vi.fn>).mockImplementation(...)`
|
|
65
|
-
2. `(runtime.onTurnStart as ReturnType<typeof vi.fn>).mockImplementation(...)`
|
|
66
|
-
|
|
67
|
-
### Approach: named-variable extraction
|
|
68
|
-
|
|
69
|
-
Extract individual `vi.fn()` stubs into named variables.
|
|
70
|
-
This is the approach the issue recommends and it aligns with the testing skill's guidance on extractable stubs.
|
|
71
|
-
|
|
72
|
-
The alternative — `vi.mocked()` — is already used in `lifecycle.test.ts` for the shutdown-order test and works for hand-built mocks, but is semantically less clean: `vi.mocked()` asserts that a value is already a mock, which is true here but opaque to readers.
|
|
73
|
-
Named variables make the mock-ness explicit at the construction site.
|
|
74
|
-
|
|
75
|
-
For `lifecycle.test.ts`, the named-variable approach also eliminates the inconsistency between the two ordering tests — one currently uses `vi.mocked()` and the other uses casts.
|
|
76
|
-
After this change both will use named stubs.
|
|
77
|
-
|
|
78
|
-
## Design Overview
|
|
79
|
-
|
|
80
|
-
### service-adapter.test.ts
|
|
81
|
-
|
|
82
|
-
Refactor the "steer, abort, waitForAll, hasRunning" block's `createDeps` to return named stubs:
|
|
83
|
-
|
|
84
|
-
```typescript
|
|
85
|
-
function createDeps(overrides: Partial<AdapterDeps> = {}) {
|
|
86
|
-
const mockGetRecord = vi.fn<AgentManagerLike["getRecord"]>();
|
|
87
|
-
const mockAbort = vi.fn<AgentManagerLike["abort"]>(() => true);
|
|
88
|
-
const mockQueueSteer = vi.fn<AgentManagerLike["queueSteer"]>(() => true);
|
|
89
|
-
|
|
90
|
-
const deps: AdapterDeps = {
|
|
91
|
-
manager: {
|
|
92
|
-
spawn: vi.fn(() => "id"),
|
|
93
|
-
getRecord: mockGetRecord,
|
|
94
|
-
listAgents: vi.fn(() => []),
|
|
95
|
-
abort: mockAbort,
|
|
96
|
-
waitForAll: vi.fn(async () => {}),
|
|
97
|
-
hasRunning: vi.fn(() => true),
|
|
98
|
-
queueSteer: mockQueueSteer,
|
|
99
|
-
},
|
|
100
|
-
resolveModel: vi.fn(),
|
|
101
|
-
getCtx: () => ({ pi: {}, ctx: {} }),
|
|
102
|
-
getModelRegistry: () => ({ find: () => null, getAll: () => [] }),
|
|
103
|
-
...overrides,
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
return { deps, mockGetRecord, mockAbort, mockQueueSteer };
|
|
107
|
-
}
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
Callers destructure what they need:
|
|
111
|
-
|
|
112
|
-
```typescript
|
|
113
|
-
const { deps, mockAbort } = createDeps();
|
|
114
|
-
mockAbort.mockReturnValue(false); // ← type-checked, no cast
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### lifecycle.test.ts
|
|
118
|
-
|
|
119
|
-
Promote the `beforeEach`-scoped `runtime` and `manager` mock construction to use named stubs.
|
|
120
|
-
The stubs that need reconfiguration (`setSessionContext`, `clearCompleted`) become named `let` variables alongside the existing `runtime`/`manager` lets, reset in `beforeEach`:
|
|
121
|
-
|
|
122
|
-
```typescript
|
|
123
|
-
let mockSetSessionContext: MockInstance<LifecycleRuntime["setSessionContext"]>;
|
|
124
|
-
let mockClearCompleted: MockInstance<LifecycleManager["clearCompleted"]>;
|
|
125
|
-
// ...assigned in beforeEach when building runtime/manager
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
Also convert the shutdown-order test's `vi.mocked()` calls to the same pattern for consistency — `unpublishService`, `clearSessionContext`, `abortAll`, `disposeNotifications`, `dispose` all become named stubs.
|
|
129
|
-
|
|
130
|
-
### tool-start.test.ts
|
|
131
|
-
|
|
132
|
-
Same pattern: promote `setUICtx` and `onTurnStart` to named `let` variables:
|
|
133
|
-
|
|
134
|
-
```typescript
|
|
135
|
-
let mockSetUICtx: MockInstance<ToolStartRuntime["setUICtx"]>;
|
|
136
|
-
let mockOnTurnStart: MockInstance<ToolStartRuntime["onTurnStart"]>;
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
## Module-Level Changes
|
|
140
|
-
|
|
141
|
-
| File | Change |
|
|
142
|
-
| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
143
|
-
| `test/service-adapter.test.ts` | Refactor `createDeps` in the "steer, abort, waitForAll, hasRunning" block to return named mock stubs alongside `deps`. Update all 5 cast sites to use named stubs. |
|
|
144
|
-
| `test/handlers/lifecycle.test.ts` | Extract `mockSetSessionContext`, `mockClearCompleted`, `mockAbortAll`, `mockDispose`, `mockClearSessionContext` as named `let` variables. Replace 2 casts and 5 `vi.mocked()` calls with named stubs. |
|
|
145
|
-
| `test/handlers/tool-start.test.ts` | Extract `mockSetUICtx` and `mockOnTurnStart` as named `let` variables. Replace 2 casts with named stubs. |
|
|
146
|
-
|
|
147
|
-
No production files are changed.
|
|
148
|
-
|
|
149
|
-
## Test Impact Analysis
|
|
150
|
-
|
|
151
|
-
1. No new tests are added — this is a refactoring of existing test infrastructure.
|
|
152
|
-
2. No tests become redundant — every existing assertion stays.
|
|
153
|
-
3. All existing tests must pass unchanged; only the mock-wiring changes.
|
|
154
|
-
|
|
155
|
-
## TDD Order
|
|
156
|
-
|
|
157
|
-
1. **Commit:** Refactor `createDeps` in `service-adapter.test.ts` to return named stubs; update all 5 cast sites.
|
|
158
|
-
All tests pass before and after.
|
|
159
|
-
Commit: `test: remove vi.fn() cast smell from service-adapter tests (#123)`
|
|
160
|
-
2. **Commit:** Extract named stubs in `lifecycle.test.ts`; replace 2 casts and 5 `vi.mocked()` calls.
|
|
161
|
-
All tests pass.
|
|
162
|
-
Commit: `test: remove vi.fn() cast smell from lifecycle tests (#123)`
|
|
163
|
-
3. **Commit:** Extract named stubs in `tool-start.test.ts`; replace 2 casts.
|
|
164
|
-
All tests pass.
|
|
165
|
-
Commit: `test: remove vi.fn() cast smell from tool-start tests (#123)`
|
|
166
|
-
|
|
167
|
-
Each step is an independent file — order doesn't matter, but one-file-per-commit keeps diffs reviewable.
|
|
168
|
-
|
|
169
|
-
## Risks and Mitigations
|
|
170
|
-
|
|
171
|
-
| Risk | Mitigation |
|
|
172
|
-
| ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
173
|
-
| Overrides via `...overrides` in `service-adapter.test.ts` could replace a manager method, leaving the named stub disconnected | Only `manager`-level overrides are spread; individual method overrides aren't used in this block. |
|
|
174
|
-
| Named stubs add return-surface to helpers | Each helper is test-local and the extra names are self-documenting. The alternative (casting) is worse. |
|
|
175
|
-
| Converting `vi.mocked()` in `lifecycle.test.ts` shutdown test expands scope slightly beyond the cast pattern | Worth it for consistency — mixing `vi.mocked()` and named stubs in the same file is a different smell. |
|
|
176
|
-
|
|
177
|
-
## Open Questions
|
|
178
|
-
|
|
179
|
-
None — the issue is fully scoped and the approach is established in the codebase.
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
issue: 131
|
|
3
|
-
issue_title: Consolidate shared test fixtures
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Consolidate shared test fixtures
|
|
7
|
-
|
|
8
|
-
## Problem Statement
|
|
9
|
-
|
|
10
|
-
Three `mockSession()` factories and three `makeDeps()` factories are duplicated across the test suite.
|
|
11
|
-
Each copy drifts independently when production interfaces change, creating maintenance burden and inconsistent mock shapes.
|
|
12
|
-
The architecture doc (Phase 8, Step F) identifies this as the first testability improvement before the IO-injection steps (G and H).
|
|
13
|
-
|
|
14
|
-
## Goals
|
|
15
|
-
|
|
16
|
-
- Extract `createMockSession()` into `test/helpers/mock-session.ts` — single source of truth for the subscribable session mock.
|
|
17
|
-
- Extract `createToolDeps()` into `test/helpers/make-deps.ts` — builds `AgentToolDeps` with sensible defaults and override support.
|
|
18
|
-
- Update all six test files to use the shared factories and remove their local copies.
|
|
19
|
-
- Keep existing test behavior unchanged — this is a pure refactor with no production code changes.
|
|
20
|
-
|
|
21
|
-
## Non-Goals
|
|
22
|
-
|
|
23
|
-
- IO injection into `session-config` (Step G, #132) — deferred.
|
|
24
|
-
- SDK boundary injection into `agent-runner` (Step H, #133) — deferred.
|
|
25
|
-
- Consolidating `makeCtx()` or `makeParams()` helpers — those are specific to each tool's parameter shape and do not share enough structure to justify extraction.
|
|
26
|
-
|
|
27
|
-
## Background
|
|
28
|
-
|
|
29
|
-
### Existing helper
|
|
30
|
-
|
|
31
|
-
`test/helpers/make-record.ts` exports `createTestRecord()`, which builds an `AgentRecord` with sensible defaults and override support.
|
|
32
|
-
It has its own unit test file (`test/helpers/make-record.test.ts`).
|
|
33
|
-
The two new factories follow the same pattern.
|
|
34
|
-
|
|
35
|
-
### `mockSession()` — 3 copies
|
|
36
|
-
|
|
37
|
-
| File | Shape |
|
|
38
|
-
| ------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
39
|
-
| `agent-manager.test.ts` | `subscribe` (vi.fn), `emit`, `dispose` (vi.fn), `steer` (vi.fn), `sessionManager` — cast as `any` |
|
|
40
|
-
| `record-observer.test.ts` | `subscribe` (vi.fn), `emit` |
|
|
41
|
-
| `ui/ui-observer.test.ts` | `subscribe` (plain fn), `emit` |
|
|
42
|
-
|
|
43
|
-
The common core is `subscribe` + `emit` (the subscribable event bus).
|
|
44
|
-
The `agent-manager` copy adds extra properties the other two don't need.
|
|
45
|
-
|
|
46
|
-
### `makeDeps()` — 3 copies
|
|
47
|
-
|
|
48
|
-
| File | Type | Manager methods | Widget methods | Extra fields |
|
|
49
|
-
| ---------------------------------- | ---------------- | -------------------------------------------------------- | ------------------------------------------- | ---------------------------- |
|
|
50
|
-
| `tools/agent-tool.test.ts` | `AgentToolDeps` | spawn, spawnAndWait, resume, getRecord, getMaxConcurrent | setUICtx, ensureTimer, update, markFinished | registry, agentDir, settings |
|
|
51
|
-
| `tools/background-spawner.test.ts` | `BackgroundDeps` | spawn, getRecord, getMaxConcurrent | ensureTimer, update | — |
|
|
52
|
-
| `tools/foreground-runner.test.ts` | `ForegroundDeps` | spawnAndWait | ensureTimer, markFinished | — |
|
|
53
|
-
|
|
54
|
-
`AgentToolDeps` is a structural superset of both `BackgroundDeps` and `ForegroundDeps`.
|
|
55
|
-
TypeScript's structural type system allows an `AgentToolDeps` value to be passed where `BackgroundDeps` or `ForegroundDeps` is expected — the narrower interfaces require a strict subset of the methods present on the wider one.
|
|
56
|
-
|
|
57
|
-
## Design Overview
|
|
58
|
-
|
|
59
|
-
### `createMockSession(overrides?)`
|
|
60
|
-
|
|
61
|
-
Returns the subscribable event bus (core shape) merged with optional overrides.
|
|
62
|
-
The core shape includes:
|
|
63
|
-
|
|
64
|
-
```typescript
|
|
65
|
-
interface MockSession {
|
|
66
|
-
subscribe: Mock<[fn: (event: any) => void], () => void>;
|
|
67
|
-
emit(event: any): void; // test-only helper, not on production Session
|
|
68
|
-
dispose: Mock;
|
|
69
|
-
steer: Mock;
|
|
70
|
-
sessionManager: { getSessionFile: Mock };
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
All fields are present in every call — callers that don't need `dispose` or `steer` simply ignore them.
|
|
75
|
-
This avoids a discriminated "minimal vs. full" shape that would reintroduce the divergence problem.
|
|
76
|
-
The `subscribe` spy is wired to a `Set<fn>` internally so `emit()` broadcasts to all subscribers, matching the existing hand-rolled pattern.
|
|
77
|
-
The return type is `MockSession & Record<string, unknown>` so call sites can pass it as `any`-typed session parameters without explicit casts.
|
|
78
|
-
|
|
79
|
-
Override support lets `agent-manager.test.ts` customize `steer` behavior or add fields:
|
|
80
|
-
|
|
81
|
-
```typescript
|
|
82
|
-
const session = createMockSession({ steer: vi.fn().mockRejectedValue(new Error("fail")) });
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### `createToolDeps(overrides?)`
|
|
86
|
-
|
|
87
|
-
Builds a full `AgentToolDeps` with mock manager, widget, activity map, registry, agent dir, and settings.
|
|
88
|
-
Accepts `Partial<AgentToolDeps>` for overrides, following the same pattern as `createTestRecord()`.
|
|
89
|
-
|
|
90
|
-
```typescript
|
|
91
|
-
function createToolDeps(overrides?: Partial<AgentToolDeps>): AgentToolDeps;
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
Consumer call sites:
|
|
95
|
-
|
|
96
|
-
```typescript
|
|
97
|
-
// agent-tool.test.ts — uses the full type directly
|
|
98
|
-
const deps = createToolDeps();
|
|
99
|
-
const tool = createAgentTool(deps);
|
|
100
|
-
|
|
101
|
-
// background-spawner.test.ts — structural typing narrows automatically
|
|
102
|
-
const deps = createToolDeps();
|
|
103
|
-
spawnBackground(deps, makeParams());
|
|
104
|
-
|
|
105
|
-
// foreground-runner.test.ts — same structural narrowing
|
|
106
|
-
const deps = createToolDeps({ manager: { spawnAndWait: vi.fn().mockResolvedValue(customRecord) } });
|
|
107
|
-
await runForeground(deps, makeParams(), undefined, undefined);
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
The background and foreground tests gain unused mock methods on `manager` and `widget`, but this is harmless — the production code's ISP compliance ensures only the narrow interface methods are called.
|
|
111
|
-
Tests that assert specific mock interactions (e.g., `expect(deps.manager.spawn).toHaveBeenCalled()`) continue to work because every method is a distinct `vi.fn()`.
|
|
112
|
-
|
|
113
|
-
When a test needs to override a single manager method, it spreads into the nested object:
|
|
114
|
-
|
|
115
|
-
```typescript
|
|
116
|
-
createToolDeps({
|
|
117
|
-
manager: { ...createToolDeps().manager, spawnAndWait: vi.fn().mockRejectedValue(err) },
|
|
118
|
-
});
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
This is slightly more verbose than today's flat override, but it happens rarely and the tradeoff is worthwhile for a single source of truth.
|
|
122
|
-
|
|
123
|
-
Alternatively, `createToolDeps` can accept a `managerOverrides` shorthand if the nested-spread pattern proves too noisy during implementation.
|
|
124
|
-
|
|
125
|
-
## Module-Level Changes
|
|
126
|
-
|
|
127
|
-
### New files
|
|
128
|
-
|
|
129
|
-
1. `test/helpers/mock-session.ts` — exports `createMockSession(overrides?)`.
|
|
130
|
-
2. `test/helpers/mock-session.test.ts` — unit tests for `createMockSession`: verifies event broadcasting, subscribe/unsubscribe, and override merging.
|
|
131
|
-
3. `test/helpers/make-deps.ts` — exports `createToolDeps(overrides?)`.
|
|
132
|
-
4. `test/helpers/make-deps.test.ts` — unit tests for `createToolDeps`: verifies default shape satisfies `AgentToolDeps`, `BackgroundDeps`, and `ForegroundDeps`; verifies override merging.
|
|
133
|
-
|
|
134
|
-
### Modified files
|
|
135
|
-
|
|
136
|
-
1. `test/agent-manager.test.ts` — remove local `mockSession()`, import `createMockSession` from helpers.
|
|
137
|
-
2. `test/record-observer.test.ts` — remove local `mockSession()`, import `createMockSession` from helpers.
|
|
138
|
-
3. `test/ui/ui-observer.test.ts` — remove local `mockSession()`, import `createMockSession` from helpers.
|
|
139
|
-
4. `test/tools/agent-tool.test.ts` — remove local `makeDeps()`, import `createToolDeps` from helpers.
|
|
140
|
-
5. `test/tools/background-spawner.test.ts` — remove local `makeDeps()`, import `createToolDeps` from helpers.
|
|
141
|
-
6. `test/tools/foreground-runner.test.ts` — remove local `makeDeps()`, import `createToolDeps` from helpers.
|
|
142
|
-
|
|
143
|
-
## Test Impact Analysis
|
|
144
|
-
|
|
145
|
-
1. The new factory unit tests (`mock-session.test.ts`, `make-deps.test.ts`) verify the shared fixture behavior that was previously only implicitly tested through the consumer test files.
|
|
146
|
-
This enables targeted debugging when a mock shape drifts from the production interface.
|
|
147
|
-
2. No existing tests become redundant — the consumer tests exercise distinct production behavior that the factory tests do not cover.
|
|
148
|
-
3. All existing tests stay as-is in terms of assertions.
|
|
149
|
-
Only the setup code (local factory → shared import) changes.
|
|
150
|
-
|
|
151
|
-
## TDD Order
|
|
152
|
-
|
|
153
|
-
1. **Red → Green: `createMockSession` factory.**
|
|
154
|
-
Write `test/helpers/mock-session.test.ts` — verify subscribe/emit broadcasting, unsubscribe, dispose/steer are vi.fn stubs, override merging.
|
|
155
|
-
Implement `test/helpers/mock-session.ts`.
|
|
156
|
-
Commit: `test: add createMockSession shared test fixture`
|
|
157
|
-
|
|
158
|
-
2. **Green: migrate `record-observer.test.ts` to `createMockSession`.**
|
|
159
|
-
Replace local `mockSession()` with import from helpers.
|
|
160
|
-
Run test file — all tests pass unchanged.
|
|
161
|
-
Commit: `test: use createMockSession in record-observer tests`
|
|
162
|
-
|
|
163
|
-
3. **Green: migrate `ui/ui-observer.test.ts` to `createMockSession`.**
|
|
164
|
-
Replace local `mockSession()` with import from helpers.
|
|
165
|
-
Run test file — all tests pass unchanged.
|
|
166
|
-
Commit: `test: use createMockSession in ui-observer tests`
|
|
167
|
-
|
|
168
|
-
4. **Green: migrate `agent-manager.test.ts` to `createMockSession`.**
|
|
169
|
-
Replace local `mockSession()` with import from helpers.
|
|
170
|
-
This file uses extra fields (`sessionManager`, `steer`, `dispose`) — verify overrides or defaults cover them.
|
|
171
|
-
Run test file — all tests pass unchanged.
|
|
172
|
-
Commit: `test: use createMockSession in agent-manager tests`
|
|
173
|
-
|
|
174
|
-
5. **Red → Green: `createToolDeps` factory.**
|
|
175
|
-
Write `test/helpers/make-deps.test.ts` — verify default shape, override merging, structural compatibility with `BackgroundDeps` and `ForegroundDeps`.
|
|
176
|
-
Implement `test/helpers/make-deps.ts`.
|
|
177
|
-
Commit: `test: add createToolDeps shared test fixture`
|
|
178
|
-
|
|
179
|
-
6. **Green: migrate `tools/agent-tool.test.ts` to `createToolDeps`.**
|
|
180
|
-
Replace local `makeDeps()` with import from helpers.
|
|
181
|
-
Run test file — all tests pass unchanged.
|
|
182
|
-
Commit: `test: use createToolDeps in agent-tool tests`
|
|
183
|
-
|
|
184
|
-
7. **Green: migrate `tools/background-spawner.test.ts` to `createToolDeps`.**
|
|
185
|
-
Replace local `makeDeps()` with import from helpers.
|
|
186
|
-
Adjust any override patterns for the wider type.
|
|
187
|
-
Run test file — all tests pass unchanged.
|
|
188
|
-
Commit: `test: use createToolDeps in background-spawner tests`
|
|
189
|
-
|
|
190
|
-
8. **Green: migrate `tools/foreground-runner.test.ts` to `createToolDeps`.**
|
|
191
|
-
Replace local `makeDeps()` with import from helpers.
|
|
192
|
-
Adjust any override patterns for the wider type.
|
|
193
|
-
Run test file — all tests pass unchanged.
|
|
194
|
-
Commit: `test: use createToolDeps in foreground-runner tests`
|
|
195
|
-
|
|
196
|
-
## Risks and Mitigations
|
|
197
|
-
|
|
198
|
-
| Risk | Mitigation |
|
|
199
|
-
| ------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
200
|
-
| Wider mock shape causes false-positive tests (tests pass even when production code calls wrong method) | The production interfaces are already ISP-narrow; the mock width only affects tests. Existing assertions on specific mock calls catch regressions. |
|
|
201
|
-
| Override merging doesn't handle nested objects (e.g., overriding a single manager method) | Factory uses shallow merge for top-level fields; document that nested overrides require spreading the default nested object. Evaluate a `managerOverrides` shorthand during implementation if the pattern is too noisy. |
|
|
202
|
-
| `createMockSession` return type is too loose (`any`) and hides type errors in tests | Return a named `MockSession` interface rather than `any`. Consumer sites that pass the mock as `any`-typed SDK parameters are already untyped at that boundary. |
|
|
203
|
-
|
|
204
|
-
## Open Questions
|
|
205
|
-
|
|
206
|
-
- Should `createToolDeps` accept a flat `managerOverrides` shorthand or require the caller to spread the nested object?
|
|
207
|
-
Decide during step 5 based on how verbose the migration turns out in steps 6–8.
|
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
issue: 132
|
|
3
|
-
issue_title: "Inject IO collaborators into `assembleSessionConfig`"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Inject IO collaborators into session-config
|
|
7
|
-
|
|
8
|
-
## Problem Statement
|
|
9
|
-
|
|
10
|
-
`assembleSessionConfig` is described as a pure configuration assembler, but it directly imports three IO-touching functions (`preloadSkills`, `buildMemoryBlock`, `buildReadOnlyMemoryBlock`) and one pure function (`buildAgentPrompt`).
|
|
11
|
-
This forces `session-config.test.ts` to use 4 `vi.mock()` calls, 8 hoisted mock functions, and assertions that verify internal call sequences rather than output properties.
|
|
12
|
-
The result is fragile tests that break on any internal restructuring even when observable behavior is unchanged.
|
|
13
|
-
|
|
14
|
-
## Goals
|
|
15
|
-
|
|
16
|
-
- Define an `AssemblerIO` interface bundling the four collaborators.
|
|
17
|
-
- Add `io: AssemblerIO` as a parameter to `assembleSessionConfig()`.
|
|
18
|
-
- Replace direct imports of the four functions with calls through `io`.
|
|
19
|
-
- Update the single production call site in `agent-runner.ts` to pass real implementations.
|
|
20
|
-
- Eliminate all 4 `vi.mock()` calls in `session-config.test.ts`.
|
|
21
|
-
- Shift test assertions toward output-property verification.
|
|
22
|
-
|
|
23
|
-
## Non-Goals
|
|
24
|
-
|
|
25
|
-
- SDK boundary injection into `agent-runner` (Step H, #133) — depends on this change but is deferred to its own issue.
|
|
26
|
-
- Consolidating shared test fixtures (#131) — independent refactor that can land before or after.
|
|
27
|
-
- Changing the behavior of `assembleSessionConfig` — this is a pure structural refactor.
|
|
28
|
-
- Injecting `getMemoryToolNames` / `getReadOnlyMemoryToolNames` — these are pure utility functions with no IO; they stay as direct imports.
|
|
29
|
-
|
|
30
|
-
## Background
|
|
31
|
-
|
|
32
|
-
### Current state
|
|
33
|
-
|
|
34
|
-
`session-config.ts` imports four functions used during assembly:
|
|
35
|
-
|
|
36
|
-
| Function | Module | IO? | Purpose in assembler |
|
|
37
|
-
| -------------------------- | ----------------- | ------------------------------ | --------------------------------------- |
|
|
38
|
-
| `preloadSkills` | `skill-loader.ts` | Yes (reads `.pi/skills` files) | Loads skill content into prompt extras |
|
|
39
|
-
| `buildMemoryBlock` | `memory.ts` | Yes (reads `MEMORY.md`) | Builds read-write memory prompt section |
|
|
40
|
-
| `buildReadOnlyMemoryBlock` | `memory.ts` | Yes (reads `MEMORY.md`) | Builds read-only memory prompt section |
|
|
41
|
-
| `buildAgentPrompt` | `prompts.ts` | No (pure) | Assembles final system prompt string |
|
|
42
|
-
|
|
43
|
-
The test file mocks all four via `vi.mock()` plus mocks `getMemoryToolNames` and `getReadOnlyMemoryToolNames` from `agent-types.ts` (pure functions that are mocked only for call-argument verification).
|
|
44
|
-
|
|
45
|
-
### Established DI pattern
|
|
46
|
-
|
|
47
|
-
`AgentManager` already injects `AgentRunner` via its constructor options — the same tell-don't-ask pattern used here.
|
|
48
|
-
`assembleSessionConfig` already receives an `AgentConfigLookup` registry by parameter (migrated in #80/#108), demonstrating the incremental injection approach.
|
|
49
|
-
|
|
50
|
-
### Architecture reference
|
|
51
|
-
|
|
52
|
-
Phase 8, Step G in `docs/architecture/architecture.md`.
|
|
53
|
-
|
|
54
|
-
### Constraints from AGENTS.md
|
|
55
|
-
|
|
56
|
-
- Keep scope tight; prefer small, reversible changes.
|
|
57
|
-
- Prefer explicit configuration over hidden behavior.
|
|
58
|
-
- Business logic should be pure functions — keep IO at the edges.
|
|
59
|
-
|
|
60
|
-
## Design Overview
|
|
61
|
-
|
|
62
|
-
### `AssemblerIO` interface
|
|
63
|
-
|
|
64
|
-
Defined in `session-config.ts` alongside the existing assembler types:
|
|
65
|
-
|
|
66
|
-
```typescript
|
|
67
|
-
export interface AssemblerIO {
|
|
68
|
-
preloadSkills: (skills: string[], cwd: string) => PreloadedSkill[];
|
|
69
|
-
buildMemoryBlock: (
|
|
70
|
-
name: string,
|
|
71
|
-
scope: MemoryScope,
|
|
72
|
-
cwd: string,
|
|
73
|
-
) => string;
|
|
74
|
-
buildReadOnlyMemoryBlock: (
|
|
75
|
-
name: string,
|
|
76
|
-
scope: MemoryScope,
|
|
77
|
-
cwd: string,
|
|
78
|
-
) => string;
|
|
79
|
-
buildAgentPrompt: (
|
|
80
|
-
config: AgentPromptConfig,
|
|
81
|
-
cwd: string,
|
|
82
|
-
env: EnvInfo,
|
|
83
|
-
parentPrompt?: string,
|
|
84
|
-
extras?: PromptExtras,
|
|
85
|
-
) => string;
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
The interface uses the same parameter types as the real functions.
|
|
90
|
-
The assembler calls `io.preloadSkills(...)` etc. instead of the direct imports.
|
|
91
|
-
|
|
92
|
-
### Call site in `agent-runner.ts`
|
|
93
|
-
|
|
94
|
-
```typescript
|
|
95
|
-
import { preloadSkills } from "./skill-loader.js";
|
|
96
|
-
import { buildMemoryBlock, buildReadOnlyMemoryBlock } from "./memory.js";
|
|
97
|
-
import { buildAgentPrompt } from "./prompts.js";
|
|
98
|
-
|
|
99
|
-
const io: AssemblerIO = {
|
|
100
|
-
preloadSkills,
|
|
101
|
-
buildMemoryBlock,
|
|
102
|
-
buildReadOnlyMemoryBlock,
|
|
103
|
-
buildAgentPrompt,
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
const cfg = assembleSessionConfig(type, ctx, options, env, registry, io);
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
The runner constructs the real IO object once and passes it through.
|
|
110
|
-
This keeps IO at the edge (runner) and makes the assembler a genuine pure function.
|
|
111
|
-
|
|
112
|
-
### Test-side stubs
|
|
113
|
-
|
|
114
|
-
Tests create a plain object with `vi.fn()` stubs satisfying `AssemblerIO`:
|
|
115
|
-
|
|
116
|
-
```typescript
|
|
117
|
-
const io: AssemblerIO = {
|
|
118
|
-
preloadSkills: vi.fn(() => []),
|
|
119
|
-
buildMemoryBlock: vi.fn(() => "memory block"),
|
|
120
|
-
buildReadOnlyMemoryBlock: vi.fn(() => "read-only memory block"),
|
|
121
|
-
buildAgentPrompt: vi.fn(() => "assembled system prompt"),
|
|
122
|
-
};
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
This replaces all four `vi.mock()` calls and the hoisted mocks for those modules.
|
|
126
|
-
|
|
127
|
-
### Pure utility functions stay as direct imports
|
|
128
|
-
|
|
129
|
-
`getMemoryToolNames` and `getReadOnlyMemoryToolNames` from `agent-types.ts` are pure functions (no IO, no filesystem access).
|
|
130
|
-
After the IO injection, the test's `vi.mock("../src/agent-types.js", ...)` can be removed and real implementations used.
|
|
131
|
-
Tests that previously controlled these mocks to verify call arguments will instead set up input tool names to produce the desired output from the real functions, then assert on the returned `SessionConfig.toolNames`.
|
|
132
|
-
|
|
133
|
-
## Module-Level Changes
|
|
134
|
-
|
|
135
|
-
### Modified files
|
|
136
|
-
|
|
137
|
-
1. `src/session-config.ts`
|
|
138
|
-
- Add `AssemblerIO` interface export.
|
|
139
|
-
- Add `io: AssemblerIO` parameter to `assembleSessionConfig()` (after `registry`).
|
|
140
|
-
- Replace `preloadSkills(...)` with `io.preloadSkills(...)`.
|
|
141
|
-
- Replace `buildMemoryBlock(...)` with `io.buildMemoryBlock(...)`.
|
|
142
|
-
- Replace `buildReadOnlyMemoryBlock(...)` with `io.buildReadOnlyMemoryBlock(...)`.
|
|
143
|
-
- Replace `buildAgentPrompt(...)` with `io.buildAgentPrompt(...)`.
|
|
144
|
-
- Remove imports of `preloadSkills`, `buildMemoryBlock`, `buildReadOnlyMemoryBlock`, `buildAgentPrompt`.
|
|
145
|
-
- Keep imports of `getMemoryToolNames`, `getReadOnlyMemoryToolNames` (pure, no change).
|
|
146
|
-
|
|
147
|
-
2. `src/agent-runner.ts`
|
|
148
|
-
- Add imports for `preloadSkills`, `buildMemoryBlock`, `buildReadOnlyMemoryBlock`, `buildAgentPrompt`.
|
|
149
|
-
- Import `AssemblerIO` type from `session-config.ts`.
|
|
150
|
-
- Construct `AssemblerIO` object from real implementations.
|
|
151
|
-
- Pass `io` to `assembleSessionConfig()`.
|
|
152
|
-
|
|
153
|
-
3. `test/session-config.test.ts`
|
|
154
|
-
- Remove all 4 `vi.mock()` calls and the corresponding hoisted mocks.
|
|
155
|
-
- Create `io` stub object with `vi.fn()` implementations.
|
|
156
|
-
- Pass `io` to every `assembleSessionConfig()` call.
|
|
157
|
-
- Update memory-section tests to use real `getMemoryToolNames` / `getReadOnlyMemoryToolNames`.
|
|
158
|
-
- Migrate mock-call assertions to output-property assertions where the output already captures the information.
|
|
159
|
-
|
|
160
|
-
## Test Impact Analysis
|
|
161
|
-
|
|
162
|
-
1. The IO injection enables testing `assembleSessionConfig` without any module mocking.
|
|
163
|
-
Tests can choose to inject real implementations with controlled inputs (integration-style) or stubs (unit-style).
|
|
164
|
-
Previously this was impossible without `vi.mock()`.
|
|
165
|
-
|
|
166
|
-
2. Several existing tests that only verified mock-call arguments become redundant once we verify the same information through output properties (e.g., "calls buildAgentPrompt with env, cwd, parentSystemPrompt, and extras" is redundant if we verify `result.systemPrompt` reflects those inputs).
|
|
167
|
-
These can be simplified or removed.
|
|
168
|
-
|
|
169
|
-
3. Tests for model resolution, isolated mode, thinking level, and unknown-type fallback stay as-is — they already assert output properties and are unaffected by the IO injection.
|
|
170
|
-
|
|
171
|
-
## TDD Order
|
|
172
|
-
|
|
173
|
-
1. **Define `AssemblerIO` and inject into `assembleSessionConfig`.**
|
|
174
|
-
Add the `AssemblerIO` interface to `session-config.ts`.
|
|
175
|
-
Add `io: AssemblerIO` as a required parameter.
|
|
176
|
-
Replace the 4 direct function calls with `io.*` calls.
|
|
177
|
-
Remove the 4 function imports from `session-config.ts`.
|
|
178
|
-
Add the 4 imports to `agent-runner.ts` and construct the `io` object at the call site.
|
|
179
|
-
Run `pnpm run check` to verify types compile.
|
|
180
|
-
Commit: `feat: inject IO collaborators into assembleSessionConfig (#132)`
|
|
181
|
-
|
|
182
|
-
2. **Migrate test file to use injected IO stubs.**
|
|
183
|
-
Create an `io` stub object with `vi.fn()` stubs matching the existing hoisted mocks' default return values.
|
|
184
|
-
Pass `io` to all `assembleSessionConfig()` calls.
|
|
185
|
-
Remove the 3 `vi.mock()` calls for `prompts.js`, `memory.js`, and `skill-loader.js`.
|
|
186
|
-
Remove the corresponding hoisted mock variables (`mockBuildAgentPrompt`, `mockBuildMemoryBlock`, `mockBuildReadOnlyMemoryBlock`, `mockPreloadSkills`).
|
|
187
|
-
Update `beforeEach` to reset the `io` stubs instead.
|
|
188
|
-
All existing tests pass with the same assertions (io stubs replace module mocks).
|
|
189
|
-
Commit: `test: replace vi.mock with injected IO stubs in session-config tests`
|
|
190
|
-
|
|
191
|
-
3. **Drop the `agent-types.js` mock; use real pure functions.**
|
|
192
|
-
Remove the `vi.mock("../src/agent-types.js", ...)` call and the `importOriginal` pattern.
|
|
193
|
-
Remove hoisted `mockGetMemoryToolNames` and `mockGetReadOnlyMemoryToolNames`.
|
|
194
|
-
Update memory-section tests to set up `mockGetToolNamesForType` return values that produce the desired output from the real `getMemoryToolNames` / `getReadOnlyMemoryToolNames`.
|
|
195
|
-
Assertions shift from "mock was called with Set" to "result.toolNames contains expected names".
|
|
196
|
-
Commit: `test: use real getMemoryToolNames in session-config tests`
|
|
197
|
-
|
|
198
|
-
4. **Shift remaining mock-call assertions to output-property checks.**
|
|
199
|
-
Replace `expect(io.buildAgentPrompt).toHaveBeenCalledWith(...)` with assertions on `result.systemPrompt` (requires io.buildAgentPrompt stub to echo identifying values).
|
|
200
|
-
Replace `expect(io.preloadSkills).toHaveBeenCalledWith(skillList, "/tmp")` with `result.extras.skillBlocks` checks (already partially present).
|
|
201
|
-
Remove test cases that are now fully redundant with output-based tests in the same describe block.
|
|
202
|
-
Clean up any unused imports and variables.
|
|
203
|
-
Commit: `test: verify output properties in session-config tests (#132)`
|
|
204
|
-
|
|
205
|
-
## Risks and Mitigations
|
|
206
|
-
|
|
207
|
-
| Risk | Mitigation |
|
|
208
|
-
| --------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
209
|
-
| Adding a parameter to `assembleSessionConfig` breaks the `agent-runner.ts` call site | Only one production call site exists; updated in the same commit (step 1). `pnpm run check` verifies. |
|
|
210
|
-
| Removing `vi.mock()` causes tests to accidentally call real IO functions | The real functions are no longer imported by `session-config.ts` after step 1. The module simply doesn't reach them. Vitest will error if any unmocked import is called. |
|
|
211
|
-
| Using real `getMemoryToolNames` / `getReadOnlyMemoryToolNames` makes tests depend on their implementation | These are pure, stable utility functions (return tool names from a set). Their behavior is well-defined and unlikely to change. Using real implementations is more robust than mocking. |
|
|
212
|
-
| Step 2 touches 40+ call sites in the test file | All changes are mechanical (add `, io` argument). A find-and-replace handles it. Each call already passes `mockAgentLookup` as the last arg; the new arg follows the same pattern. |
|
|
213
|
-
|
|
214
|
-
## Open Questions
|
|
215
|
-
|
|
216
|
-
- Should `AssemblerIO` be co-located in `session-config.ts` or extracted to a separate `session-config-types.ts`?
|
|
217
|
-
The interface is small (4 methods) and tightly coupled to the assembler.
|
|
218
|
-
Co-location in `session-config.ts` follows the existing pattern (`AssemblerContext`, `AssemblerOptions`, `SessionConfig` are all in the same file).
|
|
219
|
-
Extract only if it grows or gains consumers beyond `agent-runner.ts`.
|