@astralyn/pi 0.84.4 → 0.84.5

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 (234) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/cli/args.d.ts +1 -0
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +11 -0
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/cli/auth-command.d.ts.map +1 -1
  7. package/dist/cli/auth-command.js +5 -4
  8. package/dist/cli/auth-command.js.map +1 -1
  9. package/dist/core/agent-session.d.ts +6 -1
  10. package/dist/core/agent-session.d.ts.map +1 -1
  11. package/dist/core/agent-session.js +7 -6
  12. package/dist/core/agent-session.js.map +1 -1
  13. package/dist/core/experimental.d.ts +4 -0
  14. package/dist/core/experimental.d.ts.map +1 -1
  15. package/dist/core/experimental.js +4 -0
  16. package/dist/core/experimental.js.map +1 -1
  17. package/dist/core/extensions/runner.d.ts.map +1 -1
  18. package/dist/core/extensions/runner.js +4 -0
  19. package/dist/core/extensions/runner.js.map +1 -1
  20. package/dist/core/extensions/types.d.ts +8 -1
  21. package/dist/core/extensions/types.d.ts.map +1 -1
  22. package/dist/core/extensions/types.js.map +1 -1
  23. package/dist/core/keybindings.d.ts +29 -0
  24. package/dist/core/keybindings.d.ts.map +1 -1
  25. package/dist/core/keybindings.js +4 -0
  26. package/dist/core/keybindings.js.map +1 -1
  27. package/dist/core/model-config.d.ts +5 -0
  28. package/dist/core/model-config.d.ts.map +1 -1
  29. package/dist/core/model-config.js +1 -0
  30. package/dist/core/model-config.js.map +1 -1
  31. package/dist/core/model-registry.d.ts +2 -0
  32. package/dist/core/model-registry.d.ts.map +1 -1
  33. package/dist/core/model-registry.js +4 -0
  34. package/dist/core/model-registry.js.map +1 -1
  35. package/dist/core/project-trust.js +2 -2
  36. package/dist/core/project-trust.js.map +1 -1
  37. package/dist/core/sdk.d.ts +5 -3
  38. package/dist/core/sdk.d.ts.map +1 -1
  39. package/dist/core/sdk.js +2 -1
  40. package/dist/core/sdk.js.map +1 -1
  41. package/dist/core/session-manager.js +2 -2
  42. package/dist/core/session-manager.js.map +1 -1
  43. package/dist/core/settings-manager.d.ts +6 -0
  44. package/dist/core/settings-manager.d.ts.map +1 -1
  45. package/dist/core/settings-manager.js +12 -0
  46. package/dist/core/settings-manager.js.map +1 -1
  47. package/dist/core/system-prompt.js +1 -1
  48. package/dist/core/system-prompt.js.map +1 -1
  49. package/dist/core/tools/bash.d.ts +2 -1
  50. package/dist/core/tools/bash.d.ts.map +1 -1
  51. package/dist/core/tools/bash.js +3 -1
  52. package/dist/core/tools/bash.js.map +1 -1
  53. package/dist/core/tools/edit.d.ts.map +1 -1
  54. package/dist/core/tools/edit.js +2 -0
  55. package/dist/core/tools/edit.js.map +1 -1
  56. package/dist/core/tools/find.js +1 -1
  57. package/dist/core/tools/find.js.map +1 -1
  58. package/dist/core/tools/grep.js +1 -1
  59. package/dist/core/tools/grep.js.map +1 -1
  60. package/dist/core/tools/read.d.ts.map +1 -1
  61. package/dist/core/tools/read.js +2 -0
  62. package/dist/core/tools/read.js.map +1 -1
  63. package/dist/core/tools/write.d.ts.map +1 -1
  64. package/dist/core/tools/write.js +2 -0
  65. package/dist/core/tools/write.js.map +1 -1
  66. package/dist/extensions/background/index.d.ts +74 -0
  67. package/dist/extensions/background/index.d.ts.map +1 -0
  68. package/dist/extensions/background/index.js +332 -0
  69. package/dist/extensions/background/index.js.map +1 -0
  70. package/dist/extensions/background/manager.d.ts +81 -0
  71. package/dist/extensions/background/manager.d.ts.map +1 -0
  72. package/dist/extensions/background/manager.js +320 -0
  73. package/dist/extensions/background/manager.js.map +1 -0
  74. package/dist/extensions/background/registry.d.ts +138 -0
  75. package/dist/extensions/background/registry.d.ts.map +1 -0
  76. package/dist/extensions/background/registry.js +358 -0
  77. package/dist/extensions/background/registry.js.map +1 -0
  78. package/dist/extensions/background/render.d.ts +26 -0
  79. package/dist/extensions/background/render.d.ts.map +1 -0
  80. package/dist/extensions/background/render.js +118 -0
  81. package/dist/extensions/background/render.js.map +1 -0
  82. package/dist/extensions/index.d.ts.map +1 -1
  83. package/dist/extensions/index.js +2 -0
  84. package/dist/extensions/index.js.map +1 -1
  85. package/dist/extensions/subagent/activity.d.ts +0 -1
  86. package/dist/extensions/subagent/activity.d.ts.map +1 -1
  87. package/dist/extensions/subagent/activity.js +2 -5
  88. package/dist/extensions/subagent/activity.js.map +1 -1
  89. package/dist/extensions/subagent/agents-command.d.ts.map +1 -1
  90. package/dist/extensions/subagent/agents-command.js +308 -153
  91. package/dist/extensions/subagent/agents-command.js.map +1 -1
  92. package/dist/extensions/subagent/agents.d.ts +3 -6
  93. package/dist/extensions/subagent/agents.d.ts.map +1 -1
  94. package/dist/extensions/subagent/agents.js +22 -192
  95. package/dist/extensions/subagent/agents.js.map +1 -1
  96. package/dist/extensions/subagent/constants.d.ts +4 -5
  97. package/dist/extensions/subagent/constants.d.ts.map +1 -1
  98. package/dist/extensions/subagent/constants.js +11 -7
  99. package/dist/extensions/subagent/constants.js.map +1 -1
  100. package/dist/extensions/subagent/index.d.ts +0 -3
  101. package/dist/extensions/subagent/index.d.ts.map +1 -1
  102. package/dist/extensions/subagent/index.js +56 -188
  103. package/dist/extensions/subagent/index.js.map +1 -1
  104. package/dist/extensions/subagent/render.d.ts +1 -1
  105. package/dist/extensions/subagent/render.d.ts.map +1 -1
  106. package/dist/extensions/subagent/render.js +208 -576
  107. package/dist/extensions/subagent/render.js.map +1 -1
  108. package/dist/extensions/subagent/resolve.d.ts +2 -2
  109. package/dist/extensions/subagent/resolve.d.ts.map +1 -1
  110. package/dist/extensions/subagent/resolve.js +23 -15
  111. package/dist/extensions/subagent/resolve.js.map +1 -1
  112. package/dist/extensions/subagent/runner.d.ts +1 -2
  113. package/dist/extensions/subagent/runner.d.ts.map +1 -1
  114. package/dist/extensions/subagent/runner.js +109 -131
  115. package/dist/extensions/subagent/runner.js.map +1 -1
  116. package/dist/extensions/subagent/schema.d.ts +4 -10
  117. package/dist/extensions/subagent/schema.d.ts.map +1 -1
  118. package/dist/extensions/subagent/schema.js +8 -13
  119. package/dist/extensions/subagent/schema.js.map +1 -1
  120. package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
  121. package/dist/extensions/subagent/sdk-runner.js +9 -20
  122. package/dist/extensions/subagent/sdk-runner.js.map +1 -1
  123. package/dist/extensions/subagent/settings.d.ts +2 -2
  124. package/dist/extensions/subagent/settings.d.ts.map +1 -1
  125. package/dist/extensions/subagent/settings.js +27 -14
  126. package/dist/extensions/subagent/settings.js.map +1 -1
  127. package/dist/extensions/subagent/text.d.ts +3 -0
  128. package/dist/extensions/subagent/text.d.ts.map +1 -0
  129. package/dist/extensions/subagent/text.js +16 -0
  130. package/dist/extensions/subagent/text.js.map +1 -0
  131. package/dist/extensions/subagent/types.d.ts +13 -35
  132. package/dist/extensions/subagent/types.d.ts.map +1 -1
  133. package/dist/extensions/subagent/types.js.map +1 -1
  134. package/dist/extensions/subagent/ui/model-list.d.ts +4 -3
  135. package/dist/extensions/subagent/ui/model-list.d.ts.map +1 -1
  136. package/dist/extensions/subagent/ui/model-list.js +10 -4
  137. package/dist/extensions/subagent/ui/model-list.js.map +1 -1
  138. package/dist/index.d.ts +1 -1
  139. package/dist/index.d.ts.map +1 -1
  140. package/dist/index.js.map +1 -1
  141. package/dist/main.d.ts.map +1 -1
  142. package/dist/main.js +5 -1
  143. package/dist/main.js.map +1 -1
  144. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  145. package/dist/modes/interactive/components/model-selector.js +2 -1
  146. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  147. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  148. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  149. package/dist/modes/interactive/components/settings-selector.js +10 -0
  150. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  151. package/dist/modes/interactive/interactive-mode.d.ts +8 -2
  152. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  153. package/dist/modes/interactive/interactive-mode.js +77 -25
  154. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  155. package/dist/modes/interactive/model-catalog-refresh.d.ts +7 -0
  156. package/dist/modes/interactive/model-catalog-refresh.d.ts.map +1 -0
  157. package/dist/modes/interactive/model-catalog-refresh.js +36 -0
  158. package/dist/modes/interactive/model-catalog-refresh.js.map +1 -0
  159. package/dist/modes/interactive/theme/dark.json +2 -0
  160. package/dist/modes/interactive/theme/light.json +2 -0
  161. package/dist/modes/interactive/theme/theme-controller.d.ts +10 -2
  162. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  163. package/dist/modes/interactive/theme/theme-controller.js +23 -10
  164. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  165. package/dist/modes/interactive/theme/theme-schema.json +9 -1
  166. package/dist/modes/interactive/theme/theme.d.ts +5 -3
  167. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  168. package/dist/modes/interactive/theme/theme.js +12 -2
  169. package/dist/modes/interactive/theme/theme.js.map +1 -1
  170. package/dist/modes/json-event.d.ts +4 -1
  171. package/dist/modes/json-event.d.ts.map +1 -1
  172. package/dist/modes/json-event.js +5 -2
  173. package/dist/modes/json-event.js.map +1 -1
  174. package/dist/package-manager-cli.js +1 -1
  175. package/dist/package-manager-cli.js.map +1 -1
  176. package/dist/server/create-harness.d.ts.map +1 -1
  177. package/dist/server/create-harness.js +2 -0
  178. package/dist/server/create-harness.js.map +1 -1
  179. package/dist/utils/tools-manager.d.ts +10 -1
  180. package/dist/utils/tools-manager.d.ts.map +1 -1
  181. package/dist/utils/tools-manager.js +14 -19
  182. package/dist/utils/tools-manager.js.map +1 -1
  183. package/docs/bundled/README.md +1 -0
  184. package/docs/bundled/extensions/background.md +64 -0
  185. package/docs/bundled/extensions/subagent.md +83 -71
  186. package/docs/compaction.md +6 -6
  187. package/docs/custom-provider.md +1 -1
  188. package/docs/docs.json +4 -0
  189. package/docs/environment-variables.md +8 -2
  190. package/docs/extensions.md +6 -2
  191. package/docs/json.md +6 -4
  192. package/docs/keybindings.md +9 -2
  193. package/docs/rpc.md +15 -4
  194. package/docs/sdk.md +9 -0
  195. package/docs/settings.md +31 -0
  196. package/docs/terminal-setup.md +23 -2
  197. package/docs/themes.md +24 -3
  198. package/docs/tui.md +2 -2
  199. package/docs/usage.md +4 -3
  200. package/examples/README.md +1 -1
  201. package/examples/extensions/README.md +0 -1
  202. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  203. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  204. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  205. package/examples/extensions/gondolin/package-lock.json +2 -2
  206. package/examples/extensions/gondolin/package.json +1 -1
  207. package/examples/extensions/sandbox/package-lock.json +2 -2
  208. package/examples/extensions/sandbox/package.json +1 -1
  209. package/examples/extensions/with-deps/package-lock.json +2 -2
  210. package/examples/extensions/with-deps/package.json +1 -1
  211. package/npm-shrinkwrap.json +170 -221
  212. package/package.json +6 -6
  213. package/dist/extensions/subagent/display-name.d.ts +0 -6
  214. package/dist/extensions/subagent/display-name.d.ts.map +0 -1
  215. package/dist/extensions/subagent/display-name.js +0 -13
  216. package/dist/extensions/subagent/display-name.js.map +0 -1
  217. package/dist/extensions/subagent/ui/profile-editor.d.ts +0 -54
  218. package/dist/extensions/subagent/ui/profile-editor.d.ts.map +0 -1
  219. package/dist/extensions/subagent/ui/profile-editor.js +0 -154
  220. package/dist/extensions/subagent/ui/profile-editor.js.map +0 -1
  221. package/dist/extensions/subagent/ui/profile-picker.d.ts +0 -32
  222. package/dist/extensions/subagent/ui/profile-picker.d.ts.map +0 -1
  223. package/dist/extensions/subagent/ui/profile-picker.js +0 -149
  224. package/dist/extensions/subagent/ui/profile-picker.js.map +0 -1
  225. package/examples/extensions/subagent/README.md +0 -175
  226. package/examples/extensions/subagent/agents/planner.md +0 -37
  227. package/examples/extensions/subagent/agents/reviewer.md +0 -35
  228. package/examples/extensions/subagent/agents/scout.md +0 -50
  229. package/examples/extensions/subagent/agents/worker.md +0 -24
  230. package/examples/extensions/subagent/agents.ts +0 -126
  231. package/examples/extensions/subagent/index.ts +0 -1009
  232. package/examples/extensions/subagent/prompts/implement-and-review.md +0 -10
  233. package/examples/extensions/subagent/prompts/implement.md +0 -10
  234. package/examples/extensions/subagent/prompts/scout-and-plan.md +0 -9
