@averyyy/pi-coding-agent 0.80.10-piclient.2 → 0.82.0-piclient.1

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 (185) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/README.md +19 -3
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +2 -0
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/cli/config-selector.d.ts.map +1 -1
  7. package/dist/cli/config-selector.js +1 -1
  8. package/dist/cli/config-selector.js.map +1 -1
  9. package/dist/cli/startup-ui.d.ts.map +1 -1
  10. package/dist/cli/startup-ui.js +1 -1
  11. package/dist/cli/startup-ui.js.map +1 -1
  12. package/dist/core/agent-session-services.d.ts.map +1 -1
  13. package/dist/core/agent-session-services.js +13 -0
  14. package/dist/core/agent-session-services.js.map +1 -1
  15. package/dist/core/agent-session.d.ts +33 -3
  16. package/dist/core/agent-session.d.ts.map +1 -1
  17. package/dist/core/agent-session.js +91 -59
  18. package/dist/core/agent-session.js.map +1 -1
  19. package/dist/core/compaction/branch-summarization.d.ts +7 -1
  20. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  21. package/dist/core/compaction/branch-summarization.js +6 -2
  22. package/dist/core/compaction/branch-summarization.js.map +1 -1
  23. package/dist/core/compaction/compaction.d.ts +23 -4
  24. package/dist/core/compaction/compaction.d.ts.map +1 -1
  25. package/dist/core/compaction/compaction.js +83 -29
  26. package/dist/core/compaction/compaction.js.map +1 -1
  27. package/dist/core/compaction/utils.d.ts +1 -1
  28. package/dist/core/compaction/utils.d.ts.map +1 -1
  29. package/dist/core/compaction/utils.js +6 -17
  30. package/dist/core/compaction/utils.js.map +1 -1
  31. package/dist/core/extensions/loader.d.ts.map +1 -1
  32. package/dist/core/extensions/loader.js +13 -2
  33. package/dist/core/extensions/loader.js.map +1 -1
  34. package/dist/core/extensions/runner.d.ts +2 -1
  35. package/dist/core/extensions/runner.d.ts.map +1 -1
  36. package/dist/core/extensions/runner.js +35 -0
  37. package/dist/core/extensions/runner.js.map +1 -1
  38. package/dist/core/extensions/types.d.ts +20 -2
  39. package/dist/core/extensions/types.d.ts.map +1 -1
  40. package/dist/core/extensions/types.js.map +1 -1
  41. package/dist/core/model-config.d.ts +30 -0
  42. package/dist/core/model-config.d.ts.map +1 -1
  43. package/dist/core/model-config.js +6 -0
  44. package/dist/core/model-config.js.map +1 -1
  45. package/dist/core/model-registry.d.ts +5 -1
  46. package/dist/core/model-registry.d.ts.map +1 -1
  47. package/dist/core/model-registry.js +19 -4
  48. package/dist/core/model-registry.js.map +1 -1
  49. package/dist/core/model-resolver.d.ts.map +1 -1
  50. package/dist/core/model-resolver.js +9 -0
  51. package/dist/core/model-resolver.js.map +1 -1
  52. package/dist/core/model-runtime.d.ts +7 -3
  53. package/dist/core/model-runtime.d.ts.map +1 -1
  54. package/dist/core/model-runtime.js +42 -21
  55. package/dist/core/model-runtime.js.map +1 -1
  56. package/dist/core/prompt-templates.d.ts +1 -0
  57. package/dist/core/prompt-templates.d.ts.map +1 -1
  58. package/dist/core/prompt-templates.js +4 -4
  59. package/dist/core/prompt-templates.js.map +1 -1
  60. package/dist/core/remote-catalog-provider.d.ts +1 -1
  61. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  62. package/dist/core/remote-catalog-provider.js +21 -7
  63. package/dist/core/remote-catalog-provider.js.map +1 -1
  64. package/dist/core/resource-loader.d.ts.map +1 -1
  65. package/dist/core/resource-loader.js +1 -0
  66. package/dist/core/resource-loader.js.map +1 -1
  67. package/dist/core/sdk.d.ts.map +1 -1
  68. package/dist/core/sdk.js +6 -2
  69. package/dist/core/sdk.js.map +1 -1
  70. package/dist/core/session-manager.d.ts +9 -4
  71. package/dist/core/session-manager.d.ts.map +1 -1
  72. package/dist/core/session-manager.js +99 -23
  73. package/dist/core/session-manager.js.map +1 -1
  74. package/dist/core/settings-manager.d.ts +1 -1
  75. package/dist/core/settings-manager.d.ts.map +1 -1
  76. package/dist/core/settings-manager.js.map +1 -1
  77. package/dist/core/system-prompt.d.ts.map +1 -1
  78. package/dist/core/system-prompt.js +1 -1
  79. package/dist/core/system-prompt.js.map +1 -1
  80. package/dist/core/tools/bash.d.ts +2 -0
  81. package/dist/core/tools/bash.d.ts.map +1 -1
  82. package/dist/core/tools/bash.js +34 -5
  83. package/dist/core/tools/bash.js.map +1 -1
  84. package/dist/core/tools/read.d.ts.map +1 -1
  85. package/dist/core/tools/read.js +1 -1
  86. package/dist/core/tools/read.js.map +1 -1
  87. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  88. package/dist/core/tools/tool-definition-wrapper.js +3 -1
  89. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  90. package/dist/core/usage-totals.d.ts +19 -0
  91. package/dist/core/usage-totals.d.ts.map +1 -0
  92. package/dist/core/usage-totals.js +52 -0
  93. package/dist/core/usage-totals.js.map +1 -0
  94. package/dist/extensions/index.d.ts +3 -0
  95. package/dist/extensions/index.d.ts.map +1 -0
  96. package/dist/extensions/index.js +3 -0
  97. package/dist/extensions/index.js.map +1 -0
  98. package/dist/extensions/llama/client.d.ts +61 -0
  99. package/dist/extensions/llama/client.d.ts.map +1 -0
  100. package/dist/extensions/llama/client.js +302 -0
  101. package/dist/extensions/llama/client.js.map +1 -0
  102. package/dist/extensions/llama/huggingface.d.ts +23 -0
  103. package/dist/extensions/llama/huggingface.d.ts.map +1 -0
  104. package/dist/extensions/llama/huggingface.js +141 -0
  105. package/dist/extensions/llama/huggingface.js.map +1 -0
  106. package/dist/extensions/llama/index.d.ts +3 -0
  107. package/dist/extensions/llama/index.d.ts.map +1 -0
  108. package/dist/extensions/llama/index.js +208 -0
  109. package/dist/extensions/llama/index.js.map +1 -0
  110. package/dist/extensions/llama/provider.d.ts +10 -0
  111. package/dist/extensions/llama/provider.d.ts.map +1 -0
  112. package/dist/extensions/llama/provider.js +101 -0
  113. package/dist/extensions/llama/provider.js.map +1 -0
  114. package/dist/extensions/llama/ui.d.ts +42 -0
  115. package/dist/extensions/llama/ui.d.ts.map +1 -0
  116. package/dist/extensions/llama/ui.js +416 -0
  117. package/dist/extensions/llama/ui.js.map +1 -0
  118. package/dist/index.d.ts +2 -2
  119. package/dist/index.d.ts.map +1 -1
  120. package/dist/index.js +1 -1
  121. package/dist/index.js.map +1 -1
  122. package/dist/main.d.ts.map +1 -1
  123. package/dist/main.js +10 -4
  124. package/dist/main.js.map +1 -1
  125. package/dist/modes/interactive/components/extension-editor.d.ts +1 -2
  126. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  127. package/dist/modes/interactive/components/extension-editor.js +16 -46
  128. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  129. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  130. package/dist/modes/interactive/components/footer.js +24 -23
  131. package/dist/modes/interactive/components/footer.js.map +1 -1
  132. package/dist/modes/interactive/external-editor.d.ts +12 -0
  133. package/dist/modes/interactive/external-editor.d.ts.map +1 -0
  134. package/dist/modes/interactive/external-editor.js +37 -0
  135. package/dist/modes/interactive/external-editor.js.map +1 -0
  136. package/dist/modes/interactive/interactive-mode.d.ts +2 -1
  137. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  138. package/dist/modes/interactive/interactive-mode.js +72 -68
  139. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  140. package/dist/modes/rpc/rpc-client.d.ts +4 -0
  141. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  142. package/dist/modes/rpc/rpc-client.js +7 -0
  143. package/dist/modes/rpc/rpc-client.js.map +1 -1
  144. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  145. package/dist/modes/rpc/rpc-mode.js +5 -0
  146. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  147. package/dist/modes/rpc/rpc-types.d.ts +11 -0
  148. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  149. package/dist/modes/rpc/rpc-types.js.map +1 -1
  150. package/dist/utils/clipboard.d.ts.map +1 -1
  151. package/dist/utils/clipboard.js +19 -8
  152. package/dist/utils/clipboard.js.map +1 -1
  153. package/dist/utils/version-check.d.ts.map +1 -1
  154. package/dist/utils/version-check.js +3 -1
  155. package/dist/utils/version-check.js.map +1 -1
  156. package/docs/compaction.md +9 -4
  157. package/docs/custom-provider.md +33 -2
  158. package/docs/environment-variables.md +88 -0
  159. package/docs/extensions.md +61 -11
  160. package/docs/index.md +2 -0
  161. package/docs/json.md +5 -1
  162. package/docs/llama-cpp.md +99 -0
  163. package/docs/models.md +6 -2
  164. package/docs/prompt-templates.md +1 -0
  165. package/docs/providers.md +19 -1
  166. package/docs/rpc.md +104 -8
  167. package/docs/sdk.md +3 -0
  168. package/docs/session-format.md +17 -3
  169. package/docs/settings.md +1 -1
  170. package/docs/tui.md +41 -26
  171. package/docs/usage.md +2 -14
  172. package/examples/extensions/README.md +1 -1
  173. package/examples/extensions/custom-compaction.ts +4 -0
  174. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  175. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  176. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  177. package/examples/extensions/gondolin/package-lock.json +2 -2
  178. package/examples/extensions/gondolin/package.json +1 -1
  179. package/examples/extensions/handoff.ts +9 -1
  180. package/examples/extensions/sandbox/package-lock.json +2 -2
  181. package/examples/extensions/sandbox/package.json +1 -1
  182. package/examples/extensions/summarize.ts +3 -0
  183. package/examples/extensions/with-deps/package-lock.json +2 -2
  184. package/examples/extensions/with-deps/package.json +1 -1
  185. package/package.json +5 -4
