@osolmaz/pi-workflows 0.13.4 → 0.15.0
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/README.md +146 -160
- package/dist/builtins/autoimplement.workflow.js +3 -1
- package/dist/builtins/autoimplement.workflow.js.map +1 -1
- package/dist/builtins/change-verification.workflow.js +7 -2
- package/dist/builtins/change-verification.workflow.js.map +1 -1
- package/dist/builtins/metadata.d.ts +22 -0
- package/dist/builtins/metadata.js +10 -0
- package/dist/builtins/metadata.js.map +1 -0
- package/dist/builtins/monitor.workflow.js +4 -1
- package/dist/builtins/monitor.workflow.js.map +1 -1
- package/dist/builtins/sanity-check.workflow.js +4 -1
- package/dist/builtins/sanity-check.workflow.js.map +1 -1
- package/dist/builtins/workspace-preparation.workflow.js +3 -1
- package/dist/builtins/workspace-preparation.workflow.js.map +1 -1
- package/dist/controllers/index.d.ts +1 -2
- package/dist/controllers/index.js +0 -1
- package/dist/controllers/index.js.map +1 -1
- package/dist/controllers/sqlite.d.ts +85 -31
- package/dist/controllers/sqlite.js +541 -126
- package/dist/controllers/sqlite.js.map +1 -1
- package/dist/controllers/store.d.ts +1 -0
- package/dist/extension/controller-command.d.ts +22 -0
- package/dist/extension/controller-command.js +32 -0
- package/dist/extension/controller-command.js.map +1 -0
- package/dist/extension/index.d.ts +2 -9
- package/dist/extension/index.js +876 -2928
- package/dist/extension/index.js.map +1 -1
- package/dist/extension/message-card.d.ts +13 -0
- package/dist/extension/message-card.js +46 -0
- package/dist/extension/message-card.js.map +1 -0
- package/dist/extension/step-message.d.ts +5 -6
- package/dist/extension/step-message.js +41 -52
- package/dist/extension/step-message.js.map +1 -1
- package/dist/host/child-worker-supervisor.d.ts +50 -0
- package/dist/host/child-worker-supervisor.js +159 -0
- package/dist/host/child-worker-supervisor.js.map +1 -0
- package/dist/host/client.d.ts +48 -0
- package/dist/host/client.js +216 -0
- package/dist/host/client.js.map +1 -0
- package/dist/host/controller-worker-entry.d.ts +2 -0
- package/dist/host/controller-worker-entry.js +244 -0
- package/dist/host/controller-worker-entry.js.map +1 -0
- package/dist/host/controller-worker-protocol.d.ts +36 -0
- package/dist/host/controller-worker-protocol.js +49 -0
- package/dist/host/controller-worker-protocol.js.map +1 -0
- package/dist/host/controller-worker-supervisor.d.ts +21 -0
- package/dist/host/controller-worker-supervisor.js +54 -0
- package/dist/host/controller-worker-supervisor.js.map +1 -0
- package/dist/host/host-entry.d.ts +2 -0
- package/dist/host/host-entry.js +23 -0
- package/dist/host/host-entry.js.map +1 -0
- package/dist/host/processes.d.ts +17 -12
- package/dist/host/processes.js +154 -50
- package/dist/host/processes.js.map +1 -1
- package/dist/host/protocol.d.ts +38 -0
- package/dist/host/protocol.js +156 -0
- package/dist/host/protocol.js.map +1 -0
- package/dist/host/resolver-entry.d.ts +49 -0
- package/dist/host/resolver-entry.js +149 -0
- package/dist/host/resolver-entry.js.map +1 -0
- package/dist/host/rpc-executor.d.ts +14 -3
- package/dist/host/rpc-executor.js +63 -30
- package/dist/host/rpc-executor.js.map +1 -1
- package/dist/host/runner.d.ts +95 -29
- package/dist/host/runner.js +2311 -348
- package/dist/host/runner.js.map +1 -1
- package/dist/host/state.d.ts +174 -0
- package/dist/host/state.js +689 -0
- package/dist/host/state.js.map +1 -0
- package/dist/host/worker-entry.d.ts +10 -0
- package/dist/host/worker-entry.js +446 -0
- package/dist/host/worker-entry.js.map +1 -0
- package/dist/host/worker-protocol.d.ts +31 -0
- package/dist/host/worker-protocol.js +122 -0
- package/dist/host/worker-protocol.js.map +1 -0
- package/dist/host/worker-store.d.ts +80 -0
- package/dist/host/worker-store.js +91 -0
- package/dist/host/worker-store.js.map +1 -0
- package/dist/host/worker-supervisor.d.ts +22 -0
- package/dist/host/worker-supervisor.js +54 -0
- package/dist/host/worker-supervisor.js.map +1 -0
- package/dist/render/canvas.d.ts +2 -1
- package/dist/render/canvas.js +40 -15
- package/dist/render/canvas.js.map +1 -1
- package/dist/render/graph-render.d.ts +7 -3
- package/dist/render/graph-render.js +125 -74
- package/dist/render/graph-render.js.map +1 -1
- package/dist/state/database.js +3 -1
- package/dist/state/database.js.map +1 -1
- package/dist/state/index.d.ts +1 -0
- package/dist/state/index.js +1 -0
- package/dist/state/index.js.map +1 -1
- package/dist/state/prune.js +36 -10
- package/dist/state/prune.js.map +1 -1
- package/dist/state/schema.d.ts +1 -1
- package/dist/state/schema.js +171 -3
- package/dist/state/schema.js.map +1 -1
- package/dist/state/viewer.d.ts +46 -0
- package/dist/state/viewer.js +249 -0
- package/dist/state/viewer.js.map +1 -0
- package/dist/viewer/cli.d.ts +1 -1
- package/dist/viewer/cli.js +47 -18
- package/dist/viewer/cli.js.map +1 -1
- package/dist/workflows/composition.js +25 -2
- package/dist/workflows/composition.js.map +1 -1
- package/dist/workflows/definition.d.ts +3 -1
- package/dist/workflows/definition.js +25 -0
- package/dist/workflows/definition.js.map +1 -1
- package/dist/workflows/engine.d.ts +1 -0
- package/dist/workflows/engine.js +157 -42
- package/dist/workflows/engine.js.map +1 -1
- package/dist/workflows/errors.d.ts +3 -1
- package/dist/workflows/errors.js +4 -7
- package/dist/workflows/errors.js.map +1 -1
- package/dist/workflows/human-decision.d.ts +3 -0
- package/dist/workflows/human-decision.js +31 -0
- package/dist/workflows/human-decision.js.map +1 -1
- package/dist/workflows/index.d.ts +1 -1
- package/dist/workflows/index.js +1 -1
- package/dist/workflows/index.js.map +1 -1
- package/dist/workflows/schema.js +17 -6
- package/dist/workflows/schema.js.map +1 -1
- package/dist/{viewer → workflows}/session-reducer.d.ts +3 -1
- package/dist/{viewer → workflows}/session-reducer.js +4 -0
- package/dist/workflows/session-reducer.js.map +1 -0
- package/dist/workflows/store.d.ts +87 -1
- package/dist/workflows/store.js +892 -93
- package/dist/workflows/store.js.map +1 -1
- package/dist/workflows/tool-input.d.ts +0 -22
- package/dist/workflows/tool-input.js +1 -44
- package/dist/workflows/tool-input.js.map +1 -1
- package/dist/workflows/types.d.ts +36 -4
- package/docs/2026-08-25-workflow-follow-ups.md +8 -6
- package/docs/2026-08-30-out-of-process-workflow-host-plan.md +353 -0
- package/docs/CONTROLLERS.md +11 -11
- package/docs/DEFERRED_TURNS.md +61 -27
- package/docs/HUMAN_DECISIONS.md +12 -4
- package/docs/SQLITE_STATE.md +42 -8
- package/docs/WORKFLOW_HOST.md +452 -0
- package/docs/development.md +46 -30
- package/docs/live-replay-protocol.md +129 -100
- package/docs/plans/2026-08-19-human-decision-gates-plan.md +34 -8
- package/docs/plans/2026-08-27-workflow-terminal-restart-plan.md +399 -0
- package/docs/plans/2026-08-28-piw-incremental-viewer-plan.md +293 -0
- package/docs/plans/piw-viewer-experience-implementation-plan.md +11 -1
- package/docs/plans/tui-viewer-implementation-plan.md +5 -0
- package/docs/tui-viewer.md +18 -3
- package/docs/workflows.md +164 -156
- package/examples/workflows/command-batch.workflow.ts +2 -0
- package/examples/workflows/shell.workflow.ts +2 -1
- package/herdr-plugin.toml +1 -1
- package/package.json +1 -1
- package/skills/autodoc/SKILL.md +1 -1
- package/skills/autoimplement/SKILL.md +1 -1
- package/skills/autoplan/SKILL.md +1 -1
- package/skills/pi-workflows/SKILL.md +2 -0
- package/src/builtins/autoimplement.workflow.ts +3 -0
- package/src/builtins/change-verification.workflow.ts +7 -2
- package/src/builtins/metadata.ts +9 -0
- package/src/builtins/monitor.workflow.ts +4 -0
- package/src/builtins/sanity-check.workflow.ts +4 -0
- package/src/builtins/workspace-preparation.workflow.ts +3 -1
- package/src/controllers/index.ts +3 -5
- package/src/controllers/sqlite.ts +929 -225
- package/src/controllers/store.ts +1 -0
- package/src/extension/controller-command.ts +45 -0
- package/src/extension/index.ts +948 -3506
- package/src/extension/message-card.ts +61 -0
- package/src/extension/step-message.ts +58 -63
- package/src/host/child-worker-supervisor.ts +183 -0
- package/src/host/client.ts +293 -0
- package/src/host/controller-worker-entry.ts +311 -0
- package/src/host/controller-worker-protocol.ts +104 -0
- package/src/host/controller-worker-supervisor.ts +79 -0
- package/src/host/host-entry.ts +23 -0
- package/src/host/processes.ts +171 -54
- package/src/host/protocol.ts +196 -0
- package/src/host/resolver-entry.ts +241 -0
- package/src/host/rpc-executor.ts +76 -34
- package/src/host/runner.ts +2813 -422
- package/src/host/state.ts +1160 -0
- package/src/host/worker-entry.ts +533 -0
- package/src/host/worker-protocol.ts +165 -0
- package/src/host/worker-store.ts +229 -0
- package/src/host/worker-supervisor.ts +74 -0
- package/src/render/canvas.ts +44 -10
- package/src/render/graph-render.ts +145 -90
- package/src/state/database.ts +2 -1
- package/src/state/index.ts +14 -0
- package/src/state/prune.ts +35 -9
- package/src/state/schema.ts +171 -3
- package/src/state/viewer.ts +356 -0
- package/src/viewer/cli.ts +49 -17
- package/src/workflows/composition.ts +36 -2
- package/src/workflows/definition.ts +32 -0
- package/src/workflows/engine.ts +157 -54
- package/src/workflows/errors.ts +11 -2
- package/src/workflows/human-decision.ts +49 -0
- package/src/workflows/index.ts +2 -0
- package/src/workflows/schema.ts +19 -6
- package/src/{viewer → workflows}/session-reducer.ts +11 -1
- package/src/workflows/store.ts +1316 -108
- package/src/workflows/tool-input.ts +2 -60
- package/src/workflows/types.ts +32 -4
- package/dist/controllers/workflow-engine-scheduler.d.ts +0 -29
- package/dist/controllers/workflow-engine-scheduler.js +0 -175
- package/dist/controllers/workflow-engine-scheduler.js.map +0 -1
- package/dist/extension/controller-host.d.ts +0 -48
- package/dist/extension/controller-host.js +0 -110
- package/dist/extension/controller-host.js.map +0 -1
- package/dist/extension/deferred-turn-coordinator.d.ts +0 -32
- package/dist/extension/deferred-turn-coordinator.js +0 -143
- package/dist/extension/deferred-turn-coordinator.js.map +0 -1
- package/dist/extension/deferred-turn.d.ts +0 -44
- package/dist/extension/deferred-turn.js +0 -110
- package/dist/extension/deferred-turn.js.map +0 -1
- package/dist/extension/executor.d.ts +0 -86
- package/dist/extension/executor.js +0 -311
- package/dist/extension/executor.js.map +0 -1
- package/dist/extension/follow-up-coordinator.d.ts +0 -27
- package/dist/extension/follow-up-coordinator.js +0 -131
- package/dist/extension/follow-up-coordinator.js.map +0 -1
- package/dist/extension/recorder.d.ts +0 -84
- package/dist/extension/recorder.js +0 -528
- package/dist/extension/recorder.js.map +0 -1
- package/dist/extension/session-events.d.ts +0 -133
- package/dist/extension/session-events.js +0 -61
- package/dist/extension/session-events.js.map +0 -1
- package/dist/viewer/session-reducer.js.map +0 -1
- package/src/controllers/workflow-engine-scheduler.ts +0 -246
- package/src/extension/controller-host.ts +0 -167
- package/src/extension/deferred-turn-coordinator.ts +0 -171
- package/src/extension/deferred-turn.ts +0 -166
- package/src/extension/executor.ts +0 -411
- package/src/extension/follow-up-coordinator.ts +0 -151
- package/src/extension/recorder.ts +0 -655
- package/src/extension/session-events.ts +0 -121
package/docs/CONTROLLERS.md
CHANGED
|
@@ -19,7 +19,7 @@ The controller runtime provides:
|
|
|
19
19
|
- Recoverable records for external effects.
|
|
20
20
|
- Child workflow runs with stable request keys.
|
|
21
21
|
- Conditions and generations, with cleanup and structured events.
|
|
22
|
-
- Local
|
|
22
|
+
- Local resource control through the Pi extension and reconciliation through the global host.
|
|
23
23
|
|
|
24
24
|
The first production use case is pull request automation. A controller can observe a pull request, start a review or repair workflow, wait for checks, validate the current head, and apply an approved change through deterministic code.
|
|
25
25
|
|
|
@@ -27,7 +27,7 @@ The first production use case is pull request automation. A controller can obser
|
|
|
27
27
|
|
|
28
28
|
The graph engine remains the execution layer for finite work. A finite workflow can include another finite workflow in the same run through `includeWorkflow()`. Use a controller child run when work needs an independent retry history, stable request key, parallel lifecycle, or indefinite reconciliation. The graph engine does not import the controller runtime. The controller runtime may start workflows through a narrow scheduler interface.
|
|
29
29
|
|
|
30
|
-
The Pi extension is a
|
|
30
|
+
The Pi extension is a thin client. It resolves controller initialization in a dedicated child process and sends declarative resource commands to the one global host. The host schedules reconciliation but does not load controller definitions in its event loop. A supervised controller worker loads one definition and proposes bounded state changes through the host.
|
|
31
31
|
|
|
32
32
|
External events are wake-up hints. An event enqueues a resource key and carries no transition command. The reconciler reloads the resource and the external system before deciding what to do.
|
|
33
33
|
|
|
@@ -155,15 +155,15 @@ export type EffectRecord = {
|
|
|
155
155
|
|
|
156
156
|
The key names one intended effect. Reusing the key with another request fingerprint is an error. The next reconciliation observes the external system before retrying an existing pending or indeterminate effect. The effect can be treated as effectively once when the provider offers an idempotency token, a conditional request, or a reliable way to observe the requested result. The runtime does not promise generic exactly-once execution.
|
|
157
157
|
|
|
158
|
-
Mutation policy stays in deterministic effect drivers. Agent workflows return findings or artifacts for deterministic code to check and apply.
|
|
158
|
+
Mutation policy stays in deterministic effect drivers. Agent workflows return findings or artifacts for deterministic code to check and apply. Worker processes run as the same operating-system user and are not credential sandboxes. Deployments that require credential isolation should put authenticated effects behind a separate broker.
|
|
159
159
|
|
|
160
160
|
## Child workflows
|
|
161
161
|
|
|
162
162
|
`ctx.workflows.ensure()` creates or finds a workflow run by a stable request key and input fingerprint. Repeated reconciliations find the same active or completed request. A changed input must use a new key. An asynchronous child completion validates the reserved request and run IDs through a separate scheduler-completion command; it never reuses the controller claim that launched the child. The controller transaction reserves and saves each attempt's run ID before the scheduler starts it, so recovery can find the run row.
|
|
163
163
|
|
|
164
|
-
A child run
|
|
164
|
+
A child run has one durable execution record. The parent resource points to the current run, and workflow completion enqueues the parent key. The global host runs it through the same queue and supervised worker protocol as other workflows.
|
|
165
165
|
|
|
166
|
-
|
|
166
|
+
A stopped worker does not make the child failed by itself. The host reads the last committed node and effect state. It resumes pure or idempotent work in a new worker epoch. An uncertain manual effect becomes ambiguous and blocks automatic retry. A changed input still requires a new stable request key.
|
|
167
167
|
|
|
168
168
|
## Deletion and cleanup
|
|
169
169
|
|
|
@@ -175,9 +175,9 @@ Controllers should add finalizers only when they own something that needs cleanu
|
|
|
175
175
|
|
|
176
176
|
A source maps an external event to one or more resource keys. Sources include filesystem watches, webhooks, scheduled polling, and child workflow completion. They share the same enqueue API.
|
|
177
177
|
|
|
178
|
-
|
|
178
|
+
The global host claims controller keys and starts a supervised process group for each active reconciliation. A reconciliation deadline stops and requeues the child even when controller code ignores its abort signal. Reconciler code must still pass the signal to provider calls and keep consequential writes inside guarded effect drivers. One host owns the local database. Distributed leader election remains outside this local runtime.
|
|
179
179
|
|
|
180
|
-
The
|
|
180
|
+
The extension starts the package host on demand. Reconciliation continues when the Pi session closes. The package installs no operating-system service.
|
|
181
181
|
|
|
182
182
|
## Observability
|
|
183
183
|
|
|
@@ -202,13 +202,13 @@ A production controller must follow these rules:
|
|
|
202
202
|
|
|
203
203
|
The controller API is exported from `@osolmaz/pi-workflows/controllers`. Controller definitions use a `.controller.ts` suffix. Project definitions live under `.pi/controllers/`; global definitions live under `~/.pi/agent/controllers/`.
|
|
204
204
|
|
|
205
|
-
The implementation uses documented Pi extension APIs only.
|
|
205
|
+
The implementation uses documented Pi extension APIs only. `/controller` lists and inspects resources, applies specs, and requests reconciliation or deletion. There are no extension-local worker start or stop controls.
|
|
206
206
|
|
|
207
|
-
|
|
207
|
+
For `apply`, a source resolver child discovers the named controller, verifies its exported name, computes `initialStatus(spec)`, and hashes the source. The host accepts the proposal only while the path still follows discovery rules and the exact digest still matches. Reconcile code runs only in a supervised controller worker.
|
|
208
208
|
|
|
209
|
-
Controller resources use the canonical [SQLite state](SQLITE_STATE.md) database. `projects` separates repository-local resources by canonical project path. Controller claims use the shared lease generation, token, expiry, and expected resource revision. Effects and child workflows use
|
|
209
|
+
Controller resources use the canonical [SQLite state](SQLITE_STATE.md) database. `projects` separates repository-local resources by canonical project path. Controller claims use the shared lease generation, token, expiry, and expected resource revision. Effects and child workflows use durable request keys and receipts.
|
|
210
210
|
|
|
211
|
-
|
|
211
|
+
One global host owns that database for all Pi sessions and projects. The extension and mutating CLI paths are local protocol clients; viewers remain read-only. A controller child without an origin session uses a headless `pi --mode rpc` process for structured agent steps.
|
|
212
212
|
|
|
213
213
|
Normal workflow prompts, tool calls, and replies remain part of the Pi session. No Pi internal type, private API, or persistent Pi schema changes.
|
|
214
214
|
|
package/docs/DEFERRED_TURNS.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Deferred workflow turns
|
|
2
2
|
|
|
3
|
-
This specification defines how Pi Workflows schedules one successor agent turn after a workflow event stops or strands the current turn. It covers cancellation, timeout,
|
|
3
|
+
This specification defines how Pi Workflows schedules one successor agent turn after a workflow event stops or strands the current turn. It covers every top-level interactive terminal result, cancellation, timeout, launch failure, controller interruption, and claim loss.
|
|
4
4
|
|
|
5
|
-
The implementation
|
|
5
|
+
The implementation plans are [Guarantee one successor turn after workflow interruption](plans/2026-08-21-deferred-turn-intents-plan.md) and [Workflow terminal decision and restart](plans/2026-08-27-workflow-terminal-restart-plan.md).
|
|
6
6
|
|
|
7
7
|
## Terms
|
|
8
8
|
|
|
@@ -18,10 +18,10 @@ The implementation plan is [Guarantee one successor turn after workflow interrup
|
|
|
18
18
|
Each eligible source event creates at most one turn intent. Exactly one of these message paths can resolve it:
|
|
19
19
|
|
|
20
20
|
1. a workflow agent prompt;
|
|
21
|
-
2. a
|
|
21
|
+
2. a result presentation;
|
|
22
22
|
3. a factual fallback.
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
Every top-level interactive terminal run owns one intent. Its presentation and fallback claim that same intent before sending. A waiting presentation can resolve an earlier interruption intent, but waiting state does not create a terminal intent. A resolved intent cannot start another turn.
|
|
25
25
|
|
|
26
26
|
Cancellation and process termination remain immediate. Pi Workflows does not keep the old assistant turn alive and does not wait for the successor before stopping active work.
|
|
27
27
|
|
|
@@ -56,25 +56,25 @@ Resolution records message delivery into the Pi session or the presence of the s
|
|
|
56
56
|
Valid causes are:
|
|
57
57
|
|
|
58
58
|
```text
|
|
59
|
-
agentCancelled | timedOut | failed | launchFailed | controllerInterrupted | claimLost
|
|
59
|
+
agentCancelled | timedOut | failed | launchFailed | controllerInterrupted | claimLost | terminal | cancelled
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
The event policy is:
|
|
63
63
|
|
|
64
|
-
| Event | Intent
|
|
65
|
-
| -------------------------------------------------------------- |
|
|
66
|
-
|
|
|
67
|
-
|
|
|
68
|
-
|
|
|
69
|
-
| Workflow reports started, then crashes before its first prompt | Create after durable failure.
|
|
70
|
-
| Queued launch activation fails | Create after the queue row is durably failed.
|
|
71
|
-
| Controller interrupts an active workflow turn | Create before the turn abort when possible.
|
|
72
|
-
| Active workflow turn loses its queue claim | Create before the turn abort when possible.
|
|
73
|
-
|
|
|
74
|
-
|
|
|
75
|
-
| Workflow pause | Do not create.
|
|
76
|
-
| User Escape or held workflow | Do not create.
|
|
77
|
-
| Session shutdown | Do not create.
|
|
64
|
+
| Event | Intent | Fallback rule |
|
|
65
|
+
| -------------------------------------------------------------- | --------------------------------------------- | ---------------------------------------------------------------------------- |
|
|
66
|
+
| Top-level interactive run completes | Create one terminal intent. | Presentation and factual fallback compete for the intent. |
|
|
67
|
+
| Top-level interactive run fails or times out | Create or reuse the abort intent. | Make eligible after the terminal state is durable. |
|
|
68
|
+
| Agent or user cancels a top-level run | Create before turn abort when needed. | Make eligible after durable cancellation; the decision defaults to stopping. |
|
|
69
|
+
| Workflow reports started, then crashes before its first prompt | Create after durable failure. | Create as eligible. |
|
|
70
|
+
| Queued launch activation fails | Create after the queue row is durably failed. | Create as eligible. |
|
|
71
|
+
| Controller interrupts an active workflow turn | Create before the turn abort when possible. | Durable terminal or handoff state decides eligibility. |
|
|
72
|
+
| Active workflow turn loses its queue claim | Create before the turn abort when possible. | Keep ineligible while a new owner can continue. |
|
|
73
|
+
| Waiting result has a presentation | Do not create a terminal intent. | It can resolve an earlier interruption intent through presentation. |
|
|
74
|
+
| Controller child or internally owned run ends | Do not create a terminal intent. | Its owner receives the result. |
|
|
75
|
+
| Workflow pause | Do not create. | No automatic model turn. |
|
|
76
|
+
| User Escape or held workflow | Do not create. | No automatic model turn. |
|
|
77
|
+
| Session shutdown | Do not create. | A closing session cannot start another turn. |
|
|
78
78
|
|
|
79
79
|
A terminal failure after a successful start tool result is eligible even when it did not first call `ctx.abort()`. This rule covers asynchronous runtime validation and startup failures that the user can see in the UI but the model cannot see in its current context.
|
|
80
80
|
|
|
@@ -219,10 +219,21 @@ The fallback custom message uses this details object:
|
|
|
219
219
|
"schema": "pi-workflows.deferred-turn-message.v1",
|
|
220
220
|
"turnIntentId": "deferred-turn:...",
|
|
221
221
|
"runId": "20260821T081731Z-autoimplement-407480dd",
|
|
222
|
-
"cause": "failed"
|
|
222
|
+
"cause": "failed",
|
|
223
|
+
"presentation": {
|
|
224
|
+
"workflowName": "autoimplement",
|
|
225
|
+
"state": "failed",
|
|
226
|
+
"reasonKind": "maxSteps",
|
|
227
|
+
"restart": {
|
|
228
|
+
"count": 0,
|
|
229
|
+
"limit": 3
|
|
230
|
+
}
|
|
231
|
+
}
|
|
223
232
|
}
|
|
224
233
|
```
|
|
225
234
|
|
|
235
|
+
`presentation` contains small, bounded display fields. `reasonKind` and `restart` are present only when the run records provide them. These fields do not replace or shorten the model prompt.
|
|
236
|
+
|
|
226
237
|
The message type is `pi-workflows-deferred-turn`. Delivery uses:
|
|
227
238
|
|
|
228
239
|
```ts
|
|
@@ -232,10 +243,32 @@ The message type is `pi-workflows-deferred-turn`. Delivery uses:
|
|
|
232
243
|
}
|
|
233
244
|
```
|
|
234
245
|
|
|
235
|
-
|
|
246
|
+
### Compact TUI card
|
|
247
|
+
|
|
248
|
+
Interactive Pi registers a custom renderer for `pi-workflows-deferred-turn`. The collapsed card shows the workflow name, state or cause, run identity, and restart count when it is available. It does not show the terminal facts JSON, exact input, result, fingerprint, or model instructions.
|
|
249
|
+
|
|
250
|
+
The renderer reads only the structured message details for its compact fields. It sanitizes workflow-derived text and uses Pi's standard TUI components, theme colors, and `expanded` state. A message with missing or invalid details renders as a safe generic workflow card.
|
|
251
|
+
|
|
252
|
+
Expanding the card shows the complete existing message content. The model and session history receive that same content whether the card is collapsed or expanded. Restored messages use the same renderer and do not create another entry or model turn.
|
|
253
|
+
|
|
254
|
+
This display behavior uses the documented `pi.sendMessage()` and `pi.registerMessageRenderer()` APIs. It does not change headless or RPC delivery. Presentation messages that already use `display: false` stay hidden. It adds no Pi core change, private API, database table, migration, store, or external resource.
|
|
255
|
+
|
|
256
|
+
For a terminal run, the complete content contains the workflow identity and revision, terminal run ID, exact stored input, bounded result, terminal state and reason, restart count, and earlier terminal outcomes in the chain. It tells the model to use the current conversation, prefer a safe restart for an unfinished task after a technical or temporary failure, and stop for completed work, cancellation, missing authority, a required user decision, or a repeated failure. Values from input and result are data, not instructions.
|
|
257
|
+
|
|
258
|
+
The content comes only from existing run and queue records. Pi owns conversation history. Pi Workflows does not identify, hash, copy, or store an original user message.
|
|
236
259
|
|
|
237
260
|
Fallback delivery is disabled during session shutdown and while a user-interrupted workflow is held.
|
|
238
261
|
|
|
262
|
+
## Selected launch and restart
|
|
263
|
+
|
|
264
|
+
A terminal decision turn can reserve at most one workflow launch: `restart`, Monitor through normal `start`, or another workflow through normal `start`. The reservation records the source terminal intent, model tool call, and request fingerprint in the new run's existing launch options. It does not activate before `agent_settled`.
|
|
265
|
+
|
|
266
|
+
Repeating the same tool call adopts the existing reservation or run. A different launch from the same terminal intent fails. Session-start and queue recovery activate a surviving reservation once when the session is idle.
|
|
267
|
+
|
|
268
|
+
`restart` accepts the terminal run ID. It checks session ownership, terminal state, explicit cancellation, source identity and revision, repeated failure, and the restart limit. It creates a new immutable run from the exact stored reference, input, and safe launch settings. The old run does not change.
|
|
269
|
+
|
|
270
|
+
Restart lineage in launch options records the root run ID, parent run ID, restart number, and parent terminal fingerprint. The fingerprint covers workflow identity and revision, exact input, terminal state, canonical result or error, and terminal reason. It excludes timestamps and run IDs. The same fingerprint cannot restart twice in one chain. A chain permits three restarts after the original run. Starting Monitor does not add restart lineage.
|
|
271
|
+
|
|
239
272
|
## Delivery recovery
|
|
240
273
|
|
|
241
274
|
Every resolving message includes the intent ID in its custom-message details.
|
|
@@ -262,7 +295,7 @@ Pending `launch_failure` rows from the earlier alpha contract are incompatible.
|
|
|
262
295
|
|
|
263
296
|
## Post-completion follow-ups
|
|
264
297
|
|
|
265
|
-
Deferred turns
|
|
298
|
+
Deferred turns provide the terminal decision before ordered post-completion prompts. Those prompts represent user-requested normal work after successful completion, use `workflow_follow_up_queues` and `workflow_follow_ups`, and are delivered by the separate follow-up coordinator after the terminal intent is resolved. Neither feature reads or changes the other's rows.
|
|
266
299
|
|
|
267
300
|
See [Continue normal work after a workflow finishes](2026-08-25-workflow-follow-ups.md).
|
|
268
301
|
|
|
@@ -293,12 +326,13 @@ This is an alpha hard cutover.
|
|
|
293
326
|
|
|
294
327
|
An implementation conforms when:
|
|
295
328
|
|
|
296
|
-
-
|
|
297
|
-
-
|
|
298
|
-
- an agent self-cancel receives one fallback after settlement;
|
|
329
|
+
- every top-level interactive terminal run produces at most one intent and one decision message;
|
|
330
|
+
- an agent self-cancel and a direct cancellation receive one fallback after settlement;
|
|
299
331
|
- an asynchronous crash after a successful start result receives one fallback after settlement;
|
|
300
332
|
- a natural recovery prompt or presentation suppresses fallback by resolving the same intent;
|
|
301
|
-
-
|
|
333
|
+
- waiting checkpoints, controller children, internal owners, pause, Escape, user hold, and shutdown do not create terminal turns;
|
|
302
334
|
- claim transfer permits natural resolution by the new owner and prevents stale writes;
|
|
303
|
-
-
|
|
335
|
+
- one terminal turn reserves at most one launch and activates it after `agent_settled`;
|
|
336
|
+
- exact replay adopts the same launch, while reload, lease expiry, and send-before-resolution failure do not duplicate turns or runs;
|
|
337
|
+
- restart keeps the prior run immutable, preserves exact input, rejects cancellation and repeated fingerprints, and stops after three restarts;
|
|
304
338
|
- passive workflow notifications keep their current behavior.
|
package/docs/HUMAN_DECISIONS.md
CHANGED
|
@@ -322,19 +322,23 @@ Recovery follows these rules:
|
|
|
322
322
|
|
|
323
323
|
A required decision with no available channel remains waiting and reports the configuration problem. An automatic decision does not need a channel to apply its saved response after the deadline. A skipped plan policy creates no decision.
|
|
324
324
|
|
|
325
|
+
Direct answer handling and recovery can notice the same accepted decision at the same time. Both paths use one continuation coordinator. The coordinator prepares the deterministic continuation through the existing durable run queue. The first caller creates and claims the queue row. Only that caller receives the claim token and starts the engine. A compatible later caller adopts the existing row without starting another engine.
|
|
326
|
+
|
|
327
|
+
Adoption does not change the lease, claim generation, queue state, timestamps, or events. An adopter cannot renew, release, park, complete, or replace the winning claim. Reuse with a different workflow source, definition, input, launch options, parent, or owning session fails without changing the existing run. If the winning process stops after it claims the row, existing lease expiry and activation recovery can continue the prepared run.
|
|
328
|
+
|
|
325
329
|
## Compatibility
|
|
326
330
|
|
|
327
|
-
This alpha change updates the current request, accepted-result, receipt, resolution, continuation, and snapshot contracts in place. Old active runs refuse resume through normal source and definition identity checks. There is no compatibility reader, migration, dual path, or new schema generation. Updated viewers label a human decision as a checkpoint, show its deadline and automatic action when present, and keep the canonical subject separate. Private channel configuration and transport identifiers remain hidden.
|
|
331
|
+
This alpha change updates the current request, accepted-result, receipt, resolution, continuation, and snapshot contracts in place. Old active runs refuse resume through normal source and definition identity checks. There is no compatibility reader, migration, dual path, or new schema generation. The continuation startup fix uses existing queue and lease records. It adds no field, table, migration, or schema version. Existing compatible prepared or initialized continuations are adopted. Updated viewers label a human decision as a checkpoint, show its deadline and automatic action when present, and keep the canonical subject separate. Private channel configuration and transport identifiers remain hidden.
|
|
328
332
|
|
|
329
333
|
The engine remains independent from Pi and Telegram. Core code owns decision contracts, validation, durable acceptance, and continuation. The Pi extension owns UI and channel lifecycle. The Telegram adapter owns Bot API translation. Workflow definitions own only the question, choices, audience, and routes.
|
|
330
334
|
|
|
331
335
|
## Contract impact
|
|
332
336
|
|
|
333
337
|
- **Session state:** Pi records normal workflow messages and interactive decision results.
|
|
334
|
-
- **Other persistent data:** decision requests and resolutions can carry a deadline, automatic response, and resolution provenance in the existing decision store. The private channel index remains rebuildable.
|
|
338
|
+
- **Other persistent data:** decision requests and resolutions can carry a deadline, automatic response, and resolution provenance in the existing decision store. Continuation startup uses existing run, queue, source, binding, lease, event, continuation, and decision-effect records. It adds no new persistent shape. The private channel index remains rebuildable.
|
|
335
339
|
- **Pi internals:** none.
|
|
336
340
|
- **Public Pi API:** documented extension lifecycle and UI methods only.
|
|
337
|
-
- **Public pi-workflows API:** typed human choices, `humanDecision().onTimeout`, `humanDecisionEdge()`, the channel interface, the plan approval policy,
|
|
341
|
+
- **Public pi-workflows API:** typed human choices, `humanDecision().onTimeout`, `humanDecisionEdge()`, the channel interface, the plan approval policy, the shared plan-change workflow, and the additive queue prepare-or-adopt operation.
|
|
338
342
|
|
|
339
343
|
## Verification requirements
|
|
340
344
|
|
|
@@ -350,6 +354,10 @@ The implementation must test:
|
|
|
350
354
|
- unauthorized users and chats;
|
|
351
355
|
- stale request digests;
|
|
352
356
|
- concurrent Pi and Telegram answers;
|
|
357
|
+
- a direct verified answer racing recovery for the same accepted decision;
|
|
358
|
+
- one claim generation, one engine start, one continuation, and one execution of each continuation node;
|
|
359
|
+
- compatible continuation adoption without lease, queue, timestamp, or event mutation;
|
|
360
|
+
- incompatible continuation identity reuse without mutation;
|
|
353
361
|
- identical and conflicting retries;
|
|
354
362
|
- crashes before and after answer acceptance and continuation creation;
|
|
355
363
|
- ambiguous Telegram sends;
|
|
@@ -357,4 +365,4 @@ The implementation must test:
|
|
|
357
365
|
- decision cancellation and expiry;
|
|
358
366
|
- included `plan-approval` routes and bounded replan loops;
|
|
359
367
|
- viewer redaction; and
|
|
360
|
-
- real Pi execution without real Telegram credentials or network calls.
|
|
368
|
+
- real Pi execution without real Telegram credentials or network calls, duplicate-start failures, revision conflicts, or a stranded running continuation.
|
package/docs/SQLITE_STATE.md
CHANGED
|
@@ -8,11 +8,25 @@ Pi Workflows stores all live durable state in one database:
|
|
|
8
8
|
|
|
9
9
|
There is one database for the user installation. Project and run IDs separate data inside it. Workflow targets do not read or write this database.
|
|
10
10
|
|
|
11
|
+
## Viewer projection
|
|
12
|
+
|
|
13
|
+
The database includes the [incremental and virtualized viewer design](plans/2026-08-28-piw-incremental-viewer-plan.md).
|
|
14
|
+
|
|
15
|
+
`viewer_runs` stores one presentation revision and retained revision floor for each run. `viewer_deltas` stores ordered target patches by run, presentation revision, and delta index. `viewer_session_checkpoints` stores the bounded active message and tool state at each 256-event boundary. A viewer-visible transaction writes the domain change, advances the presentation revision, and writes its patch blobs before the same commit. Session-event transactions write each reached replay checkpoint in that transaction.
|
|
16
|
+
|
|
17
|
+
The store retains 256 presentation revisions. A reader with an older cursor must take a bounded snapshot. Patches use `add`, `replace`, `remove`, and `append`. They target small projection documents or pages. Patch creation does not reconstruct and compare complete run views.
|
|
18
|
+
|
|
19
|
+
`session_entries` and `session_events` have run-wide sequence numbers and indexed `(run_id, run_seq)` ranges. Step, trace, entry, and event reads contain at most 256 rows. Run-list queries read metadata, status, lease facts, and the presentation revision. They do not read payload bodies.
|
|
20
|
+
|
|
21
|
+
This is an in-place alpha schema change. The schema name and version remain `pi-workflows-state` version 1. The DDL digest and exact shape changed. An older alpha database fails with the standard reset instruction and remains untouched. There is no compatibility reader, migration shim, dual path, feature flag, alias, or `v2` schema.
|
|
22
|
+
|
|
11
23
|
## Storage boundary
|
|
12
24
|
|
|
13
25
|
The database stores:
|
|
14
26
|
|
|
15
27
|
- workflow definitions, runs, events, node attempts, outputs, and updates
|
|
28
|
+
- global host epochs, command receipts, worker epochs, and worker messages
|
|
29
|
+
- durable origin-session interaction requests and submissions
|
|
16
30
|
- captured Pi session entries and events
|
|
17
31
|
- run and controller queues, claims, retries, and continuations
|
|
18
32
|
- human-decision requests, submissions, resolutions, and cancellations
|
|
@@ -98,7 +112,8 @@ The shared records do not replace domain schemas. The following `STRICT` tables
|
|
|
98
112
|
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
99
113
|
| Schema and projects | `schema_meta`, `projects` |
|
|
100
114
|
| Content | `blobs` |
|
|
101
|
-
| Shared lifecycle | `resources`, `leases`, `events`
|
|
115
|
+
| Shared lifecycle | `resources`, `leases`, `events`, `workflow_host_state` |
|
|
116
|
+
| Host protocol | `host_commands`, `run_workers`, `worker_messages`, `interactive_requests`, `interactive_submissions` |
|
|
102
117
|
| Workflows | `workflow_definitions`, `runs`, `run_sources`, `run_steps`, `run_bindings`, `run_queue`, `node_attempts`, `workflow_updates` |
|
|
103
118
|
| Live settings | `workflow_settings`, `workflow_setting_changes` |
|
|
104
119
|
| Post-run follow-ups | `workflow_follow_up_queues`, `workflow_follow_ups` |
|
|
@@ -111,6 +126,24 @@ The shared records do not replace domain schemas. The following `STRICT` tables
|
|
|
111
126
|
|
|
112
127
|
Foreign keys join projects, runs, attempts, decisions, controllers, effects, and channel records. Partial unique indexes enforce one active node attempt per run, one queued or running reservation per Pi session, one decision winner, and one deterministic effect key. A parked waiting parent does not block its continuation. Reserving that continuation settles the parked parent queue in the same transaction, so a failed reservation leaves the parent recoverable.
|
|
113
128
|
|
|
129
|
+
### Hosted commands and interactions
|
|
130
|
+
|
|
131
|
+
`workflow_host_state` stores the one current host epoch and its live local
|
|
132
|
+
claim. `host_commands` stores each client request fingerprint, operation,
|
|
133
|
+
outcome, revision, and receipt or error. Repeating an exact request adopts the
|
|
134
|
+
stored receipt. Reusing an ID or idempotency key for another request is a
|
|
135
|
+
conflict.
|
|
136
|
+
|
|
137
|
+
`run_workers` records each worker epoch before spawn and later records its exact
|
|
138
|
+
process identity and terminal outcome. `worker_messages` deduplicates accepted
|
|
139
|
+
state-changing child messages.
|
|
140
|
+
|
|
141
|
+
`interactive_requests` owns durable origin-session work. It stores the run,
|
|
142
|
+
node attempt, target session, contract, presentation claim, accepted
|
|
143
|
+
submission, and revision. `interactive_submissions` stores the idempotency key,
|
|
144
|
+
payload, outcome, and receipt. Pi reload can adopt the saved presentation entry
|
|
145
|
+
without inserting another visible message.
|
|
146
|
+
|
|
114
147
|
## Content-addressed values
|
|
115
148
|
|
|
116
149
|
`blobs` stores canonical JSON and UTF-8 text as bytes. Its primary key is the 32-byte SHA-256 digest of the bytes.
|
|
@@ -125,9 +158,9 @@ Readers derive `steps`, `outputs`, `results`, carried-step count, current-node f
|
|
|
125
158
|
|
|
126
159
|
An agent definition records `expectedOutput` as either a submitted-output description or `{ "kind": "assistant-message", "maxChars"?: number }`. Omitted `maxChars` means that Pi Workflows adds no character limit.
|
|
127
160
|
|
|
128
|
-
A completed interactive assistant-message attempt
|
|
161
|
+
A completed interactive assistant-message attempt stores the accepted visible text as its node output. Its small receipt keeps the text digest, final Pi session entry ID, optional author-supplied limit, and whether recovery adopted an existing response.
|
|
129
162
|
|
|
130
|
-
An interrupted assistant-message attempt keeps its attempt ID
|
|
163
|
+
An interrupted assistant-message attempt keeps its attempt ID. The extension adopts a matching durable request and existing Pi branch entry instead of displaying the prompt or accepting the response twice. Submitted and non-agent attempts use a fresh execution attempt after an uncommitted worker exit.
|
|
131
164
|
|
|
132
165
|
## Write contract
|
|
133
166
|
|
|
@@ -139,6 +172,7 @@ verify the exact schema
|
|
|
139
172
|
verify the actor and operation
|
|
140
173
|
verify the expected resource revision
|
|
141
174
|
verify the claim token, generation, and expiry when ownership is required
|
|
175
|
+
renew that exact still-live token and generation
|
|
142
176
|
verify the domain transition
|
|
143
177
|
write content-addressed values
|
|
144
178
|
increment the resource revision
|
|
@@ -165,7 +199,7 @@ Reading or finding a row never gives write authority.
|
|
|
165
199
|
- Control commands have narrow explicit operations, such as requesting cancellation or deletion.
|
|
166
200
|
- Model-originated workflow answers cannot resolve protected human decisions.
|
|
167
201
|
|
|
168
|
-
|
|
202
|
+
The global host is the normal state writer. Its protected stores check ownership and renew the exact live claim in the same transaction as the write. A stale or expired owner cannot renew itself. Pi extensions and mutating CLI commands use the local host protocol. Shared scans, status commands, lists, viewers, and the Rust `piw` program are read-only.
|
|
169
203
|
|
|
170
204
|
## Competing outcomes
|
|
171
205
|
|
|
@@ -185,9 +219,9 @@ Status is a pure projection of domain rows, immutable facts, current leases, and
|
|
|
185
219
|
|
|
186
220
|
A settings scope uses its resource revision as its public change number. Each accepted patch, current value, and node binding is saved in one transaction. A checkpoint continuation keeps the same settings resources and transfers them to the continuation run.
|
|
187
221
|
|
|
188
|
-
A follow-up queue records acceptance order and
|
|
222
|
+
A follow-up queue records acceptance order and settlement state. Failure, timeout, and cancellation cancel unsent items.
|
|
189
223
|
|
|
190
|
-
- A terminal run fact overrides stale
|
|
224
|
+
- A terminal run fact overrides stale delivery state.
|
|
191
225
|
- An accepted decision is accepted even if its continuation effect is still pending.
|
|
192
226
|
- A cancelled decision is cancelled even if parent cleanup is still pending.
|
|
193
227
|
- A stale owner is not shown as current.
|
|
@@ -197,7 +231,7 @@ Read paths do not repair state. Owner reconcilers apply pending effects and writ
|
|
|
197
231
|
|
|
198
232
|
## Projects and concurrency
|
|
199
233
|
|
|
200
|
-
All projects use the same file. `projects` stores a stable ID and canonical path. Project-scoped controller and run queries use that key.
|
|
234
|
+
All projects use the same file. `projects` stores a stable ID and canonical path. Project-scoped controller and run queries use that key. One global host owns the file for the user installation. Its socket, lock, and exact child-process registry are under `~/.pi/agent/workflows/host/`. A second live host is rejected even when it was started from another project.
|
|
201
235
|
|
|
202
236
|
SQLite WAL permits concurrent readers while one writer commits. Writers are serialized by SQLite and must keep transactions short. Hashing, model calls, shell work, and external requests happen outside write transactions.
|
|
203
237
|
|
|
@@ -235,4 +269,4 @@ It does not print actor IDs, channel references, payloads, or credentials.
|
|
|
235
269
|
|
|
236
270
|
This is a hard cut. Pi Workflows has no normal reader or writer for older live storage. It does not use dual reads, dual writes, aliases, versioned state roots, or automatic import.
|
|
237
271
|
|
|
238
|
-
Older state remains untouched.
|
|
272
|
+
Older state remains untouched. Pi Workflows fails before mutation with this instruction: “Pi Workflows durable state is incompatible. Back up and move state.sqlite with its -wal and -shm files, then start Pi Workflows to create a new state.sqlite database. The incompatible state was not changed.”
|