@@ -0,0 +1,64 @@
1
+ # background — background bash tasks
2
+
3
+ Adds `bg_bash`, `bg_logs`, and `bg_kill` tools plus the `/bg` command. Long-running commands (dev servers, watch builds, slow tests) run in the background while the agent keeps working; when a task ends, its status, exit code, and a tail of its output arrive automatically as a notification.
4
+
5
+ ## Tools
6
+
7
+ `bg_bash` starts a command and returns immediately with a task id and output file path:
8
+
9
+ ```json
10
+ { "command": "npm run build", "timeout": 300 }
11
+ ```
12
+
13
+ The optional `timeout` is in seconds; on expiry the task is killed and reported as `timeout`. The tool result only reports the start — the completion notification is the single source of truth for the outcome, so there is never a need to poll with sleep loops or repeated `bg_logs` calls.
14
+
15
+ `bg_logs` reads a bounded slice of a task's output file while it runs or after it ends:
16
+
17
+ ```json
18
+ { "taskId": "bg-3f2a91", "mode": "tail", "bytes": 8192 }
19
+ ```
20
+
21
+ `mode` defaults to `tail`; `bytes` defaults to 8KB and clamps between 256 bytes and 50KB. Truncated reads state the omission up front and always include the full output path.
22
+
23
+ `bg_kill` stops a single running task by killing its whole process tree:
24
+
25
+ ```json
26
+ { "taskId": "bg-3f2a91" }
27
+ ```
28
+
29
+ Killing does not bypass the normal pipeline: the task still finalizes as `killed` and its completion notification still arrives.
30
+
31
+ Task ids accept a unique prefix (with or without the `bg-` part); an ambiguous prefix is an error listing the candidates.
32
+
33
+ ## Completion delivery
34
+
35
+ When a task ends, the extension sends a `background-task` notification: a small XML message carrying the task id, terminal status, exit code, runtime, output file path, and the sanitized last ~4KB of output. While the agent is streaming, the notification queues behind the current run and is delivered when the run settles; when the agent is idle, it wakes a new turn so the result is acted on immediately.
36
+
37
+ The transcript renders this notification as a one-line summary (`✓ bg-3f2a91 npm run build — completed, exit 0 in 34s`) with the output path below; expanding it shows the embedded output tail.
38
+
39
+ ## /bg
40
+
41
+ `/bg` opens an inline task menu in the editor slot (like `/model`); the chat transcript stays visible above it. The list shows each task's status glyph, id, duration, and command; `Enter` opens the selected task's live output view, which replaces the menu.
42
+
43
+ | Key | In the task list | In the output view |
44
+ |---|---|---|
45
+ | `↑` / `↓` | Select task | — |
46
+ | `Enter` | Open the selected task's output | — |
47
+ | `k` | Kill the selected running task | Kill the viewed task |
48
+ | `PgUp` / `PgDn` | — | Scroll the output; `PgUp` freezes it, scrolling back to the bottom resumes following |
49
+ | `Esc` | Close the menu | Back to the task list |
50
+
51
+ The output view polls the output file once per second and only ever reads the last 128KB. Outside an interactive TUI, `/bg` prints a bounded task summary instead.
52
+
53
+ ## Statusline
54
+
55
+ Running and finished counts appear in the footer as `bg 2 running · 1 done`; the segment disappears when no tasks exist.
56
+
57
+ ## Limits and lifecycle
58
+
59
+ - Background tasks inherit the session's `PI_*` environment variables (`PI_SESSION_ID`, `PI_MODEL`, …) just like the built-in bash tool, snapshotted when the task starts.
60
+ - Output streams directly to a system-temp file (`pi-bg-<id>.log`), never into the project or into memory. Memory holds only a byte counter.
61
+ - Output is capped at 20MB. Hitting the cap kills the task and marks it `failed` rather than silently truncating.
62
+ - At most 8 tasks may run concurrently; `bg_bash` reports the running tasks when the limit is reached.
63
+ - Aborting the current turn (Esc) does not kill background tasks — that is what `bg_kill` and `/bg` are for.
64
+ - Session shutdown, `/reload`, new sessions, and session switches kill all running tasks; those kills are silent (no notification flood). There is no restart reattachment: finished-task records live only for the current session.
@@ -1,111 +1,123 @@
1
1
  # subagent — isolated foreground delegation
