@osolmaz/pi-workflows 0.9.1 → 0.11.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 +64 -19
- package/dist/builtins/autodoc.workflow.d.ts +58 -0
- package/dist/builtins/autodoc.workflow.js +266 -0
- package/dist/builtins/autodoc.workflow.js.map +1 -0
- package/dist/builtins/autoimplement.workflow.d.ts +353 -0
- package/dist/builtins/autoimplement.workflow.js +961 -0
- package/dist/builtins/autoimplement.workflow.js.map +1 -0
- package/dist/builtins/autoplan.workflow.d.ts +58 -0
- package/dist/builtins/autoplan.workflow.js +190 -0
- package/dist/builtins/autoplan.workflow.js.map +1 -0
- package/dist/builtins/catalog.js +9 -1
- package/dist/builtins/catalog.js.map +1 -1
- package/dist/builtins/index.d.ts +6 -0
- package/dist/builtins/index.js +7 -0
- package/dist/builtins/index.js.map +1 -0
- package/dist/builtins/monitor.workflow.d.ts +29 -3
- package/dist/builtins/monitor.workflow.js +325 -13
- package/dist/builtins/monitor.workflow.js.map +1 -1
- package/dist/builtins/plan-approval.workflow.d.ts +83 -0
- package/dist/builtins/plan-approval.workflow.js +148 -0
- package/dist/builtins/plan-approval.workflow.js.map +1 -0
- package/dist/builtins/plan-presentation.d.ts +7 -0
- package/dist/builtins/plan-presentation.js +44 -0
- package/dist/builtins/plan-presentation.js.map +1 -0
- package/dist/extension/decision-channels.d.ts +132 -0
- package/dist/extension/decision-channels.js +1082 -0
- package/dist/extension/decision-channels.js.map +1 -0
- package/dist/extension/index.d.ts +1 -0
- package/dist/extension/index.js +426 -11
- package/dist/extension/index.js.map +1 -1
- package/dist/extension/widget.js +26 -2
- package/dist/extension/widget.js.map +1 -1
- package/dist/extension/workflow-tool.d.ts +1 -37
- package/dist/extension/workflow-tool.js +1 -42
- package/dist/extension/workflow-tool.js.map +1 -1
- package/dist/host/rpc-bridge.js +4 -21
- package/dist/host/rpc-bridge.js.map +1 -1
- package/dist/render/graph-render.js +46 -10
- package/dist/render/graph-render.js.map +1 -1
- package/dist/viewer/render.js +36 -2
- package/dist/viewer/render.js.map +1 -1
- package/dist/workflows/catalog.d.ts +1 -0
- package/dist/workflows/catalog.js +6 -0
- package/dist/workflows/catalog.js.map +1 -1
- package/dist/workflows/composition.d.ts +45 -0
- package/dist/workflows/composition.js +485 -0
- package/dist/workflows/composition.js.map +1 -0
- package/dist/workflows/decision-presentation.d.ts +18 -0
- package/dist/workflows/decision-presentation.js +417 -0
- package/dist/workflows/decision-presentation.js.map +1 -0
- package/dist/workflows/decision.d.ts +11 -5
- package/dist/workflows/decision.js.map +1 -1
- package/dist/workflows/definition.d.ts +22 -3
- package/dist/workflows/definition.js +46 -3
- package/dist/workflows/definition.js.map +1 -1
- package/dist/workflows/engine.d.ts +2 -1
- package/dist/workflows/engine.js +199 -18
- package/dist/workflows/engine.js.map +1 -1
- package/dist/workflows/graph.js +8 -6
- package/dist/workflows/graph.js.map +1 -1
- package/dist/workflows/human-decision.d.ts +87 -0
- package/dist/workflows/human-decision.js +583 -0
- package/dist/workflows/human-decision.js.map +1 -0
- package/dist/workflows/index.d.ts +5 -2
- package/dist/workflows/index.js +4 -1
- package/dist/workflows/index.js.map +1 -1
- package/dist/workflows/loader.d.ts +5 -4
- package/dist/workflows/loader.js +118 -18
- package/dist/workflows/loader.js.map +1 -1
- package/dist/workflows/schema.d.ts +3 -1
- package/dist/workflows/schema.js +64 -2
- package/dist/workflows/schema.js.map +1 -1
- package/dist/workflows/store.js +39 -2
- package/dist/workflows/store.js.map +1 -1
- package/dist/workflows/tool-input.d.ts +72 -0
- package/dist/workflows/tool-input.js +141 -0
- package/dist/workflows/tool-input.js.map +1 -0
- package/dist/workflows/types.d.ts +300 -2
- package/docs/CONTROLLERS.md +1 -1
- package/docs/DESIGN_PHILOSOPHY.md +1 -1
- package/docs/HUMAN_DECISIONS.md +371 -0
- package/docs/HUMAN_DECISION_PRESENTATIONS.md +323 -0
- package/docs/MONITOR.md +46 -18
- package/docs/WORKFLOW_COMPOSITION.md +333 -0
- package/docs/plans/2026-08-19-human-decision-gates-plan.md +296 -0
- package/docs/plans/2026-08-19-human-decision-presentations-plan.md +172 -0
- package/docs/plans/2026-08-19-provider-compatible-workflow-tool-schema-plan.md +45 -0
- package/docs/plans/2026-08-19-workflow-composition-plan.md +308 -0
- package/docs/run-bundles.md +45 -10
- package/docs/workflows.md +106 -15
- package/examples/workflows/approved-plan.workflow.ts +58 -0
- package/examples/workflows/autoimplement.workflow.ts +1 -92
- package/examples/workflows/autoplan.workflow.ts +1 -0
- package/examples/workflows/human-decision.workflow.ts +62 -0
- package/herdr-plugin.toml +1 -1
- package/package.json +6 -1
- package/schemas/decision-presentation-v1.schema.json +83 -0
- package/schemas/human-decision-accepted-v1.schema.json +44 -0
- package/schemas/human-decision-accepted-v2.schema.json +50 -0
- package/schemas/human-decision-answer-attempt-v1.schema.json +37 -0
- package/schemas/human-decision-cancellation-v1.schema.json +15 -0
- package/schemas/human-decision-continuation-v1.schema.json +16 -0
- package/schemas/human-decision-delivery-v1.schema.json +28 -0
- package/schemas/human-decision-delivery-v2.schema.json +36 -0
- package/schemas/human-decision-receipt-v1.schema.json +33 -0
- package/schemas/human-decision-receipt-v2.schema.json +39 -0
- package/schemas/human-decision-request-v1.schema.json +59 -0
- package/schemas/human-decision-request-v2.schema.json +69 -0
- package/schemas/human-decision-resolution-v1.schema.json +27 -0
- package/schemas/human-decision-resolution-v2.schema.json +27 -0
- package/schemas/human-decision-settlement-v1.schema.json +28 -0
- package/skills/autodoc/SKILL.md +43 -0
- package/skills/autoimplement/SKILL.md +58 -0
- package/skills/autoimplement/agents/openai.yaml +4 -0
- package/skills/autoplan/SKILL.md +25 -0
- package/skills/monitor/SKILL.md +8 -1
- package/skills/pi-workflows/SKILL.md +5 -3
- package/src/builtins/autodoc.workflow.ts +325 -0
- package/src/builtins/autoimplement.workflow.ts +1123 -0
- package/src/builtins/autoplan.workflow.ts +231 -0
- package/src/builtins/catalog.ts +9 -1
- package/src/builtins/index.ts +32 -0
- package/src/builtins/monitor.workflow.ts +396 -15
- package/src/builtins/plan-approval.workflow.ts +190 -0
- package/src/builtins/plan-presentation.ts +57 -0
- package/src/extension/decision-channels.ts +1533 -0
- package/src/extension/index.ts +499 -9
- package/src/extension/widget.ts +39 -2
- package/src/extension/workflow-tool.ts +5 -81
- package/src/host/rpc-bridge.ts +7 -30
- package/src/render/graph-render.ts +54 -5
- package/src/viewer/render.ts +56 -3
- package/src/workflows/catalog.ts +7 -0
- package/src/workflows/composition.ts +642 -0
- package/src/workflows/decision-presentation.ts +501 -0
- package/src/workflows/decision.ts +12 -5
- package/src/workflows/definition.ts +118 -8
- package/src/workflows/engine.ts +257 -20
- package/src/workflows/graph.ts +8 -6
- package/src/workflows/human-decision.ts +819 -0
- package/src/workflows/index.ts +89 -0
- package/src/workflows/loader.ts +186 -18
- package/src/workflows/schema.ts +79 -2
- package/src/workflows/store.ts +45 -2
- package/src/workflows/tool-input.ts +202 -0
- package/src/workflows/types.ts +374 -2
- package/examples/workflows/elegant-solution.workflow.ts +0 -95
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Add reusable human decision gates
|
|
3
|
+
author: Onur Solmaz <2453968+osolmaz@users.noreply.github.com>
|
|
4
|
+
date: 2026-08-19
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Add reusable human decision gates
|
|
8
|
+
|
|
9
|
+
Pi Workflows must let any workflow stop after a proposal, ask the operator in Pi and Telegram, and continue from a verified human choice. A `replan` choice must collect the operator's exact alternative text, send it back to planning, and present the revised plan for another decision.
|
|
10
|
+
|
|
11
|
+
The canonical behavior and public contracts are in [Human decisions](../HUMAN_DECISIONS.md). This plan covers the practical implementation in Pi Workflows without changing Pi core or adding a persistent operating-system service.
|
|
12
|
+
|
|
13
|
+
## Outcome
|
|
14
|
+
|
|
15
|
+
Workflow authors get three reusable levels:
|
|
16
|
+
|
|
17
|
+
1. `humanDecision()` adds a custom typed decision gate to any graph.
|
|
18
|
+
2. The included `plan-approval` workflow provides standard `continue`, `stop`, and `replan` exits.
|
|
19
|
+
3. The standalone `autodoc` workflow records selected plans and is composed into autoimplement and monitor repair.
|
|
20
|
+
|
|
21
|
+
Pi and Telegram implement one channel interface. Workflows address a named audience and contain no transport details. The first valid human response wins, stale and conflicting responses fail, and crash recovery creates one continuation.
|
|
22
|
+
|
|
23
|
+
## Scope
|
|
24
|
+
|
|
25
|
+
### Planning workflow contracts
|
|
26
|
+
|
|
27
|
+
- Add a standalone typed `autodoc` built-in with `ready` and `blocked` exits.
|
|
28
|
+
- Make autodoc locate an already selected plan, update or adopt canonical documents, run documentation checks, and return a documented-plan record.
|
|
29
|
+
- Keep autodoc separate from solution selection and implementation.
|
|
30
|
+
- Make autoimplement locate and record an existing plan from input, conversation context, or referenced documents.
|
|
31
|
+
- Block autoimplement when no clear plan exists.
|
|
32
|
+
- Skip autodoc only when plan discovery verifies current canonical documents or an explicit documentation receipt has a matching plan digest.
|
|
33
|
+
- Route every evidence-driven revision through `autoplan`, then `autodoc`, before implementation resumes.
|
|
34
|
+
- Never run initial autoplan only because the structured plan input is absent.
|
|
35
|
+
|
|
36
|
+
### Public authoring API
|
|
37
|
+
|
|
38
|
+
- Add `defineHumanChoices()`, `choice()`, and `textInput()`.
|
|
39
|
+
- Add `humanDecision()` as a typed checkpoint helper.
|
|
40
|
+
- Add `humanDecisionEdge()` with exhaustive TypeScript cases.
|
|
41
|
+
- Infer a discriminated response union from the choice contract.
|
|
42
|
+
- Validate the request and selected choice at runtime, including any choice input.
|
|
43
|
+
- Export a reusable typed `plan-approval` workflow.
|
|
44
|
+
|
|
45
|
+
### Engine and storage
|
|
46
|
+
|
|
47
|
+
- Add a human decision contract to checkpoint definitions and snapshots.
|
|
48
|
+
- Preserve the original workflow input when a human decision continues.
|
|
49
|
+
- Make the accepted response the gate's output in the continuation.
|
|
50
|
+
- Keep legacy checkpoint continuation unchanged.
|
|
51
|
+
- Add immutable records for requests, deliveries, answer attempts, accepted answers, settlement results, and continuation results.
|
|
52
|
+
- Accept the first valid response with a no-replace write.
|
|
53
|
+
- Adopt identical retries and reject conflicting responses.
|
|
54
|
+
- Derive one continuation identity from the accepted decision.
|
|
55
|
+
- Reject stale responses by decision ID and canonical request digest.
|
|
56
|
+
- Rebuild the pending-decision index from immutable records.
|
|
57
|
+
|
|
58
|
+
### Host and channels
|
|
59
|
+
|
|
60
|
+
- Add a `HumanDecisionChannel` interface outside the engine layer.
|
|
61
|
+
- Add a Pi channel using documented TUI APIs.
|
|
62
|
+
- Add a Telegram channel using the Bot API and private profiles.
|
|
63
|
+
- Add named audience resolution and private channel configuration.
|
|
64
|
+
- Add a setup command that writes private configuration with mode `600`, references an existing mode-`0600` token file, and verifies the Telegram bot without reading the token into a prompt or printing it.
|
|
65
|
+
- Keep Telegram optional. Pi Workflows must start and run normal workflows without Telegram configuration.
|
|
66
|
+
- Use one leased long-poll owner per Telegram profile across active Pi processes.
|
|
67
|
+
|
|
68
|
+
### Documentation and display
|
|
69
|
+
|
|
70
|
+
- Add the authoring API to `docs/workflows.md`.
|
|
71
|
+
- Add human decision state to `docs/run-bundles.md`.
|
|
72
|
+
- Add channel setup and recovery instructions.
|
|
73
|
+
- Add a custom gate example and a composed plan approval example.
|
|
74
|
+
- Show pending and accepted choices in TypeScript and Rust viewers.
|
|
75
|
+
- Redact credentials, chat IDs, user IDs, message IDs, and private profile names from model-visible and public presentation.
|
|
76
|
+
|
|
77
|
+
## Non-goals
|
|
78
|
+
|
|
79
|
+
- Change Pi core or use undocumented Pi APIs.
|
|
80
|
+
- Create a Telegram bot or copy a token without explicit source and destination approval.
|
|
81
|
+
- Add Telegram-specific logic to monitor, autoimplement, autoplan, or user workflows.
|
|
82
|
+
- Run an always-on service when no Pi process is active.
|
|
83
|
+
- Promise exactly-once Telegram message creation after an ambiguous Bot API response.
|
|
84
|
+
- Add arbitrary forms in the first release. Choice buttons and one text input cover the required flows.
|
|
85
|
+
- Change existing checkpoints or historical run bundles.
|
|
86
|
+
- Enable human approval by default in existing built-in workflows.
|
|
87
|
+
|
|
88
|
+
## Design decisions
|
|
89
|
+
|
|
90
|
+
### Extend checkpoints instead of the engine graph
|
|
91
|
+
|
|
92
|
+
`humanDecision()` returns `nodeType: "checkpoint"`. The engine already knows how to park a run and create a continuation. The added contract defines who can answer, how to validate the answer, and how to deliver the request.
|
|
93
|
+
|
|
94
|
+
The new behavior applies only when a checkpoint carries a human decision contract. Ordinary checkpoints keep using the continuation input supplied by `/workflow answer`.
|
|
95
|
+
|
|
96
|
+
### Separate workflow intent from delivery
|
|
97
|
+
|
|
98
|
+
A workflow declares its question and choices together with the subject and audience. Private host configuration maps the audience to Pi, Telegram, or later channels. This keeps workflow files portable and lets one Telegram adapter serve every workflow.
|
|
99
|
+
|
|
100
|
+
### Verify the answer source in the host
|
|
101
|
+
|
|
102
|
+
The model-facing workflow tool is not a human channel. It must reject `answer` while a human decision is waiting. The Pi UI path and Telegram adapter call an internal submission API that assigns the source and actor. Callers cannot supply a trusted source label themselves.
|
|
103
|
+
|
|
104
|
+
### Keep exact response text
|
|
105
|
+
|
|
106
|
+
The Telegram adapter accepts replan text only as a reply to the exact `ForceReply` prompt created for the pending decision and choice. It validates the numeric user and chat IDs and preserves the received text. Planning receives that string without a choice-classification model call.
|
|
107
|
+
|
|
108
|
+
### Make answer acceptance exact
|
|
109
|
+
|
|
110
|
+
Channel delivery can be retried or fail independently. Decision acceptance is one atomic no-replace operation. The accepted response and deterministic continuation identity prevent two channels from starting two continuations.
|
|
111
|
+
|
|
112
|
+
### Handle Telegram delivery limits honestly
|
|
113
|
+
|
|
114
|
+
Telegram Bot API `sendMessage` has no client idempotency key. The adapter writes an intent before sending. A confirmed response records the Telegram message ID. A timeout after a possible send becomes `unknown` and is not retried automatically. This prevents an automatic duplicate at the cost of a possibly missing Telegram notification. Pi remains available, and an operator can request a new delivery attempt.
|
|
115
|
+
|
|
116
|
+
## Data model
|
|
117
|
+
|
|
118
|
+
Add versioned JSON schemas for:
|
|
119
|
+
|
|
120
|
+
- `human-decision-request-v1`;
|
|
121
|
+
- `human-decision-delivery-v1`;
|
|
122
|
+
- `human-decision-answer-attempt-v1`;
|
|
123
|
+
- `human-decision-accepted-v1`;
|
|
124
|
+
- `human-decision-cancellation-v1`;
|
|
125
|
+
- `human-decision-resolution-v1`;
|
|
126
|
+
- `human-decision-receipt-v1` for redacted continuation state;
|
|
127
|
+
- `human-decision-settlement-v1`; and
|
|
128
|
+
- `human-decision-continuation-v1`.
|
|
129
|
+
|
|
130
|
+
Use canonical JSON for request and answer digests. Keep credential values and private channel configuration outside every schema.
|
|
131
|
+
|
|
132
|
+
Store decision records under the existing workflow state root:
|
|
133
|
+
|
|
134
|
+
```text
|
|
135
|
+
decisions/<decision-id>/
|
|
136
|
+
request.json
|
|
137
|
+
deliveries/<channel>/<attempt-id>.json
|
|
138
|
+
answers/<attempt-id>.json
|
|
139
|
+
resolution.json
|
|
140
|
+
accepted.json
|
|
141
|
+
cancelled.json
|
|
142
|
+
settlements/<channel>/<attempt-id>.json
|
|
143
|
+
continuation.json
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
All final records use no-replace creation and adopt only byte-identical content. Temporary files remain in the same filesystem so rename and exclusive-create rules stay valid.
|
|
147
|
+
|
|
148
|
+
A private SQLite index may track pending decisions, channel leases, Telegram update offsets, opaque callback IDs, and known message IDs. It is a projection and can be deleted and rebuilt from immutable records plus current private channel state.
|
|
149
|
+
|
|
150
|
+
## Work plan
|
|
151
|
+
|
|
152
|
+
### Contracts and compile-time API
|
|
153
|
+
|
|
154
|
+
- Add generic choice and input types.
|
|
155
|
+
- Build the response union from choice keys.
|
|
156
|
+
- Add `humanDecision()` and exhaustive `humanDecisionEdge()`.
|
|
157
|
+
- Extend workflow validation and definition snapshots.
|
|
158
|
+
- Add compile-time fixtures for every invalid route shape.
|
|
159
|
+
|
|
160
|
+
### Durable decision storage
|
|
161
|
+
|
|
162
|
+
- Add schemas and generated types.
|
|
163
|
+
- Add canonical request and response digest helpers.
|
|
164
|
+
- Add the decision store with no-replace writes and identical-byte adoption.
|
|
165
|
+
- Add a rebuildable pending-decision projection.
|
|
166
|
+
- Test concurrent writers and partial records.
|
|
167
|
+
|
|
168
|
+
### Safe human decision continuation
|
|
169
|
+
|
|
170
|
+
- Detect a human decision at `continueRun()`.
|
|
171
|
+
- Validate the accepted response through the node contract.
|
|
172
|
+
- Preserve the parent's original workflow input.
|
|
173
|
+
- Expose the response as the checkpoint output.
|
|
174
|
+
- derive and adopt the continuation identity; and
|
|
175
|
+
- leave the legacy checkpoint path unchanged.
|
|
176
|
+
|
|
177
|
+
Test crashes before acceptance, after acceptance, during continuation creation, and after continuation completion.
|
|
178
|
+
|
|
179
|
+
### Channel management
|
|
180
|
+
|
|
181
|
+
- Add the channel interface and audience resolver in the extension layer.
|
|
182
|
+
- Start channels during documented session lifecycle hooks.
|
|
183
|
+
- Stop them idempotently during shutdown and reload.
|
|
184
|
+
- Fan out one decision to all audience channels.
|
|
185
|
+
- Send every channel response through the same acceptance method.
|
|
186
|
+
- Settle all confirmed channel messages after acceptance, cancellation, or expiry.
|
|
187
|
+
|
|
188
|
+
### Pi channel
|
|
189
|
+
|
|
190
|
+
- Render pending decisions in the workflow widget.
|
|
191
|
+
- Open a TUI choice view from the checkpoint notification and workflow command.
|
|
192
|
+
- Open a text editor for text choices.
|
|
193
|
+
- Mark answers from this path as Pi interactive answers.
|
|
194
|
+
- Reject model-tool answers for human decisions.
|
|
195
|
+
- Restore pending decisions after restart.
|
|
196
|
+
|
|
197
|
+
### Telegram channel
|
|
198
|
+
|
|
199
|
+
- Add private profile and credential-reference parsing.
|
|
200
|
+
- Add a configuration command that accepts a private token-file reference and performs `getMe` verification without copying or displaying the token.
|
|
201
|
+
- Add the shared long-poll lease and durable update offset.
|
|
202
|
+
- Render choice buttons with opaque callback IDs.
|
|
203
|
+
- Implement the bound `ForceReply` text flow.
|
|
204
|
+
- Verify every bound reply field, including the actor, chat, reply message, decision ID, selected choice, and request digest.
|
|
205
|
+
- Record every delivery outcome without leaking request URLs or tokens.
|
|
206
|
+
- Edit confirmed messages after a decision settles.
|
|
207
|
+
|
|
208
|
+
Use a fake Bot API in all automated tests. Do not require a real token or network access.
|
|
209
|
+
|
|
210
|
+
### Autodoc and autoimplement
|
|
211
|
+
|
|
212
|
+
- Define the typed standalone `autodoc` built-in workflow.
|
|
213
|
+
- Add a durable documented-plan result shared by autodoc, autoimplement, and monitor.
|
|
214
|
+
- Replace autoimplement's missing-input redesign route with existing-plan discovery.
|
|
215
|
+
- Block when discovery finds no clear plan.
|
|
216
|
+
- Skip autodoc for current canonical documents.
|
|
217
|
+
- Route undocumented and revised plans through autodoc.
|
|
218
|
+
- Keep autoplan only on evidence-driven redesign edges.
|
|
219
|
+
|
|
220
|
+
### Reusable plan approval
|
|
221
|
+
|
|
222
|
+
- Define the typed `plan-approval` built-in workflow.
|
|
223
|
+
- Return named `continue`, `stop`, and `replan` exits.
|
|
224
|
+
- Include the accepted decision receipt in every exit.
|
|
225
|
+
- Return exact instructions from `replan`.
|
|
226
|
+
- Add an example that loops through `autoplan`, plan approval, and implementation.
|
|
227
|
+
- Keep monitor and autoimplement behavior unchanged unless their input requests the approval workflow.
|
|
228
|
+
|
|
229
|
+
### Viewers and documentation
|
|
230
|
+
|
|
231
|
+
- Display the audience label, choice labels, waiting state, and accepted choice.
|
|
232
|
+
- Keep actor and transport details out of public or model-visible views.
|
|
233
|
+
- Document setup, authoring, cancellation, recovery, Telegram delivery ambiguity, and the no-service limitation.
|
|
234
|
+
- Update the plan with meaningful implementation departures.
|
|
235
|
+
|
|
236
|
+
## Implementation note
|
|
237
|
+
|
|
238
|
+
The setup command uses an existing mode-`0600` token file instead of collecting and copying a token. This keeps credential ownership with the existing private store and follows the no-copy credential boundary while still verifying the bot with `getMe`.
|
|
239
|
+
|
|
240
|
+
## Acceptance criteria
|
|
241
|
+
|
|
242
|
+
- Autodoc runs alone, adopts current documents, updates stale documents, and blocks without a selected plan.
|
|
243
|
+
- Autoimplement uses the plan already present in context or documentation and never devises merely because `input.plan` is absent.
|
|
244
|
+
- Every revised plan is documented before implementation resumes.
|
|
245
|
+
- A TypeScript workflow can define custom human choices and route them exhaustively.
|
|
246
|
+
- A text choice returns the exact submitted text.
|
|
247
|
+
- The engine and run snapshot still identify the node as a checkpoint.
|
|
248
|
+
- The workflow tool cannot answer a protected human decision.
|
|
249
|
+
- Pi and Telegram can receive the same decision through one audience profile.
|
|
250
|
+
- The first concurrent valid answer wins and creates one continuation.
|
|
251
|
+
- An identical retry is adopted; a conflicting or stale answer is rejected.
|
|
252
|
+
- The original workflow input survives a human-decision continuation.
|
|
253
|
+
- Old checkpoints and old bundles pass their existing tests unchanged.
|
|
254
|
+
- The Telegram adapter accepts text only from the bound reply and approved numeric actor.
|
|
255
|
+
- A missing Telegram profile leaves Pi decisions usable.
|
|
256
|
+
- A Telegram timeout does not cause an automatic duplicate send.
|
|
257
|
+
- Restart recovery adopts confirmed deliveries and accepted continuations.
|
|
258
|
+
- The standard plan approval workflow loops through replan and requires approval for the revised digest.
|
|
259
|
+
- No credential or private channel value appears in source, fixtures, run bundles, logs, screenshots, or model-visible output.
|
|
260
|
+
|
|
261
|
+
## Verification
|
|
262
|
+
|
|
263
|
+
Run focused tests while implementing:
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
npx vitest run test/human-decision-api.test.ts test/human-decision-store.test.ts
|
|
267
|
+
npx vitest run test/human-decision-engine.test.ts test/run-resume.test.ts
|
|
268
|
+
npx vitest run test/pi-decision-channel.test.ts test/telegram-decision-channel.test.ts
|
|
269
|
+
npx vitest run test/plan-approval.test.ts test/composition.test.ts
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Run all repository gates before review:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
npm run check
|
|
276
|
+
npm run test:e2e
|
|
277
|
+
cargo test --manifest-path tui/Cargo.toml
|
|
278
|
+
npx slophammer-ts@latest dry .
|
|
279
|
+
npx slophammer-ts@latest check . --only ts.dependency-boundaries-required
|
|
280
|
+
npx -y @simpledoc/simpledoc check
|
|
281
|
+
git diff --check
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Run Pi Reviewer against the pushed branch. Fix every P0 and P1 finding and rerun it. Address valid P2 findings, but do not rerun review solely because of a P2-only change. Open or update a pull request and leave it unmerged unless merge is separately authorized.
|
|
285
|
+
|
|
286
|
+
## Release
|
|
287
|
+
|
|
288
|
+
This work adds compatible public APIs and additive persisted records. Release it as the next minor pre-1.0 version after the compatibility checks, viewer tests, real-Pi tests, and recovery tests pass.
|
|
289
|
+
|
|
290
|
+
## Contract impact
|
|
291
|
+
|
|
292
|
+
- **Session state:** normal workflow messages and interactive decision results.
|
|
293
|
+
- **Other persistent data:** additive decision records, a rebuildable private channel index, and private channel configuration.
|
|
294
|
+
- **Pi internals:** none.
|
|
295
|
+
- **Public Pi API:** documented extension lifecycle plus command and UI methods only.
|
|
296
|
+
- **Public Pi Workflows API:** typed human choices, `humanDecision()`, `humanDecisionEdge()`, the channel interface, and the `plan-approval` workflow.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Add readable human decision presentations
|
|
3
|
+
author: Onur Solmaz <2453968+osolmaz@users.noreply.github.com>
|
|
4
|
+
date: 2026-08-19
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Add readable human decision presentations
|
|
8
|
+
|
|
9
|
+
Pi Workflows currently sends a structured human decision body to Telegram with
|
|
10
|
+
`JSON.stringify()`. A plan approval therefore reaches the operator as machine
|
|
11
|
+
JSON. Pi also shows only the decision title in its basic selection prompt.
|
|
12
|
+
|
|
13
|
+
The operator must receive clear text in every channel. Structured data must
|
|
14
|
+
remain the durable source for validation, routing, and audit evidence. The
|
|
15
|
+
[human decision presentations specification](../HUMAN_DECISION_PRESENTATIONS.md)
|
|
16
|
+
defines the selected contract.
|
|
17
|
+
|
|
18
|
+
## Outcome
|
|
19
|
+
|
|
20
|
+
Add one versioned, channel-independent presentation format beside the canonical
|
|
21
|
+
subject. Pi and Telegram render the same complete content with their own native
|
|
22
|
+
layout. The visible presentation and machine subject are both bound to the
|
|
23
|
+
accepted decision.
|
|
24
|
+
|
|
25
|
+
The design uses the existing checkpoint engine, decision store, channel
|
|
26
|
+
interface, and documented Pi extension APIs. It does not require Pi core,
|
|
27
|
+
another service, or a Telegram change.
|
|
28
|
+
|
|
29
|
+
## Scope
|
|
30
|
+
|
|
31
|
+
- Add `DecisionPresentation v1` and `HumanDecisionRequest v2` schemas and types.
|
|
32
|
+
- Add deterministic presentation normalization and digests.
|
|
33
|
+
- Keep the current typed subject as machine truth.
|
|
34
|
+
- Require an explicit presentation for new structured subjects.
|
|
35
|
+
- Add a reusable plan presenter.
|
|
36
|
+
- Render complete readable messages in Pi and Telegram.
|
|
37
|
+
- Add durable multipart delivery evidence and safe recovery.
|
|
38
|
+
- Update TypeScript and Rust viewers.
|
|
39
|
+
- Preserve v1 definitions and immutable run bundles.
|
|
40
|
+
|
|
41
|
+
## Non-goals
|
|
42
|
+
|
|
43
|
+
- Do not modify Pi core or use undocumented Pi APIs.
|
|
44
|
+
- Do not change Telegram or create a delivery relay.
|
|
45
|
+
- Do not add a template language or general rich text system.
|
|
46
|
+
- Do not derive new operator text from arbitrary v2 subject data.
|
|
47
|
+
- Do not rewrite v1 requests, accepted answers, or run bundles.
|
|
48
|
+
- Do not store Telegram identifiers or credentials in public durable records.
|
|
49
|
+
|
|
50
|
+
## Implementation
|
|
51
|
+
|
|
52
|
+
### 1. Add the durable contracts
|
|
53
|
+
|
|
54
|
+
Create schemas and TypeScript types for the presentation, v2 request, and
|
|
55
|
+
multipart delivery evidence. Keep all v1 schemas and readers unchanged.
|
|
56
|
+
|
|
57
|
+
Generate and validate canonical examples. Reject unknown blocks, object-valued
|
|
58
|
+
display fields, missing summaries, missing presentations, and excessive
|
|
59
|
+
content.
|
|
60
|
+
|
|
61
|
+
### 2. Add deterministic normalization
|
|
62
|
+
|
|
63
|
+
Add a workflow-core module that validates the flat presentation blocks,
|
|
64
|
+
normalizes line endings, enforces the specification limits, and computes the
|
|
65
|
+
presentation digest. Keep it independent of Pi and Telegram.
|
|
66
|
+
|
|
67
|
+
Add a v1 compatibility presenter. A string body becomes a paragraph. An object
|
|
68
|
+
body becomes readable sections, labels, fields, and lists in stable key order.
|
|
69
|
+
The adapter reads only the historical display body.
|
|
70
|
+
|
|
71
|
+
### 3. Update the authoring API and request identity
|
|
72
|
+
|
|
73
|
+
Add the preferred `subject` plus `presentation` request form. Keep the current
|
|
74
|
+
`body` form as a deprecated compatibility overload. The preferred form fails
|
|
75
|
+
validation when either value is missing.
|
|
76
|
+
|
|
77
|
+
For v2, compute separate subject and presentation digests and bind the request
|
|
78
|
+
revision, subject, visible presentation, choices, and input prompts into the
|
|
79
|
+
overall request digest. Select the v1 or v2 digest algorithm from the stored
|
|
80
|
+
request schema.
|
|
81
|
+
|
|
82
|
+
### 4. Add the plan presenter
|
|
83
|
+
|
|
84
|
+
Create one reusable presenter for plan approvals. Derive its summary and
|
|
85
|
+
sections from the same typed plan stored in the subject. Use it in the built-in
|
|
86
|
+
plan approval path and composed workflows. Do not serialize missing or unknown
|
|
87
|
+
fields.
|
|
88
|
+
|
|
89
|
+
### 5. Narrow the channel boundary
|
|
90
|
+
|
|
91
|
+
Normalize the stored request before channel dispatch. Give each channel only
|
|
92
|
+
the normalized presentation and typed choices. Remove direct channel access to
|
|
93
|
+
the subject and remove the `JSON.stringify()` fallback.
|
|
94
|
+
|
|
95
|
+
### 6. Render complete Telegram messages
|
|
96
|
+
|
|
97
|
+
Render plain text with no parse mode. Precompute all message parts, split at
|
|
98
|
+
readable boundaries, add deterministic part numbers and a short fingerprint,
|
|
99
|
+
and put buttons on the final part only.
|
|
100
|
+
|
|
101
|
+
Write intent before sending and one durable content receipt for each confirmed
|
|
102
|
+
part. Keep remote IDs in the private projection. Stop automatic delivery after
|
|
103
|
+
an ambiguous send. Never clip approval content.
|
|
104
|
+
|
|
105
|
+
### 7. Add the full Pi decision view
|
|
106
|
+
|
|
107
|
+
Use documented `ctx.ui.custom()` APIs and existing TUI components to show the
|
|
108
|
+
complete presentation, fingerprint, choices, and text prompt. Support wrapping,
|
|
109
|
+
scrolling, resizing, cancellation, and theme changes. Preserve the abort signal
|
|
110
|
+
that closes Pi when another channel wins.
|
|
111
|
+
|
|
112
|
+
### 8. Update recovery and viewers
|
|
113
|
+
|
|
114
|
+
Recover confirmed multipart sends without duplication. Resume only when the
|
|
115
|
+
next part is provably unsent. Keep one accepted answer and one continuation.
|
|
116
|
+
|
|
117
|
+
Update the TypeScript and Rust viewers to show the human presentation by
|
|
118
|
+
default and machine data as separate detail. Continue to render v1 through the
|
|
119
|
+
compatibility presenter without changing stored bytes.
|
|
120
|
+
|
|
121
|
+
### 9. Verify compatibility and failure handling
|
|
122
|
+
|
|
123
|
+
Add tests for:
|
|
124
|
+
|
|
125
|
+
- presentation schemas, normalization, bounds, Unicode, and canonical digests;
|
|
126
|
+
- subject and presentation changes that reject stale answers;
|
|
127
|
+
- old definitions, pending v1 decisions, and accepted v1 decisions;
|
|
128
|
+
- complete and sparse plan presentations;
|
|
129
|
+
- Pi and Telegram content parity;
|
|
130
|
+
- unsafe markup-like text and terminal control characters;
|
|
131
|
+
- single-part and multipart Telegram messages;
|
|
132
|
+
- partial, ambiguous, resumed, and settled delivery;
|
|
133
|
+
- Pi scrolling, input, resize, cancellation, and external settlement;
|
|
134
|
+
- one answer and one continuation under concurrency and crash injection;
|
|
135
|
+
- TypeScript and Rust viewer parity; and
|
|
136
|
+
- absence of raw JSON subject serialization in channel output.
|
|
137
|
+
|
|
138
|
+
## Rollout
|
|
139
|
+
|
|
140
|
+
The preferred authoring path starts emitting v2 after release. Existing
|
|
141
|
+
body-based workflows continue to create and read v1 until a separate removal is
|
|
142
|
+
approved. No migration runs. Historical records remain immutable.
|
|
143
|
+
|
|
144
|
+
A live Telegram smoke can use an already configured private audience profile.
|
|
145
|
+
The test must not print, copy, or persist credentials. Fake Bot API and real-Pi
|
|
146
|
+
end-to-end tests remain the required automated evidence.
|
|
147
|
+
|
|
148
|
+
## Acceptance criteria
|
|
149
|
+
|
|
150
|
+
- New structured decisions cannot reach a channel without an explicit readable
|
|
151
|
+
presentation.
|
|
152
|
+
- Telegram and Pi show the same complete decision meaning.
|
|
153
|
+
- Telegram never shows raw JSON or silently truncates approval content.
|
|
154
|
+
- Pi shows the full decision instead of only its title.
|
|
155
|
+
- The accepted record binds the exact subject and visible presentation.
|
|
156
|
+
- V1 definitions and bundles remain readable without rewrites.
|
|
157
|
+
- Ambiguous Telegram sends fail closed without duplicate messages or
|
|
158
|
+
continuation.
|
|
159
|
+
- All repository, documentation, privacy, TypeScript, Rust, and real-Pi checks
|
|
160
|
+
pass.
|
|
161
|
+
|
|
162
|
+
## Verification
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
npm run check
|
|
166
|
+
npm run test:e2e
|
|
167
|
+
cargo test --manifest-path tui/Cargo.toml
|
|
168
|
+
npx slophammer-ts@latest dry .
|
|
169
|
+
npx slophammer-ts@latest check . --only ts.dependency-boundaries-required
|
|
170
|
+
npx -y @simpledoc/simpledoc check
|
|
171
|
+
npm pack --dry-run --json
|
|
172
|
+
```
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Provider-compatible workflow tool schema plan
|
|
3
|
+
author: Onur Solmaz <2453968+osolmaz@users.noreply.github.com>
|
|
4
|
+
date: 2026-08-19
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Provider-compatible workflow tool schema plan
|
|
8
|
+
|
|
9
|
+
## Goal
|
|
10
|
+
|
|
11
|
+
Fix the workflow tool schema so strict OpenAI-compatible providers accept it without weakening action validation. Apply the fix to the interactive Pi extension and the headless RPC bridge in PR #33.
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
- Every provider-facing tool schema has `type: "object"` at its root.
|
|
16
|
+
- Provider-facing schemas do not use root unions or conditional object schemas.
|
|
17
|
+
- Each action keeps its current required fields and rejects fields for other actions.
|
|
18
|
+
- The exact action schemas remain the source for TypeScript types and runtime validation.
|
|
19
|
+
- Invalid input is rejected before workflow state changes or RPC output.
|
|
20
|
+
- The existing action names and input fields do not change.
|
|
21
|
+
|
|
22
|
+
## Implementation
|
|
23
|
+
|
|
24
|
+
1. Define the exact action object schemas in a shared, Pi-independent workflow module.
|
|
25
|
+
2. Build the interactive and submission-only schemas from those action objects.
|
|
26
|
+
3. Generate flat provider-facing object schemas from the same action definitions.
|
|
27
|
+
4. Parse each tool call against the exact action schema before dispatch.
|
|
28
|
+
5. Use the shared submission schema in the RPC bridge.
|
|
29
|
+
6. Add unit tests for valid actions, missing fields, wrong-action fields, nested update data, and both provider schema roots.
|
|
30
|
+
7. Add an integration test that sends the schemas through Pi's OpenAI Completions adapter to a strict local endpoint.
|
|
31
|
+
|
|
32
|
+
## Non-goals
|
|
33
|
+
|
|
34
|
+
- Do not change Pi core or provider adapters.
|
|
35
|
+
- Do not add provider-specific branches.
|
|
36
|
+
- Do not add a schema version, new action format, or compatibility path.
|
|
37
|
+
- Do not change persisted workflow data.
|
|
38
|
+
|
|
39
|
+
## Acceptance
|
|
40
|
+
|
|
41
|
+
- The strict local endpoint accepts both workflow tool schemas.
|
|
42
|
+
- Runtime parsing rejects malformed calls before execution.
|
|
43
|
+
- `npm run check`, `npm run test:e2e`, Rust tests, Slophammer checks, and `git diff --check` pass.
|
|
44
|
+
- Pi Reviewer reports no P0 or P1 findings.
|
|
45
|
+
- PR #33 CI passes before merge.
|