@gotgenes/pi-subagents 18.0.1 → 18.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/docs/architecture/architecture.md +165 -203
  3. package/docs/architecture/history/phase-19-implement-ui-decisions.md +282 -0
  4. package/package.json +6 -7
  5. package/src/config/default-agents.ts +3 -0
  6. package/src/lifecycle/subagent.ts +25 -14
  7. package/src/observation/notification.ts +23 -10
  8. package/src/observation/subagent-events-observer.ts +1 -3
  9. package/src/runtime.ts +2 -1
  10. package/src/service/service-adapter.ts +20 -17
  11. package/src/session/model-resolver.ts +31 -30
  12. package/src/tools/agent-tool.ts +17 -13
  13. package/src/tools/get-result-report.ts +60 -0
  14. package/src/tools/get-result-tool.ts +25 -40
  15. package/src/tools/helpers.ts +21 -5
  16. package/src/tools/spawn-config.ts +5 -5
  17. package/src/tools/steer-tool.ts +37 -27
  18. package/src/types.ts +4 -1
  19. package/src/ui/session-navigator.ts +0 -2
  20. package/.prettierignore +0 -5
  21. package/AGENTS.md +0 -7
  22. package/docs/plans/0048-implement-subagents-api.md +0 -304
  23. package/docs/plans/0049-remove-group-join-output-file-rpc.md +0 -180
  24. package/docs/plans/0051-update-adr-0001-hard-fork.md +0 -77
  25. package/docs/plans/0052-remove-scheduled-subagents.md +0 -133
  26. package/docs/plans/0053-extract-model-resolution-from-execute.md +0 -181
  27. package/docs/plans/0054-decompose-index-into-modules.md +0 -302
  28. package/docs/plans/0057-structured-debug-logging.md +0 -154
  29. package/docs/plans/0061-session-format-transcript.md +0 -284
  30. package/docs/plans/0066-replace-as-any-with-sdk-types.md +0 -215
  31. package/docs/plans/0069-create-subagent-runtime.md +0 -345
  32. package/docs/plans/0070-extract-event-handlers.md +0 -306
  33. package/docs/plans/0071-extract-session-config-assembler.md +0 -362
  34. package/docs/plans/0072-inject-agent-manager-collaborators.md +0 -329
  35. package/docs/plans/0076-inject-cwd-into-agent-manager.md +0 -102
  36. package/docs/plans/0077-inject-project-agents-dir.md +0 -115
  37. package/docs/plans/0080-consolidate-agent-config-lookup.md +0 -247
  38. package/docs/plans/0084-extract-git-worktree-manager.md +0 -142
  39. package/docs/plans/0087-evolve-subagent-runtime-methods.md +0 -240
  40. package/docs/plans/0098-extract-agent-record-state-machine.md +0 -435
  41. package/docs/plans/0099-replace-ctx-with-parent-snapshot.md +0 -488
  42. package/docs/plans/0100-replace-callback-threading-with-session-subscription.md +0 -454
  43. package/docs/plans/0102-consolidate-test-record-factory.md +0 -176
  44. package/docs/plans/0108-extract-agent-type-registry.md +0 -322
  45. package/docs/plans/0109-extract-settings-manager.md +0 -276
  46. package/docs/plans/0110-agent-activity-tracker.md +0 -297
  47. package/docs/plans/0111-split-agent-record-lifecycle.md +0 -582
  48. package/docs/plans/0112-replace-agent-manager-callbacks.md +0 -241
  49. package/docs/plans/0113-disambiguate-spawn-options.md +0 -155
  50. package/docs/plans/0114-narrow-agent-tool-menu-deps.md +0 -279
  51. package/docs/plans/0115-decompose-agent-tool.md +0 -337
  52. package/docs/plans/0116-type-housekeeping.md +0 -351
  53. package/docs/plans/0118-settings-manager-apply-methods.md +0 -271
  54. package/docs/plans/0123-remove-vi-fn-cast-smell.md +0 -179
  55. package/docs/plans/0131-consolidate-shared-test-fixtures.md +0 -207
  56. package/docs/plans/0132-inject-io-into-session-config.md +0 -219
  57. package/docs/plans/0133-inject-sdk-boundary-into-agent-runner.md +0 -373
  58. package/docs/plans/0134-reduce-as-any-casts.md +0 -366
  59. package/docs/plans/0135-extract-display-helpers.md +0 -182
  60. package/docs/plans/0136-decompose-agent-menu.md +0 -300
  61. package/docs/plans/0144-consolidate-observation-model.md +0 -263
  62. package/docs/plans/0145-decompose-execute-push-ctx-to-boundary.md +0 -290
  63. package/docs/plans/0146-narrow-ui-context.md +0 -319
  64. package/docs/plans/0147-inject-wrap-text-into-conversation-viewer.md +0 -166
  65. package/docs/plans/0148-split-agent-widget-rendering.md +0 -255
  66. package/docs/plans/0152-add-prompt-snippet.md +0 -91
  67. package/docs/plans/0164-reorganize-into-domain-directories.md +0 -409
  68. package/docs/plans/0165-decompose-resolved-spawn-config.md +0 -157
  69. package/docs/plans/0166-extract-parent-session-info.md +0 -231
  70. package/docs/plans/0167-narrow-runner-io.md +0 -150
  71. package/docs/plans/0168-extract-tool-filter-config.md +0 -173
  72. package/docs/plans/0169-extract-run-context-from-run-options.md +0 -194
  73. package/docs/plans/0170-reduce-build-content-lines-complexity.md +0 -225
  74. package/docs/plans/0171-reduce-render-result-complexity.md +0 -200
  75. package/docs/plans/0172-extract-turn-formatting.md +0 -206
  76. package/docs/plans/0180-reorder-append-prompt-for-kv-cache.md +0 -100
  77. package/docs/plans/0185-remove-persistent-agent-memory.md +0 -161
  78. package/docs/plans/0188-replace-any-casts-with-sdk-types.md +0 -162
  79. package/docs/plans/0192-define-session-context-interface.md +0 -107
  80. package/docs/plans/0193-runtime-owns-context-queries.md +0 -245
  81. package/docs/plans/0194-align-tool-interfaces-for-structural-typing.md +0 -139
  82. package/docs/plans/0195-convert-tool-factories-to-classes.md +0 -264
  83. package/docs/plans/0196-convert-runner-menu-to-classes.md +0 -268
  84. package/docs/plans/0205-decompose-render-widget-lines.md +0 -140
  85. package/docs/plans/0206-decompose-show-agent-detail.md +0 -211
  86. package/docs/plans/0207-decompose-agent-widget-update.md +0 -242
  87. package/docs/plans/0208-extract-shared-test-fixtures.md +0 -298
  88. package/docs/plans/0214-convert-remaining-closure-factories-to-classes.md +0 -261
  89. package/docs/plans/0215-decompose-build-parent-context.md +0 -166
  90. package/docs/plans/0216-decompose-start-agent.md +0 -255
  91. package/docs/plans/0217-extract-overwrite-guard.md +0 -176
  92. package/docs/plans/0218-push-sdk-boundary-in-settings.md +0 -172
  93. package/docs/plans/0219-reduce-test-duplication-top-3-clone-families.md +0 -162
  94. package/docs/plans/0227-evolve-agent-record-into-agent.md +0 -322
  95. package/docs/plans/0228-async-start-agent-dissolve-run-handle.md +0 -288
  96. package/docs/plans/0229-agent-born-complete.md +0 -564
  97. package/docs/plans/0230-extract-concurrency-queue.md +0 -265
  98. package/docs/plans/0231-push-exec-registry-to-runner.md +0 -245
  99. package/docs/plans/0232-agent-resume-internal-observer-lifecycle.md +0 -180
  100. package/docs/plans/0237-remove-disallowed-tools.md +0 -180
  101. package/docs/plans/0238-remove-extensions-filtering.md +0 -191
  102. package/docs/plans/0239-collapse-filter-active-tools.md +0 -217
  103. package/docs/plans/0242-rename-agent-tool-to-subagent.md +0 -165
  104. package/docs/plans/0256-extract-worktree-isolation.md +0 -256
  105. package/docs/plans/0257-extract-child-session-factory.md +0 -285
  106. package/docs/plans/0262-add-workspace-provider-seam.md +0 -264
  107. package/docs/plans/0264-remove-extension-lifecycle-control.md +0 -277
  108. package/docs/plans/0265-born-complete-subagent-session.md +0 -333
  109. package/docs/plans/0270-type-consumable-public-surface.md +0 -204
  110. package/docs/plans/0272-export-workspace-collaborator-types.md +0 -147
  111. package/docs/plans/0277-encapsulate-agent-session.md +0 -304
  112. package/docs/plans/0280-rename-agent-to-subagent.md +0 -197
  113. package/docs/plans/0360-custom-agents-default-append.md +0 -132
  114. package/docs/plans/0373-extract-subagent-state.md +0 -250
  115. package/docs/plans/0374-encapsulate-subagent-start-notification.md +0 -268
  116. package/docs/plans/0375-extract-run-listener-workspace-bracket.md +0 -300
  117. package/docs/plans/0376-extract-manager-observer.md +0 -232
  118. package/docs/plans/0377-split-widget-delegation-from-runtime.md +0 -254
  119. package/docs/plans/0378-consolidate-lifecycle-test-fixtures.md +0 -243
  120. package/docs/plans/0379-consolidate-ui-tools-test-fixtures.md +0 -335
  121. package/docs/plans/0380-extract-layered-settings-loader.md +0 -223
  122. package/docs/plans/0381-replace-concurrency-queue-with-limiter.md +0 -267
  123. package/docs/plans/0400-include-parent-prompt-in-replace-mode.md +0 -199
  124. package/docs/plans/0403-abort-subagents-on-interrupt.md +0 -180
  125. package/docs/plans/0412-unify-session-mock-builders.md +0 -146
  126. package/docs/plans/0420-fold-run-metrics-live-activity-onto-record.md +0 -228
  127. package/docs/plans/0421-migrate-activity-readers-to-record-getters.md +0 -309
  128. package/docs/plans/0422-delete-activity-tracker-ui-observer.md +0 -204
  129. package/docs/plans/0423-widget-self-drive-from-lifecycle.md +0 -264
  130. package/docs/plans/0424-drop-widget-dep-from-subagent-tool.md +0 -166
  131. package/docs/plans/0425-reconcile-subagent-events-contract.md +0 -144
  132. package/docs/plans/0426-consolidate-residual-test-clone-families.md +0 -235
  133. package/docs/plans/0427-reconsider-ui-direction.md +0 -212
  134. package/docs/plans/0441-remove-agent-definition-management-subtree.md +0 -180
  135. package/docs/plans/0442-dissolve-agents-conversation-viewer.md +0 -195
  136. package/docs/plans/0443-consolidate-remaining-test-clone-families.md +0 -268
  137. package/docs/plans/0444-shrink-widget-to-background-agents.md +0 -156
  138. package/docs/plans/0445-native-session-navigation.md +0 -365
  139. package/docs/plans/0446-spike-session-navigation-entry-criteria.md +0 -171
  140. package/docs/plans/0447-extract-subagents-settings-command.md +0 -220
  141. package/docs/plans/0448-block-disabled-agent-spawn.md +0 -207
  142. package/docs/plans/0462-navigation-renderer-tui-components.md +0 -338
  143. package/docs/plans/0463-file-snapshot-source-evicted-agents.md +0 -306
  144. package/docs/plans/0470-refresh-readme-command-surface.md +0 -159
  145. package/docs/retro/0048-implement-subagents-api.md +0 -44
  146. package/docs/retro/0049-remove-group-join-output-file-rpc.md +0 -49
  147. package/docs/retro/0051-update-adr-0001-hard-fork.md +0 -39
  148. package/docs/retro/0053-extract-model-resolution-from-execute.md +0 -40
  149. package/docs/retro/0054-decompose-index-into-modules.md +0 -53
  150. package/docs/retro/0057-structured-debug-logging.md +0 -77
  151. package/docs/retro/0061-session-format-transcript.md +0 -41
  152. package/docs/retro/0066-replace-as-any-with-sdk-types.md +0 -44
  153. package/docs/retro/0069-create-subagent-runtime.md +0 -43
  154. package/docs/retro/0070-extract-event-handlers.md +0 -49
  155. package/docs/retro/0071-extract-session-config-assembler.md +0 -60
  156. package/docs/retro/0072-inject-agent-manager-collaborators.md +0 -46
  157. package/docs/retro/0076-inject-cwd-into-agent-manager.md +0 -35
  158. package/docs/retro/0077-inject-project-agents-dir.md +0 -33
  159. package/docs/retro/0080-consolidate-agent-config-lookup.md +0 -35
  160. package/docs/retro/0084-extract-git-worktree-manager.md +0 -37
  161. package/docs/retro/0087-evolve-subagent-runtime-methods.md +0 -42
  162. package/docs/retro/0098-extract-agent-record-state-machine.md +0 -46
  163. package/docs/retro/0099-replace-ctx-with-parent-snapshot.md +0 -37
  164. package/docs/retro/0100-replace-callback-threading-with-session-subscription.md +0 -36
  165. package/docs/retro/0102-consolidate-test-record-factory.md +0 -30
  166. package/docs/retro/0108-extract-agent-type-registry.md +0 -41
  167. package/docs/retro/0109-extract-settings-manager.md +0 -55
  168. package/docs/retro/0110-agent-activity-tracker.md +0 -44
  169. package/docs/retro/0111-split-agent-record-lifecycle.md +0 -61
  170. package/docs/retro/0112-replace-agent-manager-callbacks.md +0 -35
  171. package/docs/retro/0113-disambiguate-spawn-options.md +0 -29
  172. package/docs/retro/0114-narrow-agent-tool-menu-deps.md +0 -38
  173. package/docs/retro/0115-decompose-agent-tool.md +0 -51
  174. package/docs/retro/0116-type-housekeeping.md +0 -42
  175. package/docs/retro/0118-settings-manager-apply-methods.md +0 -40
  176. package/docs/retro/0123-remove-vi-fn-cast-smell.md +0 -49
  177. package/docs/retro/0131-consolidate-shared-test-fixtures.md +0 -46
  178. package/docs/retro/0132-inject-io-into-session-config.md +0 -33
  179. package/docs/retro/0133-inject-sdk-boundary-into-agent-runner.md +0 -45
  180. package/docs/retro/0134-reduce-as-any-casts.md +0 -56
  181. package/docs/retro/0135-extract-display-helpers.md +0 -38
  182. package/docs/retro/0136-decompose-agent-menu.md +0 -43
  183. package/docs/retro/0144-consolidate-observation-model.md +0 -39
  184. package/docs/retro/0145-decompose-execute-push-ctx-to-boundary.md +0 -56
  185. package/docs/retro/0146-narrow-ui-context.md +0 -70
  186. package/docs/retro/0147-inject-wrap-text-into-conversation-viewer.md +0 -90
  187. package/docs/retro/0148-split-agent-widget-rendering.md +0 -39
  188. package/docs/retro/0152-add-prompt-snippet.md +0 -34
  189. package/docs/retro/0164-reorganize-into-domain-directories.md +0 -82
  190. package/docs/retro/0165-decompose-resolved-spawn-config.md +0 -78
  191. package/docs/retro/0166-extract-parent-session-info.md +0 -66
  192. package/docs/retro/0167-narrow-runner-io.md +0 -63
  193. package/docs/retro/0168-extract-tool-filter-config.md +0 -76
  194. package/docs/retro/0169-extract-run-context-from-run-options.md +0 -68
  195. package/docs/retro/0170-reduce-build-content-lines-complexity.md +0 -72
  196. package/docs/retro/0171-reduce-render-result-complexity.md +0 -77
  197. package/docs/retro/0172-extract-turn-formatting.md +0 -80
  198. package/docs/retro/0180-reorder-append-prompt-for-kv-cache.md +0 -62
  199. package/docs/retro/0185-remove-persistent-agent-memory.md +0 -73
  200. package/docs/retro/0188-replace-any-casts-with-sdk-types.md +0 -69
  201. package/docs/retro/0192-define-session-context-interface.md +0 -59
  202. package/docs/retro/0193-runtime-owns-context-queries.md +0 -75
  203. package/docs/retro/0194-align-tool-interfaces-for-structural-typing.md +0 -62
  204. package/docs/retro/0195-convert-tool-factories-to-classes.md +0 -84
  205. package/docs/retro/0196-convert-runner-menu-to-classes.md +0 -73
  206. package/docs/retro/0205-decompose-render-widget-lines.md +0 -64
  207. package/docs/retro/0206-decompose-show-agent-detail.md +0 -67
  208. package/docs/retro/0207-decompose-agent-widget-update.md +0 -92
  209. package/docs/retro/0208-extract-shared-test-fixtures.md +0 -102
  210. package/docs/retro/0214-convert-remaining-closure-factories-to-classes.md +0 -66
  211. package/docs/retro/0215-decompose-build-parent-context.md +0 -61
  212. package/docs/retro/0216-decompose-start-agent.md +0 -80
  213. package/docs/retro/0217-extract-overwrite-guard.md +0 -63
  214. package/docs/retro/0218-push-sdk-boundary-in-settings.md +0 -72
  215. package/docs/retro/0219-reduce-test-duplication-top-3-clone-families.md +0 -64
  216. package/docs/retro/0227-evolve-agent-record-into-agent.md +0 -80
  217. package/docs/retro/0228-async-start-agent-dissolve-run-handle.md +0 -80
  218. package/docs/retro/0229-agent-born-complete.md +0 -89
  219. package/docs/retro/0230-extract-concurrency-queue.md +0 -38
  220. package/docs/retro/0231-push-exec-registry-to-runner.md +0 -71
  221. package/docs/retro/0232-agent-resume-internal-observer-lifecycle.md +0 -109
  222. package/docs/retro/0237-remove-disallowed-tools.md +0 -78
  223. package/docs/retro/0238-remove-extensions-filtering.md +0 -72
  224. package/docs/retro/0239-collapse-filter-active-tools.md +0 -70
  225. package/docs/retro/0242-rename-agent-tool-to-subagent.md +0 -82
  226. package/docs/retro/0256-extract-worktree-isolation.md +0 -89
  227. package/docs/retro/0257-extract-child-session-factory.md +0 -33
  228. package/docs/retro/0262-add-workspace-provider-seam.md +0 -89
  229. package/docs/retro/0264-remove-extension-lifecycle-control.md +0 -91
  230. package/docs/retro/0265-born-complete-subagent-session.md +0 -97
  231. package/docs/retro/0270-type-consumable-public-surface.md +0 -108
  232. package/docs/retro/0272-export-workspace-collaborator-types.md +0 -38
  233. package/docs/retro/0277-encapsulate-agent-session.md +0 -80
  234. package/docs/retro/0280-rename-agent-to-subagent.md +0 -96
  235. package/docs/retro/0360-custom-agents-default-append.md +0 -81
  236. package/docs/retro/0373-extract-subagent-state.md +0 -94
  237. package/docs/retro/0374-encapsulate-subagent-start-notification.md +0 -171
  238. package/docs/retro/0375-extract-run-listener-workspace-bracket.md +0 -104
  239. package/docs/retro/0376-extract-manager-observer.md +0 -81
  240. package/docs/retro/0377-split-widget-delegation-from-runtime.md +0 -105
  241. package/docs/retro/0378-consolidate-lifecycle-test-fixtures.md +0 -100
  242. package/docs/retro/0379-consolidate-ui-tools-test-fixtures.md +0 -52
  243. package/docs/retro/0380-extract-layered-settings-loader.md +0 -97
  244. package/docs/retro/0381-replace-concurrency-queue-with-limiter.md +0 -95
  245. package/docs/retro/0400-include-parent-prompt-in-replace-mode.md +0 -84
  246. package/docs/retro/0403-abort-subagents-on-interrupt.md +0 -90
  247. package/docs/retro/0412-unify-session-mock-builders.md +0 -80
  248. package/docs/retro/0420-fold-run-metrics-live-activity-onto-record.md +0 -90
  249. package/docs/retro/0421-migrate-activity-readers-to-record-getters.md +0 -105
  250. package/docs/retro/0422-delete-activity-tracker-ui-observer.md +0 -97
  251. package/docs/retro/0423-widget-self-drive-from-lifecycle.md +0 -112
  252. package/docs/retro/0424-drop-widget-dep-from-subagent-tool.md +0 -89
  253. package/docs/retro/0425-reconcile-subagent-events-contract.md +0 -101
  254. package/docs/retro/0426-consolidate-residual-test-clone-families.md +0 -100
  255. package/docs/retro/0427-reconsider-ui-direction.md +0 -102
  256. package/docs/retro/0441-remove-agent-definition-management-subtree.md +0 -97
  257. package/docs/retro/0442-dissolve-agents-conversation-viewer.md +0 -108
  258. package/docs/retro/0443-consolidate-remaining-test-clone-families.md +0 -28
  259. package/docs/retro/0444-shrink-widget-to-background-agents.md +0 -81
  260. package/docs/retro/0445-native-session-navigation.md +0 -122
  261. package/docs/retro/0446-spike-session-navigation-entry-criteria.md +0 -99
  262. package/docs/retro/0447-extract-subagents-settings-command.md +0 -91
  263. package/docs/retro/0448-block-disabled-agent-spawn.md +0 -75
  264. package/docs/retro/0462-navigation-renderer-tui-components.md +0 -105
  265. package/docs/retro/0463-file-snapshot-source-evicted-agents.md +0 -103
  266. package/docs/retro/0470-refresh-readme-command-surface.md +0 -40
  267. package/src/observation/notification-state.ts +0 -27
  268. package/vitest.config.ts +0 -14