2
2
 
3
- Adds the `subagent` tool and `/agents` profile settings command. It delegates a bounded task to an isolated in-process `AgentSession`; it is not a background worker or a fleet manager.
3
+ Adds the `subagent` tool and `/agents` settings command. It delegates bounded work to isolated in-process `AgentSession` workers; it is not a background-worker or fleet-management system.
4
+
5
+ ## Tool contract
6
+
7
+ Every call supplies one ordered `tasks` array with 1–8 items:
8
+
9
+ ```json
10
+ {
11
+ "tasks": [
12
+ {
13
+ "prompt": "Locate the provider retry implementation and report exact symbols.",
14
+ "agent": "explorer",
15
+ "cwd": "src/core"
16
+ }
17
+ ]
18
+ }
19
+ ```
4
20
 
5
- ## Tool modes
21
+ Each item has:
6
22
 
7
- Exactly one mode is required per call:
23
+ ```text
24
+ prompt Required self-contained worker briefing
25
+ agent? explorer or general; defaults to explorer
26
+ cwd? Directory inside the parent working directory
27
+ ```
8
28
 
9
- - **Single**: `agent`, `description`, and `prompt`.
10
- - **Parallel**: `tasks`, an array of independent task objects.
29
+ There is no separate single-task or parallel mode. One item launches one worker; multiple items launch concurrent workers. A session-scoped gate permits at most five active workers across all sibling `subagent` calls, so additional items wait for a slot. Results always follow input order, regardless of completion order.
11
30
 
12
- There is deliberately no chain mode: sequential work is driven by the parent, which reads each report before writing the next briefing.
31
+ All tasks are preflighted before any worker starts. Profile, working-directory, model, thinking-level, or authentication failure in one item rejects the entire call without launching the other workers. Once execution begins, one worker failing does not cancel independent siblings.
13
32
 
14
- Every task object has:
33
+ Sequential work uses another `subagent` call after the parent has read the previous report and written the next briefing.
15
34
 
16
- ```text
17
- agent? Agent profile name; defaults to general
18
- description Short UI label
19
- prompt Self-contained worker briefing
20
- cwd? Relative or absolute directory inside the parent working directory
21
- ```
35
+ ## Built-in profiles
22
36
 
23
- Parallel batches allow at most eight tasks. A session-scoped gate runs at most five workers concurrently, including sibling `subagent` calls from the same parent session.
37
+ There are exactly two profiles:
24
38
 
25
- ## Agent profiles
39
+ - **Explorer** (`explorer`, default): read-only investigation with `read`, `grep`, `find`, `ls`, and `bash`. Bash remains available for Git history and inspection commands such as `git log`, `git diff`, `git blame`, `git show`, `git status`, `wc`, `head`, and `tail`. Its system prompt forbids redirects, heredoc writes, temporary files, state-changing Git commands, installs, and network access.
40
+ - **General** (`general`): implementation, file changes, and stateful verification with `read`, `bash`, `edit`, and `write`.
26
41
 
27
- Profiles are Markdown files with YAML frontmatter:
42
+ There are no user or project profile files. Child sessions load no extensions, skills, prompt templates, or themes, so workers cannot recursively call `subagent` or inherit unrelated extension capabilities. Explorer continues to skip project context files such as `AGENTS.md`; General loads trusted project context normally.
28
43
 