package/docs/rpc.md CHANGED
@@ -23,7 +23,7 @@ Common options:
23
23
  - **Responses**: JSON objects with `type: "response"` indicating command success/failure
24
24
  - **Events**: Agent events streamed to stdout as JSON lines
25
25
 
26
- All commands support an optional `id` field for request/response correlation. If provided, the corresponding response will include the same `id`.
26
+ All commands support an optional `id` field for request/response correlation. If provided, the corresponding response will include the same `id`. `bash_execution_update` events also include the `id` of their originating `bash` command.
27
27
 
28
28
  ### Framing
29
29
 
@@ -313,6 +313,26 @@ Response:
313
313
  }
314
314
  ```
315
315
 
316
+ #### get_available_thinking_levels
317
+
318
+ List the thinking levels supported by the current model. Returns `["off"]` for a model without reasoning support.
319
+
320
+ ```json
321
+ {"type": "get_available_thinking_levels"}
322
+ ```
323
+
324
+ Response:
325
+ ```json
326
+ {
327
+ "type": "response",
328
+ "command": "get_available_thinking_levels",
329
+ "success": true,
330
+ "data": {
331
+ "levels": ["off", "minimal", "low", "medium", "high"]
332
+ }
333
+ }
334
+ ```
335
+
316
336
  ### Queue Modes
317
337
 
318
338
  #### set_steering_mode
@@ -375,12 +395,20 @@ Response:
375
395
  "firstKeptEntryId": "abc123",
376
396
  "tokensBefore": 150000,
377
397
  "estimatedTokensAfter": 32000,
398
+ "usage": {
399
+ "input": 32000,
400
+ "output": 1200,
401
+ "cacheRead": 0,
402
+ "cacheWrite": 0,
403
+ "totalTokens": 33200,
404
+ "cost": {"input": 0.01, "output": 0.02, "cacheRead": 0, "cacheWrite": 0, "total": 0.03}
405
+ },
378
406
  "details": {}
379
407
  }
380
408
  }
381
409
  ```
