@astralyn/pi 1.4.9 → 1.4.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +54 -0
- package/dist/bundle/chunks/{chunk-3PKXUKTB.js → chunk-6GTUUUCJ.js} +123 -123
- package/dist/bundle/chunks/{chunk-BAGHIP5J.js → chunk-MF3T3ETJ.js} +3 -3
- package/dist/bundle/chunks/{chunk-F66AY3WR.js → chunk-UCH27AVQ.js} +1 -1
- package/dist/bundle/chunks/{execute-P22VMM2H.js → execute-FQKRO4XJ.js} +1 -1
- package/dist/bundle/chunks/{virtual-modules-VKMBQTR2.js → virtual-modules-6IJ6V2CG.js} +1 -1
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/core/agent-session.d.ts +34 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +99 -2
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/isolated-session.d.ts +7 -2
- package/dist/core/isolated-session.d.ts.map +1 -1
- package/dist/core/isolated-session.js +7 -3
- package/dist/core/isolated-session.js.map +1 -1
- package/dist/core/session-manager.d.ts +17 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +29 -0
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/tasks/delivery.d.ts +42 -7
- package/dist/core/tasks/delivery.d.ts.map +1 -1
- package/dist/core/tasks/delivery.js +129 -15
- package/dist/core/tasks/delivery.js.map +1 -1
- package/dist/core/tasks/execution.d.ts +27 -14
- package/dist/core/tasks/execution.d.ts.map +1 -1
- package/dist/core/tasks/execution.js +90 -86
- package/dist/core/tasks/execution.js.map +1 -1
- package/dist/core/tasks/limits.d.ts +13 -1
- package/dist/core/tasks/limits.d.ts.map +1 -1
- package/dist/core/tasks/limits.js +14 -1
- package/dist/core/tasks/limits.js.map +1 -1
- package/dist/core/tasks/output.d.ts +9 -1
- package/dist/core/tasks/output.d.ts.map +1 -1
- package/dist/core/tasks/output.js +23 -10
- package/dist/core/tasks/output.js.map +1 -1
- package/dist/core/tasks/presentation.d.ts +1 -1
- package/dist/core/tasks/presentation.d.ts.map +1 -1
- package/dist/core/tasks/presentation.js +6 -4
- package/dist/core/tasks/presentation.js.map +1 -1
- package/dist/core/tasks/record.d.ts +41 -29
- package/dist/core/tasks/record.d.ts.map +1 -1
- package/dist/core/tasks/record.js +82 -37
- package/dist/core/tasks/record.js.map +1 -1
- package/dist/core/tasks/reminder.js +2 -2
- package/dist/core/tasks/reminder.js.map +1 -1
- package/dist/core/tasks/runtime.d.ts +17 -14
- package/dist/core/tasks/runtime.d.ts.map +1 -1
- package/dist/core/tasks/runtime.js +68 -116
- package/dist/core/tasks/runtime.js.map +1 -1
- package/dist/core/tasks/scheduler.d.ts +3 -1
- package/dist/core/tasks/scheduler.d.ts.map +1 -1
- package/dist/core/tasks/scheduler.js +16 -12
- package/dist/core/tasks/scheduler.js.map +1 -1
- package/dist/core/tasks/session.d.ts +24 -3
- package/dist/core/tasks/session.d.ts.map +1 -1
- package/dist/core/tasks/session.js +73 -9
- package/dist/core/tasks/session.js.map +1 -1
- package/dist/core/tasks/store.d.ts +17 -4
- package/dist/core/tasks/store.d.ts.map +1 -1
- package/dist/core/tasks/store.js +45 -48
- package/dist/core/tasks/store.js.map +1 -1
- package/dist/core/tasks/types.d.ts +72 -29
- package/dist/core/tasks/types.d.ts.map +1 -1
- package/dist/core/tasks/types.js +7 -0
- package/dist/core/tasks/types.js.map +1 -1
- package/dist/core/tasks/wait.d.ts +19 -0
- package/dist/core/tasks/wait.d.ts.map +1 -0
- package/dist/core/tasks/wait.js +45 -0
- package/dist/core/tasks/wait.js.map +1 -0
- package/dist/core/tools/shell-execution.d.ts.map +1 -1
- package/dist/core/tools/shell-execution.js +2 -1
- package/dist/core/tools/shell-execution.js.map +1 -1
- package/dist/core/tools/shell-tool.d.ts.map +1 -1
- package/dist/core/tools/shell-tool.js +20 -13
- package/dist/core/tools/shell-tool.js.map +1 -1
- package/dist/extensions/agent/activity-lines.d.ts +10 -0
- package/dist/extensions/agent/activity-lines.d.ts.map +1 -0
- package/dist/extensions/agent/activity-lines.js +76 -0
- package/dist/extensions/agent/activity-lines.js.map +1 -0
- package/dist/extensions/agent/activity.d.ts +25 -4
- package/dist/extensions/agent/activity.d.ts.map +1 -1
- package/dist/extensions/agent/activity.js +76 -21
- package/dist/extensions/agent/activity.js.map +1 -1
- package/dist/extensions/agent/artifacts.d.ts +15 -0
- package/dist/extensions/agent/artifacts.d.ts.map +1 -0
- package/dist/extensions/agent/artifacts.js +44 -0
- package/dist/extensions/agent/artifacts.js.map +1 -0
- package/dist/extensions/agent/progress.d.ts +30 -4
- package/dist/extensions/agent/progress.d.ts.map +1 -1
- package/dist/extensions/agent/progress.js +84 -11
- package/dist/extensions/agent/progress.js.map +1 -1
- package/dist/extensions/agent/render.d.ts.map +1 -1
- package/dist/extensions/agent/render.js +8 -24
- package/dist/extensions/agent/render.js.map +1 -1
- package/dist/extensions/agent/report.d.ts +11 -3
- package/dist/extensions/agent/report.d.ts.map +1 -1
- package/dist/extensions/agent/report.js +32 -7
- package/dist/extensions/agent/report.js.map +1 -1
- package/dist/extensions/agent/tool.d.ts.map +1 -1
- package/dist/extensions/agent/tool.js +20 -5
- package/dist/extensions/agent/tool.js.map +1 -1
- package/dist/extensions/agent/types.d.ts +2 -0
- package/dist/extensions/agent/types.d.ts.map +1 -1
- package/dist/extensions/agent/types.js.map +1 -1
- package/dist/extensions/agent/worker.d.ts +7 -0
- package/dist/extensions/agent/worker.d.ts.map +1 -1
- package/dist/extensions/agent/worker.js +9 -3
- package/dist/extensions/agent/worker.js.map +1 -1
- package/dist/extensions/search/index.d.ts.map +1 -1
- package/dist/extensions/search/index.js +6 -7
- package/dist/extensions/search/index.js.map +1 -1
- package/dist/extensions/tasks/tool/actions.d.ts.map +1 -1
- package/dist/extensions/tasks/tool/actions.js +15 -11
- package/dist/extensions/tasks/tool/actions.js.map +1 -1
- package/dist/extensions/tasks/tool/schema.d.ts +1 -1
- package/dist/extensions/tasks/tool/schema.d.ts.map +1 -1
- package/dist/extensions/tasks/tool/schema.js +5 -5
- package/dist/extensions/tasks/tool/schema.js.map +1 -1
- package/dist/extensions/tasks/tool/types.d.ts +2 -0
- package/dist/extensions/tasks/tool/types.d.ts.map +1 -1
- package/dist/extensions/tasks/tool/types.js.map +1 -1
- package/dist/extensions/tasks/tool.d.ts.map +1 -1
- package/dist/extensions/tasks/tool.js +3 -2
- package/dist/extensions/tasks/tool.js.map +1 -1
- package/dist/extensions/tasks/ui/completion-render.d.ts.map +1 -1
- package/dist/extensions/tasks/ui/completion-render.js +2 -2
- package/dist/extensions/tasks/ui/completion-render.js.map +1 -1
- package/dist/extensions/tasks/ui/footer.d.ts +37 -0
- package/dist/extensions/tasks/ui/footer.d.ts.map +1 -0
- package/dist/extensions/tasks/ui/footer.js +129 -0
- package/dist/extensions/tasks/ui/footer.js.map +1 -0
- package/dist/extensions/tasks/ui/frame.d.ts +36 -0
- package/dist/extensions/tasks/ui/frame.d.ts.map +1 -0
- package/dist/extensions/tasks/ui/frame.js +33 -0
- package/dist/extensions/tasks/ui/frame.js.map +1 -0
- package/dist/extensions/tasks/ui/help.d.ts +6 -0
- package/dist/extensions/tasks/ui/help.d.ts.map +1 -0
- package/dist/extensions/tasks/ui/help.js +53 -0
- package/dist/extensions/tasks/ui/help.js.map +1 -0
- package/dist/extensions/tasks/ui/inspector.d.ts +4 -3
- package/dist/extensions/tasks/ui/inspector.d.ts.map +1 -1
- package/dist/extensions/tasks/ui/inspector.js +25 -6
- package/dist/extensions/tasks/ui/inspector.js.map +1 -1
- package/dist/extensions/tasks/ui/layout.d.ts +15 -18
- package/dist/extensions/tasks/ui/layout.d.ts.map +1 -1
- package/dist/extensions/tasks/ui/layout.js +162 -255
- package/dist/extensions/tasks/ui/layout.js.map +1 -1
- package/dist/extensions/tasks/ui/list.d.ts +3 -1
- package/dist/extensions/tasks/ui/list.d.ts.map +1 -1
- package/dist/extensions/tasks/ui/list.js +19 -14
- package/dist/extensions/tasks/ui/list.js.map +1 -1
- package/dist/extensions/tasks/ui/manager.d.ts +17 -5
- package/dist/extensions/tasks/ui/manager.d.ts.map +1 -1
- package/dist/extensions/tasks/ui/manager.js +147 -90
- package/dist/extensions/tasks/ui/manager.js.map +1 -1
- package/dist/extensions/tasks/ui/model.d.ts +32 -5
- package/dist/extensions/tasks/ui/model.d.ts.map +1 -1
- package/dist/extensions/tasks/ui/model.js +7 -7
- package/dist/extensions/tasks/ui/model.js.map +1 -1
- package/dist/extensions/tasks/ui/panes.d.ts +40 -0
- package/dist/extensions/tasks/ui/panes.d.ts.map +1 -0
- package/dist/extensions/tasks/ui/panes.js +144 -0
- package/dist/extensions/tasks/ui/panes.js.map +1 -0
- package/dist/extensions/tasks/ui/render.d.ts.map +1 -1
- package/dist/extensions/tasks/ui/render.js +11 -7
- package/dist/extensions/tasks/ui/render.js.map +1 -1
- package/dist/extensions/tasks/ui/viewport.d.ts +12 -4
- package/dist/extensions/tasks/ui/viewport.d.ts.map +1 -1
- package/dist/extensions/tasks/ui/viewport.js +23 -7
- package/dist/extensions/tasks/ui/viewport.js.map +1 -1
- package/dist/extensions/tasks/ui/views.d.ts +12 -6
- package/dist/extensions/tasks/ui/views.d.ts.map +1 -1
- package/dist/extensions/tasks/ui/views.js +39 -32
- package/dist/extensions/tasks/ui/views.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts +11 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +43 -17
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +37 -2
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +11 -0
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +48 -0
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +1 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +2 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/bundled/extensions/agent.md +39 -7
- package/docs/bundled/tasks.md +25 -21
- package/docs/extensions.md +14 -10
- package/docs/json.md +3 -0
- package/docs/rpc.md +14 -0
- package/docs/sdk.md +11 -1
- package/docs/session-format.md +10 -4
- package/docs/sessions.md +1 -1
- package/docs/usage.md +2 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
|
@@ -16,9 +16,11 @@ The bundled `Agent` extension adds the `Agent` tool and `/agent` settings comman
|
|
|
16
16
|
- `description` is an optional short (3–5 word) label for the Transcript and `/tasks`; otherwise Pi derives one from the prompt.
|
|
17
17
|
- `background` is optional. Foreground waits for the report; `true` returns a Task ID once the Agent has initialized, or at once while it waits for a slot, and delivers the report automatically. Interactive **Ctrl+B** can detach a foreground call without restarting it.
|
|
18
18
|
|
|
19
|
+
Background Agents, whether requested with `background: true` or detached with **Ctrl+B**, are admitted only while the `tasks` tool is active, because the parent could otherwise start work it cannot read, wait for or stop. When `tasks` is disabled or deactivated, `background: true` is rejected without starting anything and **Ctrl+B** leaves the call in the foreground; foreground calls are otherwise unaffected. A call becomes background only once the Agent has initialized and accepted the work, so a detach requested during initialization waits for that, and if initialization fails first the call answers in the foreground.
|
|
20
|
+
|
|
19
21
|
Issue parallel `Agent` calls for independent work. Each call is a separate Transcript row and Task, including its own completion notification; there is no aggregate batch view. At most four Agents run at once in a session; additional calls wait as queued Tasks and start when a slot frees. A queued background call returns its Task ID immediately, and **Ctrl+B** can move a queued foreground call to the background before it starts. Parallel tasks must not perform overlapping writes.
|
|
20
22
|
|
|
21
|
-
Agents use the parent's working directory and share its canonical model/authentication runtime. Their isolated
|
|
23
|
+
Agents use the parent's working directory and share its canonical model/authentication runtime. Their isolated sessions have `read`, `bash`, `edit`, and `write`, with shell commands covering file discovery and search. They load applicable repository instructions and do not load extensions, skills, prompt templates, or themes. They cannot recursively delegate or start managed background work. In a saved session, each Agent also keeps its complete report and its child transcript beside the session (see [Saved reports and transcripts](#saved-reports-and-transcripts)); an unsaved session keeps neither.
|
|
22
24
|
|
|
23
25
|
Resource discovery preserves the parent's project-trust decision. Declining trust skips project `.pi/SYSTEM.md` and `.pi/APPEND_SYSTEM.md` while still loading repository context files such as `AGENTS.md`. Execution uses an isolated snapshot of global settings and trusted project overrides, including request and shell settings; cache warming is disabled for Agents.
|
|
24
26
|
|
|
@@ -51,18 +53,48 @@ The Transcript only describes status and current work. It never includes the Pro
|
|
|
51
53
|
|
|
52
54
|
| State | Collapsed | Expanded |
|
|
53
55
|
|---|---|---|
|
|
54
|
-
| Running | One line with the latest tool, a short path or command target, and elapsed time | The same heading plus the latest five
|
|
56
|
+
| Running | One line with the latest tool, a short path or command target, and elapsed time | The same heading plus the latest five tool calls as aligned `glyph tool target · duration` rows |
|
|
55
57
|
| Background handoff | One `Background · /tasks` status line | Identical |
|
|
56
58
|
| Completed | One duration and `/tasks` status line | Identical |
|
|
57
59
|
| Failed or cancelled | One short diagnostic or cancellation line | Identical |
|
|
58
60
|
|
|
59
|
-
Shell activity shows only the first non-empty command line and retains the actual tool name. The human-only Tasks display holds bounded argument summaries and tool-failure excerpts; successful intermediate tool output is not retained in the parent Tasks record. While running, model-facing `tasks read` returns one status line, such as `Agent running · 3 tool calls · latest: bash npm test`; after settlement it returns the final report. Intermediate assistant text and Tool calls never reach the parent model. To change direction, kill the Agent and delegate again with a better briefing.
|
|
61
|
+
Shell activity shows only the first non-empty command line and retains the actual tool name. Path targets that lie inside the Agent's working directory are shown relative to it, with forward slashes; paths outside it stay absolute. The human-only Tasks display holds bounded argument summaries and one-line tool-failure excerpts; successful intermediate tool output is not retained in the parent Tasks record. While running, model-facing `tasks read` returns one status line, such as `Agent running · 3 tool calls · latest: bash npm test`; after settlement it returns the final report. Intermediate assistant text and Tool calls never reach the parent model. To change direction, kill the Agent and delegate again with a better briefing.
|
|
60
62
|
|
|
61
63
|
In `/tasks`, each Agent remains an independent row:
|
|
62
64
|
|
|
63
|
-
- **Output** shows
|
|
64
|
-
|
|
65
|
+
- **Output** shows only what a person needs from the Agent's current state. While it runs, that is its compact tool calls, one per line, with no heading:
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
… 12 earlier tool calls
|
|
69
|
+
✓ read src/core/tasks/store.ts · 4ms
|
|
70
|
+
✓ bash npm test · 6.2s
|
|
71
|
+
× bash npm run check · 41.0s
|
|
72
|
+
src/index.ts:12:5 - error TS2322
|
|
73
|
+
✶ read README.md · 3.1s
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Each call is `glyph tool target · duration`, with the tool-name column padded to the longest shown name (at most 8 characters) so targets line up, and the durations right-aligned in one column at the end of the longest row. The glyphs are the task status markers used throughout `/tasks`: `✓` for success, `×` for failure, `○` for cancellation, and for a running call the same animated spinner as a running task. When more than the latest 50 calls happened, the first line counts the earlier ones. A failed call adds one line under its target holding the first non-empty line of its error, clipped to about 160 characters. Durations read `42ms` under a second, `6.2s` under a minute, then `1m 5s`. While the Agent runs, the list is styled with the theme: the glyph in its task status color (running accent, success green, failure red, cancellation warning), the tool name as a tool title, the target muted and the duration dim, with the error line in the error color. Targets are clipped to the panel width, never the duration, and the running call shows how long it has been running. The plain-text fallback uses the same markers with `›` for a running call and no column alignment. The Transcript's expanded row renders the same rows through the same code, so the two always agree. The model never sees this list; `tasks read` still returns the one-line status. Once the Agent finishes, whatever its outcome, Output shows only its final report (Markdown for a completed report) or, for a failed or cancelled Agent, its report so far and diagnostic. Oversized reports remain available through their managed output file.
|
|
77
|
+
- **Details** shows the full Prompt, working directory, model, and thinking level. Once the Agent settles, it also shows `Tool calls` (every call, for example `23 · 2 failed`), `Edited` (see below) and, in a saved session, the `Report` and `Transcript` paths.
|
|
78
|
+
|
|
79
|
+
Use `tasks read`, `tasks wait`, or `tasks kill` with the Task ID. Reading requires no view options: the status line or report is the model projection, while the `/tasks` panel adds the human-only tool-call list while the Agent runs. Selection, scrolling, cancellation, foreground detach, history, and completion delivery are owned by the shared Tasks implementation. Parent cancellation stops foreground-owned work, including cancellation received during startup; detached work continues until it finishes or is killed. Reload, session replacement, and shutdown cancel active Agents.
|
|
80
|
+
|
|
81
|
+
Inline reports are bounded to 24 KiB. In a saved session, a longer report is read from its saved `report.md` (below), and the tool result includes a bash-style `Full output: <path>` notice naming it. In an unsaved session, the full text goes to a managed temporary Markdown file instead, named the same way. Use `read` on that path or `tasks read` for retained output; a failure to save the file falls back to a bounded report without changing the Agent's outcome. Activity history is limited to the latest 50 tool calls, and published task results use the shared Tasks limits. A background completion delivers the report from its beginning, whole when it fits the notification budget, so the parent reads the same report a foreground call would have returned. Inline report previews, Details, usage, and completion state restore through the parent session branch. Temporary output files follow the Tasks lifecycle and never survive restart; saved reports and transcripts do survive, but live execution never resumes.
|
|
82
|
+
|
|
83
|
+
### Saved reports and transcripts
|
|
84
|
+
|
|
85
|
+
When the main session is saved, an Agent keeps these files in `<session-name>/agents/<task-id>/`, where `<session-name>/` is the artifacts directory beside the session's `.jsonl` file:
|
|
86
|
+
|
|
87
|
+
- `report.md` holds the complete final report, whatever its size. Tasks retention and shutdown never delete it, so the `Full output:` path in a saved transcript stays valid after `pi -c`.
|
|
88
|
+
- `transcript.jsonl` is the Agent's conversation as an ordinary Pi session file whose header `parentSession` is the main session file. It is a record only: it is never listed in `/resume` or continued by `pi -c`, and an Agent never resumes. It exists once the Agent has started its conversation.
|
|
89
|
+
|
|
90
|
+
Deleting the session from `/resume` deletes these files with it. Forks and clones do not copy them. Sessions that are not saved (`--no-session`) keep neither file.
|
|
91
|
+
|
|
92
|
+
A settled Agent's Details also carry:
|
|
65
93
|
|
|
66
|
-
|
|
94
|
+
| Row | Meaning |
|
|
95
|
+
| --- | --- |
|
|
96
|
+
| `Tool calls` | Every call the Agent made, with failures: `23` or `23 · 2 failed`. Not limited to the latest 50 listed. |
|
|
97
|
+
| `Edited` | Files the Agent changed with `edit` or `write` calls that succeeded (not through `bash`), once each in first-edit order, relative to the working directory when inside it: `src/a.ts, README.md +3 more`. Omitted when none. |
|
|
98
|
+
| `Report`, `Transcript` | Paths of the saved files. |
|
|
67
99
|
|
|
68
|
-
|
|
100
|
+
When the Agent edited files, the report returned to the model ends with one more line, `Edited (edit/write): a.ts, b.ts +N more`, after any truncation notice and bounded to 1 KiB. A failed or cancelled Agent reports the same rows and line.
|
package/docs/bundled/tasks.md
CHANGED
|
@@ -10,7 +10,7 @@ Start Bash through the native `bash` tool (the optional native Windows `powershe
|
|
|
10
10
|
{ "command": "npm run build", "timeout": 120, "background": true }
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
Omitting `background` keeps the normal foreground wait. A background submission returns an execution reference, not a successful final outcome. Up to eight background executions run at once; a ninth background submission is rejected without starting. Foreground commands are never limited by background work. `bg create` has been removed; its old stored results and background notifications show their saved text in transcripts.
|
|
13
|
+
Omitting `background` keeps the normal foreground wait. A background submission returns an execution reference, not a successful final outcome; an executor that already has its final result when it accepts answers the caller instead. A task is `background` only once its caller has been released: a submission, or a Ctrl+B request made while the executor is still preparing, waits for the executor to accept, and a task answered inline stays foreground, is saved as a foreground record, and never appears in `tasks list`. Up to eight background executions run at once, counting any still waiting for that acceptance; a ninth background submission is rejected without starting. Foreground commands are never limited by background work. `bg create` has been removed; its old stored results and background notifications show their saved text in transcripts.
|
|
14
14
|
|
|
15
15
|
In interactive mode, **Ctrl+B** moves eligible foreground managed tasks to the background, oldest first, while background slots remain; when every slot is taken it says so instead. Once a foreground execution has run for ten seconds and can still move, the statusline shows `Ctrl+B to run in background`, even when no background tasks exist. The hint is hidden while every background slot is taken, background execution is disabled, or no eligible foreground execution remains. It uses the configured shortcut and disappears if that shortcut is disabled. The shortcut works even when `/tasks` owns focus. The same execution continues: no cancellation, restart or timeout reset. The handoff result names the path the work took, because the model cannot see it: a command submitted with `background: true` reports a handoff from an empty log, while one moved mid-run reports that its execution continued unchanged, that the log already holds output, and that a supplied timeout is still measured from command startup. It does not detach ordinary file tools, or user `!` shell commands.
|
|
16
16
|
|
|
@@ -18,6 +18,8 @@ When nothing is eligible, the key is not consumed: it falls through to other bin
|
|
|
18
18
|
|
|
19
19
|
Configure `app.tasks.detach` in `keybindings.json` to change or disable the shortcut. The default `tui.editor.cursorLeft` is now `left`, freeing Ctrl+B. To restore Emacs cursor behavior, disable or rebind detach before assigning Ctrl+B to cursor-left.
|
|
20
20
|
|
|
21
|
+
Background work, submitted or detached, is admitted only while the `tasks` tool is active: without it the model could start work it cannot read, wait for or stop. If the bundled `builtin:tasks` extension is disabled or the tool is deactivated, `background: true` is rejected with a message saying that no work was started, the detach key and statusline hint disappear, and foreground execution is unaffected. Work admitted earlier keeps running and its completion is still delivered.
|
|
22
|
+
|
|
21
23
|
Hosts can prohibit background execution with `backgroundAllowed: false`. This restriction survives runtime replacement and does not depend on task kind; foreground execution remains available.
|
|
22
24
|
|
|
23
25
|
## Management tool
|
|
@@ -31,13 +33,13 @@ Hosts can prohibit background execution with `backgroundAllowed: false`. This re
|
|
|
31
33
|
| `wait` | optional `taskId`, `waitMs`, `sinceBytes` | Waits for one task, or for any task running at call time when `taskId` is omitted |
|
|
32
34
|
| `kill` | `taskId` | Requests cancellation of the selected task |
|
|
33
35
|
|
|
34
|
-
Use the execution ID returned by the native tool or `tasks list`. An unknown or stale `taskId` fails with the session's current tasks listed inline (active first, then recent finishes), so the next call can use a real ID without a separate list call; an ambiguous prefix lists exactly the tasks it matched. Only `wait` makes `taskId` optional: omitting it waits for the first terminal result among background tasks that were running when the call started, and returns `no_tasks` immediately when that cohort is empty. Tasks started during the wait are not part of the cohort.
|
|
36
|
+
The tool is the only way the model can follow background work, which is why background needs it (see [Start or detach work](#start-or-detach-work)). Use the execution ID returned by the native tool or `tasks list`. An unknown or stale `taskId` fails with the session's current tasks listed inline (active first, then recent finishes), so the next call can use a real ID without a separate list call; an ambiguous prefix lists exactly the tasks it matched. Only `wait` makes `taskId` optional: omitting it waits for the first terminal result among background tasks that were running when the call started, and returns `no_tasks` immediately when that cohort is empty. Tasks started during the wait are not part of the cohort.
|
|
35
37
|
|
|
36
38
|
```json
|
|
37
|
-
{ "action": "read", "taskId": "<execution-id>", "
|
|
39
|
+
{ "action": "read", "taskId": "<execution-id>", "bytes": 8192 }
|
|
38
40
|
```
|
|
39
41
|
|
|
40
|
-
Reads default to
|
|
42
|
+
Reads default to 8KB. Without `mode`, a report such as an Agent's is read from its start and a log such as a command's from its end; `mode` can be `head` or `tail` and always wins. `details.mode`, and with it the Transcript row, names the end actually read, and settled waits follow the same default. `bytes` clamps between 256 bytes and 48KB. A Bash output path is included when available. Tasks without a log return their bounded published result. Executors can separately attach a human-only display: `/tasks` shows it in place of the result, while `tasks read`, settled waits, and completion context always use the result. Only a completion's own display survives settlement. Agent Tool calls use this display channel, so no read-view parameter is needed. Every read and settled wait reports its byte range and where to continue, for example `bytes 92160–100352 of 100352 · next sinceBytes 100352`. Use a returned offset with that task's ID: a head read continues forward from it, while a tail read keeps the newest unread window. Offsets count raw source bytes, so undecodable UTF-8 cannot change the continuation position. `waitAny` does not accept a cross-task offset.
|
|
41
43
|
|
|
42
44
|
```json
|
|
43
45
|
{ "action": "wait", "taskId": "<execution-id>", "waitMs": 20000, "sinceBytes": 4096 }
|
|
@@ -51,7 +53,7 @@ Wait for any task already running at call time by omitting the ID:
|
|
|
51
53
|
|
|
52
54
|
`waitMs` defaults to 20 seconds and clamps between 1 second and 10 minutes. A task that reaches a terminal state produces a `settled` outcome; expiry produces `timed_out` and leaves execution running. New steering input produces `interrupted` and ends only the wait, so the new input can proceed without cancelling the task; follow-up input does not interrupt it. A background completion steered into the run can interrupt a wait on another task the same way.
|
|
53
55
|
|
|
54
|
-
Wait output is limited to 32KB. With `taskId`,
|
|
56
|
+
Wait output is limited to 32KB. With `taskId`, `sinceBytes` can anchor the read. A report continues forward from that offset so no unread middle is skipped; for a log, when more than 32KB was written after the offset, the wait returns the newest 32KB and reports how many bytes it skipped. `sinceBytes` is rejected without `taskId` because offsets belong to one task. Interrupted waits do not read output. A settled waitAny reads the winning task and lists initial cohort members still running. Continue independent work instead of sleep-polling or repeatedly reading; wait when the next step genuinely depends on a result.
|
|
55
57
|
|
|
56
58
|
```json
|
|
57
59
|
{ "action": "kill", "taskId": "<execution-id>" }
|
|
@@ -63,15 +65,17 @@ All model-facing management responses, including listings and error messages, ar
|
|
|
63
65
|
|
|
64
66
|
## `/tasks` panel
|
|
65
67
|
|
|
66
|
-
The fullscreen panel has one scrollable list. **Active** groups queued, running and stopping work; **Finished** groups all retained results on the selected branch, including foreground shell results, newest first. Empty groups are hidden. Each task is one row: its status glyph, its source label such as Bash or Agent in an aligned dim column, the title, and right-aligned metadata. The metadata shows elapsed time, the status name for every status except running, completed and failed, whose glyphs are unambiguous, and an ID suffix when two titles are identical.
|
|
68
|
+
The fullscreen panel has one scrollable list. **Active** groups queued, running and stopping work; **Finished** groups all retained results on the selected branch, including foreground shell results, newest first. Empty groups are hidden. Each task is one row: its status glyph, its source label such as Bash or Agent in an aligned dim column, the title, and right-aligned metadata. The metadata shows elapsed time, the status name for every status except running, completed and failed, whose glyphs are unambiguous, and an ID suffix when two titles are identical. The list's top border names the panel and counts what is shown (`Tasks · 2 active · 5 finished`); its bottom border shows the visible range (`1-12 of 40`) only when the list overflows. While a stop question is open, the target row's metadata reads `stop?` in the warning color. Durations omit zero components and separate remaining units (`8s`, `1m`, `1m 5s`, `1h 5m`). The background action is offered only when the selected task can move.
|
|
67
69
|
|
|
68
70
|
Selection follows the task when it finishes; new work does not steal focus or replace browsed output. The list preserves the selected row's screen position where space permits. Reopening selects the newest task started since the panel last closed; when nothing new started, it keeps the remembered selection. The right-hand tab is remembered as well, while the runtime remains available. Runtime replacement resets these preferences, and branch navigation removes results outside the visible branch. History remains bounded by the retention limits below.
|
|
69
71
|
|
|
70
|
-
At 100 columns or more, the task list sits beside an inspector. The inspector's first row
|
|
72
|
+
At 100 columns or more, the task list sits beside an inspector; the list takes 40% of the width, between 34 and 60 columns. Each pane's title is in its top border: the list's `Tasks`, and the inspector's **Output** and **Details** tabs. The inspector's first row is the selected task's title in bold and its second is a meta line, `Bash · Running · Background · 12s`, with the status in its outcome color; a rule joined to the pane's border separates this header from the tab's content. **Output** shows the result directly; **Details** starts with the task ID, then holds what the executor declared — its input such as the full command or prompt (inline when it is one line, as a block when it spans several), facts such as the directory, model or exit code — and the log location. Long values wrap inside their own column, with continuation lines hanging under the value, and unbroken tokens such as paths break at the column width. Each task and tab keeps its reading position for the lifetime of the panel. Tab switches between the two panes, preserving the right-hand tab. Left/Right switch Output/Details only when the inspector has focus.
|
|
73
|
+
|
|
74
|
+
The focused pane has a highlighted border. Task selection uses a persistent row background, and the selected right-hand tab uses an underline; neither changes when focus moves. When the system theme has no background colors, the selected row uses inverse text. There are no focus arrows or extra title colors. Narrow terminals show one pane at a time at full width, with the same Tab navigation, no focus highlight, and the title and meta rows in the inspector. In a narrow terminal the inspector is a drill-down page: Escape returns to the list, and Escape in the list closes the panel; in the wide layout Escape closes the panel from either pane. The footer names the action as `Esc back` or `Esc close`. The minimum supported size is 60 columns by 14 rows; below it, a centered dialog asks for a larger window and covers the screen, because the panel keeps input focus while open.
|
|
71
75
|
|
|
72
|
-
The
|
|
76
|
+
The footer shows context hints on the left and pins the Escape action to the right edge. When the row is too narrow, the lowest-priority hints go first: pane and tab switching, then the arrow hint, open, find, stop and background, with `? keys` kept longest. A message appears there only when an action did not do what was asked, as a warning (`!`) for a no-op or refusal such as a reached background limit or a task that already finished, or as an error (`×`) for an unexpected failure. It replaces the hints and clears on the next key or click, or after about four seconds. A successful stop or background request shows no message: the row and the header already read `Stopping` or the new mode.
|
|
73
77
|
|
|
74
|
-
Every executor is presented the same way, from data it declares: a label such as Bash or Agent, an input, labelled facts, and whether its output is a log or a report.
|
|
78
|
+
Every executor is presented the same way, from data it declares: a label such as Bash or Agent, an input, labelled facts, and whether its output is a log or a report. Only a log streams from its file, with a reading state (following, browsing or finished) and a follow control. Any other output shows what its executor published, updated as soon as it publishes rather than on the log poll: while the task runs, the lines its executor renders for the panel (styled and fitted to the pane, such as a running Agent's colored tool calls with an elapsed time), otherwise its human-readable display when it has one, otherwise the result that models read. A report is never read from an attached file, so a report saved in full still shows its published beginning, with the file listed in Details as **Full report**. A completed report uses the native Markdown renderer. Output follows the tail of a log and of a live report; a settled report opens at its first line, and keeps the position you scrolled to. When a report overflows, its scroll range appears in the pane's bottom border. A running Agent shows its compact tool calls, written as in the transcript (`✓ read README.md · 4ms`), and a finished one shows its final report. A task without an input shows its title in Details. Missing logs fall back to the saved result. Task status, failure reasons and output-read errors remain distinct.
|
|
75
79
|
|
|
76
80
|
| Default key | Action |
|
|
77
81
|
|---|---|
|
|
@@ -79,35 +83,35 @@ Every executor is presented the same way, from data it declares: a label such as
|
|
|
79
83
|
| Left / Right | Output / Details, only while the inspector has focus |
|
|
80
84
|
| Tab / Shift+Tab | Switch between list and inspector, preserving the current tab |
|
|
81
85
|
| Up / Down | Select a task or scroll the focused region |
|
|
82
|
-
| Enter | Open the selected task: focus the inspector,
|
|
86
|
+
| Enter | Open the selected task: focus the inspector, which fills the width in a narrow terminal |
|
|
83
87
|
| Page Up / Page Down | Page the focused list or region |
|
|
84
88
|
| Home / End | Top / bottom of the list or bounded preview |
|
|
85
89
|
| `f` | Follow the latest output, or load the final output after completion, while Output has focus |
|
|
86
90
|
| `b` | Move only the selected eligible foreground task to the background |
|
|
87
|
-
| `k`, then Enter | Request cancellation of the selected whole task. The footer asks `Stop Bash "npm test"?` while the list and inspector stay visible
|
|
91
|
+
| `k`, then Enter | Request cancellation of the selected whole task. The footer asks `Stop Bash "npm test"?` while the list and inspector stay visible and the target row reads `stop?`; Escape cancels. Confirmation has no time limit and closes if its target finishes |
|
|
88
92
|
| `?` | Show configurable controls, grouped into Navigate, View and Act; Up/Down scroll the help |
|
|
89
|
-
| Escape | Close the current search, help or confirmation first; otherwise close the panel |
|
|
93
|
+
| Escape | Close the current search, help or confirmation first; then, in a narrow terminal, return from the inspector to the list; otherwise close the panel |
|
|
90
94
|
| Ctrl+B | Detach **all** eligible foreground executions through the host |
|
|
91
95
|
|
|
92
|
-
Click a pane to focus it, a task row to select it, or a tab label to display it. The mouse wheel scrolls the pane under the pointer without changing keyboard focus or task selection. Footer hints are clickable as well
|
|
96
|
+
Click a pane to focus it, a task row to select it, or a tab label to display it. The mouse wheel scrolls the pane under the pointer without changing keyboard focus or task selection. Footer hints and the Escape action are clickable as well; a click while a message is showing dismisses it. While a stop question owns the footer, only its stop and cancel actions respond. Each mode answers only to its own targets: search to its candidates and cancel, help to its footer, so a click never activates the panel behind them.
|
|
93
97
|
|
|
94
|
-
Shell output initially follows the tail
|
|
98
|
+
Shell output initially follows the tail; the inspector's bottom border shows **Live**. Scrolling up enters **Browsing · f follow**, which holds a bounded output snapshot while status continues updating, and the label itself is clickable. In Output, press `f`, End, or scroll down to the bottom to resume following. If the task finishes while browsing, the border offers `Finished · f load final output`. Only a log has this reading state; a published result is always the current one. The Details bottom border shows its scroll range only when Details overflow. Closing or scrolling never pauses, restarts or cancels execution.
|
|
95
99
|
|
|
96
|
-
The panel polls only selected tail
|
|
100
|
+
The panel polls only the selected attached log's tail once per second, up to 48 KiB per read; navigation and settlement can request an immediate refresh. Progress updates and animation do not add log reads. A truncated tail shows its preview and total byte counts; ordinary complete output omits these statistics. Empty output and expired logs have explicit messages; an unavailable log falls back to the saved result when available. Selecting a task retains its result and log without delaying completion notifications. Closing releases subscriptions, the retention lease and timers.
|
|
97
101
|
|
|
98
102
|
Controls use the `app.tasks.*` bindings: `search`, `previousTab`, `nextTab`, `nextFocus`, `previousFocus`, `top`, `bottom`, `follow`, `kill`, `confirmStop`, `detachSelected`, `detach` and `help`. List paging uses `tui.select.pageUp` / `pageDown`; Details and Output paging use `tui.editor.pageUp` / `pageDown`. All are configurable. The former view and direct-focus bindings have been removed.
|
|
99
103
|
|
|
100
104
|
The `/hotkeys` table lists the task bindings next to the editor ones, and the panel's `?` help lists every control, so both detach scopes are discoverable without reading these docs.
|
|
101
105
|
|
|
102
|
-
The statusline counts only queued, running and stopping background tasks: `1 background task · /tasks to view` or `2 background tasks · /tasks to view`. Foreground tasks and retained results do not contribute to the count; the summary disappears when no active background tasks remain. Finished results remain available in `/tasks`. The independent detach hint can appear alone or after the summary: `1 background task · /tasks to view · Ctrl+B to run in background`. The count uses normal text, `/tasks` and the shortcut use the accent color, and descriptions and separators are muted. The model-facing `tasks list` keeps its background-only scope and foreground omission count.
|
|
106
|
+
The statusline counts only queued, running and stopping background tasks: `1 background task · /tasks to view` or `2 background tasks · /tasks to view`. Foreground tasks and retained results do not contribute to the count; the summary disappears when no active background tasks remain. Finished results remain available in `/tasks`. The independent detach hint can appear alone or after the summary: `1 background task · /tasks to view · Ctrl+B to run in background`. The count uses normal text, `/tasks` and the shortcut use the accent color, and descriptions and separators are muted. The model-facing `tasks list` keeps its background-only scope and foreground omission count. A task whose detach is waiting for its executor to accept still shows as foreground, and is not counted, until the executor accepts.
|
|
103
107
|
|
|
104
108
|
## Completion notifications
|
|
105
109
|
|
|
106
110
|
Interactive `task-completion` messages have a compact collapsed summary: the executor's label, outcome, duration, short ID, and the task title. Failures retain a short reason; log paths, output and worker reports stay out of the collapsed view. In fullscreen mode, left-click the notification to expand or collapse that message independently. The blank spacer above it is not a click target. The configured tool-output expansion binding (default Ctrl+O) remains available for toggling output expansion across the transcript.
|
|
107
111
|
|
|
108
|
-
Expanded notifications separate the input under its own label, such as **Command** or **Prompt** (or **Task** without one), **Details** with the declared facts such as directory and exit code, **Result** or **Error**, a bounded plain-text **Output** preview, **Log** and the full execution ID. A log's saved output keeps its end, where the outcome is; a report's keeps its beginning, where the conclusion is. Both carry an explicit truncation flag. Screen line limits are independent of source truncation.
|
|
112
|
+
Expanded notifications separate the input under its own label, such as **Command** or **Prompt** (or **Task** without one), **Details** with the declared facts such as directory and exit code, **Result** or **Error**, a bounded plain-text **Output** preview, **Log** and the full execution ID. A log's saved output keeps its end, where the outcome is; a report's keeps its beginning, where the conclusion is. Both carry an explicit truncation flag. Screen line limits are independent of source truncation. The card ends with the task ID; it carries no separate closing line. A failed shell task's card states its error once: the output holds only what the command printed.
|
|
109
113
|
|
|
110
|
-
Rendering reads the self-contained terminal snapshot in message `details`, so `/reload`, history eviction, expired logs and restart do not require a live task lookup. The session generates model-facing `content` from the same facts; `details` never enters model context or usage accounting. Replay details retain up to 40 KiB of output. The automatic model-facing notification includes only an 8 KiB tail of a log, plus the log path and truncation guidance for `tasks read`; a report arrives from its beginning, whole when it fits the 48 KiB budget, as its foreground result would. Commands containing `Output:` and literal truncation notices remain ordinary data. See the [snapshot contract](../session-format.md#background-records).
|
|
114
|
+
Rendering reads the self-contained terminal snapshot in message `details`, so `/reload`, history eviction, expired logs and restart do not require a live task lookup. The session generates model-facing `content` from the same facts; `details` never enters model context or usage accounting. Replay details retain up to 40 KiB of output. A shell task's result holds the command's output only; its failure is the separate error, which the notification states once on its `Error:` line instead of repeating it at the end of the output. The automatic model-facing notification includes only an 8 KiB tail of a log, plus the log path and truncation guidance for `tasks read`; a report arrives from its beginning, whole when it fits the 48 KiB budget, as its foreground result would. Commands containing `Output:` and literal truncation notices remain ordinary data. See the [snapshot contract](../session-format.md#background-records).
|
|
111
115
|
|
|
112
116
|
Only the current structured completion format (version 2) is specialized. Older completions, including version-1 shell and report completions, and malformed details receive a bounded plain **Details** view of their saved message; no text reconstruction or migration is performed. Legacy `background-task` notifications show as plain messages. HTML export and `/tree` selector labels continue to display the saved message content.
|
|
113
117
|
|
|
@@ -125,9 +129,9 @@ Managed logs are ephemeral: they are retained with the runtime record and cleane
|
|
|
125
129
|
|
|
126
130
|
Each settlement appends one version-3 `task-record` custom entry holding the terminal snapshot and its usage. A foreground snapshot omits its output, which the transcript already saves in the tool result, and restoration reads it back from there. The runtime restores version-3 terminal history from the selected branch for programmatic reads and the panel's Finished group, selecting the newest records independently for each history. Older `task-result` records are left in the session file and are not migrated or restored; usage from released sessions still counts. Live execution never resumes after restart, and restoration does not replay accounting or completion events. Restored records drop their log path: logs never outlive the runtime that wrote them. See [session format](../session-format.md#background-records).
|
|
127
131
|
|
|
128
|
-
|
|
132
|
+
Settled history outside the selected branch can be released and restored on return, so it does not fill the new branch's history budget. An undelivered completion is a retention lease held by the session's delivery: its record and output stay protected, even while its branch is hidden, until the model has the completion, a direct SDK waiter acknowledges it, or its runtime closes or is replaced; completions still pending when a runtime is replaced are not delivered by its successor. A bare runtime outside a session holds no such lease, so its settled records are ordinary history. Leases, pins and active reads use a separate allowance within the total runtime retention cap; restoration respects the same cap.
|
|
129
133
|
|
|
130
|
-
Completion delivery follows the same queueing path as interactive input. While the agent is running, a completion is steered into that run, so it lands right after the current tool batch — exactly like a message the user types mid-run, and behind any already queued steering. An idle session starts a completion turn instead. User preflight (input hooks, model and authentication checks, compaction) still holds delivery, so a user message is always the first thing a new run sees. One bounded completion is in flight at a time. Each execution produces one completion. A terminal `tasks wait` coordinates with automatic delivery only after its tool result is persisted: while `tasks wait` prepares a result for persistence, that task is not announced, and aborting during output reading does not lose the pending completion. A settled waitAny applies the same receipt to its winning task and releases the rest of the cohort for ordinary delivery. Direct SDK waits remain observational until explicitly acknowledged. Plain reads and panel selection retain output without delaying notifications. Progress and repeated reads do not inject messages or add usage. `agent_settled` still describes the main agent, not the end of all background executions.
|
|
134
|
+
Completion delivery follows the same queueing path as interactive input. While the agent is running, a completion is steered into that run, so it lands right after the current tool batch — exactly like a message the user types mid-run, and behind any already queued steering. An idle session starts a completion turn instead. User preflight (input hooks, model and authentication checks, compaction) still holds delivery, so a user message is always the first thing a new run sees. One bounded completion is in flight at a time. Each execution produces one completion. A terminal `tasks wait` coordinates with automatic delivery only after its tool result is persisted: while `tasks wait` prepares a result for persistence, that task is not announced, and aborting during output reading does not lose the pending completion. A settled waitAny applies the same receipt to its winning task and releases the rest of the cohort for ordinary delivery. Direct SDK waits remain observational until explicitly acknowledged with `session.acknowledgeTaskDelivery(id)`. Plain reads and panel selection retain output without delaying notifications. Progress and repeated reads do not inject messages or add usage. `agent_settled` still describes the main agent, not the end of all background executions; `session_quiescent` and `session.waitForQuiescence()` mark the point where no task is unsettled and no completion turn remains. Print and JSON mode wait for that point before exiting.
|
|
131
135
|
|
|
132
136
|
After a successful compaction, the next main-agent request includes one bounded, request-local reminder listing background tasks still active at that moment. It warns against duplicate work without creating a turn or entering session history. A successful assistant response consumes it; failed or aborted requests leave it eligible for the next attempt. If no tasks are active, the reminder is cleared instead of being carried forward to unrelated future work.
|
|
133
137
|
|
|
@@ -135,6 +139,6 @@ Failed completion delivery leaves the terminal result available for inspection r
|
|
|
135
139
|
|
|
136
140
|
Queued extension `nextTurn` context accompanies completion turns and stays queued until each message is persisted. A failed or partially persisted turn therefore retries only the context that has not been saved.
|
|
137
141
|
|
|
138
|
-
If an executor ignores cancellation and settles after bounded cleanup has retired its runtime or branch, the old session quarantines its bounded result and reported usage: the latest 32 records remain in memory, and persisted sessions also append `<session-file>.tasks-late.jsonl
|
|
142
|
+
If an executor ignores cancellation and settles after bounded cleanup has retired its runtime or branch, the old session quarantines its bounded result and reported usage: the latest 32 records remain in memory, and persisted sessions also append `<session-file>.tasks-late.jsonl`, which `/resume` deletion removes with the session. These audit records are excluded from active totals and are not automatically reconciled. A completed cleanup grace period is not proof that an uncooperative executor stopped.
|
|
139
143
|
|
|
140
144
|
The previous extension-owned interactive-prompt stall watchdog was not ported. Pi no longer automatically flags a prompt-looking shell tail as `waiting for input` or sends stall remediation notifications. Use non-interactive commands and inspect/stop stalled work manually; legacy stall notifications show as plain saved messages.
|
package/docs/extensions.md
CHANGED
|
@@ -1257,14 +1257,15 @@ Session-bound `TasksContext` supervises native and extension-owned execution. Fo
|
|
|
1257
1257
|
|
|
1258
1258
|
| Method | Contract |
|
|
1259
1259
|
|---|---|
|
|
1260
|
-
| `execute<T>(execution)` | Returns `{ kind: "result", result, status, error? }` or `{ kind: "background", task }` |
|
|
1260
|
+
| `execute<T>(execution)` | Returns `{ kind: "result", result, status, error? }` or `{ kind: "background", task, reason }`, where `reason` is `"submitted"` when the caller asked for `background` and `"detached"` when it was moved while the work ran |
|
|
1261
1261
|
| `list()` / `get(id)` | Bounded, read-only (frozen) retained snapshots; IDs support unique prefixes |
|
|
1262
|
-
| `
|
|
1262
|
+
| `presentOutput(id, width, theme)` | The running task's live Output lines from its executor's `present` (below), or `undefined` for an unknown, settled or presenter-less task, or when the presenter throws. Hosts that render task Output, such as `/tasks`, call it on every repaint and use the default view when it returns nothing |
|
|
1263
|
+
| `read(id, options?)` | Bounded head, tail, or byte-offset model-readable output; excludes human-only display text. `options`: `mode`, `bytes`, `sinceBytes`. Without `mode`, a `report` is read from its start and a `log` from its end. With `sinceBytes`, `head` continues forward from that offset and `tail` keeps the newest window at or after it. Returned ranges and `endByte` use raw source bytes. A `wait` or `waitAny` read follows the same default |
|
|
1263
1264
|
| `wait(id, options?)` | One observation of one task. `options`: `timeoutMs`, `signal`, `toolCallId`, and `read: { bytes?, sinceBytes? }`. Returns `{ outcome, waitedMs, task, read? }` where `outcome` is `settled`, `timed_out`, `interrupted` (host steering), or `closed` (host shut down; state unconfirmed). Timeout, cancellation, or interruption ends the wait, not execution |
|
|
1264
1265
|
| `waitAny(options?)` | Observes the first task running at call time to settle, with `timeoutMs`, `signal`, `toolCallId`, and `read: { bytes? }`. Returns `{ outcome, waitedMs, task?, read?, running }`; `outcome` adds `no_tasks` for an empty cohort. Later tasks are excluded |
|
|
1265
1266
|
| `kill(id)` | Requests cancellation; `stopping` is not a terminal status |
|
|
1266
|
-
| `detach(id)` / `detachForeground()` | Hands off one task, or eligible foreground tasks oldest first while background slots remain, without restarting them; throws when every background slot is taken |
|
|
1267
|
-
| `canDetach(id)` | Reports whether an execution can move now, including host policy and available background slots; does not change the execution |
|
|
1267
|
+
| `detach(id)` / `detachForeground()` | Hands off one task, or eligible foreground tasks oldest first while background slots remain, without restarting them; throws when every background slot is taken. Returns `false` / `0` while the host cannot supervise background work (see below) |
|
|
1268
|
+
| `canDetach(id)` | Reports whether an execution can move now, including host policy, the `tasks` tool being active, and available background slots; does not change the execution |
|
|
1268
1269
|
| `subscribe(listener)` | Observes task state and progress |
|
|
1269
1270
|
| `retain(id)` | Returns an idempotent release function protecting retained data, without delaying notifications |
|
|
1270
1271
|
|
|
@@ -1273,21 +1274,24 @@ Session-bound `TasksContext` supervises native and extension-owned execution. Fo
|
|
|
1273
1274
|
| Field | Contract |
|
|
1274
1275
|
|---|---|
|
|
1275
1276
|
| `label` | Human source name for the panel and completion card, such as `Bash` or `Agent`; defaults to `kind` |
|
|
1276
|
-
| `output` | `"log"` (default) or `"report"`. A log's outcome is at its end, so a background completion gives the model an 8 KiB tail. A report leads with its conclusion, so it arrives from its beginning, whole when it fits the 48 KiB context budget, as its foreground result would; a completed report renders as Markdown in `/tasks` |
|
|
1277
|
+
| `output` | `"log"` (default) or `"report"`. A log's outcome is at its end, so a background completion gives the model an 8 KiB tail, and `read()` returns its end unless `mode` says otherwise. A report leads with its conclusion, so it arrives from its beginning, whole when it fits the 48 KiB context budget, as its foreground result would, and `read()` returns its start unless `mode` says otherwise; a completed report renders as Markdown in `/tasks` |
|
|
1277
1278
|
| `input` | `{ label, text, truncated, language? }`: what the task was asked to do, such as a command or briefing. Shown in Details and the expanded completion card, highlighted when `language` is set |
|
|
1278
1279
|
| `facts` | Up to 16 labelled `[label, value]` Details rows, such as `["Directory", cwd]` |
|
|
1279
|
-
| `concurrency` | `{ key, limit }`: at most `limit` executions sharing `key` run at once. Later ones wait as `queued` tasks and `run` starts when a slot frees |
|
|
1280
|
+
| `concurrency` | `{ key, limit }`: at most `limit` executions sharing `key` run at once. Lanes belong to one `kind`, so another executor can reuse the key. Later ones wait as `queued` tasks and `run` starts when a slot frees |
|
|
1280
1281
|
| `background`, `signal`, `onUpdate` | Requested handoff, parent cancellation, and foreground progress forwarding |
|
|
1282
|
+
| `present` | `(width, theme)` returning `string[]` or `undefined`: renders the running task's Output in `/tasks` with its own styling, such as colored columns or an elapsed time. Return lines already fitted to `width` (the panel clips any that are wider), or `undefined` for the default view. It runs synchronously on every repaint, so keep it cheap, and it must not return untrusted text without removing terminal sequences. It exists in memory for this execution only: never persisted, not part of any `TaskSnapshot`, dropped at settlement and absent after a restore. A throwing presenter is ignored. `display` stays the plain fallback for other consumers |
|
|
1281
1283
|
|
|
1282
1284
|
`kind` is an executor-owned source label matching `[a-z][a-z0-9-]{0,63}`; the runtime never dispatches on it. Presentation is declared data: the panel and completion card render `label`, `input`, `facts`, and `output` the same way for every executor. Input and facts restore with terminal task history; facts also appear in the completion notification. At most eight background executions, queued ones included, are retained as active at once; foreground executions are not limited by them. Foreground and background results have separate history quotas.
|
|
1283
1285
|
|
|
1284
|
-
A caller can be handed off to the background while its task is queued, before `run` starts, or after `run` calls `accept()`. A queued task becomes `running` when its `run` starts; cancelling it settles it as `cancelled` without starting it.
|
|
1286
|
+
A caller can be handed off to the background while its task is queued, before `run` starts, or after `run` calls `accept()`. A release requested while `run` is still preparing (a `background: true` submission, or a user detach) waits for `accept()`; if `run` settles first, the caller gets the result inline and the task stays `foreground`. `mode` is therefore `background` exactly when the caller was released with a background outcome. A queued task becomes `running` when its `run` starts; cancelling it settles it as `cancelled` without starting it.
|
|
1285
1287
|
|
|
1286
|
-
|
|
1288
|
+
Background work is admitted, submitted or detached, only while the host can supervise it: the session's `tasks` management tool must be active, because the model could otherwise start work it cannot read, wait for or stop. A rejected submission starts nothing and its error says so; work admitted earlier keeps running and delivering if the tool is deactivated later.
|
|
1287
1289
|
|
|
1288
|
-
`
|
|
1290
|
+
`run` returns `TaskCompletion<T>`: `{ result, status?, display?, error?, facts?, usage? }`. The original tool result is returned to a foreground caller; task history keeps only its bounded text. Optional `display` is the human-only view that `/tasks` shows in place of the result; `tasks read`, settled waits, and completion context always use `result`. A terminal snapshot carries a display only if this completion supplies one: the last progress display does not survive settlement. Terminal `facts` replace launch facts with the same label, as the shell does with `["Exit", "42"]`. Explicit terminal statuses are `completed`, `partial`, `failed`, `cancelled`, and `timeout`. The host settles usage once, preferring `usage`, then `result.usage`, then the latest published usage; managed foreground results omit usage to avoid billing it twice.
|
|
1289
1291
|
|
|
1290
|
-
|
|
1292
|
+
`TaskControl<T>` exposes `id`, `signal`, `mode`, `onModeChange(listener)`, `accept()`, `publish(update)`, `attachOutput(path, cleanup?)`, and `cancel()`. `publish({ result, display?, usage? })` replaces the bounded model-readable result and optionally the live human-only display and cumulative usage; while it runs `/tasks` shows the display in place of the result, while model reads and completion notifications use only the result. A task with an attached output file is read from that file instead. Call `accept()` after whole-invocation preflight, before allowing a background handoff; `onModeChange` listeners run when the mode becomes `background`. Use the control's signal throughout execution. Parent-call cancellation is disconnected after handoff, while runtime shutdown still cancels the task. Mode subscriptions concern only this task; executors do not need the global registry to observe their own handoff or cancel themselves.
|
|
1293
|
+
|
|
1294
|
+
Completion messages store `{ version: 3, task }` in `details`, a bounded terminal `TaskSnapshot`; only their bounded `content` enters model context. Built-in `tasks wait` binds delivery to the actual tool call, and the host confirms it after successful persistence; a settled waitAny binds only its winning task. Reads and waits without a `toolCallId`, including `waitAny`, do not acknowledge delivery, and arbitrary tool-result detail fields cannot acknowledge a task. An undelivered completion is a retention lease the session holds on its task: the record and its output stay available until the model has it, and a runtime embedded without a session never holds one, so its settled records are ordinary bounded history.
|
|
1291
1295
|
|
|
1292
1296
|
```typescript
|
|
1293
1297
|
const outcome = await ctx.tasks.execute({
|
package/docs/json.md
CHANGED
|
@@ -33,6 +33,7 @@ type AgentSessionEvent =
|
|
|
33
33
|
| Exclude<AgentEvent, { type: "agent_end" }>
|
|
34
34
|
| { type: "agent_end"; messages: AgentMessage[]; willRetry: boolean }
|
|
35
35
|
| { type: "agent_settled"; aborted: boolean }
|
|
36
|
+
| { type: "session_quiescent" }
|
|
36
37
|
| { type: "queue_update"; steering: readonly string[]; followUp: readonly string[] }
|
|
37
38
|
| { type: "compaction_start"; reason: "manual" | "threshold" | "overflow" }
|
|
38
39
|
| { type: "entry_appended"; entry: SessionEntry }
|
|
@@ -49,6 +50,8 @@ type AgentSessionEvent =
|
|
|
49
50
|
```
|
|
50
51
|
```
|
|
51
52
|
|
|
53
|
+
`session_quiescent` means nothing more will happen without new input: no run, compaction, retry, or branch summary, no unsettled Background task, and no Background completion waiting to start a turn. It is emitted once each time the session reaches that state, after the `agent_settled` of the last run. In `--mode json` the stream ends with it: print mode waits for quiescence after every prompt, so the turns that Background completions start are part of the stream, and a line on stderr names the tasks it is waiting for.
|
|
54
|
+
|
|
52
55
|
`queue_update` emits the full pending steering and follow-up queues whenever they change. `compaction_start` and `compaction_end` cover both manual and automatic compaction.
|
|
53
56
|
|
|
54
57
|
Base events retained by `AgentSessionEvent` come from `AgentEvent` in [`@earendil-works/pi-agent-core`](https://www.npmjs.com/package/@earendil-works/pi-agent-core); its `agent_end` member is replaced above:
|
package/docs/rpc.md
CHANGED
|
@@ -201,6 +201,7 @@ Response:
|
|
|
201
201
|
"thinkingLevel": "medium",
|
|
202
202
|
"isStreaming": false,
|
|
203
203
|
"isCompacting": false,
|
|
204
|
+
"isQuiescent": true,
|
|
204
205
|
"steeringMode": "all",
|
|
205
206
|
"followUpMode": "one-at-a-time",
|
|
206
207
|
"sessionFile": "/path/to/session.jsonl",
|
|
@@ -213,6 +214,8 @@ Response:
|
|
|
213
214
|
}
|
|
214
215
|
```
|
|
215
216
|
|
|
217
|
+
`isQuiescent` is true when no run, compaction, retry, unsettled Background task, or pending Background completion turn remains (see [session_quiescent](#session_quiescent)).
|
|
218
|
+
|
|
216
219
|
The `model` field is a full [Model](#model) object when one is selected, otherwise it is omitted. The `sessionFile` and `sessionName` fields are also omitted when unavailable; `sessionName` is the display name set via `set_session_name`.
|
|
217
220
|
|
|
218
221
|
#### get_messages
|
|
@@ -895,6 +898,7 @@ Events are streamed to stdout as JSON lines during agent operation. Events do no
|
|
|
895
898
|
| `agent_start` | Agent begins processing |
|
|
896
899
|
| `agent_end` | One low-level agent run completes (may still be followed by retry, compaction, or queued continuations) |
|
|
897
900
|
| `agent_settled` | Agent run is fully settled; no automatic retry, compaction retry, or queued continuation remains |
|
|
901
|
+
| `session_quiescent` | Nothing more will happen without new input, including Background tasks and the turns their completions start |
|
|
898
902
|
| `turn_start` | New turn begins |
|
|
899
903
|
| `turn_end` | Turn completes (includes assistant message and tool results) |
|
|
900
904
|
| `message_start` | Message begins |
|
|
@@ -947,6 +951,16 @@ Emitted after the full session-level run settles. At this point Pi will not cont
|
|
|
947
951
|
{"type": "agent_settled", "aborted": false}
|
|
948
952
|
```
|
|
949
953
|
|
|
954
|
+
### session_quiescent
|
|
955
|
+
|
|
956
|
+
Emitted when nothing more will happen without new input: no run, compaction, retry, or branch summary is active, no Background task is unsettled, and no Background completion is waiting to start a turn. A Background completion starts a new run after `agent_settled`, so a client that needs "all work done" waits for this event instead. It is emitted once per transition into that state, after the `agent_settled` of the last run. A completion whose delivery failed does not count, because it is retried only on the next input.
|
|
957
|
+
|
|
958
|
+
```json
|
|
959
|
+
{"type": "session_quiescent"}
|
|
960
|
+
```
|
|
961
|
+
|
|
962
|
+
`RpcClient.waitForQuiescence(timeout?)` resolves on this event, or at once when `get_state` reports `isQuiescent`; `collectEventsUntilQuiescent(timeout?)` collects events until it. `waitForIdle()` and `collectEvents()` still resolve on the first `agent_settled`. Closing stdin shuts the process down immediately, without waiting for Background work.
|
|
963
|
+
|
|
950
964
|
### turn_start / turn_end
|
|
951
965
|
|
|
952
966
|
A turn consists of one assistant response plus any resulting tool calls and results.
|
package/docs/sdk.md
CHANGED
|
@@ -71,6 +71,10 @@ interface AgentSession {
|
|
|
71
71
|
// Send a prompt and wait for completion
|
|
72
72
|
prompt(text: string, options?: PromptOptions): Promise<void>;
|
|
73
73
|
|
|
74
|
+
// Resolve once no run, compaction, retry or Background work remains, including completion turns
|
|
75
|
+
waitForQuiescence(signal?: AbortSignal): Promise<void>;
|
|
76
|
+
readonly isQuiescent: boolean;
|
|
77
|
+
|
|
74
78
|
// Queue messages, optionally with image attachments
|
|
75
79
|
steer(text: string, images?: ImageContent[]): Promise<void>;
|
|
76
80
|
followUp(text: string, images?: ImageContent[]): Promise<void>;
|
|
@@ -250,12 +254,15 @@ Background is a session-owned capability, not a daemon or a flag on `createAgent
|
|
|
250
254
|
|
|
251
255
|
An embedding can opt in with `await session.bindExtensions({ tasksEnabled: true })`. Bind before prompting; this also binds extensions and emits their session-start lifecycle. When using `AgentSessionRuntime`, rebind the replacement session through the runtime's rebind callback. Setting `mode` or providing a UI alone does not enable Background.
|
|
252
256
|
|
|
257
|
+
Background work is admitted only while the `tasks` management tool is active in the session, so the model that starts work can always read, wait for and stop it. The bundled `builtin:tasks` extension provides that tool; a session that disables the extension or deactivates the tool rejects `background: true` and every detach path (the error says no work was started), while work already admitted keeps running and delivering.
|
|
258
|
+
|
|
253
259
|
The host must choose:
|
|
254
260
|
|
|
255
261
|
- **Lifetime and cancellation:** a settled main-agent turn is not the end of background work. `session.abort()` cancels foreground-owned work, not detached work. Use `session.tasks.kill(id)` for a whole execution, or `await session.tasks.shutdown(graceMs?)` to close admission, cancel all owned work and drain within a bounded grace period (default 2 seconds, maximum 60 seconds). A non-cooperating executor can outlive that grace period.
|
|
256
262
|
- **Result-driven turns and cost:** automatic completions join the host's prompt queue, so a running turn receives them as steering and an idle session starts a completion turn. Use the nestable `session.pauseTaskNotifications()` to defer delivery; its returned release function is idempotent. Pausing does not stop execution or its costs. Budget worker activity and completion-triggered turns explicitly.
|
|
257
|
-
- **Observation and delivery:** `session.tasks` exposes the [public supervision methods](extensions.md#ctxtasks). `read()`, `wait()`, and `waitAny()` observe; a terminal snapshot alone does not acknowledge model delivery. `waitAny()` covers only tasks running at call time and reports `no_tasks` for an empty cohort. Both return a typed `outcome` (`settled`, `timed_out`, `interrupted`, or `closed`), and steering interrupts only waits, never execution. The built-in `tasks wait` tool passes its tool-call ID as `toolCallId`, so the runtime holds the observed result back from notifications and the host confirms it only after persisting that tool result, even if extensions rewrite its details. A direct SDK waiter that consumes the result outside model history omits `toolCallId` and can explicitly call `session.
|
|
263
|
+
- **Observation and delivery:** `session.tasks` exposes the [public supervision methods](extensions.md#ctxtasks). `read()`, `wait()`, and `waitAny()` observe; a terminal snapshot alone does not acknowledge model delivery. `waitAny()` covers only tasks running at call time and reports `no_tasks` for an empty cohort. Both return a typed `outcome` (`settled`, `timed_out`, `interrupted`, or `closed`), and steering interrupts only waits, never execution. The built-in `tasks wait` tool passes its tool-call ID as `toolCallId`, so the runtime holds the observed result back from notifications and the host confirms it only after persisting that tool result, even if extensions rewrite its details. A direct SDK waiter that consumes the result outside model history omits `toolCallId` and can explicitly call `session.acknowledgeTaskDelivery(task.id)` after successful consumption, which stops the session from notifying the model about it (an unknown or already delivered ID is ignored). An undelivered completion keeps its task and output retained until it is delivered or acknowledged, or its runtime closes. A timeout or cancelled wait does not stop the execution. Failed notification delivery leaves the result available for inspection; after fixing the host failure, call `session.retryTaskNotifications()` explicitly. Pi does not retry a failed delivery forever on a timer.
|
|
258
264
|
- **Shutdown:** `await runtime.dispose()` handles background shutdown and extension lifecycle when using the runtime API. For a directly owned session, drain Background, abort the main agent, then dispose; synchronous `session.dispose()` alone is not an awaited drain.
|
|
265
|
+
- **Waiting for all work:** `prompt()` resolves when its own run settles, before any Background completion turn. `await session.waitForQuiescence(signal?)` resolves once the session is quiescent: no run, compaction, retry or branch summary, no unsettled Background task, and no completion left to deliver (the `session_quiescent` event marks the same moment, once per transition). It uses no timers and rejects when `signal` aborts or the session is disposed. A completion whose delivery failed does not count, since it retries only on the next input; a Background task that never ends keeps the wait open, so pass a signal when that matters.
|
|
259
266
|
|
|
260
267
|
A deliberately single-turn embedding can suppress completion-triggered turns and cancel leftover work on exit:
|
|
261
268
|
|
|
@@ -378,6 +385,9 @@ session.subscribe((event) => {
|
|
|
378
385
|
// Main agent, retries, compaction, and queued continuations have settled
|
|
379
386
|
// Background executions may still be active
|
|
380
387
|
break;
|
|
388
|
+
case "session_quiescent":
|
|
389
|
+
// Also no unsettled Background task and no completion turn still to come
|
|
390
|
+
break;
|
|
381
391
|
|
|
382
392
|
// Turn lifecycle (one LLM response + tool calls)
|
|
383
393
|
case "turn_start":
|
package/docs/session-format.md
CHANGED
|
@@ -10,11 +10,15 @@ Sessions are stored as JSONL (JSON Lines) files. Each line is a JSON object with
|
|
|
10
10
|
|
|
11
11
|
Pi resolves the working directory to an absolute path, removes one leading `/` or `\`, replaces every `/`, `\`, and `:` with `-`, then wraps the result in `--`. For example, `/path/to/project` is stored under `--path-to-project--`; `C:\Users\me\project` is stored under `--C--Users-me-project--`. By default the session ID is a UUID; callers can supply their own through the SDK or `--session-id`.
|
|
12
12
|
|
|
13
|
+
## Session Artifacts
|
|
14
|
+
|
|
15
|
+
A session file `<name>.jsonl` owns an artifacts directory `<name>/` beside it, created on demand by whatever writes there. The bundled `Agent` extension keeps each Agent's complete report and transcript in `<name>/agents/<task-id>/` (see [Agent](bundled/extensions/agent.md)). The directory holds nested session files, but session discovery reads only `.jsonl` files directly inside the session directory, so they never appear in `/resume` or `pi -c`. Forking or cloning a session does not copy artifacts: they belong to the session that created them. Sessions that are not persisted (`--no-session`) have no artifacts directory.
|
|
16
|
+
|
|
13
17
|
## Deleting Sessions
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
A session consists of its `.jsonl` file, its artifacts directory, and the `<name>.jsonl.tasks-late.jsonl` sidecar when present. To remove a session by hand, delete all three under `~/.pi/agent/sessions/`.
|
|
16
20
|
|
|
17
|
-
Pi also supports deleting sessions interactively from `/resume` (select a session and press `Ctrl+D`, then confirm). When available, pi uses the `trash` CLI to avoid permanent deletion.
|
|
21
|
+
Pi also supports deleting sessions interactively from `/resume` (select a session and press `Ctrl+D`, then confirm). It removes the session file, its artifacts directory and its sidecar together. When available, pi uses the `trash` CLI, passing every path in one invocation, to avoid permanent deletion; otherwise it deletes them permanently. The deletion succeeds when the session file is gone, and files that could not be removed are reported.
|
|
18
22
|
|
|
19
23
|
## Session Version
|
|
20
24
|
|
|
@@ -344,7 +348,7 @@ Managed execution uses ordinary version-3 custom entries; it does not add a new
|
|
|
344
348
|
|
|
345
349
|
`task.id` is the execution ID, not a worker display number. `usage` has the `Usage` shape above and is absent when the executor reported none. Consumers count only the first valid usage settlement per ID within the entries they aggregate; malformed records, unsupported versions, blank IDs, and non-finite or negative usage/cost values are ignored. A later valid duplicate is not an adjustment. Do not create these host-owned entries yourself or bill again from a result/read/notification.
|
|
346
350
|
|
|
347
|
-
A `TaskSnapshot` has `id`, `kind` (executor-owned source label, such as `bash`, `powershell`, or an extension-defined label), `label` (human source name, such as `Bash` or `Agent`), `title`, `output` (`log` or `report`), `toolCallId`, `anchorId`, `mode`, `status`, and numeric millisecond `startedAt`; optional fields include `endedAt`, `input`, `facts`, `display`, `outputPath`, `result`, and `error`. `input` is `{ label, text, truncated, language? }`, what the task was asked to do; `facts` are up to 16 `[label, value]` Details rows, such as `["Exit", "1"]`. `result` is the bounded model-readable text and `display` is bounded human-only
|
|
351
|
+
A `TaskSnapshot` has `id`, `kind` (executor-owned source label, such as `bash`, `powershell`, or an extension-defined label), `label` (human source name, such as `Bash` or `Agent`), `title`, `output` (`log` or `report`), `toolCallId`, `anchorId`, `mode`, `status`, and numeric millisecond `startedAt`; optional fields include `endedAt`, `input`, `facts`, `display`, `outputPath`, `result`, and `error`. `input` is `{ label, text, truncated, language? }`, what the task was asked to do; `facts` are up to 16 `[label, value]` Details rows, such as `["Exit", "1"]`. `result` is the bounded model-readable text and `display` is the bounded human-only view that `/tasks` shows in place of the result; both use `{ text, truncated }`. Only the result, error and facts reach model context. Truncation flags record clipping at the producing/retention boundary. Mode (`foreground` or `background`) is independent of status and records where the task actually ran: `background` only when its caller was released with a background outcome, so a task whose result was returned inline is `foreground` even if background was requested. A terminal snapshot carries `display` only when the executor's completion supplied it. Persisted terminal statuses are `completed`, `partial`, `failed`, `cancelled`, or `timeout`; live snapshots can also be `queued`, `running`, or `stopping`.
|
|
348
352
|
|
|
349
353
|
The retained result text is bounded (up to 48 KiB) and carries no executor-private details; images are replaced with a text omission marker. Source truncation is explicit; the reader never recognizes truncation by matching output text. `outputPath`, if present, points to an ephemeral executor-owned file which may already have been removed on eviction or runtime shutdown; restored records drop it. Save important output separately.
|
|
350
354
|
|
|
@@ -385,7 +389,7 @@ A completion is acknowledged only after its message is persisted. A terminal `ta
|
|
|
385
389
|
|
|
386
390
|
Session-wide statistics aggregate the ledger across all entries; the bundled Statusline uses the active branch. Accrued retries, failures, cancellations and worker compaction count when usage is reported. No usage is invented for a provider that does not expose it, and worker billing does not occupy the parent's context window. See [SDK session statistics](sdk.md#session-statistics).
|
|
387
391
|
|
|
388
|
-
**Late settlement quarantine:** an executor that ignores cancellation and settles after its runtime or launch branch is retired cannot append to the replacement session or move its active leaf. The originating session retains the latest 32 bounded quarantine records in memory. For persisted sessions it also appends audit JSONL to `<session-file>.tasks-late.jsonl`, with `{ version: 1, sessionId, generation, task, usage? }`. A sidecar write failure is reported and leaves only the bounded in-memory record. This sidecar is separate from the session tree and active totals; it is not automatically reconciled, replayed or used to resume execution. Preserve it if you need to audit late provider costs
|
|
392
|
+
**Late settlement quarantine:** an executor that ignores cancellation and settles after its runtime or launch branch is retired cannot append to the replacement session or move its active leaf. The originating session retains the latest 32 bounded quarantine records in memory. For persisted sessions it also appends audit JSONL to `<session-file>.tasks-late.jsonl`, with `{ version: 1, sessionId, generation, task, usage? }`. A sidecar write failure is reported and leaves only the bounded in-memory record. This sidecar is separate from the session tree and active totals; it is not automatically reconciled, replayed or used to resume execution. Preserve it if you need to audit late provider costs. Deleting the session from `/resume` also removes its sidecar.
|
|
389
393
|
|
|
390
394
|
### CustomMessageEntry
|
|
391
395
|
|
|
@@ -516,6 +520,7 @@ Import `SessionManager` and its session types from `@astralyn/pi` as shown above
|
|
|
516
520
|
|
|
517
521
|
- `SessionManager.create(cwd: string, sessionDir?: string, options?: NewSessionOptions): SessionManager` — create a persisted session.
|
|
518
522
|
- `SessionManager.open(path: string, sessionDir?: string, cwdOverride?: string): SessionManager` — open a session file. `cwdOverride` takes precedence over the header's `cwd`.
|
|
523
|
+
- `SessionManager.createAt(path: string, cwd: string, options?: NewSessionOptions): SessionManager` — create a persisted session at an exact file path, creating its directory. As for any session, the file appears once it holds a conversation.
|
|
519
524
|
- `SessionManager.continueRecent(cwd: string, sessionDir?: string): SessionManager` — open the most recent session or create one.
|
|
520
525
|
- `SessionManager.inMemory(cwd?: string, options?: NewSessionOptions, entries?: FileEntry[]): SessionManager` — create a non-persisted session, optionally initialized from entries.
|
|
521
526
|
- `SessionManager.forkFrom(sourcePath: string, targetCwd: string, sessionDir?: string, options?: NewSessionOptions): SessionManager` — fork into another working directory.
|
|
@@ -567,6 +572,7 @@ All of these return the appended entry ID:
|
|
|
567
572
|
- `getEntries(): SessionEntry[]` and `getHeader(): SessionHeader | null`
|
|
568
573
|
- `getSessionName(): string | undefined`
|
|
569
574
|
- `getCwd(): string`, `getSessionDir(): string`, `getSessionId(): string`, and `getSessionFile(): string | undefined`
|
|
575
|
+
- `getArtifactDir(): string | undefined` — the directory the session file owns (`<name>/` for `<name>.jsonl`), or `undefined` when the session is not persisted. It is not created for you; create it before writing. Also available on `ctx.sessionManager` in extensions.
|
|
570
576
|
- `usesDefaultSessionDir(): boolean` and `isPersisted(): boolean`
|
|
571
577
|
|
|
572
578
|
## Virtual selections and nested calls
|
package/docs/sessions.md
CHANGED
|
@@ -48,7 +48,7 @@ In the picker you can:
|
|
|
48
48
|
- rename with Ctrl+R
|
|
49
49
|
- delete with Ctrl+D, then confirm
|
|
50
50
|
|
|
51
|
-
When available, pi uses the `trash` CLI for deletion instead of permanently removing files.
|
|
51
|
+
Deleting a session also removes its artifacts directory (such as saved Agent reports and transcripts) and its late-task sidecar. When available, pi uses the `trash` CLI for deletion instead of permanently removing files.
|
|
52
52
|
|
|
53
53
|
## Naming Sessions
|
|
54
54
|
|
package/docs/usage.md
CHANGED
|
@@ -178,6 +178,8 @@ See [Pi Packages](packages.md) for package sources and security notes.
|
|
|
178
178
|
|
|
179
179
|
Print mode writes errors to stderr. A final assistant response with an `error` or `aborted` stop reason exits nonzero; a response cut off at the model's output token limit (a `length` stop reason) still prints its partial text to stdout, warns on stderr, and also exits nonzero.
|
|
180
180
|
|
|
181
|
+
Print mode and `--mode json` wait for Background tasks started by a prompt: the process stays alive until every unsettled task has finished and the turn that delivers its result has completed, so the printed response is the one that follows the result. While it waits, one line on stderr names the running tasks. Ctrl+C (`SIGINT`) or `SIGTERM` stops the wait, terminates the work and exits (130 and 143); a second signal exits at once.
|
|
182
|
+
|
|
181
183
|
In print mode, pi also reads piped stdin and merges it into the initial prompt:
|
|
182
184
|
|
|
183
185
|
```bash
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astralyn/pi",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.10",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@astralyn/pi",
|
|
9
|
-
"version": "1.4.
|
|
9
|
+
"version": "1.4.10",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@earendil-works/pi-agent-core": "1.4.0",
|