29
- ```yaml
30
- ---
31
- name: reviewer
32
- description: Read-only implementation reviewer
33
- tools: read, grep, find, ls
34
- model: anthropic/claude-sonnet-4-5
35
- thinking: medium
36
- backend: sdk
37
- ---
44
+ Worker contexts are isolated, but workers share the parent's checkout. Concurrent tasks therefore must be independent and must not perform overlapping writes.
38
45
 
39
- Review the delegated task independently and report exact evidence.
40
- ```
46
+ ## Model and thinking selection
41
47
 
42
- Sources and precedence are:
48
+ Model and thinking resolution has two layers:
43
49
 
44
50
  ```text
45
- built-in < ~/.pi/agent/agents/*.md < trusted-project/.pi/agents/*.md
51
+ saved /agents override > current parent session
46
52
  ```
47
53
 
48
- Project definitions are loaded only after Pi trusts the project. Invalid Markdown definitions appear as `/agents` diagnostics without hiding valid profiles.
54
+ Callers cannot select model or thinking per task. Run `/agents` to configure Explorer or General:
49
55
 
50
- Built-in profiles:
56
+ 1. Select **Explorer** or **General**.
57
+ 2. Select **Model** or **Thinking**.
58
+ 3. Choose a concrete value or **inherit**.
51
59
 
52
- - `general`: read, bash, edit, and write.
53
- - `explorer`: `read`, `grep`, `find`, and `ls`, plus `bash` constrained by its system prompt to read-only inspection (git history, counting, and similar).
60
+ Each confirmed choice is saved immediately; there is no draft, Apply, or Save step. Choosing **inherit** immediately removes that override. Escape only navigates back and never rolls back choices already confirmed.
54
61
 
55
- A profile may only allow Pi built-in tools. Child sessions load no extensions, skills, or prompt templates, so a worker cannot recursively call `subagent` or inherit unrelated extension capabilities. Project context files such as `AGENTS.md` remain available, except for the built-in `explorer`, which skips them: read-only exploration needs no commit/PR rules, and the parent interprets its results.
56
-
57
- ## Model and thinking selection
62
+ The TUI model picker supports search, scoped/all models, unavailable saved models, and catalog refresh. Thinking choices are limited to levels supported by the effective model.
58
63
 
59
- The model/thinking resolution has exactly two layers:
64
+ Overrides are saved atomically in:
60
65
 
61
66
  ```text
62
- saved /agents profile override > current parent session
67
+ ~/.pi/agent/subagent.json
63
68
  ```
64
69
 
65
- Callers cannot pick models per call, and profile Markdown `model`/`thinking`
66
- frontmatter is intentionally ignored: agent files travel across machines, so a
67
- pinned model rarely exists in the reader's environment.
70
+ Only `explorer` and `general` keys are valid. A stale or invalid `subagent.json` (older formats, unknown profiles, or malformed JSON) is reset to an empty, fully inheriting config the first time it is loaded, so an old file never blocks the tool or `/agents`. Overrides affect future workers and never change the parent session's model or thinking level.
68
71
 
69
- Run `/agents` to choose a profile. The TUI presents display-only title labels
70
- (`explorer` becomes `Explorer`, `code-reviewer` becomes `Code Reviewer`) in
71
- identifier order, while tool calls, profile files, and saved configuration keep
72
- the lowercase identifier. The selected profile's human-facing description
73
- appears below the list in full and wraps to the terminal width; built-in
74
- profiles keep longer delegation guidance out of this UI copy.
72
+ ## Lifecycle and retry
75
73
 
76
- The profile editor keeps model search and thinking selection on one screen:
74
+ - The parent call waits until every worker reaches a terminal state.
75
+ - Parent abort, `/reload`, `/new`, `/resume`, `/fork`, and session shutdown abort active and queued workers.
76
+ - Provider auto-retry remains visible as `Retrying (n/m) in Xs`.
77
+ - A retryable failure that produced no turns or tool use may be retried at task level up to two more times. Runs with partial work are never restarted.
78
+ - Retry backoff does not hold a concurrency slot; another queued worker can run while the failed task waits.
79
+ - A parent abort or session shutdown interrupts queued and retrying workers immediately.
77
80
 
78
- - type to search configured models;
79
- - use `Tab` to switch between scoped and all models when a scope exists;
80
- - use the configured thinking-cycle key (`Shift+Tab` by default) to choose
81
- **inherit** or a level supported by the highlighted model;
82
- - use `Enter` to save the model and thinking choice together, or `Esc` to return
83
- without saving.
81
+ Child sessions share the parent's canonical model/authentication runtime, so extension-registered providers and current credentials do not need to be mirrored into a second runtime.
84
82
 
85
- **inherit** follows the parent session's current model or thinking value. An
86
- explicit model is stored as `provider/model`; an explicit thinking override is
87
- stored as its supported level.
83
+ ## Transcript UI
88
84
 
89
- Overrides are user-owned and saved atomically in:
85
+ While running, the collapsed view shows a progress header followed by one
86
+ row per task in original input order:
90
87
 
91
88
  ```text
92
- ~/.pi/agent/subagent.json
89
+ › 2/4 done · 12s
90
+ › Explorer · Locate retry scheduling — Run git log
91
+ ✓ Explorer · Map provider registration
92
+ ○ Explorer · Find related tests
93
+ ○ General · Apply focused fix
94
+ ```
95
+
96
+ Every task is always listed: there is no row cap, no active-first
97
+ reordering, and no `+N more` truncation. Live rows append the current
98
+ activity, failure reason, or retry countdown.
99
+
100
+ Expanded running calls show profile/model/thinking/cwd metrics, retry state, and the bounded Activity history for each task. Streaming assistant text is not copied into the parent transcript.
101
+
102
+ Once settled, the collapsed view keeps the same one-row-per-task layout under an aggregate line with the batch outcome, counts, cost, and duration:
103
+
104
+ ```text
105
+ ✓ 3 completed · 1 failed · 24s · $0.031
106
+ ✓ Explorer · Locate retry scheduling · 12s
107
+ ✓ Explorer · Map provider registration · 8.4s
108
+ × General · Apply focused fix · 1m 3s
109
+ ✓ Explorer · Find related tests · 21s
93
110
  ```
94
111
 
95
- They apply only to future subagent runs and never change the parent session's `/model` or thinking level.
112
+ The expanded settled view shows, for each task:
96
113
 
97
- ## Lifecycle and output
114
+ - the complete original Prompt from the tool call;
115
+ - model, thinking, cwd, usage, cost, and duration;
116
+ - Error when present;
117
+ - the final Report, or `Report · partial` when a failed/aborted worker produced useful output.
98
118
 
