@osolmaz/pi-workflows 0.16.5 → 0.16.6
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 +5 -5
- package/dist/builtins/autoimplement.workflow.d.ts +5 -1
- package/dist/builtins/autoimplement.workflow.js +29 -10
- package/dist/builtins/autoimplement.workflow.js.map +1 -1
- package/dist/client/client.js +3 -1
- package/dist/client/client.js.map +1 -1
- package/dist/client/protocol.d.ts +1 -1
- package/dist/client/protocol.js +18 -1
- package/dist/client/protocol.js.map +1 -1
- package/dist/client/view.d.ts +7 -5
- package/dist/extension/index.d.ts +2 -1
- package/dist/extension/index.js +115 -165
- package/dist/extension/index.js.map +1 -1
- package/dist/extension/recorder.d.ts +1 -1
- package/dist/extension/recorder.js +2 -2
- package/dist/extension/recorder.js.map +1 -1
- package/dist/extension/step-message.d.ts +1 -1
- package/dist/extension/step-message.js +4 -4
- package/dist/extension/step-message.js.map +1 -1
- package/dist/extension/workflow-message-coordinator.d.ts +12 -1
- package/dist/extension/workflow-message-coordinator.js +65 -54
- package/dist/extension/workflow-message-coordinator.js.map +1 -1
- package/dist/resource-managers/index.d.ts +1 -2
- package/dist/resource-managers/index.js +1 -2
- package/dist/resource-managers/index.js.map +1 -1
- package/dist/resource-managers/sqlite.d.ts +2 -295
- package/dist/resource-managers/sqlite.js +71 -1528
- package/dist/resource-managers/sqlite.js.map +1 -1
- package/dist/resource-managers/types.d.ts +2 -7
- package/dist/server/resource-runner-entry.js +2 -6
- package/dist/server/resource-runner-entry.js.map +1 -1
- package/dist/server/rpc-bridge.js +1 -1
- package/dist/server/rpc-bridge.js.map +1 -1
- package/dist/server/rpc-executor.js +2 -4
- package/dist/server/rpc-executor.js.map +1 -1
- package/dist/server/server-entry.js +3 -0
- package/dist/server/server-entry.js.map +1 -1
- package/dist/server/server.d.ts +9 -8
- package/dist/server/server.js +364 -541
- package/dist/server/server.js.map +1 -1
- package/dist/server/state.d.ts +16 -29
- package/dist/server/state.js +105 -319
- package/dist/server/state.js.map +1 -1
- package/dist/server/view.d.ts +4 -5
- package/dist/server/view.js +51 -51
- package/dist/server/view.js.map +1 -1
- package/dist/server/workflow-runner-entry.d.ts +1 -1
- package/dist/server/workflow-runner-entry.js +1 -49
- package/dist/server/workflow-runner-entry.js.map +1 -1
- package/dist/server/workflow-runner-protocol.d.ts +2 -7
- package/dist/server/workflow-runner-protocol.js +5 -10
- package/dist/server/workflow-runner-protocol.js.map +1 -1
- package/dist/server/workflow-runner-store.d.ts +5 -6
- package/dist/server/workflow-runner-store.js +7 -14
- package/dist/server/workflow-runner-store.js.map +1 -1
- package/dist/state/attempt-time.d.ts +21 -0
- package/dist/state/attempt-time.js +95 -0
- package/dist/state/attempt-time.js.map +1 -0
- package/dist/state/json.d.ts +2 -1
- package/dist/state/json.js.map +1 -1
- package/dist/state/project-store.d.ts +39 -0
- package/dist/state/project-store.js +154 -0
- package/dist/state/project-store.js.map +1 -0
- package/dist/state/prune.js +0 -7
- package/dist/state/prune.js.map +1 -1
- package/dist/state/schema.js +23 -23
- package/dist/state/workflow-messages.d.ts +1 -1
- package/dist/state/workflow-messages.js +3 -1
- package/dist/state/workflow-messages.js.map +1 -1
- package/dist/viewer/backup.js +5 -0
- package/dist/viewer/backup.js.map +1 -1
- package/dist/workflows/diagnostics.d.ts +8 -0
- package/dist/workflows/diagnostics.js +61 -0
- package/dist/workflows/diagnostics.js.map +1 -0
- package/dist/workflows/engine.d.ts +2 -15
- package/dist/workflows/engine.js +125 -245
- package/dist/workflows/engine.js.map +1 -1
- package/dist/workflows/human-decision.d.ts +3 -7
- package/dist/workflows/human-decision.js +2 -56
- package/dist/workflows/human-decision.js.map +1 -1
- package/dist/workflows/index.d.ts +2 -1
- package/dist/workflows/index.js +1 -0
- package/dist/workflows/index.js.map +1 -1
- package/dist/workflows/queue.d.ts +267 -0
- package/dist/workflows/queue.js +1248 -0
- package/dist/workflows/queue.js.map +1 -0
- package/dist/workflows/requests.d.ts +47 -0
- package/dist/workflows/requests.js +158 -0
- package/dist/workflows/requests.js.map +1 -0
- package/dist/workflows/schema.js +2 -4
- package/dist/workflows/schema.js.map +1 -1
- package/dist/workflows/store.d.ts +11 -16
- package/dist/workflows/store.js +174 -169
- package/dist/workflows/store.js.map +1 -1
- package/dist/workflows/tool-input.d.ts +6 -9
- package/dist/workflows/tool-input.js +15 -12
- package/dist/workflows/tool-input.js.map +1 -1
- package/dist/workflows/transitions.d.ts +38 -0
- package/dist/workflows/transitions.js +276 -0
- package/dist/workflows/transitions.js.map +1 -0
- package/dist/workflows/types.d.ts +9 -42
- package/dist/workflows/workflow-message-content.d.ts +7 -1
- package/dist/workflows/workflow-message-content.js +22 -4
- package/dist/workflows/workflow-message-content.js.map +1 -1
- package/docs/2026-08-25-workflow-follow-ups.md +5 -5
- package/docs/2026-09-02-unify-workflow-messages-plan.md +2 -0
- package/docs/2026-09-04-workflow-run-state-plan.md +2 -0
- package/docs/2026-09-06-durable-execution-plan.md +176 -0
- package/docs/DEFERRED_TURNS.md +84 -105
- package/docs/HUMAN_DECISIONS.md +17 -19
- package/docs/HUMAN_DECISION_PRESENTATIONS.md +1 -1
- package/docs/SQLITE_STATE.md +68 -29
- package/docs/WORKFLOW_SERVER.md +21 -10
- package/docs/WORKFLOW_STEP_MESSAGES.md +72 -54
- package/docs/plans/2026-08-04-controller-runtime-plan.md +2 -0
- package/docs/plans/2026-08-21-deferred-turn-intents-plan.md +2 -0
- package/docs/plans/2026-08-27-workflow-terminal-restart-plan.md +2 -0
- package/docs/workflows.md +94 -45
- package/examples/workflows/autoresearch.workflow.ts +0 -2
- package/examples/workflows/branch.workflow.ts +0 -4
- package/examples/workflows/echo.workflow.ts +0 -2
- package/examples/workflows/live-settings.workflow.ts +0 -2
- package/examples/workflows/two-turn.workflow.ts +0 -2
- package/herdr-plugin.toml +1 -1
- package/package.json +1 -1
- package/protocol/fixtures/client-v1.json +1 -1
- package/skills/pi-workflows/SKILL.md +8 -7
- package/src/builtins/autoimplement.workflow.ts +31 -10
- package/src/client/client.ts +3 -1
- package/src/client/protocol.ts +21 -1
- package/src/client/view.ts +9 -5
- package/src/extension/index.ts +117 -189
- package/src/extension/recorder.ts +2 -2
- package/src/extension/step-message.ts +4 -4
- package/src/extension/workflow-message-coordinator.ts +78 -50
- package/src/resource-managers/index.ts +1 -9
- package/src/resource-managers/sqlite.ts +330 -2655
- package/src/resource-managers/types.ts +2 -3
- package/src/server/resource-runner-entry.ts +2 -7
- package/src/server/rpc-bridge.ts +1 -1
- package/src/server/rpc-executor.ts +4 -9
- package/src/server/server-entry.ts +3 -0
- package/src/server/server.ts +416 -641
- package/src/server/state.ts +122 -466
- package/src/server/view.ts +56 -60
- package/src/server/workflow-runner-entry.ts +2 -55
- package/src/server/workflow-runner-protocol.ts +5 -15
- package/src/server/workflow-runner-store.ts +12 -27
- package/src/state/attempt-time.ts +122 -0
- package/src/state/json.ts +2 -1
- package/src/state/project-store.ts +218 -0
- package/src/state/prune.ts +0 -13
- package/src/state/schema.ts +23 -23
- package/src/state/workflow-messages.ts +4 -2
- package/src/viewer/backup.ts +7 -0
- package/src/workflows/diagnostics.ts +78 -0
- package/src/workflows/engine.ts +133 -291
- package/src/workflows/human-decision.ts +3 -81
- package/src/workflows/index.ts +8 -2
- package/src/workflows/queue.ts +2091 -0
- package/src/workflows/requests.ts +283 -0
- package/src/workflows/schema.ts +2 -6
- package/src/workflows/store.ts +223 -231
- package/src/workflows/tool-input.ts +20 -12
- package/src/workflows/transitions.ts +330 -0
- package/src/workflows/types.ts +9 -46
- package/src/workflows/workflow-message-content.ts +28 -4
- package/dist/resource-managers/runtime.d.ts +0 -59
- package/dist/resource-managers/runtime.js +0 -423
- package/dist/resource-managers/runtime.js.map +0 -1
- package/src/resource-managers/runtime.ts +0 -576
package/docs/HUMAN_DECISIONS.md
CHANGED
|
@@ -18,7 +18,7 @@ A workflow author can:
|
|
|
18
18
|
- collect exact text with a choice such as `replan`;
|
|
19
19
|
- address a logical audience instead of a Telegram chat or Pi session;
|
|
20
20
|
- reuse a standard plan approval workflow; and
|
|
21
|
-
- rely on one accepted answer and one
|
|
21
|
+
- rely on one accepted answer and one resumed attempt after a crash or concurrent reply.
|
|
22
22
|
|
|
23
23
|
The feature uses the existing checkpoint execution primitive. It does not add another engine node type.
|
|
24
24
|
|
|
@@ -124,7 +124,7 @@ When the engine reaches the node, it:
|
|
|
124
124
|
4. asks the configured channels to deliver it; and
|
|
125
125
|
5. parks the run in `waiting` state.
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
A valid answer completes the exact checkpoint attempt in the same run. The original workflow input stays unchanged. The answer becomes that node's output. Ordinary checkpoints also complete in place, but use the normal `answer` action. A protected decision accepts only the verified human path or its declared timeout policy.
|
|
128
128
|
|
|
129
129
|
## Request and response contracts
|
|
130
130
|
|
|
@@ -265,15 +265,15 @@ Human decisions use the canonical [SQLite state](SQLITE_STATE.md) database:
|
|
|
265
265
|
- `human_decisions` stores each immutable request;
|
|
266
266
|
- `human_decision_submissions` records human, policy, channel, and control candidates;
|
|
267
267
|
- `human_decision_resolutions` stores the one accepted-or-cancelled winner;
|
|
268
|
-
- `
|
|
269
|
-
- `effects` and `effect_attempts` record
|
|
268
|
+
- `interactive_requests` and `interactive_submissions` bind the accepted resolution to the exact node attempt;
|
|
269
|
+
- `effects` and `effect_attempts` record run settlement, external delivery, and external settlement work; and
|
|
270
270
|
- `channels`, `channel_cursors`, and `channel_messages` store channel identity, polling position, and decision delivery or settlement receipts.
|
|
271
271
|
|
|
272
272
|
A valid human answer, eligible timeout policy, explicit cancellation, or no-default expiry competes for the same resolution primary key. The winning transaction records the immutable resolution, audit event, and required effects together. A retry adopts the existing matching result. A conflicting or late answer receives the durable winner.
|
|
273
273
|
|
|
274
|
-
A deadline with a validated default response is timeout-policy acceptance. It cannot become expiry cancellation. No-default expiry can cancel. Automatic policy and
|
|
274
|
+
A deadline with a validated default response is timeout-policy acceptance. It cannot become expiry cancellation. No-default expiry can cancel. Automatic policy and execution require the current owner's token and lease generation. A verified channel can submit a human candidate without gaining run ownership.
|
|
275
275
|
|
|
276
|
-
The
|
|
276
|
+
The scheduler resumes the same run and exact request. Accepted resolution and redacted receipt records carry the provenance, decision ID, request digest, gate node ID, choice, acceptance time, and answer digest. Human actor, channel, event, and idempotency details remain private and do not enter model-visible status output.
|
|
277
277
|
|
|
278
278
|
## Planning workflow composition
|
|
279
279
|
|
|
@@ -312,7 +312,7 @@ Recovery follows these rules:
|
|
|
312
312
|
- ambiguous Telegram sends are not retried automatically;
|
|
313
313
|
- duplicate channel updates are harmless;
|
|
314
314
|
- stale responses are rejected;
|
|
315
|
-
- one human or timeout response
|
|
315
|
+
- one human or timeout response completes one exact checkpoint attempt;
|
|
316
316
|
- the winning human answer or timeout policy settles or cancels the pending Pi decision workflow message;
|
|
317
317
|
- confirmed channel settlement is adopted without another remote call;
|
|
318
318
|
- failed channel settlement has a bounded retry count and cannot create an unbounded record loop; and
|
|
@@ -320,20 +320,18 @@ Recovery follows these rules:
|
|
|
320
320
|
|
|
321
321
|
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.
|
|
322
322
|
|
|
323
|
-
Direct answer handling and recovery can
|
|
324
|
-
|
|
325
|
-
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.
|
|
323
|
+
Direct answer handling and recovery can observe the same accepted decision. Both use the exact saved request and the common scheduler. Response acceptance makes the original run eligible; it does not create or directly launch another run. One lease generation owns execution. An identical response retry adopts its receipt, while a conflicting payload or wrong request kind is rejected before queue changes. Source verification and generation fencing remain required after interruption.
|
|
326
324
|
|
|
327
325
|
## Compatibility
|
|
328
326
|
|
|
329
|
-
This alpha
|
|
327
|
+
This alpha contract changes in place. Incompatible state remains untouched and fails with a backup-and-reset instruction. There is no compatibility reader, migration, dual path, or new schema generation. Viewers show the decision deadline and declared automatic action, while keeping the canonical subject separate. Private channel configuration and transport identifiers remain hidden.
|
|
330
328
|
|
|
331
|
-
The engine remains independent from Pi and Telegram. Core code owns decision contracts and validation. The server owns durable acceptance,
|
|
329
|
+
The engine remains independent from Pi and Telegram. Core code owns decision contracts and validation. The server owns durable acceptance, scheduling, workflow messages, and channel-child supervision. The Pi extension owns documented session presentation and controls. The Telegram adapter child owns Bot API translation. Workflow definitions own only the question, choices, audience, and routes.
|
|
332
330
|
|
|
333
331
|
## Contract impact
|
|
334
332
|
|
|
335
333
|
- **Session state:** Pi records normal workflow messages and interactive decision results.
|
|
336
|
-
- **Other persistent data:** decision requests and resolutions can carry a deadline, automatic response, and resolution provenance in the existing decision store.
|
|
334
|
+
- **Other persistent data:** decision requests and resolutions can carry a deadline, automatic response, and resolution provenance in the existing decision store. Same-run resumption uses the existing request, queue, source, binding, lease, event, and effect records. External channel attempts use the shared effect records, and channel delivery and settlement records remain separate feature evidence.
|
|
337
335
|
- **Pi internals:** none.
|
|
338
336
|
- **Public Pi API:** documented extension lifecycle, message, command, session, and status APIs only.
|
|
339
337
|
- **Public pi-workflows API:** typed human choices, `humanDecision().onTimeout`, `humanDecisionEdge()`, channel profile configuration, the plan approval policy, the shared plan-change workflow, and the additive queue prepare-or-adopt operation.
|
|
@@ -345,7 +343,7 @@ The implementation must test:
|
|
|
345
343
|
- compile-time exhaustive choice routing;
|
|
346
344
|
- choices with no input and choices with exact text input;
|
|
347
345
|
- runtime choice and input validation;
|
|
348
|
-
-
|
|
346
|
+
- ordinary and protected checkpoints completing in the original run;
|
|
349
347
|
- model-tool answer rejection;
|
|
350
348
|
- Pi decision workflow messages, branch adoption, branch-specific decision messages, and verified answers;
|
|
351
349
|
- supervised channel-child protocol fencing and restart recovery;
|
|
@@ -354,14 +352,14 @@ The implementation must test:
|
|
|
354
352
|
- stale request digests;
|
|
355
353
|
- concurrent Pi and Telegram answers;
|
|
356
354
|
- a direct verified answer racing recovery for the same accepted decision;
|
|
357
|
-
- one claim generation
|
|
358
|
-
-
|
|
359
|
-
-
|
|
355
|
+
- one authoritative claim generation and no extra run after a decision;
|
|
356
|
+
- accepted-response adoption without new model work or copied state;
|
|
357
|
+
- request identity and response-kind mismatches rejected before domain mutation;
|
|
360
358
|
- identical and conflicting retries;
|
|
361
|
-
- crashes before and after answer acceptance and
|
|
359
|
+
- crashes before and after answer acceptance and same-run resumption;
|
|
362
360
|
- ambiguous Telegram sends;
|
|
363
361
|
- one supervised long-poll adapter per profile and server-restart recovery;
|
|
364
362
|
- decision cancellation and expiry;
|
|
365
363
|
- included `plan-approval` routes and bounded replan loops;
|
|
366
364
|
- viewer redaction; and
|
|
367
|
-
- real Pi execution without real Telegram credentials or network calls, duplicate-start failures, revision conflicts, or a stranded
|
|
365
|
+
- real Pi execution without real Telegram credentials or network calls, duplicate-start failures, revision conflicts, or a stranded resumed run.
|
|
@@ -279,7 +279,7 @@ presentation. Renderers treat all text as untrusted and inert.
|
|
|
279
279
|
- Ambiguous Telegram delivery remains unknown and is not retried blindly.
|
|
280
280
|
- A channel failure does not choose a default answer.
|
|
281
281
|
- Rules for the first valid answer and stale answers remain unchanged, as do
|
|
282
|
-
cancellation and settlement rules together with
|
|
282
|
+
cancellation and settlement rules together with exact same-run response adoption.
|
|
283
283
|
|
|
284
284
|
## Verification
|
|
285
285
|
|
package/docs/SQLITE_STATE.md
CHANGED
|
@@ -16,6 +16,8 @@ The database includes the [incremental and virtualized viewer design](plans/2026
|
|
|
16
16
|
|
|
17
17
|
`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. `run_view_content` stores generated reference bytes under the exact run ID, content digest, and media type. It is separate from general state blobs, and content reads require all three identities. 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.
|
|
18
18
|
|
|
19
|
+
Run views expose the presentation cursor as `revision` and the execution resource revision as `runRevision`. Commands such as restart use `runRevision`. Conversation capture can advance the presentation cursor without changing execution, so the two values must not be substituted for each other.
|
|
20
|
+
|
|
19
21
|
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.
|
|
20
22
|
|
|
21
23
|
`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.
|
|
@@ -30,7 +32,7 @@ The database stores:
|
|
|
30
32
|
- global server epochs, command receipts, runner epochs, and runner messages
|
|
31
33
|
- durable origin-session interaction requests and submissions
|
|
32
34
|
- captured Pi session entries and events
|
|
33
|
-
- run and resource manager queues, claims,
|
|
35
|
+
- run and resource manager queues, claims, and declared retries
|
|
34
36
|
- human-decision requests, submissions, resolutions, and cancellations
|
|
35
37
|
- managed resources, finalizers, effects, and child workflows
|
|
36
38
|
- workflow messages that Pi must add to origin conversations
|
|
@@ -112,31 +114,31 @@ Telegram delivery and settlement use these shared effect records. The server rec
|
|
|
112
114
|
|
|
113
115
|
The shared records do not replace domain schemas. The following `STRICT` tables keep the state explicit:
|
|
114
116
|
|
|
115
|
-
| Area | Tables
|
|
116
|
-
| ------------------- |
|
|
117
|
-
| Schema and projects | `schema_meta`, `projects`
|
|
118
|
-
| Content | `blobs`, `run_view_content`
|
|
119
|
-
| Shared lifecycle | `resources`, `leases`, `events`, `workflow_host_state`
|
|
120
|
-
| Server protocol | `host_commands`, `run_workers`, `worker_messages`, `interactive_requests`, `interactive_submissions`
|
|
121
|
-
| Workflows | `workflow_definitions`, `runs`, `run_sources`, `run_steps`, `run_bindings`, `run_queue`, `node_attempts`, `workflow_updates` |
|
|
122
|
-
| Live settings | `workflow_settings`, `workflow_setting_changes`
|
|
123
|
-
| Post-run follow-ups | `workflow_follow_ups`
|
|
124
|
-
| Session capture | `session_segments`, `session_entries`, `attempt_entries`, `session_events`
|
|
125
|
-
| Human decisions | `human_decisions`, `human_decision_resolutions`, `human_decision_submissions
|
|
126
|
-
| Managed resources | `controller_resources`, `controller_finalizers`, `controller_queue`, `controller_workflows`
|
|
127
|
-
| Effects | `effects`, `effect_attempts`
|
|
128
|
-
| Pi messages | `workflow_messages`, `workflow_turns`
|
|
129
|
-
| Channels | `channels`, `channel_cursors`, `channel_messages`
|
|
117
|
+
| Area | Tables |
|
|
118
|
+
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
119
|
+
| Schema and projects | `schema_meta`, `projects` |
|
|
120
|
+
| Content | `blobs`, `run_view_content` |
|
|
121
|
+
| Shared lifecycle | `resources`, `leases`, `events`, `workflow_host_state` |
|
|
122
|
+
| Server protocol | `host_commands`, `run_workers`, `worker_messages`, `interactive_requests`, `interactive_submissions` |
|
|
123
|
+
| Workflows | `workflow_definitions`, `runs`, `run_sources`, `run_steps`, `run_bindings`, `run_queue`, `node_attempts`, `attempt_active_intervals`, `workflow_updates` |
|
|
124
|
+
| Live settings | `workflow_settings`, `workflow_setting_changes` |
|
|
125
|
+
| Post-run follow-ups | `workflow_follow_ups` |
|
|
126
|
+
| Session capture | `session_segments`, `session_entries`, `attempt_entries`, `session_events` |
|
|
127
|
+
| Human decisions | `human_decisions`, `human_decision_resolutions`, `human_decision_submissions` |
|
|
128
|
+
| Managed resources | `controller_resources`, `controller_finalizers`, `controller_queue`, `controller_workflows` |
|
|
129
|
+
| Effects | `effects`, `effect_attempts` |
|
|
130
|
+
| Pi messages | `workflow_messages`, `workflow_turns` |
|
|
131
|
+
| Channels | `channels`, `channel_cursors`, `channel_messages` |
|
|
130
132
|
|
|
131
133
|
The `host_*`, `run_workers`, `worker_*`, and `controller_*` names remain version-1 internal SQLite identifiers. The `host` and `controller` actor and owner values and the `~/.pi/agent/workflows/host/` state directory also remain internal identifiers. Public APIs and documentation call these components the workflow server, workflow runner, resource manager, resource runner, and managed resource. The alpha hard cut adds no alias or second storage path.
|
|
132
134
|
|
|
133
|
-
`workflow_messages` is the only table that owns adding workflow content to Pi. It stores the target session, message kind, source record, content digest, session order, `pending`, `sent`, or `cancelled` state, confirmed Pi entry ID, and creation and update times. The table stores no sender, send lease, `sending` state, or separate sent time. Active-branch evidence changes `pending` or `cancelled` to `sent`. Initial
|
|
135
|
+
`workflow_messages` is the only table that owns adding workflow content to Pi. It stores the target session, message kind, source record, content digest, session order, `pending`, `sent`, or `cancelled` state, confirmed Pi entry ID, and creation and update times. The table stores no sender, send lease, `sending` state, or separate sent time. Active-branch evidence changes `pending` or `cancelled` to `sent`. Initial and resumed prompts are all `step` messages; their custom details contain the reason. Interactive requests, decisions, terminal runs, notifications, follow-ups, and settings keep their own domain state.
|
|
134
136
|
|
|
135
137
|
`workflow_turns` stores the server-approved ownership of one Pi model turn. Each row names the exact workflow message, run, session, and turn ID. A partial unique index permits only one open turn for a message. The server checks for an exact saved turn or another open turn before insertion, so a normal conflict returns a controlled protocol error instead of a raw SQLite error. Terminalization ends every open turn for that run as `lost` in the same transaction. It cancels pending step and decision messages, plus follow-ups when the run did not complete successfully. Committed notifications remain eligible. Matching late reports adopt the saved result, while conflicting identities remain errors.
|
|
136
138
|
|
|
137
139
|
`channels` stores configured channel resource identities. `channel_cursors` stores the last accepted external polling position. `channel_messages` stores immutable decision delivery and settlement records for audit and duplicate evidence. External application state and Telegram message references belong to `effects` and `effect_attempts`.
|
|
138
140
|
|
|
139
|
-
Foreign keys join projects, runs, attempts, decisions, managed resources, effects, and channel records. Partial unique indexes enforce one active node attempt per run, one pending step message per
|
|
141
|
+
Foreign keys join projects, runs, attempts, decisions, managed resources, effects, and channel records. Partial unique indexes enforce one active node attempt per run, one pending step message per request, one nonterminal interactive run per Pi session, one decision winner, and one deterministic effect key. A waiting or paused run keeps its session reservation. Checkpoint responses complete nodes in that same run; they do not reserve child runs.
|
|
140
142
|
|
|
141
143
|
### ServerBacked commands and interactions
|
|
142
144
|
|
|
@@ -150,7 +152,7 @@ conflict.
|
|
|
150
152
|
process identity and terminal outcome. `worker_messages` deduplicates accepted
|
|
151
153
|
state-changing child messages.
|
|
152
154
|
|
|
153
|
-
`interactive_requests` owns the durable request contract and workflow state for origin-session work. It stores the run, node attempt, target session, contract, request status, accepted submission,
|
|
155
|
+
`interactive_requests` owns the durable request contract and workflow state for origin-session work. It stores the run, node attempt, target session, contract, request status, accepted submission, and revision. Pause is stored once on the run and derived for its one pending interaction. `interactive_submissions` stores the idempotency key, payload, outcome, and receipt. It stores no Pi presentation claim or Pi session entry. `workflow_messages` owns those facts, and the extension reports the active Pi branch after reload.
|
|
154
156
|
|
|
155
157
|
## Content-addressed values
|
|
156
158
|
|
|
@@ -158,19 +160,56 @@ state-changing child messages.
|
|
|
158
160
|
|
|
159
161
|
Insertion verifies the digest, media type, byte length, and exact bytes. Repeated content adopts the existing row. This replaces separate artifact files while keeping outputs, errors, settled Pi entries, and rendered channel text deduplicated. Automatic retention and explicit prune remove unreferenced blobs after they delete safe old run trees. They retain each blob referenced by a database foreign key or active runner transfer.
|
|
160
162
|
|
|
161
|
-
Runs do not store a nested `WorkflowRunState` blob. `runs` stores run-level facts and hashes for independent values. `run_sources` stores source identity without source JSON blobs. `node_attempts` stores structured workflow outputs and small execution receipts. `session_entries` is the only stored copy of each settled Pi entry. `attempt_entries` links an attempt to its prompt, response, first, and last Pi entries. `run_steps` stores ordered attempt membership
|
|
163
|
+
Runs do not store a nested `WorkflowRunState` blob. `runs` stores run-level facts and hashes for independent values. `run_sources` stores source identity without source JSON blobs. `node_attempts` stores structured workflow outputs and small execution receipts. `session_entries` is the only stored copy of each settled Pi entry. `attempt_entries` links an attempt to its prompt, response, first, and last Pi entries. `run_steps` stores ordered attempt membership. Each completed checkpoint keeps its own accepted output.
|
|
162
164
|
|
|
163
|
-
Readers derive `steps`, `outputs`, `results`,
|
|
165
|
+
Readers derive `steps`, `outputs`, `results`, current-node fields, waiting state, source objects, and accepted decision receipts from these rows. Compact trace events do not copy prompts, node outputs, run inputs, final outputs, action receipts, or assistant receipts.
|
|
164
166
|
|
|
165
167
|
The run store reads each independent value through its declared media type. Input and final output use JSON readers. Run errors and presentation instructions use text readers. Terminal-message construction uses one typed terminal-data result instead of guessing the blob type. A missing or wrong media type fails presentation after the terminal state commits; it cannot roll back that state.
|
|
166
168
|
|
|
169
|
+
### State verification
|
|
170
|
+
|
|
171
|
+
`state status` reports invariant violations with the affected run IDs. `state verify`
|
|
172
|
+
and inactive-backup verification check the same facts after SQLite integrity and
|
|
173
|
+
foreign-key checks. They detect terminal queue mismatches, waiting runs without
|
|
174
|
+
responses, pending requests on inactive attempts, missing accepted submissions,
|
|
175
|
+
invalid active clocks, and conflicting Pi turns. Verification does not repair
|
|
176
|
+
state or create replacement work.
|
|
177
|
+
|
|
178
|
+
Queued, starting, running, and parked queue phases can coexist with live execution
|
|
179
|
+
states during admission and response validation. They are not contradictions by
|
|
180
|
+
themselves. A pending settlement effect also explains a terminal result whose queue
|
|
181
|
+
has not yet settled. Expired claims remain recovery facts, not proof of completed
|
|
182
|
+
work.
|
|
183
|
+
|
|
184
|
+
### Active execution time
|
|
185
|
+
|
|
186
|
+
`node_attempts.started_at` is historical data and never changes. `timeout_ms`
|
|
187
|
+
stores the resolved active-time budget: SQL `NULL` means not yet configured,
|
|
188
|
+
zero means explicitly unlimited, and a positive value is the budget in milliseconds.
|
|
189
|
+
The public contract uses `null` for an unlimited timeout.
|
|
190
|
+
|
|
191
|
+
`attempt_active_intervals` records numbered active intervals in the same database.
|
|
192
|
+
Only one interval can be open for an attempt. Each interval keeps its start,
|
|
193
|
+
last observation, end, and measured elapsed time. The host measures duration with
|
|
194
|
+
a monotonic clock and saves samples during normal polling. Wall-clock changes
|
|
195
|
+
cannot spend or restore the active budget. Pause, disconnect, and settlement close
|
|
196
|
+
the interval. Reconnect opens another interval only for an unpaused, active model
|
|
197
|
+
turn. Duplicate starts and overlapping inactive causes cannot count time twice.
|
|
198
|
+
|
|
199
|
+
After a crash, recovery closes an open interval at its last durable observation.
|
|
200
|
+
It does not charge the unobserved gap or server downtime. At most the time since
|
|
201
|
+
the last sample is uncounted. Human decision expiry remains an absolute wall-clock
|
|
202
|
+
deadline. Step start and finish timestamps remain wall-clock history, separate
|
|
203
|
+
from the active-time budget. Interval rows follow their attempt through existing
|
|
204
|
+
foreign-key retention and backup rules.
|
|
205
|
+
|
|
167
206
|
### Assistant-message attempts
|
|
168
207
|
|
|
169
208
|
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.
|
|
170
209
|
|
|
171
210
|
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.
|
|
172
211
|
|
|
173
|
-
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.
|
|
212
|
+
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. A submitted agent request also retains its exact attempt while waiting, validating, or recovering an accepted receipt. A declared execution retry creates a new attempt; transport recovery does not.
|
|
174
213
|
|
|
175
214
|
## Write contract
|
|
176
215
|
|
|
@@ -202,7 +241,7 @@ A TypeScript write permit carries the expected facts between layers. It is not a
|
|
|
202
241
|
|
|
203
242
|
Reading or finding a row never gives write authority.
|
|
204
243
|
|
|
205
|
-
- A run owner may advance the run, apply automatic decision policy,
|
|
244
|
+
- A run owner may advance the exact run, apply its declared automatic decision policy, and settle its queue work.
|
|
206
245
|
- A resource manager claim owner may update resource manager status, reserve effects, and start child workflows for that resource.
|
|
207
246
|
- A verified human channel actor may submit one answer candidate for the named decision. It does not gain run ownership.
|
|
208
247
|
- The server-owned channel adapter path may update only its channel cursor, decision delivery and settlement records, and exact managed effects.
|
|
@@ -221,18 +260,18 @@ A deadline with a validated default response is timeout-policy acceptance. It ca
|
|
|
221
260
|
|
|
222
261
|
Late or repeated commands return or adopt the durable winner. They do not overwrite it.
|
|
223
262
|
|
|
224
|
-
The same rule applies to run terminal outcomes,
|
|
263
|
+
The same rule applies to run terminal outcomes, exact-request acceptance, queue settlement, resource manager effects, retry scheduling, channel settlement, and workflow-turn reports through their domain constraints and expected revisions. A matching turn report adopts the saved ownership result. A different report for the same turn ID remains a conflict.
|
|
225
264
|
|
|
226
265
|
## Read contract
|
|
227
266
|
|
|
228
267
|
Durable status is a pure projection of domain rows, immutable facts, current leases, effect results, and exact workflow-turn start and end reports. The server uses these facts to produce one live run view. An open workflow turn can change display status only. It cannot change workflow authority. Every renderer consumes the server-produced display status and allowed controls without running another status reducer.
|
|
229
268
|
|
|
230
|
-
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
|
|
269
|
+
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 resumes in the same run and keeps the same settings resources.
|
|
231
270
|
|
|
232
|
-
`workflow_follow_ups` records source acceptance order, removal, and cancellation. The source and message stay attached to the
|
|
271
|
+
`workflow_follow_ups` records source acceptance order, removal, and cancellation. The source and message stay attached to the run that accepted them. The server uses that run's outcome; an explicit restart does not retarget the prompt. `workflow_messages` owns message state and Pi entry evidence. Failure, timeout, and cancellation cancel unsent follow-up messages.
|
|
233
272
|
|
|
234
273
|
- A terminal run fact overrides stale message state and has no open workflow turn.
|
|
235
|
-
- An accepted decision
|
|
274
|
+
- An accepted decision stays accepted while the scheduler waits for execution capacity.
|
|
236
275
|
- A cancelled decision is cancelled even if parent cleanup is still pending.
|
|
237
276
|
- A stale owner is not shown as current.
|
|
238
277
|
- An ambiguous external effect is shown as unresolved.
|
|
@@ -249,9 +288,9 @@ This contract is for local storage on one machine. It does not claim distributed
|
|
|
249
288
|
|
|
250
289
|
## Automatic retention
|
|
251
290
|
|
|
252
|
-
The server keeps terminal root-run trees for 30 days from `finished_at`. A tree is eligible only when every restart
|
|
291
|
+
The server keeps terminal root-run trees for 30 days from `finished_at`. A tree is eligible only when every restart descendant is terminal, older than the cutoff, free of protected work, and free of references from outside the tree.
|
|
253
292
|
|
|
254
|
-
Automatic cleanup keeps a tree when it has a waiting or parked run, a live queue row, a pending workflow message, an open workflow turn, a pending interaction or human decision, a recording session segment, a queued follow-up, an active lease, an unsettled effect, controller ownership, an active runner content hash, a resumable checkpoint, an undelivered terminal result, or a
|
|
293
|
+
Automatic cleanup keeps a tree when it has a waiting or parked run, a live queue row, a pending workflow message, an open workflow turn, a pending interaction or human decision, a recording session segment, a queued follow-up, an active lease, an unsettled effect, controller ownership, an active runner content hash, a resumable checkpoint, an undelivered terminal result, or a run or step reference from outside the tree. Unknown or conflicting ownership also blocks deletion.
|
|
255
294
|
|
|
256
295
|
The server requests cleanup after startup recovery and after workflow runners exit. It also schedules the next daily check after a completed sweep. Overlapping requests use one in-process task. Cleanup starts only while there is no active or pending workflow runner, resource-manager runner, state-maintenance command, or shutdown. One server process completes no more than one sweep in 24 hours. A due sweep that finds work active or stops between trees remains due. The next idle lifecycle trigger or a five-minute idle retry continues it.
|
|
257
296
|
|
package/docs/WORKFLOW_SERVER.md
CHANGED
|
@@ -115,6 +115,16 @@ Claim rejection uses `ClaimLostError` with one internal reason:
|
|
|
115
115
|
|
|
116
116
|
Logs may show the run ID, generation, and reason. They must not show a raw token or token hash.
|
|
117
117
|
|
|
118
|
+
## Worker scheduling
|
|
119
|
+
|
|
120
|
+
`WorkflowRunQueueStore` in `src/workflows/queue.ts` owns run reservations, queue state, and execution claims. `SqliteResourceManagerStore` owns managed resources and reconcile state, not workflow scheduling. The host is the only reconciliation runtime; the separate `ResourceManagerRuntime` API has been removed. Reconcile results and failure requeues commit atomically, and a worker that loses its claim cannot write a failure or start a retry. They share the existing SQLite connection and revision helpers; neither introduces another database.
|
|
121
|
+
|
|
122
|
+
One scheduler admits workflow runners and resource-manager reconciles. Start and restart reserve a queued run; resume makes existing work eligible. Accepted responses, validation candidates, and expired interactive deadlines use the same admission path. Requests remain durable while capacity is full.
|
|
123
|
+
|
|
124
|
+
The default capacity is four execution workers. Set `PI_WORKFLOWS_MAX_WORKERS` to a positive integer before starting the host to change it. Embedded test hosts can use `WorkflowServer({ maxWorkers })`. Capacity includes pending launches and live workers. The scheduler alternates workflow and resource-manager admissions when both have work. Claim renewal, cancellation, and cleanup do not wait for an execution slot.
|
|
125
|
+
|
|
126
|
+
An interactive run holds its origin-session reservation while queued, running, waiting, or paused. Independent headless runs do not reserve a Pi session. Only terminal completion or explicit cancellation releases an interactive reservation.
|
|
127
|
+
|
|
118
128
|
## Run lifecycle
|
|
119
129
|
|
|
120
130
|
The run and queue projections follow these states:
|
|
@@ -259,15 +269,16 @@ Each history page has both an item limit and an encoded byte budget. Oversized v
|
|
|
259
269
|
|
|
260
270
|
The closed `display.status` set is `queued`, `running`, `waiting`, `paused`, `completed`, `failed`, `timed_out`, `cancelled`, and `ambiguous`.
|
|
261
271
|
|
|
262
|
-
The server
|
|
272
|
+
The server keeps execution status separate from worker and Pi activity:
|
|
273
|
+
|
|
274
|
+
1. A durable terminal result keeps its terminal label, including during reporting or cleanup. An unresolved external effect still exposes a review action.
|
|
275
|
+
2. A nonterminal run with an ambiguous external effect is `ambiguous`.
|
|
276
|
+
3. A durable pause is `paused`, even while its worker or Pi turn stops.
|
|
277
|
+
4. A pending request is `waiting`. Its kind determines the response action: `submit` and `update` for an agent, `answer` for an ordinary checkpoint, `human-answer` for a protected decision, and no tool completion action for a visible-response request.
|
|
278
|
+
5. Otherwise, active worker or Pi execution is `running`.
|
|
279
|
+
6. Parked resumable work or admitted work that has not started is `queued`.
|
|
263
280
|
|
|
264
|
-
|
|
265
|
-
2. A live supervised runner or an exact active origin-session workflow turn is `running`.
|
|
266
|
-
3. A durable terminal result keeps its terminal label after its presentation turn ends.
|
|
267
|
-
4. A durable pause is `paused` after its active Pi turn ends.
|
|
268
|
-
5. A pending interaction, decision, or presentation with no exact active turn is `waiting`.
|
|
269
|
-
6. Parked resumable work with no pending interaction is `queued`.
|
|
270
|
-
7. Admitted work that has not started is `queued`.
|
|
281
|
+
`display.activity` reports the supervised worker or exact Pi turn independently. Waiting alone never permits an answer. Command handlers check the exact request again before they change state.
|
|
271
282
|
|
|
272
283
|
Server connection failure is the client condition `unavailable`, not a `display.status` value. `paused` is never inferred from a parked queue, pending interaction, stale cursor, or missing activity report.
|
|
273
284
|
|
|
@@ -383,7 +394,7 @@ Active-branch absence is usable only when the branch has no matching ID, Pi is i
|
|
|
383
394
|
|
|
384
395
|
The extension subscribes to the active origin-session live run view and projects it into Pi's documented widget and status APIs. It never opens SQLite, runs workflow code, or derives a display status. `Shift+Up` and `Shift+Down` scroll the widget. When Herdr is available, the widget also shows `Ctrl+Shift+R piw`, and `/piw` remains the command fallback. Both actions open or focus the exact run from the same view.
|
|
385
396
|
|
|
386
|
-
A tool update or submission goes to the server
|
|
397
|
+
A tool update or submission goes to the server with an exact `requestId`, the tool-call idempotency key, and the current origin-session coordinator authority. The server resolves the immutable node and attempt from that request. It checks session ownership and request kind before receipt lookup or mutation. An identical submission can adopt its saved result after settlement. A new submission records a provisional `validating` candidate. It then schedules a supervised workflow child. Only that child loads workflow code and runs the node's `validate` function. The child reports `interaction.accepted` or `interaction.rejected` to the server. The server settles the request only after acceptance. A rejected payload leaves the same request pending and returns the stored actionable error to the model. If the child stops before it reports a result, the server rejects the provisional submission and leaves the request ready for a corrected retry.
|
|
387
398
|
|
|
388
399
|
An ordinary checkpoint accepts the model-facing `answer` action and starts a continuation run. A protected human decision never accepts that tool action. The extension displays the decision without starting a model turn, and a person answers it with `/workflow answer` through `decision.answer`. When a protected decision reaches its saved `onTimeout` deadline, the server takes a control claim on the waiting parent, atomically records the validated default, closes the pending interaction, releases the parent claim, and reserves the continuation. A human answer cannot win after that deadline.
|
|
389
400
|
|
|
@@ -397,7 +408,7 @@ A notify node creates a passive `notification` message in the same transaction a
|
|
|
397
408
|
|
|
398
409
|
A run with headless execution mode uses the existing `pi --mode rpc` integration for agent steps. The Pi child uses a separate process group registered with the server. The runner stops that group during normal completion. Cancellation gives the runner a bounded cleanup interval, and the server reaps the registered group if the runner exits first.
|
|
399
410
|
|
|
400
|
-
The headless child receives only the workflow step prompt, configured model arguments, and the bridge extension. Its submission uses the same
|
|
411
|
+
The headless child receives only the workflow step prompt, configured model arguments, and the bridge extension. Its submission uses the same exact request contract as origin-session work. A headless run cannot use a visible assistant-message step because it has no origin Pi session.
|
|
401
412
|
|
|
402
413
|
The run binding records `interactive` or `headless` execution mode. Viewers show that mode without exposing provider credentials.
|
|
403
414
|
|