@@ -1,166 +0,0 @@
1
- ---
2
- issue: 147
3
- issue_title: "Inject text wrapping into ConversationViewer (Phase 9, Step O)"
4
- ---
5
-
6
- # Inject text wrapping into ConversationViewer
7
-
8
- ## Problem Statement
9
-
10
- `ConversationViewer` calls `wrapTextWithAnsi` directly from `@earendil-works/pi-tui` in four places inside `buildContentLines`.
11
- Because the function is a module-level binding, tests must intercept it via a hoisted `vi.mock("@earendil-works/pi-tui")` factory that replaces the entire TUI module.
12
- This is the last `vi.mock` on an SDK module in the test suite, added specifically to exercise the overwidth-clamping safety net.
13
-
14
- ## Goals
15
-
16
- - Accept `wrapText: (text: string, width: number) => string[]` via `ConversationViewerOptions`.
17
- - Destructure `ConversationViewerOptions` in the constructor signature (dependency bag convention).
18
- - Replace all four `wrapTextWithAnsi` calls in `buildContentLines` with `this.wrapText`.
19
- - Remove `wrapTextWithAnsi` from `conversation-viewer.ts`'s `@earendil-works/pi-tui` import.
20
- - Pass `wrapTextWithAnsi` at the production call site in `agent-menu.ts`.
21
- - Eliminate the hoisted `vi.mock("@earendil-works/pi-tui")` from `conversation-viewer.test.ts`.
22
-
23
- ## Non-Goals
24
-
25
- - Injecting `truncateToWidth` or any other TUI function (only `wrapTextWithAnsi` is relevant here).
26
- - Changing the overwidth-clamping behavior of `buildContentLines`.
27
- - Touching `agent-widget.ts` (tracked separately as Issue #148, Step P — already closed).
28
-
29
- ## Background
30
-
31
- `ui/conversation-viewer.ts` is the live conversation overlay rendered when a user selects an agent in the `/agents` menu.
32
- Its `buildContentLines` method formats messages from the agent session into displayable lines, calling `wrapTextWithAnsi` to soft-wrap text to the available terminal width.
33
-
34
- The overwidth-clamping safety net (`truncateToWidth` applied after `wrapTextWithAnsi`) exists because a prior upstream bug returned lines wider than the requested width.
35
- The `vi.mock` in the test is the mechanism for simulating that bug by returning overwidth strings from `wrapTextWithAnsi`.
36
-
37
- The only production call site for `new ConversationViewer(...)` is in the `viewAgentConversation` closure inside `createAgentsMenuHandler` in `ui/agent-menu.ts`.
38
-
39
- Architecture reference: `docs/architecture/architecture.md` § Phase 9, Step O.
40
-
41
- ## Design Overview
42
-
43
- ### `ConversationViewerOptions` — add `wrapText`
44
-
45
- ```typescript
46
- export interface ConversationViewerOptions {
47
- tui: TUI;
48
- session: AgentSession;
49
- record: AgentRecord;
50
- activity: AgentActivityTracker | undefined;
51
- theme: Theme;
52
- done: (result: undefined) => void;
53
- registry: AgentConfigLookup;
54
- wrapText: (text: string, width: number) => string[];
55
- }
56
- ```
57
-
58
- The field is **required** — it must be supplied at every construction site.
59
- No default is provided; the default would be an invisible SDK dependency hidden inside the class.
60
-
61
- ### Constructor destructuring
62
-
63
- The constructor adopts the dependency bag convention — destructure the options object rather than accessing via `options.*`:
64
-
65
- ```typescript
66
- constructor({
67
- tui, session, record, activity, theme, done, registry, wrapText,
68
- }: ConversationViewerOptions) {
69
- this.tui = tui;
70
- this.session = session;
71
- // … etc.
72
- this.wrapText = wrapText;
73
- this.unsubscribe = session.subscribe(() => { … });
74
- }
75
- ```
76
-
77
- ### Production wiring — `agent-menu.ts`
78
-
79
- `agent-menu.ts` statically imports `wrapTextWithAnsi` from `@earendil-works/pi-tui` and passes it when constructing `ConversationViewer`:
80
-
81
- ```typescript
82
- import { wrapTextWithAnsi } from "@earendil-works/pi-tui";
83
- // …
84
- return new ConversationViewer({
85
- tui, session, record, activity, theme, done, registry,
86
- wrapText: wrapTextWithAnsi,
87
- });
88
- ```
89
-
90
- Adding `wrapText` to `AgentMenuDeps` and threading it through the closure would violate the Law of Demeter — `AgentMenuDeps` has no conceptual ownership of a text-wrapping function.
91
- The `viewAgentConversation` closure is the direct consumer; the import belongs there.
92
-
93
- ### Test strategy
94
-
95
- After DI, tests pass `wrapText` directly in `ConversationViewerOptions`:
96
-
97
- - **"render width safety" tests**: pass `wrapText: wrapTextWithAnsi` (real function, statically imported — no mock).
98
- - **"safety net" tests**: pass a stub `wrapText: () => ["X".repeat(width + 50)]` inline in options — no `vi.mock` needed.
99
- - The "mock is intercepting wrapTextWithAnsi" test is removed (it verified the mock mechanism, not viewer behavior).
100
- - The module-level `wrapOverride` variable and the `vi.mock` block are removed entirely.
101
- - The `await import("@earendil-works/pi-tui")` and `await import("../src/ui/conversation-viewer.js")` dynamic imports are converted to ordinary top-level `import` statements.
102
-
103
- ## Module-Level Changes
104
-
105
- | File | Change |
106
- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
107
- | `src/ui/conversation-viewer.ts` | Add `wrapText` field to `ConversationViewerOptions`; add `private wrapText` field; destructure options in constructor; replace 4× `wrapTextWithAnsi(...)` with `this.wrapText(...)`; remove `wrapTextWithAnsi` from the `@earendil-works/pi-tui` import line |
108
- | `src/ui/agent-menu.ts` | Add `import { wrapTextWithAnsi } from "@earendil-works/pi-tui"`; pass `wrapText: wrapTextWithAnsi` in `viewAgentConversation` |
109
- | `test/conversation-viewer.test.ts` | Convert top-level dynamic `await import()` to static imports; remove `vi.mock`, `wrapOverride`, and "mock is intercepting" test; add `wrapText` to every `new ConversationViewer({…})` call; update safety-net tests to pass inline stub `wrapText` |
110
-
111
- No symbols are removed from exported API (`ConversationViewerOptions`, `ConversationViewer`, `VIEWPORT_HEIGHT_PCT` all remain).
112
- The `wrapText` addition to `ConversationViewerOptions` is a breaking change for any external consumers that construct `ConversationViewer` — check for usages outside this package.
113
-
114
- Grep check: `ConversationViewer` appears only in `src/ui/conversation-viewer.ts`, `src/ui/agent-menu.ts`, and `test/conversation-viewer.test.ts` — no other files construct it.
115
-
116
- ## Test Impact Analysis
117
-
118
- 1. **New unit-test capability**: The safety-net tests can now inject exactly the stub they need without patching a module.
119
- Each test is self-contained and immediately legible — the stub is declared inline at the call site.
120
-
121
- 2. **Tests that become redundant**: The "mock is intercepting wrapTextWithAnsi" test verified the test mechanism, not production behavior.
122
- It is deleted.
123
- The `wrapOverride` reset in `beforeEach` is no longer needed.
124
-
125
- 3. **Tests that stay**: All "render width safety" tests and all overwidth-clamping tests remain; they exercise real viewer behavior with real or controlled inputs.
126
-
127
- ## TDD Order
128
-
129
- ### Cycle 1 — Add `wrapText` field and update production wiring
130
-
131
- 1. **Red**: Update one `new ConversationViewer({…})` in the test to include `wrapText: vi.fn()` — TypeScript rejects the unknown field.
132
- 2. **Green**:
133
- - Add `wrapText: (text: string, width: number) => string[]` to `ConversationViewerOptions`.
134
- - Add `private wrapText: (text: string, width: number) => string[]` field to the class.
135
- - Destructure options in the constructor; assign `this.wrapText = wrapText`.
136
- - Replace all four `wrapTextWithAnsi(...)` calls with `this.wrapText(...)` in `buildContentLines`.
137
- - Remove `wrapTextWithAnsi` from the `@earendil-works/pi-tui` import in `conversation-viewer.ts`.
138
- - In `agent-menu.ts`: add static import of `wrapTextWithAnsi` from `@earendil-works/pi-tui`; pass `wrapText: wrapTextWithAnsi`.
139
- - Update **all** `new ConversationViewer({…})` calls in `conversation-viewer.test.ts` to include `wrapText`.
140
- "Render width safety" tests pass `wrapText: wrapTextWithAnsi` (real function, still imported via the existing `vi.mock` shim for now).
141
- Safety-net tests pass a stub inline: `wrapText: () => ["X".repeat(w + 50)]`.
142
- - Delete the "mock is intercepting wrapTextWithAnsi" test.
143
- 3. **Verify**: `pnpm vitest run test/conversation-viewer.test.ts` passes.
144
- 4. **Commit**: `feat: inject wrapText into ConversationViewer (Phase 9, Step O) (#147)`
145
-
146
- ### Cycle 2 — Remove the module mock
147
-
148
- 1. **Red**: Remove the `vi.mock("@earendil-works/pi-tui", …)` block, the `wrapOverride` variable, and the `beforeEach(() => { wrapOverride = null; })` reset.
149
- Convert `const { visibleWidth } = await import("@earendil-works/pi-tui")` to `import { visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui"`.
150
- Convert `const { ConversationViewer } = await import("../src/ui/conversation-viewer.js")` to `import { ConversationViewer } from "../src/ui/conversation-viewer.js"`.
151
- Run tests — they should still pass (the mock was no longer needed after Cycle 1).
152
- 2. **Green**: Tests pass without any module mock.
153
- 3. **Verify**: `pnpm vitest run test/conversation-viewer.test.ts` and `pnpm run check` both pass.
154
- 4. **Commit**: `refactor: remove vi.mock from conversation-viewer tests (#147)`
155
-
156
- ## Risks and Mitigations
157
-
158
- | Risk | Mitigation |
159
- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
160
- | Missing a `new ConversationViewer({…})` call site in tests | Grep confirms only `test/conversation-viewer.test.ts` constructs the viewer; all instances are in-file |
161
- | TypeScript missing the `private wrapText` field type | Use `pnpm run check` after Cycle 1 to verify no type errors |
162
- | The dynamic `await import()` pattern in tests was necessary for some other reason | The only purpose was to run after `vi.mock` hoisting; once the mock is gone, static imports work fine |
163
-
164
- ## Open Questions
165
-
166
- None — the issue's "Changes" section is unambiguous and the call-site inventory is small.
@@ -1,255 +0,0 @@
1
- ---
2
- issue: 148
3
- issue_title: "Split AgentWidget rendering from lifecycle (Phase 9, Step P)"
4
- ---
5
-
6
- # Split AgentWidget rendering from lifecycle
7
-
8
- ## Problem Statement
9
-
10
- `AgentWidget` (374 lines) mixes rendering, lifecycle management, spinner animation, state filtering, and status bar management in a single class.
11
- `renderWidget` alone is ~109 lines, and `renderFinishedLine` adds another ~40.
12
- The constructor takes 3 concrete collaborators (`AgentManager`, `Map<string, AgentActivityTracker>`, `AgentTypeRegistry`) with no interface extraction.
13
- Rendering logic cannot be unit-tested without instantiating the full widget with its lifecycle machinery.
14
-
15
- ## Goals
16
-
17
- - Extract pure rendering functions from `AgentWidget` into `ui/widget-renderer.ts`.
18
- - Make `AgentWidget` a thin lifecycle/polling wrapper that delegates to pure render functions.
19
- - Enable direct unit testing of rendering logic with plain data — no widget lifecycle, no mocks for `setInterval`/`setWidget`/`requestRender`.
20
-
21
- ## Non-Goals
22
-
23
- - Changing the visual output of the widget (this is a pure refactor).
24
- - Extracting the status bar logic into a separate module (could follow up).
25
- - Narrowing the `AgentManager` dependency to an interface (tracked separately in the architecture doc).
26
- - Injecting `truncateToWidth` (tracked as #147, Step O — an independent track).
27
-
28
- ## Background
29
-
30
- ### Dependency: #144 (Step L) — Consolidate observation model
31
-
32
- Issue #144 is **closed/implemented**.
33
- The renderer now reads stats (`toolUses`, `lifetimeUsage`, `compactionCount`) from `AgentRecord` and live UI state (`activeTools`, `responseText`, `turnCount`, `maxTurns`) from `AgentActivityTracker`.
34
- No dual-counting fallback exists.
35
-
36
- ### Existing pure helpers
37
-
38
- `ui/display.ts` already contains stateless formatting functions (`formatMs`, `formatTurns`, `formatSessionTokens`, `describeActivity`, `getDisplayName`, `getPromptModeLabel`, `SPINNER`, `ERROR_STATUSES`, `Theme`).
39
- The new `widget-renderer.ts` will consume these — it does not duplicate them.
40
-
41
- ### Rendering data flow
42
-
43
- The widget's `renderWidget` currently:
44
-
45
- 1. Calls `this.manager.listAgents()` to get `AgentRecord[]`.
46
- 2. Categorizes into running/queued/finished.
47
- 3. Filters finished agents via `this.shouldShowFinished()`.
48
- 4. Looks up `this.agentActivity.get(a.id)` for live stats.
49
- 5. Calls `this.registry` for display names.
50
- 6. Reads `this.widgetFrame` for spinner animation.
51
- 7. Assembles tree-style lines with overflow logic.
52
-
53
- Steps 3–7 are pure given the right inputs.
54
- Steps 1–2 are also pure categorization.
55
-
56
- ## Design Overview
57
-
58
- ### Separation of concerns
59
-
60
- The rendering extraction splits the widget into two layers:
61
-
62
- 1. **`widget-renderer.ts`** — Pure functions that accept data and return `string[]`.
63
- No `this`, no timers, no SDK types, no side effects.
64
- 2. **`agent-widget.ts`** — Thin lifecycle wrapper that owns timers, UICtx, finished-turn aging, and calls the renderer with live data.
65
-
66
- ### Renderer input shape
67
-
68
- Rather than passing the full `AgentRecord` class (which carries mutation methods and phase collaborators), the renderer receives a plain data slice:
69
-
70
- ```typescript
71
- /** Minimal agent snapshot for rendering — no class methods, no mutation surface. */
72
- export interface WidgetAgent {
73
- readonly id: string;
74
- readonly type: SubagentType;
75
- readonly status: string;
76
- readonly description: string;
77
- readonly toolUses: number;
78
- readonly startedAt: number;
79
- readonly completedAt?: number;
80
- readonly error?: string;
81
- readonly lifetimeUsage?: Readonly<LifetimeUsage>;
82
- readonly compactionCount: number;
83
- }
84
- ```
85
-
86
- This is structurally compatible with `AgentRecord` (the class satisfies it), so no mapping code is needed at the call site — `listAgents()` returns `AgentRecord[]` which satisfies `WidgetAgent[]`.
87
-
88
- ### Renderer input for activity
89
-
90
- Activity state is read from `AgentActivityTracker`.
91
- The renderer needs a read-only view per agent:
92
-
93
- ```typescript
94
- /** Read-only activity snapshot for widget rendering. */
95
- export interface WidgetActivity {
96
- readonly activeTools: ReadonlyMap<string, string>;
97
- readonly responseText: string;
98
- readonly turnCount: number;
99
- readonly maxTurns?: number;
100
- readonly session?: SessionLike;
101
- }
102
- ```
103
-
104
- `AgentActivityTracker` already satisfies this structurally (it exposes these as getters).
105
-
106
- ### Agent config lookup
107
-
108
- The renderer needs `getDisplayName` and `getPromptModeLabel`, which take a `SubagentType` and an `AgentConfigLookup`.
109
- The renderer accepts `AgentConfigLookup` (the existing interface from `agent-types.ts`) — not the concrete `AgentTypeRegistry` class.
110
-
111
- ### Renderer API
112
-
113
- ```typescript
114
- /** Pure rendering of the widget body. Returns lines to display. */
115
- export function renderWidgetLines(params: {
116
- agents: readonly WidgetAgent[];
117
- activityMap: ReadonlyMap<string, WidgetActivity>;
118
- registry: AgentConfigLookup;
119
- spinnerFrame: number;
120
- terminalWidth: number;
121
- shouldShowFinished: (agentId: string, status: string) => boolean;
122
- }): string[];
123
-
124
- /** Pure rendering of a single finished agent line (no tree connector prefix). */
125
- export function renderFinishedLine(
126
- agent: WidgetAgent,
127
- activity: WidgetActivity | undefined,
128
- registry: AgentConfigLookup,
129
- theme: Theme,
130
- ): string;
131
-
132
- /** Pure rendering of a single running agent (header + activity lines, no tree connector prefix). */
133
- export function renderRunningLines(
134
- agent: WidgetAgent,
135
- activity: WidgetActivity | undefined,
136
- registry: AgentConfigLookup,
137
- spinnerFrame: number,
138
- theme: Theme,
139
- ): [header: string, activity: string];
140
- ```
141
-
142
- The top-level `renderWidgetLines` encapsulates the full categorization, overflow logic, and tree-connector fixup.
143
- The per-agent functions are exported for fine-grained testing.
144
-
145
- The `shouldShowFinished` callback is injected rather than re-implementing the aging logic inside the renderer, keeping the renderer pure and the aging state in the widget.
146
-
147
- ### Call site in AgentWidget
148
-
149
- ```typescript
150
- // Inside renderWidget(tui, theme):
151
- const w = tui.terminal.columns;
152
- return renderWidgetLines({
153
- agents: this.manager.listAgents(),
154
- activityMap: this.agentActivity,
155
- registry: this.registry,
156
- spinnerFrame: this.widgetFrame,
157
- terminalWidth: w,
158
- shouldShowFinished: (id, status) => this.shouldShowFinished(id, status),
159
- });
160
- ```
161
-
162
- The widget's `renderWidget` method shrinks to ~5 lines.
163
-
164
- ### Tell-Don't-Ask verification
165
-
166
- The renderer receives pre-collected data and returns formatted strings.
167
- It does not reach through collaborators — it reads flat fields from `WidgetAgent` and `WidgetActivity`.
168
- The widget tells the renderer "render this data"; the renderer returns lines.
169
- No Law of Demeter violations.
170
-
171
- ## Module-Level Changes
172
-
173
- ### New file: `src/ui/widget-renderer.ts`
174
-
175
- - `WidgetAgent` interface (structural subset of `AgentRecord`).
176
- - `WidgetActivity` interface (structural subset of `AgentActivityTracker`).
177
- - `renderWidgetLines()` — top-level rendering with categorization, overflow, tree connectors.
178
- - `renderFinishedLine()` — single finished-agent line.
179
- - `renderRunningLines()` — single running-agent header + activity pair.
180
- - Imports from `display.ts` (`SPINNER`, `ERROR_STATUSES`, `formatMs`, `formatTurns`, `formatSessionTokens`, `describeActivity`, `getDisplayName`, `getPromptModeLabel`, `Theme`), from `usage.ts` (`getLifetimeTotal`, `getSessionContextPercent`, `LifetimeUsage`, `SessionLike`), and from `@earendil-works/pi-tui` (`truncateToWidth`).
181
-
182
- ### Modified: `src/ui/agent-widget.ts`
183
-
184
- - Remove `renderWidget()` method body — replace with call to `renderWidgetLines()`.
185
- - Remove `renderFinishedLine()` method entirely.
186
- - Remove direct imports of display helpers and usage helpers that are now only consumed by `widget-renderer.ts`.
187
- - Keep: constructor, `setUICtx`, `onTurnStart`, `ensureTimer`, `shouldShowFinished`, `markFinished`, `update`, `dispose`, `UICtx` type, `MAX_WIDGET_LINES`.
188
- - The inline type on `renderFinishedLine`'s parameter `a` is replaced by the `WidgetAgent` import.
189
-
190
- ### New file: `test/widget-renderer.test.ts`
191
-
192
- - Unit tests for `renderWidgetLines`, `renderFinishedLine`, `renderRunningLines`.
193
- - Uses plain data objects (no mocks for `AgentManager`, `setInterval`, or SDK).
194
- - Stub `Theme` matching the pattern in `test/renderer.test.ts`.
195
-
196
- ### No changes to
197
-
198
- - `src/index.ts` — the widget is constructed the same way; renderer is internal to the widget module.
199
- - `src/ui/display.ts` — unchanged; consumed by the new renderer.
200
- - `src/usage.ts` — unchanged.
201
-
202
- ## Test Impact Analysis
203
-
204
- 1. The extraction enables direct unit testing of widget rendering that was previously impossible — testing `renderWidget` required constructing a full `AgentWidget` with mocked `AgentManager`, fake timers, and a stubbed UICtx.
205
- The new tests cover: finished-agent line formatting (all status variants), running-agent header/activity rendering, overflow logic, tree-connector fixup, empty-state handling, and `shouldShowFinished` filtering.
206
- 2. No existing tests become redundant — there are currently **no** unit tests for `AgentWidget` rendering.
207
- The existing `display.test.ts` tests lower-level formatters and remains as-is.
208
- 3. `renderer.test.ts` tests the notification renderer — unrelated, stays as-is.
209
-
210
- ## TDD Order
211
-
212
- 1. **Red → Green:** Test `renderFinishedLine` for a completed agent (success icon, stats, duration).
213
- Commit: `test: add renderFinishedLine tests for completed status`
214
-
215
- 2. **Red → Green:** Test `renderFinishedLine` for error/aborted/steered/stopped statuses (icon and status text variations).
216
- Commit: `test: renderFinishedLine error and terminal status variants`
217
-
218
- 3. **Red → Green:** Test `renderRunningLines` (spinner frame, stats, activity description, token display).
219
- Commit: `test: add renderRunningLines tests`
220
-
221
- 4. **Red → Green:** Test `renderWidgetLines` — basic case with one running agent (heading, tree connectors).
222
- Commit: `test: renderWidgetLines single running agent`
223
-
224
- 5. **Red → Green:** Test `renderWidgetLines` — mixed running + finished + queued, verifying categorization and ordering.
225
- Commit: `test: renderWidgetLines mixed agent states`
226
-
227
- 6. **Red → Green:** Test `renderWidgetLines` — overflow cap with many agents, verifying the priority (running > queued > finished) and overflow summary line.
228
- Commit: `test: renderWidgetLines overflow behavior`
229
-
230
- 7. **Red → Green:** Test `renderWidgetLines` — empty state returns `[]`; finished-only state uses dim heading.
231
- Commit: `test: renderWidgetLines empty and finished-only states`
232
-
233
- 8. **Green → Refactor:** Extract `renderFinishedLine`, `renderRunningLines`, and `renderWidgetLines` into `src/ui/widget-renderer.ts`.
234
- All tests pass against the extracted module.
235
- Commit: `refactor: extract widget rendering into widget-renderer`
236
-
237
- 9. **Green → Refactor:** Wire `AgentWidget.renderWidget()` to delegate to `renderWidgetLines()`.
238
- Remove the inlined rendering logic from `agent-widget.ts`.
239
- Remove unused imports.
240
- Commit: `refactor: AgentWidget delegates rendering to widget-renderer`
241
-
242
- 10. **Verify:** Run full test suite (`pnpm vitest run`) and type check (`pnpm run check`).
243
- Commit: none (verification only).
244
-
245
- ## Risks and Mitigations
246
-
247
- | Risk | Mitigation |
248
- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
249
- | Structural compatibility between `AgentRecord` and `WidgetAgent` could drift if `AgentRecord` renames a field. | TypeScript's structural checking catches this at the call site in `agent-widget.ts` — `listAgents()` returns `AgentRecord[]` which must satisfy `readonly WidgetAgent[]`. |
250
- | `truncateToWidth` is an external dependency (`@earendil-works/pi-tui`) in the renderer. | Step O (#147) will inject it; for now, the renderer imports it directly, matching the current widget behavior. |
251
- | Overflow logic is complex and hand-tested — extraction could introduce subtle line-count bugs. | TDD steps 4–7 exercise overflow edge cases before the extraction step. The extraction is a mechanical move with tests already passing. |
252
-
253
- ## Open Questions
254
-
255
- - None — the design follows the architecture doc's Step P specification and the dependency (#144) is already implemented.
@@ -1,91 +0,0 @@
1
- ---
2
- issue: 152
3
- issue_title: "Add promptSnippet to pi-subagents tools"
4
- ---
5
-
6
- # Add `promptSnippet` to pi-subagents tools
7
-
8
- ## Problem Statement
9
-
10
- The `Agent`, `get_subagent_result`, and `steer_subagent` tools are the only tools across the monorepo that lack `promptSnippet`.
11
- Pi's `buildSystemPrompt` uses `promptSnippet` to build a concise tool summary in the system prompt.
12
- Without it, these tools rely entirely on their `description` field for model guidance.
13
- The `Agent` tool's description is especially long (embeds full usage guidelines), so a short snippet would give the model a better quick-reference view.
14
-
15
- ## Goals
16
-
17
- - Add `promptSnippet` to each of the three tool registrations in pi-subagents.
18
- - Match the established `"<toolName>: <one-liner>"` format used by pi-github-tools and pi-colgrep.
19
-
20
- ## Non-Goals
21
-
22
- - Changing `description`, `promptGuidelines`, or any other tool registration field.
23
- - Adding `promptSnippet` to tools in other packages (already done).
24
-
25
- ## Background
26
-
27
- Sibling packages pi-github-tools and pi-colgrep already provide `promptSnippet` on every tool.
28
- The convention is a single string in the form `"tool_name: Short imperative description."`.
29
- For example: `"ci_list: List recent CI runs for a workflow."`.
30
-
31
- The three tool factories live in:
32
-
33
- | Factory | File |
34
- | --------------------- | ------------------------------ |
35
- | `createAgentTool` | `src/tools/agent-tool.ts` |
36
- | `createGetResultTool` | `src/tools/get-result-tool.ts` |
37
- | `createSteerTool` | `src/tools/steer-tool.ts` |
38
-
39
- Each factory returns a plain object with `name`, `label`, `description`, `parameters`, and `execute`.
40
- Adding `promptSnippet` is a single property addition per factory.
41
-
42
- ## Design Overview
43
-
44
- No structural change — this is a property addition to three existing object literals.
45
-
46
- Proposed snippets:
47
-
48
- - **Agent** — `"Agent: Launch a specialized agent for complex, multi-step tasks."`
49
- - **get_subagent_result** — `"get_subagent_result: Check status and retrieve results from a background agent."`
50
- - **steer_subagent** — `"steer_subagent: Send a mid-run message to redirect a running background agent."`
51
-
52
- These are the exact phrasings from the issue.
53
- Exact wording may be refined during implementation.
54
-
55
- ## Module-Level Changes
56
-
57
- ### `src/tools/agent-tool.ts`
58
-
59
- Add `promptSnippet` property to the object returned by `createAgentTool`, after `label`.
60
-
61
- ### `src/tools/get-result-tool.ts`
62
-
63
- Add `promptSnippet` property to the object returned by `createGetResultTool`, after `label`.
64
-
65
- ### `src/tools/steer-tool.ts`
66
-
67
- Add `promptSnippet` property to the object returned by `createSteerTool`, after `label`.
68
-
69
- ## Test Impact Analysis
70
-
71
- Existing tool-definition tests (`test/tools/agent-tool.test.ts`, `get-result-tool.test.ts`, `steer-tool.test.ts`) assert `name`, `label`, and `description` but not `promptSnippet`.
72
- New assertions will verify the property exists with the expected value.
73
- No existing tests need modification — the new property is additive.
74
-
75
- ## TDD Order
76
-
77
- 1. **Red → Green:** Add `promptSnippet` assertions to the tool-definition tests for all three tools, then add the `promptSnippet` property to each factory.
78
- Commit: `feat: add promptSnippet to Agent, get_subagent_result, and steer_subagent (#152)`
79
-
80
- This is a single-cycle change — one test step, one implementation step, one commit.
81
-
82
- ## Risks and Mitigations
83
-
84
- | Risk | Mitigation |
85
- | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
86
- | Snippet wording doesn't match what Pi displays well | The snippets mirror the first sentence of each tool's `description`; can be tweaked in a follow-up without breaking anything. |
87
- | SDK `defineTool` doesn't pass through `promptSnippet` | Sibling packages already use it successfully, confirming SDK support. |
88
-
89
- ## Open Questions
90
-
91
- None.