99
- - The parent tool call waits until every worker reaches a terminal state.
100
- - Parent abort, `/reload`, `/new`, `/resume`, `/fork`, and session shutdown abort active child sessions. Queued workers do not survive the call.
101
- - Parallel worker failures do not cancel other independent workers.
102
- - Transient provider errors auto-retry: the worker session retries retryable stream errors with backoff (visible as a live `Retrying (n/m) in Xs…` countdown), and a failure that produced no work (for example a preflight auth throw) is rerun at the task level up to two more times. Provider and task retries share one absolute-deadline state; at zero it reads `Retrying now…`, and parent abort/session shutdown interrupts backoff immediately. Runs with partial work behind them are never rerun.
103
- - Progress is rendered in Pi's native tool transcript. While a call is running, the Subagent renderer re-schedules its own repaint once per second, independently of worker output and the main Working spinner. Silent single and parallel runs therefore keep advancing their own elapsed clocks in collapsed and expanded views, and queued retries keep counting down. Once settled, the final duration is fixed and refresh stops.
104
- - The collapsed view stays lean in both phases: while running, one bounded intent line (for example `Verifying changes`) carries tool uses, the `ctx:` context watermark, cost, and elapsed time above the current tool marked with `›` and the live output tail; once settled, the sentence-aware result excerpt is followed by a single metrics line (`tok · $ · duration`, plus tool uses and `ctx:` for single runs) and the configured expand hint. Live lines never quote token totals — mid-run totals are cache-inflated. The call-level status dot belongs to the tool shell; run and activity rows only use `›`, `○`, `✓`, `×`, and `■`, and parallel run rows carry stable dim ordinals that match the expanded section numbers. `Ctrl+O` expands each run into a report cover sheet: a status line, a metrics line, a fixed two-line `Prompt` preview (`… continues, N more lines`, honest about the 1KB bound), an `Activity · last n of N` digest whose successful rows are quiet aligned one-liners, a `Working` tail while streaming, and the full `Report` (or `Error`, with `Report · partial` for salvaged output) rendered as Markdown. Expanded batches start with a numbered contents list whose numbers match the `── N · ✓ Agent` section headers.
105
- - Failed and aborted batch runs place their bounded reason on a separate error-colored line below the run headline instead of cutting it into the status row. Reasons are capped at 200 characters and keep their hanging indent when wrapped; successful settled excerpts prefer complete leading sentences within their 96-character budget. Rounded durations switch to minute form at 60 seconds without producing `1m 60s`.
106
- - Full child transcripts are not stored separately. Bounded run details remain in the parent tool result, so completed calls restore naturally in the parent session tree.
107
- - Nested usage is returned with the tool result and included in parent session accounting.
119
+ Activity is intentionally a running-state view; settled transparency comes from the original Prompt and final Report. Full child transcripts are not stored separately. Activity, errors, reports, usage, and model-facing output remain bounded, and completed calls restore through the parent session tree.
108
120
 
109
121
  ## Deliberate non-features
110
122
 
111
- There are no background agents, persistent worker IDs, unread state, fleet panel, statusline widget, send/stop/resume control plane, completion notifications, swarm/coordinator, worktree isolation, nested agents, MCP, hooks, or agent memory.
123
+ There are no custom profiles, background agents, persistent worker IDs, unread state, fleet panel, statusline widget, send/stop/resume control plane, completion notifications, chain mode, swarm/coordinator, worktree isolation, nested agents, MCP, hooks, or agent memory.
@@ -1,6 +1,6 @@
1
1
  # Compaction & Branch Summarization
2
2
 
3
- LLMs have limited context windows. When conversations grow too long, pi uses compaction to summarize older content while preserving recent work. This page covers both auto-compaction and branch summarization.
3
+ LLMs have limited context windows. When conversations grow too long, Pi uses compaction to summarize older content while preserving recent work. This page covers both auto-compaction and branch summarization.
4
4
 
5
5
  ## Public API
6
6
 
@@ -51,7 +51,7 @@ You can also trigger manually with `/compact [instructions]`, where optional ins
51
51
  Before compaction:
52
52
 
53
53
  entry: 0 1 2 3 4 5 6 7 8 9
54
- ┌─────┬─────┬─────┬─────┬──────┬─────┬─────┬──────┬──────┬─────┐
54
+ ┌─────┬─────┬─────┬──────┬─────┬─────┬──────┬──────┬─────┬─────┐
55
55
  │ hdr │ usr │ ass │ tool │ usr │ ass │ tool │ tool │ ass │ tool│
56
56
  └─────┴─────┴─────┴──────┴─────┴─────┴──────┴──────┴─────┴─────┘
57
57
  └────────┬───────┘ └──────────────┬──────────────┘
@@ -62,7 +62,7 @@ Before compaction:
62
62
  After compaction (new entry appended):
63
63
 
64
64
  entry: 0 1 2 3 4 5 6 7 8 9 10
65
- ┌─────┬─────┬─────┬─────┬──────┬─────┬─────┬──────┬──────┬─────┬─────┐
65
+ ┌─────┬─────┬─────┬──────┬─────┬─────┬──────┬──────┬─────┬─────┬─────┐
66
66
  │ hdr │ usr │ ass │ tool │ usr │ ass │ tool │ tool │ ass │ tool│ cmp │
67
67
  └─────┴─────┴─────┴──────┴─────┴─────┴──────┴──────┴─────┴─────┴─────┘
68
68
  └──────────┬──────┘ └──────────────────────┬───────────────────┘
@@ -105,7 +105,7 @@ Split turn (one huge turn exceeds budget):
105
105
  turnPrefixMessages = [usr, ass, tool, ass, tool, tool]