382
410
 
383
- `estimatedTokensAfter` is a heuristic estimate over the rebuilt message context immediately after compaction, not a provider-exact token count.
411
+ `estimatedTokensAfter` is a heuristic estimate over the rebuilt message context immediately after compaction, not a provider-exact token count. `usage` reports the LLM call or calls that generated the summary and may be omitted by custom compaction handlers.
384
412
 
385
413
  #### set_auto_compaction
386
414
 
@@ -427,15 +455,18 @@ Response:
427
455
 
428
456
  #### bash
429
457
 
430
- Execute a shell command and add output to conversation context.
458
+ Execute a shell command and add output to conversation context. Output streams as `bash_execution_update` events while the command runs; the response contains the final result.
431
459
 
432
460
  ```json
433
- {"type": "bash", "command": "ls -la"}
461
+ {"id": "req-1", "type": "bash", "command": "ls -la"}
434
462
  ```
435
463
 
464
+ Include an `id` to associate streamed `bash_execution_update` events with this command.
465
+
436
466
  Response:
437
467
  ```json
438
468
  {
469
+ "id": "req-1",
439
470
  "type": "response",
440
471
  "command": "bash",
441
472
  "success": true,
@@ -466,7 +497,7 @@ If output was truncated, includes `fullOutputPath`:
466
497
 
467
498
  **How bash results reach the LLM:**
468
499
 
469
- The `bash` command executes immediately and returns a `BashResult`. Internally, a `BashExecutionMessage` is created and stored in the agent's message state. This message does NOT emit an event.
500
+ The `bash` command executes immediately and returns a `BashResult`. Internally, a `BashExecutionMessage` is created and stored in the agent's message state.
470
501
 
471
502
  When the next `prompt` command is sent, all messages (including `BashExecutionMessage`) are transformed before being sent to the LLM. The `BashExecutionMessage` is converted to a `UserMessage` with this format:
472
503
 
@@ -481,7 +512,6 @@ drwxr-xr-x ...
481
512
  This means:
482
513
  1. Bash output is included in the LLM context on the **next prompt**, not immediately
483
514
  2. Multiple bash commands can be executed before a prompt; all outputs will be included
484
- 3. No event is emitted for the `BashExecutionMessage` itself
485
515
 
486
516
  #### abort_bash
487
517
 
@@ -537,7 +567,7 @@ Response:
537
567
  }
538
568
  ```