106
106
  ```
107
107
 
108
- For split turns, pi generates two summaries and merges them:
108
+ For split turns, Pi generates two summaries and merges them:
109
109
  1. **History summary**: Previous context (if any)
110
110
  2. **Turn prefix summary**: The early part of the split turn
111
111
 
@@ -152,7 +152,7 @@ Pi uses an internal preparation step before `compact()`. For direct programmatic
152
152
 
153
153
  ### When It Triggers
154
154
 
155
- When you use `/tree` to navigate to a different branch, pi offers to summarize the work you're leaving. This injects context from the left branch into the new branch.
155
+ When you use `/tree` to navigate to a different branch, Pi offers to summarize the work you're leaving. This injects context from the left branch into the new branch.
156
156
 
157
157
  ### How It Works
158
158
 
@@ -181,7 +181,7 @@ After navigation with summary:
181
181
 
182
182
  ### Cumulative File Tracking
183
183
 
184
- Both compaction and branch summarization track files cumulatively. When generating a summary, pi extracts file operations from:
184
+ Both compaction and branch summarization track files cumulatively. When generating a summary, Pi extracts file operations from:
185
185
  - Tool calls in the messages being summarized
186
186
  - Previous compaction or branch summary `details` (if any)
187
187
 
@@ -169,7 +169,7 @@ Set `api` on the provider as the default, or on a model when one provider has mo
169
169
  | `openai-responses` | OpenAI Responses APIs |
170
170
  | `azure-openai-responses` | Azure OpenAI Responses APIs |
171
171
  | `openai-codex-responses` | OpenAI Codex Responses APIs |
172
- | `mistral-conversations` | Mistral Conversations APIs |
172
+ | `mistral-conversations` | Native Mistral Chat Completions streaming |
173
173
  | `google-generative-ai` | Google Generative AI APIs |
174
174
  | `google-vertex` | Google Vertex AI APIs |
175
175
  | `bedrock-converse-stream` | Amazon Bedrock Converse Stream APIs |
package/docs/docs.json CHANGED
@@ -56,6 +56,10 @@
56
56
  "title": "Overview",
57
57
  "path": "bundled/README.md"
58
58
  },
59
+ {
60
+ "title": "Background",
61
+ "path": "bundled/extensions/background.md"
62
+ },
59
63
  {
60
64
  "title": "DeepWiki",
61
65
  "path": "bundled/extensions/deepwiki.md"
@@ -3,14 +3,19 @@
3
3
  Pi uses environment variables in three ways:
4
4
 
5
5
  - Variables such as `PI_OFFLINE` configure the Pi process.
6
- - Pi sets `PI_CODING_AGENT` so child processes can detect that they run inside Pi.
6
+ - Pi sets process markers so child processes can identify Pi as the launching agent.
7
7
  - Commands run by the LLM-callable bash tool receive `PI_*` variables describing the current session.
8
8
 
9
9
  Provider API-key variables are documented separately in [Providers](providers.md#environment-variables-or-auth-file).
10
10
 
11
11
  ## Process Marker
12
12
 
13
- The CLI and RPC entry points set `PI_CODING_AGENT=true`. Child processes inherit it and can use it to detect that they run inside Pi. It is not session-specific and is not set automatically when Pi is embedded through the SDK.
13
+ The CLI and RPC entry points set two process markers:
14
+
15
+ - `AI_AGENT=pi` is a generic marker that lets tooling identify Pi as the agent that launched the process.
16
+ - `PI_CODING_AGENT=true` is Pi-specific and lets child processes detect that they run inside Pi.
17
+
18
+ Child processes inherit both markers. They are not session-specific and are not set automatically when Pi is embedded through the SDK.
14
19
 
15
20
  ## Bash Tool Session Environment
16
21
 
@@ -82,6 +87,7 @@ These variables are read by Pi itself:
82
87
  | `PI_CACHE_RETENTION` | Set to `long` for extended provider prompt caching where supported |
83
88
  | `PI_SHARE_VIEWER_URL` | Override the base URL used by `/share` |
84
89
  | `PI_HARDWARE_CURSOR` | Set to `1` to show the hardware cursor; see [Terminal setup](terminal-setup.md) |
90
+ | `PI_TUI_ESC_TIMEOUT` | How long to wait after a lone ESC before treating it as Escape, in milliseconds; defaults to `100` over SSH and `10` otherwise. Increase it if Alt-key input is misread as Escape |
85
91
  | `VISUAL`, `EDITOR` | Fallback external editor for Ctrl+G when `externalEditor` is unset; defaults to Notepad on Windows and `nano` elsewhere |
86
92
  | `HTTP_PROXY`, `HTTPS_PROXY` | Proxy outbound HTTP requests |
87
93
 
@@ -999,9 +999,9 @@ ctx.sessionManager.buildContextEntries() // Active branch entries with compac
999
999
  ctx.sessionManager.getLeafId() // Current leaf entry ID
1000
1000
  ```
1001
1001
 
1002
- ### ctx.modelRegistry / ctx.model / ctx.thinkingLevel / ctx.scopedModels
1002
+ ### ctx.modelRegistry / ctx.modelRuntime / ctx.model / ctx.thinkingLevel / ctx.scopedModels
1003
1003
 
1004
- Access to models, providers, and resolved authentication. `ctx.modelRegistry.getProvider(id)` returns the effective pi-ai provider, while `getProviderAuth(id)` resolves its current API key, headers, base URL, and provider-scoped environment without requiring a loaded model. `ctx.model` is the active model (or `undefined` when none is active), and `ctx.thinkingLevel` is its current effective thinking level when the session runtime provides one.
1004
+ Access to models, providers, and resolved authentication. `ctx.modelRegistry.getProvider(id)` returns the effective pi-ai provider, while `getProviderAuth(id)` resolves its current API key, headers, base URL, and provider-scoped environment without requiring a loaded model. `ctx.modelRuntime` is the canonical `ModelRuntime` owned by the current session; use it when creating nested SDK sessions so they share the same provider registrations, model catalog, and credentials instead of constructing and synchronizing a mirror runtime. `ctx.model` is the active model (or `undefined` when none is active), and `ctx.thinkingLevel` is its current effective thinking level when the session runtime provides one.
1005
1005
 
1006
1006
  `ctx.scopedModels` is the read-only list of models scoped to the current session—the same set shown by `/scoped-models`. Pi resolves it at session start from `--models` and the `enabledModels` setting, matching `provider/modelId` or bare `modelId` patterns with minimatch. An empty list means no scope is configured and every available model is usable. Each entry is `{ model, thinkingLevel? }`; use this list when a custom model picker should mirror the built-in scope rather than enumerate the full registry.
1007
1007
 
@@ -1448,12 +1448,16 @@ pi.sendUserMessage([
1448
1448
  // During streaming - must specify delivery mode
1449
1449
  pi.sendUserMessage("Focus on error handling", { deliverAs: "steer" });
1450
1450
  pi.sendUserMessage("And then summarize", { deliverAs: "followUp" });
1451
+
1452
+ // Opt in to extension command dispatch and skill/prompt template expansion
1453
+ pi.sendUserMessage("/review src/index.ts", { expandPromptTemplates: true });
1451
1454
  ```
1452
1455
 
1453
1456
  **Options:**
1454
1457
  - `deliverAs` - Required when agent is streaming:
1455
1458
  - `"steer"` - Queues the message for delivery after the current assistant turn finishes executing its tool calls
1456
1459
  - `"followUp"` - Waits for agent to finish all tools
1460
+ - `expandPromptTemplates` - Dispatch extension commands and expand skill commands and prompt templates. Defaults to `false`.
1457
1461
 
1458
1462
  When not streaming, the message is sent immediately and triggers a new turn. When streaming without `deliverAs`, throws an error.
1459
1463
 
package/docs/json.md CHANGED
@@ -17,6 +17,7 @@ type JsonAgentSessionEvent =
17
17
  | Exclude<AgentSessionEvent, { type: "message_update" }>
18
18
  | {
19
19
  type: "message_update";
20
+ usage: Usage;
20
21
  assistantMessageEvent: WithoutPartial<AssistantMessageEvent>;
21
22
  };
22
23
  ```
@@ -93,16 +94,17 @@ Followed by events as they occur:
93
94
  {"type":"agent_start"}
94
95
  {"type":"turn_start"}
95
96
  {"type":"message_start","message":{"role":"assistant","content":[],...}}
96
- {"type":"message_update","assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":"Hello"}}
97
+ {"type":"message_update","usage":{...},"assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":"Hello"}}
97
98
  {"type":"message_end","message":{...}}
98
99
  {"type":"turn_end","message":{...},"toolResults":[]}
99
100
  {"type":"agent_end","messages":[...],"willRetry":false}
100
101
  ```
101
102
 
102
103
  `message_update` records are delta-only. They omit both the cumulative `message` field and
103
- `assistantMessageEvent.partial` to keep stream size linear. Use `contentIndex` and `delta`
104
- to assemble live text, thinking, or tool-call arguments if needed. `message_end` contains
105
- the final authoritative message.
104
+ `assistantMessageEvent.partial` to keep stream size linear. The top-level `usage` field contains
105
+ the latest cumulative provider-reported usage and may remain zero when a provider only reports
106
+ usage at completion. Use `contentIndex` and `delta` to assemble live text, thinking, or tool-call
107
+ arguments if needed. `message_end` contains the final authoritative message.
106
108
 
107
109
  ## Example
108
110
 
@@ -86,7 +86,7 @@ The dedicated history actions always change history entries, regardless of the c
86
86
 
87
87
  ### TUI Fullscreen Viewport
88
88
 
89
- These actions apply when interactive mode uses `--tui-mode fullscreen` and target the primary transcript scroll region. Two-finger trackpad and mouse-wheel input scroll the region under the pointer, falling back to the transcript over the fixed editor/status/footer dock. Clicking an OSC 8 hyperlink opens it in the default handler. Dragging with the primary mouse button selects text and copies it to the clipboard; holding at the transcript's top or bottom edge auto-scrolls into off-screen content.
89
+ These actions apply when interactive mode uses `--tui-mode fullscreen` and target the primary transcript scroll region. Two-finger trackpad and mouse-wheel input scroll the region under the pointer, falling back to the transcript over the fixed editor/status/footer dock. Clicking an OSC 8 hyperlink opens it in the default handler. Dragging with the primary mouse button selects text and copies it to the clipboard; holding at the transcript's top or bottom edge auto-scrolls into off-screen content. See [Terminal setup](terminal-setup.md) for terminal-specific mouse and trackpad behavior.
90
90
 
91
91
  Fullscreen transcript bindings take precedence over editor bindings. The default unmodified navigation keys therefore control the transcript in fullscreen mode, while their `ctrl` variants continue to control the editor. Outside fullscreen mode, both variants control the editor.
92
92
 
@@ -97,7 +97,7 @@ Fullscreen transcript bindings take precedence over editor bindings. The default
97
97
  | `pageUp`, `pageDown` | Editor | Transcript |
98
98
  | `ctrl+pageUp`, `ctrl+pageDown` | Editor | Editor |
99
99
 
100
- This routing remains configurable through the ordinary action bindings. For example, `"tui.altScreen.pageUp": "ctrl+pageUp"` makes `pageUp` control the editor and `ctrl+pageUp` control the transcript in fullscreen mode. Bind `tui.altScreen.halfPageUp` and `tui.altScreen.halfPageDown` for smaller transcript steps while keeping the full-page bindings. Setting `"tui.altScreen.pageUp": []` disables that transcript shortcut entirely. User bindings replace the defaults for that action.
100
+ This routing remains configurable through the ordinary action bindings. For example, `"tui.altScreen.pageUp": "ctrl+pageUp"` makes `pageUp` control the editor and `ctrl+pageUp` control the transcript in fullscreen mode. Bind `tui.altScreen.halfPageUp` and `tui.altScreen.halfPageDown` for half-page steps, or bind `tui.altScreen.lineUp` and `tui.altScreen.lineDown` for single-line steps. Setting `"tui.altScreen.pageUp": []` disables that transcript shortcut entirely. User bindings replace the defaults for that action.
101
101
 
102
102
  | Keybinding id | Default | Description |
103
103
  |--------|---------|-------------|
@@ -105,8 +105,14 @@ This routing remains configurable through the ordinary action bindings. For exam
105
105
  | `tui.altScreen.pageDown` | `pageDown` | Scroll the transcript down by one page |
106
106
  | `tui.altScreen.halfPageUp` | *(none)* | Scroll the transcript up by half a page |
107
107
  | `tui.altScreen.halfPageDown` | *(none)* | Scroll the transcript down by half a page |
108
+ | `tui.altScreen.lineUp` | *(none)* | Scroll the transcript up by one line |
109
+ | `tui.altScreen.lineDown` | *(none)* | Scroll the transcript down by one line |
108
110
  | `tui.altScreen.previousPrompt` | `ctrl+shift+up` | Jump to the previous marked message |
109
111
  | `tui.altScreen.nextPrompt` | `ctrl+shift+down` | Jump to the next marked message |
112
+ | `tui.altScreen.search` | `ctrl+shift+f` | Search the rendered transcript |
113
+ | `tui.altScreen.searchNext` | `enter`, `ctrl+g` | Select the next search match while searching |
114
+ | `tui.altScreen.searchPrevious` | `shift+enter`, `ctrl+shift+g` | Select the previous search match while searching |
115
+ | `tui.altScreen.searchClose` | `escape` | Close transcript search |
110
116
  | `tui.altScreen.top` | `home` | Scroll to the beginning of the transcript |
111
117
  | `tui.altScreen.bottom` | `end` | Scroll to the transcript end and follow new output |
112
118
 
@@ -120,6 +126,7 @@ This routing remains configurable through the ordinary action bindings. For exam
120
126
  | `app.suspend` | `ctrl+z` (none on Windows) | Suspend to background |
121
127
  | `app.editor.external` | `ctrl+g` | Open in external editor (`externalEditor`, `$VISUAL`, `$EDITOR`, Notepad on Windows, or `nano` elsewhere) |
122
128
  | `app.clipboard.pasteImage` | `ctrl+v` (`alt+v` on Windows) | Paste image or text from clipboard |
129
+ | `app.backgroundTasks.kill` | `k` | Stop the selected task in the Background task menu |
123
130
 
124
131
  ### Sessions
125
132
 
package/docs/rpc.md CHANGED
@@ -954,6 +954,14 @@ Emitted during streaming of assistant messages. Contains a delta event without a
954
954
  ```json