539
569
 
540
- `tokens` contains assistant usage totals for the current session state. `contextUsage` contains the actual current context-window estimate used for compaction and footer display.
570
+ `tokens` and `cost` include assistant messages, usage reported by tools, and compaction/branch-summary generation across the full session. `contextUsage` contains the actual current context-window estimate used for compaction and footer display.
541
571
 
542
572
  `contextUsage` is omitted when no model or context window is available. `contextUsage.tokens` and `contextUsage.percent` are `null` immediately after compaction until a fresh post-compaction assistant response provides valid usage data.
543
573
 
@@ -801,7 +831,7 @@ Each command has:
801
831
 
802
832
  ## Events
803
833
 
804
- Events are streamed to stdout as JSON lines during agent operation. Events do NOT include an `id` field (only responses do).
834
+ Events are streamed to stdout as JSON lines during agent operation. Events do not generally include an `id` field; `bash_execution_update` includes the `id` of its originating `bash` command when one was provided.
805
835
 
806
836
  ### Event Types
807
837
 
@@ -815,6 +845,7 @@ Events are streamed to stdout as JSON lines during agent operation. Events do NO
815
845
  | `message_start` | Message begins |
816
846
  | `message_update` | Streaming update (text/thinking/toolcall deltas) |
817
847
  | `message_end` | Message completes |
848
+ | `bash_execution_update` | Direct RPC bash command output chunk |
818
849
  | `tool_execution_start` | Tool begins execution |
819
850
  | `tool_execution_update` | Tool execution progress (streaming output) |
820
851
  | `tool_execution_end` | Tool completes |
@@ -823,6 +854,9 @@ Events are streamed to stdout as JSON lines during agent operation. Events do NO
823
854
  | `compaction_end` | Compaction completes |
824
855
  | `auto_retry_start` | Auto-retry begins (after transient error) |
825
856
  | `auto_retry_end` | Auto-retry completes (success or final failure) |
857
+ | `summarization_retry_scheduled` | Retry scheduled for a transient compaction or branch-summary summarization error |
858
+ | `summarization_retry_attempt_start` | Retried summarization request starts |
859
+ | `summarization_retry_finished` | Summarization retry loop completes |
826
860
  | `extension_error` | Extension threw an error |
827
861
 
828
862
  ### agent_start
@@ -920,6 +954,20 @@ Example streaming a text response:
920
954
  {"type":"message_update","message":{...},"assistantMessageEvent":{"type":"text_end","contentIndex":0,"content":"Hello world","partial":{...}}}
921
955
  ```
922
956
 
957
+ ### bash_execution_update
958
+
959
+ Emitted once for each output chunk from a direct `bash` command. `id` matches the command's `id`, allowing clients to associate output with the correct command.
960
+
961
+ Events stream all output while the command runs, even if the final `bash` response's `output` is truncated.
962
+
963
+ ```json
964
+ {
965
+ "type": "bash_execution_update",
966
+ "id": "req-1",
967
+ "delta": "total 48\n"
968
+ }
969
+ ```
970
+
923
971
  ### tool_execution_start / tool_execution_update / tool_execution_end
924
972
 
925
973
  Emitted when a tool begins, streams progress, and completes execution.
@@ -996,6 +1044,14 @@ The `reason` field is `"manual"`, `"threshold"`, or `"overflow"`.
996
1044
  "firstKeptEntryId": "abc123",
997
1045
  "tokensBefore": 150000,
998
1046
  "estimatedTokensAfter": 32000,
1047
+ "usage": {
1048
+ "input": 32000,
1049
+ "output": 1200,
1050
+ "cacheRead": 0,
1051
+ "cacheWrite": 0,
1052
+ "totalTokens": 33200,
1053
+ "cost": {"input": 0.01, "output": 0.02, "cacheRead": 0, "cacheWrite": 0, "total": 0.03}
1054
+ },
999
1055
  "details": {}
1000
1056
  },
1001
1057
  "aborted": false,
@@ -1041,6 +1097,36 @@ On final failure (max retries exceeded):
1041
1097
  }
1042
1098
  ```
1043
1099
 
1100
+ ### summarization_retry_scheduled / summarization_retry_attempt_start / summarization_retry_finished
1101
+
1102
+ Emitted when compaction or branch-summary summarization retries after a transient provider error. These events use the same retry settings as automatic assistant-turn retries.
1103
+
1104
+ ```json
1105
+ {
1106
+ "type": "summarization_retry_scheduled",
1107
+ "attempt": 1,
1108
+ "maxAttempts": 3,
1109
+ "delayMs": 2000,
1110
+ "errorMessage": "terminated"
1111
+ }
1112
+ ```
1113
+
1114
+ ```json
1115
+ {
1116
+ "type": "summarization_retry_attempt_start",
1117
+ "source": "compaction",
1118
+ "reason": "threshold"
1119
+ }
1120
+ ```
1121
+
1122
+ For branch summaries, `source` is `"branchSummary"` and no `reason` is present.
1123
+
1124
+ ```json
1125
+ {
1126
+ "type": "summarization_retry_finished"
1127
+ }
1128
+ ```
1129
+
1044
1130
  ### extension_error
1045
1131
 
1046
1132
  Emitted when an extension throws an error.
@@ -1348,11 +1434,21 @@ Stop reasons: `"stop"`, `"length"`, `"toolUse"`, `"error"`, `"aborted"`
1348
1434
  "toolCallId": "call_123",
1349
1435
  "toolName": "bash",
1350
1436
  "content": [{"type": "text", "text": "total 48\ndrwxr-xr-x ..."}],
1437
+ "usage": {
1438
+ "input": 100,
1439
+ "output": 50,
1440
+ "cacheRead": 0,
1441
+ "cacheWrite": 0,
1442
+ "totalTokens": 150,
1443
+ "cost": {"input": 0.0003, "output": 0.00075, "cacheRead": 0, "cacheWrite": 0, "total": 0.00105}
1444
+ },
1351
1445
  "isError": false,
1352
1446
  "timestamp": 1733234567890
1353
1447
  }
1354
1448
  ```
1355
1449
 
1450
+ `usage` is optional and reports nested LLM work performed by the tool. When present, it contributes to session token and cost totals.
1451
+
1356
1452
  ### BashExecutionMessage
1357
1453
 
1358
1454
  Created by the `bash` RPC command (not by LLM tool calls):
package/docs/sdk.md CHANGED
@@ -319,6 +319,9 @@ session.subscribe((event) => {
319
319
  case "compaction_end":
320
320
  case "auto_retry_start":
321
321
  case "auto_retry_end":
322
+ case "summarization_retry_scheduled":
323
+ case "summarization_retry_attempt_start":
324
+ case "summarization_retry_finished":
322
325
  break;
323
326
  }
324
327
  });
@@ -96,6 +96,7 @@ interface ToolResultMessage {
96
96
  toolName: string;
97
97
  content: (TextContent | ImageContent)[];
98
98
  details?: any; // Tool-specific metadata
99
+ usage?: Usage; // Nested LLM work performed by the tool
99
100
  isError: boolean;
100
101
  timestamp: number;
101
102
  }
@@ -231,9 +232,18 @@ Created when context is compacted. Stores a summary of earlier messages.
231
232
  {"type":"compaction","id":"f6g7h8i9","parentId":"e5f6g7h8","timestamp":"2024-12-03T14:10:00.000Z","summary":"User discussed X, Y, Z...","firstKeptEntryId":"c3d4e5f6","tokensBefore":50000}
232
233
  ```
233
234
 
235
+ Newer harness-generated compactions embed the retained post-compaction context directly on the entry, instead of `firstKeptEntryId`:
236
+
237
+ ```json
238
+ {"type":"compaction","id":"f6g7h8i9","parentId":"e5f6g7h8","timestamp":"2024-12-03T14:10:00.000Z","summary":"User discussed X, Y, Z...","tokensBefore":50000,"retainedTail":[{"role":"user","content":"latest request"},{"role":"assistant","content":[{"type":"text","text":"latest reply"}],"provider":"anthropic","model":"claude-sonnet-4-5","usage":{...},"stopReason":"stop"}]}
239
+ ```
240
+
234
241
  Optional fields:
242
+ - `usage`: LLM usage from generating the summary; included in session token and cost totals
243
+ - `retainedTail`: Materialized `AgentMessage[]` kept after compaction. This is optional only for backward compatibility with older sessions. Newer harness-generated compactions include it so we can rebuild context from this checkpoint without walking older entries before the compaction entry.
235
244
  - `details`: Implementation-specific data (e.g., `{ readFiles: string[], modifiedFiles: string[] }` for default, or custom data for extensions)
236
245
  - `fromHook`: `true` if generated by an extension, `false`/`undefined` if pi-generated (legacy field name)
246
+ - `firstKeptEntryId`: for compatibility with old entry format.
237
247
 
238
248
  ### BranchSummaryEntry
239
249
 
@@ -244,6 +254,7 @@ Created when switching branches via `/tree` with an LLM generated summary of the
244
254
  ```
245
255
 
246
256
  Optional fields:
257
+ - `usage`: LLM usage from generating the summary; included in session token and cost totals
247
258
  - `details`: File tracking data (`{ readFiles: string[], modifiedFiles: string[] }`) for default, or custom data for extensions
248
259
  - `fromHook`: `true` if generated by an extension, `false`/`undefined` if pi-generated (legacy field name)
249
260
 
@@ -311,8 +322,9 @@ Entries form a tree:
311
322
  1. Collects all entries on the path
312
323
  2. If a `CompactionEntry` is on the path:
313
324
  - Includes the compaction entry first
314
- - Then entries from `firstKeptEntryId` to compaction
315
- - Then entries after compaction
325
+ - If `retainedTail` is present, it acts as a self-contained checkpoint and entries after the compaction are included
326
+ - Otherwise entries from `firstKeptEntryId` to the compaction are included
327
+ - Then entries after compaction are included
316
328
  3. Preserves non-message entries in the selected range so interactive mode can render them
317
329
 
318
330
  `buildSessionContext()` builds on that entry list to produce the message list for the LLM:
@@ -320,11 +332,13 @@ Entries form a tree:
320
332
  1. Extracts current model and thinking level settings from the full path
321
333
  2. Converts selected entries to messages:
322
334
  - `message` -> stored `AgentMessage`
323
- - `compaction` -> `compactionSummary`
335
+ - `compaction` -> `compactionSummary` plus `retainedTail` when present
324
336
  - `branch_summary` -> `branchSummary`
325
337
  - `custom_message` -> `CustomMessage`
326
338
  - `custom` -> no context message
327
339
 
340
+ This makes newer compactions act like self-contained checkpoints. `retainedTail` is optional only so older sessions that only store `firstKeptEntryId` continue to load correctly.
341
+
328
342
  ## Parsing Example
329
343
 
330
344
  ```typescript
package/docs/settings.md CHANGED
@@ -142,7 +142,7 @@ Set `PI_SKIP_VERSION_CHECK=1` to disable the Pi version update check. Use `--off
142
142
  | `retry.provider.maxRetries` | number | `0` | Provider/SDK retry attempts |
143
143
  | `retry.provider.maxRetryDelayMs` | number | `60000` | Max server-requested delay before failing (60s) |
144
144
 
145
- When a provider requests a retry delay longer than `retry.provider.maxRetryDelayMs` (e.g., Google's "quota will reset after 5h"), the request fails immediately with an informative error instead of waiting silently. Set to `0` to disable the cap.
145
+ When a provider requests a retry delay longer than `retry.provider.maxRetryDelayMs`, the request fails immediately with an informative error instead of waiting silently. Set it to `0` to disable the limit.
146
146
 
147
147
  Keep `retry.provider.maxRetries` at `0` unless provider-level retries are explicitly needed. Setting it above `0` can make SDK/provider retries handle out-of-usage-limit errors before Pi sees them, which may block the agent until the provider quota resets in some circumstances.
148
148
 
package/docs/tui.md CHANGED
@@ -90,19 +90,32 @@ Without this propagation, typing with an IME (Chinese, Japanese, Korean, etc.) w
90
90
 
91
91
  ```typescript
92
92
  pi.on("session_start", async (_event, ctx) => {
93
- const handle = ctx.ui.custom(myComponent);
94
- // handle.requestRender() - trigger re-render
95
- // handle.close() - restore normal UI
93
+ const result = await ctx.ui.custom<string | null>((tui, theme, keybindings, done) =>
94
+ new MyComponent({
95
+ theme,
96
+ keybindings,
97
+ onChange: () => tui.requestRender(),
98
+ onSelect: (value) => done(value),
99
+ onCancel: () => done(null),
100
+ })
101
+ );
96
102
  });
97
103
  ```
98
104
 
99
- **In custom tools** via `pi.ui.custom()`:
105
+ **In custom tools** via `ctx.ui.custom()`:
100
106
 
101
107
  ```typescript
102
- async execute(toolCallId, params, onUpdate, ctx, signal) {
103
- const handle = pi.ui.custom(myComponent);
104
- // ...
105
- handle.close();
108
+ async execute(toolCallId, params, signal, onUpdate, ctx) {
109
+ const result = await ctx.ui.custom<string | null>((tui, theme, keybindings, done) =>
110
+ new MyComponent({
111
+ theme,
112
+ keybindings,
113
+ onChange: () => tui.requestRender(),
114
+ onSelect: (value) => done(value),
115
+ onCancel: () => done(null),
116
+ })
117
+ );
118
+ // Use result...
106
119
  }
107
120
  ```
108
121
 
@@ -374,24 +387,26 @@ Usage in an extension:
374
387
  ```typescript
375
388
  pi.registerCommand("pick", {
376
389
  description: "Pick an item",
377
- handler: async (args, ctx) => {
390
+ handler: async (_args, ctx) => {
378
391
  const items = ["Option A", "Option B", "Option C"];
379
- const selector = new MySelector(items);
380
-
381
- let handle: { close: () => void; requestRender: () => void };
382
-
383
- await new Promise<void>((resolve) => {
384
- selector.onSelect = (item) => {
385
- ctx.ui.notify(`Selected: ${item}`, "info");
386
- handle.close();
387
- resolve();
388
- };
389
- selector.onCancel = () => {
390
- handle.close();
391
- resolve();
392
+ const selected = await ctx.ui.custom<string | null>((tui, _theme, _keybindings, done) => {
393
+ const selector = new MySelector(items);
394
+ selector.onSelect = done;
395
+ selector.onCancel = () => done(null);
396
+
397
+ return {
398
+ render: (width) => selector.render(width),
399
+ handleInput: (data) => {
400
+ selector.handleInput(data);
401
+ tui.requestRender();
402
+ },
403
+ invalidate: () => selector.invalidate(),
392
404
  };
393
- handle = ctx.ui.custom(selector);
394
405
  });
406
+
407
+ if (selected !== null) {
408
+ ctx.ui.notify(`Selected: ${selected}`, "info");
409
+ }
395
410
  }
396
411
  });
397
412
  ```
@@ -486,7 +501,7 @@ class CachedComponent {
486
501
  }
487
502
  ```
488
503
 
489
- Call `invalidate()` when state changes, then `handle.requestRender()` to trigger re-render.
504
+ Call `invalidate()` when state changes, then use the injected `tui.requestRender()` to trigger re-render.
490
505
 
491
506
  ## Invalidation and Theme Changes
492
507
 
@@ -885,9 +900,9 @@ class VimEditor extends CustomEditor {
885
900
 
886
901
  export default function (pi: ExtensionAPI) {
887
902
  pi.on("session_start", (_event, ctx) => {
888
- // Factory receives theme and keybindings from the app
903
+ // Factory receives the TUI, theme, and keybindings from the app
889
904
  ctx.ui.setEditorComponent((tui, theme, keybindings) =>
890
- new VimEditor(theme, keybindings)
905
+ new VimEditor(tui, theme, keybindings)
891
906
  );
892
907
  });
893
908
  }
package/docs/usage.md CHANGED
@@ -11,7 +11,7 @@ The interface has four main areas:
11
11
  - **Startup header** - shortcuts, loaded context files, prompt templates, skills, and extensions
12
12
  - **Messages** - user messages, assistant responses, tool calls, tool results, notifications, errors, and extension UI
13
13
  - **Editor** - where you type; border color indicates the current thinking level
14
- - **Footer** - working directory, session name, token/cache usage, cost, context usage, and current model
14
+ - **Footer** - working directory, session name, token/cache usage, cost, context usage, and current model. Totals include assistant responses, usage reported by tools, and summary generation.
15
15
 
16
16
  The editor can be replaced temporarily by built-in UI such as `/settings` or by custom extension UI.
17
17
 
@@ -37,6 +37,7 @@ Type `/` in the editor to open command completion. Extensions can register custo
37
37
  | Command | Description |
38
38
  |---------|-------------|
39
39
  | `/login`, `/logout` | Manage OAuth or API-key credentials |
40
+ | [`/llama`](llama-cpp.md) | Download, load, and unload llama.cpp router models |
40
41
  | `/model` | Switch models |
41
42
  | `/scoped-models` | Enable/disable models for Ctrl+P cycling |
42
43
  | `/settings` | Thinking level, theme, message delivery, transport |
@@ -288,19 +289,6 @@ pi --tools read,grep,find,ls -p "Review the code"
288
289
  pi --exclude-tools ask_question
289
290
  ```
290
291
 
291
- ### Environment Variables
292
-
293
- | Variable | Description |
294
- |----------|-------------|
295
- | `PI_CODING_AGENT_DIR` | Override config directory; default is `~/.pi/agent` |
296
- | `PI_CODING_AGENT_SESSION_DIR` | Override session storage directory; overridden by `--session-dir` |
297
- | `PI_PACKAGE_DIR` | Override package directory, useful for Nix/Guix store paths |
298
- | `PI_OFFLINE` | Disable startup network operations, including update checks, package update checks, and install/update telemetry |
299
- | `PI_SKIP_VERSION_CHECK` | Skip the Pi version update check at startup. This prevents the `pi.dev` latest-version request |
300
- | `PI_TELEMETRY` | Override install/update telemetry and provider attribution headers: `1`/`true`/`yes` or `0`/`false`/`no`. This does not disable update checks |
301
- | `PI_CACHE_RETENTION` | Set to `long` for extended prompt cache where supported |
302
- | `VISUAL`, `EDITOR` | Fallback external editor for Ctrl+G when `externalEditor` is unset; defaults to Notepad on Windows and `nano` elsewhere |
303
-
304
292
  ## Design Principles
305
293
 
306
294
  Pi keeps the core small and pushes workflow-specific behavior into extensions, skills, prompt templates, and packages.
@@ -162,7 +162,7 @@ export default function (pi: ExtensionAPI) {
162
162
  parameters: Type.Object({
163
163
  name: Type.String({ description: "Name to greet" }),
164
164
  }),
165
- async execute(toolCallId, params, onUpdate, ctx, signal) {
165
+ async execute(toolCallId, params, signal, onUpdate, ctx) {
166
166
  return {
167
167
  content: [{ type: "text", text: `Hello, ${params.name}!` }],
168
168
  details: {},
@@ -13,6 +13,7 @@
13
13
  * pi --extension examples/extensions/custom-compaction.ts
14
14
  */
15
15
 
16
+ import { uuidv7 } from "@earendil-works/pi-ai";
16
17
  import { complete } from "@earendil-works/pi-ai/compat";
17
18
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
18
19
  import { convertToLlm, serializeConversation } from "@earendil-works/pi-coding-agent";
@@ -96,6 +97,8 @@ ${conversationText}
96
97
  env: auth.env,
97
98
  maxTokens: 8192,
98
99
  signal,
100
+ cacheRetention: "none",
101
+ sessionId: uuidv7(),
99
102
  },
100
103
  );
101
104
 
@@ -116,6 +119,7 @@ ${conversationText}
116
119
  summary,
117
120
  firstKeptEntryId,
118
121
  tokensBefore,
122
+ usage: response.usage,
119
123
  },
120
124
  };
121
125
  } catch (error) {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider",
3
- "version": "0.80.10",
3
+ "version": "0.82.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-custom-provider",
9
- "version": "0.80.10",
9
+ "version": "0.82.0",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sdk": "^0.52.0"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider-anthropic",
3
3
  "private": true,
4
- "version": "0.80.10",
4
+ "version": "0.82.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider-gitlab-duo",
3
3
  "private": true,
4
- "version": "0.80.10",
4
+ "version": "0.82.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-gondolin",
3
- "version": "0.80.10",
3
+ "version": "0.82.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-gondolin",
9
- "version": "0.80.10",
9
+ "version": "0.82.0",
10
10
  "dependencies": {
11
11
  "@earendil-works/gondolin": "0.12.0"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-gondolin",
3
3
  "private": true,
4
- "version": "0.80.10",
4
+ "version": "0.82.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -13,6 +13,7 @@
13
13
  */
14
14
 
15
15
  import type { AgentMessage } from "@earendil-works/pi-agent-core";
16
+ import { uuidv7 } from "@earendil-works/pi-ai";
16
17
  import { complete, type Message } from "@earendil-works/pi-ai/compat";
17
18
  import type { ExtensionAPI, SessionEntry } from "@earendil-works/pi-coding-agent";
18
19
  import { BorderedLoader, convertToLlm, serializeConversation } from "@earendil-works/pi-coding-agent";
@@ -136,7 +137,14 @@ export default function (pi: ExtensionAPI) {
136
137
  const response = await complete(
137
138
  ctx.model!,
138
139
  { systemPrompt: SYSTEM_PROMPT, messages: [userMessage] },
139
- { apiKey: auth.apiKey, headers: auth.headers, env: auth.env, signal: loader.signal },
140
+ {
141
+ apiKey: auth.apiKey,
142
+ headers: auth.headers,
143
+ env: auth.env,
144
+ signal: loader.signal,
145
+ cacheRetention: "none",
146
+ sessionId: uuidv7(),
147
+ },
140
148
  );
141
149
 
142
150
  if (response.stopReason === "aborted") {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-sandbox",
3
- "version": "1.10.10",
3
+ "version": "1.12.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-sandbox",
9
- "version": "1.10.10",
9
+ "version": "1.12.0",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sandbox-runtime": "^0.0.26"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-sandbox",
3
3
  "private": true,
4
- "version": "1.10.10",
4
+ "version": "1.12.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,3 +1,4 @@
1
+ import { uuidv7 } from "@earendil-works/pi-ai";
1
2
  import { complete, getModel } from "@earendil-works/pi-ai/compat";
2
3
  import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
3
4
  import { DynamicBorder, getMarkdownTheme } from "@earendil-works/pi-coding-agent";
@@ -193,6 +194,8 @@ export default function (pi: ExtensionAPI) {
193
194
  headers: auth.headers,
194
195
  env: auth.env,
195
196
  reasoningEffort: "high",
197
+ cacheRetention: "none",
198
+ sessionId: uuidv7(),
196
199
  },
197
200
  );
198
201
 
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
- "version": "0.80.10",
3
+ "version": "0.82.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-with-deps",
9
- "version": "0.80.10",
9
+ "version": "0.82.0",
10
10
  "dependencies": {
11
11
  "ms": "^2.1.3"
12
12
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
3
  "private": true,
4
- "version": "0.80.10",
4
+ "version": "0.82.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",