955
955
  {
956
956
  "type": "message_update",
957
+ "usage": {
958
+ "input": 100,
959
+ "output": 1,
960
+ "cacheRead": 0,
961
+ "cacheWrite": 0,
962
+ "totalTokens": 101,
963
+ "cost": {"input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0, "total": 0}
964
+ },
957
965
  "assistantMessageEvent": {
958
966
  "type": "text_delta",
959
967
  "contentIndex": 0,
@@ -978,12 +986,15 @@ The `assistantMessageEvent` field contains one of these delta types:
978
986
 
979
987
  Example streaming a text response:
980
988
  ```json
981
- {"type":"message_update","assistantMessageEvent":{"type":"text_start","contentIndex":0}}
982
- {"type":"message_update","assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":"Hello"}}
983
- {"type":"message_update","assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":" world"}}
984
- {"type":"message_update","assistantMessageEvent":{"type":"text_end","contentIndex":0,"content":"Hello world"}}
989
+ {"type":"message_update","usage":{...},"assistantMessageEvent":{"type":"text_start","contentIndex":0}}
990
+ {"type":"message_update","usage":{...},"assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":"Hello"}}
991
+ {"type":"message_update","usage":{...},"assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":" world"}}
992
+ {"type":"message_update","usage":{...},"assistantMessageEvent":{"type":"text_end","contentIndex":0,"content":"Hello world"}}
985
993
  ```
986
994
 
995
+ The top-level `usage` field contains the latest cumulative provider-reported usage. It may remain
996
+ zero until completion when a provider does not report usage during streaming.
997
+
987
998
  `message_update` intentionally omits the former cumulative `message` field and
988
999
  `assistantMessageEvent.partial`. Clients that need a live partial message must assemble it
989
1000
  from `message_start` and subsequent events using `contentIndex`. Treat `message_end.message`
package/docs/sdk.md CHANGED
@@ -408,6 +408,13 @@ import { createAgentSession, ModelRuntime } from "@astralyn/pi";
408
408
 
409
409
  const modelRuntime = await ModelRuntime.create();
410
410
 
411
+ // create() restores cached catalogs but does not refresh them from pi.dev by default.
412
+ // Opt in to a create-time network refresh and bound how long it may take:
413
+ const refreshedRuntime = await ModelRuntime.create({
414
+ allowModelNetwork: true,
415
+ modelRefreshTimeoutMs: 15_000,
416
+ });
417
+
411
418
  // Find specific built-in models (doesn't check whether API keys exist)
412
419
  const opus = getModel("anthropic", "claude-opus-4-5");
413
420
  const sonnet = getModel("anthropic", "claude-sonnet-4-5");
@@ -439,6 +446,8 @@ If no model is provided:
439
446
  2. Uses default from settings
440
447
  3. Prefers a known provider default among available models, then falls back to the first available model
441
448
 
449
+ Remote catalogs are persisted locally so later runtimes can restore them without a network request. The default file is `~/.pi/agent/models-store.json`; set `modelsStorePath` to choose another location, or inject `modelsStore` to control persistence. Network refreshes are throttled to once per provider every four hours unless forced. To force an immediate refresh, call `await modelRuntime.refresh({ allowNetwork: true, force: true, signal })`. Setting `PI_OFFLINE` disables model network access.
450
+
442
451
  To match CLI model parsing, use the exported resolver helpers:
443
452
 
444
453
  ```typescript
package/docs/settings.md CHANGED
@@ -66,6 +66,7 @@ Use `/trust` in interactive mode to save a project trust decision for future ses
66
66
  | `autocompleteMaxVisible` | number | `5` | Max visible items in autocomplete dropdown (3-20) |
67
67
  | `showHardwareCursor` | boolean | `false` | Show the terminal cursor while TUI positions it for IME support |
68
68
  | `tuiMode` | string | `"fullscreen"` | Interactive TUI mode: `"fullscreen"` or `"regular"`. Changes from `/settings` apply immediately; `--tui-mode` overrides this setting at startup |
69
+ | `fullscreenExitOutput` | string | `"transcript"` | Fullscreen exit output: `"transcript"` prints the final transcript and resume hint, while `"resume-hint"` restores the previous screen and prints only the resume hint. Has no effect in regular TUI mode |
69
70
  | `fullscreenScrollbar` | string | `"auto"` | Fullscreen transcript scrollbar: `"auto"` shows it temporarily while scrolling, `"always"` reserves the rightmost column and keeps it visible, and `"hidden"` hides it. Has no effect in regular TUI mode |
70
71
 
71
72
  For VS Code, include `--wait` so pi resumes after the editor exits:
@@ -191,6 +192,20 @@ Keep `retry.provider.maxRetries` at `0` unless provider-level retries are explic
191
192
  | `shellCommandPrefix` | string | - | Prefix for every bash command (e.g., `"shopt -s expand_aliases"`) |
192
193
  | `npmCommand` | string[] | - | Command argv used for npm package lookup/install operations (e.g., `["mise", "exec", "node@20", "--", "npm"]`) |
193
194
 
195
+ Windows paths in JSON must use forward slashes or escaped backslashes:
196
+
197
+ ```json
198
+ {
199
+ "shellPath": "C:/Program Files/Git/bin/bash.exe"
200
+ }
201
+ ```
202
+
203
+ ```json
204
+ {
205
+ "shellPath": "C:\\Program Files\\Git\\bin\\bash.exe"
206
+ }
207
+ ```
208
+
194
209
  ```json
195
210
  {
196
211
  "npmCommand": ["mise", "exec", "node@20", "--", "npm"]
@@ -199,6 +214,22 @@ Keep `retry.provider.maxRetries` at `0` unless provider-level retries are explic
199
214
 
200
215
  `npmCommand` is used for all npm package-manager operations, including installs, uninstalls, and dependency installs inside git packages. User-scoped npm packages install under `~/.pi/agent/npm/`; project-scoped npm packages install under `.pi/npm/`. Use argv-style entries exactly as the process should be launched. When `npmCommand` is configured, git package dependency installs use plain `install` to avoid npm-specific flags in wrappers or alternate package managers.
201
216
 
217
+ ### Tools
218
+
219
+ | Setting | Type | Default | Description |
220
+ |---------|------|---------|-------------|
221
+ | `defaultTools` | string[] | - | Built-in tools enabled initially. When omitted, Pi uses its standard defaults |
222
+
223
+ `defaultTools` selects the built-in tools enabled at startup. Extension and SDK custom tools remain enabled:
224
+
225
+ ```json
226
+ {
227
+ "defaultTools": ["bash", "edit", "write"]
228
+ }
229
+ ```
230
+
231
+ An empty array starts with no built-in tools while preserving extension and SDK custom tools. `--tools` replaces this behavior with a strict allowlist for all tools, `--no-tools` disables all tools, and `--no-builtin-tools` disables the built-in defaults. `--exclude-tools` filters the resulting list. A project `defaultTools` array replaces the global array.
232
+
202
233
  ### Sessions
203
234
 
204
235
  | Setting | Type | Default | Description |
@@ -2,9 +2,26 @@
2
2
 
3
3
  Pi uses the [Kitty keyboard protocol](https://sw.kovidgoyal.net/kitty/keyboard-protocol/) for reliable modifier key detection. Most modern terminals support this protocol, but some require configuration.
4
4
 
5
- ## Kitty, iTerm2
5
+ ## Kitty
6
6
 
7
- Work out of the box.
7
+ Works out of the box.
8
+
9
+ ## iTerm2
10
+
11
+ ### Regular TUI mode
12
+
13
+ Works out of the box.
14
+
15
+ ### Fullscreen TUI mode
16
+
17
+ Pi owns the viewport, so iTerm2 sends mouse-wheel reports instead of scrolling its native scrollback. With iTerm2's default fast-trackpad behavior, those reports can lose most of an accelerated wheel delta, making fullscreen scrolling much slower than regular scrolling.
18
+
19
+ If fast mouse-wheel gestures move only about one line at a time in fullscreen mode:
20
+
21
+ 1. Open **iTerm2 → Settings → Advanced**.
22
+ 2. Search for **Trackpad scrolls fast?** and set it to **No**.
23
+
24
+ This is an iTerm2-wide workaround and may also change native trackpad scrolling. The underlying behavior is tracked in [iTerm2 issue 9619](https://gitlab.com/gnachman/iterm2/-/work_items/9619).
8
25
 
9
26
  ## Apple Terminal
10
27
 
@@ -32,6 +49,10 @@ If Claude Code 2.x or newer is the only reason you added that mapping, you can r
32
49
 
33
50
  Pi binds `Ctrl+J` as a default newline alias, so `Shift+Enter` keeps working in tmux via that remap without extra pi configuration.
34
51
 
52
+ ### Fullscreen TUI mode
53
+
54
+ In fullscreen mode, links remain clickable, but Ghostty does not show its hover underline or lower-left URL preview while pi captures mouse input. Hold `Shift+Command` on macOS or `Shift+Ctrl` on Linux to use Ghostty's native link handling.
55
+
35
56
  ## WezTerm
36
57
 
37
58
  WezTerm usually works out of the box for `Shift+Enter` via xterm modifyOtherKeys. To use the Kitty keyboard protocol explicitly, create `~/.wezterm.lua`: