@osolmaz/pi-workflows 0.16.5 → 0.16.7
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 +116 -166
- 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/widget.js +1 -1
- package/dist/extension/widget.js.map +1 -1
- package/dist/extension/workflow-message-coordinator.d.ts +12 -3
- package/dist/extension/workflow-message-coordinator.js +108 -94
- package/dist/extension/workflow-message-coordinator.js.map +1 -1
- package/dist/render/graph-render.js +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 +6 -5
- package/dist/server/view.js +68 -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 -16
- package/dist/workflows/engine.js +128 -252
- package/dist/workflows/engine.js.map +1 -1
- package/dist/workflows/errors.d.ts +1 -1
- package/dist/workflows/errors.js +2 -2
- package/dist/workflows/errors.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 +177 -174
- 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/2026-09-07-workflow-handoff-plan.md +84 -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 +83 -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 +111 -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 +118 -190
- package/src/extension/recorder.ts +2 -2
- package/src/extension/step-message.ts +4 -4
- package/src/extension/widget.ts +1 -1
- package/src/extension/workflow-message-coordinator.ts +133 -95
- package/src/render/graph-render.ts +1 -1
- 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 +73 -58
- 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 +136 -299
- package/src/workflows/errors.ts +4 -2
- 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 +226 -236
- 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
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import type { StateDatabase } from "../state/database.js";
|
|
3
|
+
import { canonicalJson, type JsonValue } from "../state/json.js";
|
|
4
|
+
import { WorkflowMessageStore } from "../state/workflow-messages.js";
|
|
5
|
+
import type { HumanDecisionReceipt } from "./types.js";
|
|
6
|
+
|
|
7
|
+
export type WorkflowRequestKind = "agent" | "assistant" | "checkpoint" | "decision";
|
|
8
|
+
|
|
9
|
+
export type WorkflowCheckpointState = {
|
|
10
|
+
request: InteractiveRequestRecord;
|
|
11
|
+
output?: JsonValue;
|
|
12
|
+
humanDecision?: HumanDecisionReceipt;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type InteractiveRequestRecord = {
|
|
16
|
+
requestId: string;
|
|
17
|
+
runId: string;
|
|
18
|
+
attemptId: string;
|
|
19
|
+
targetSessionId: string;
|
|
20
|
+
kind: WorkflowRequestKind;
|
|
21
|
+
contract: JsonValue;
|
|
22
|
+
revision: number;
|
|
23
|
+
status: "pending" | "settled" | "cancelled";
|
|
24
|
+
acceptedSubmissionId: string | null;
|
|
25
|
+
createdAt: string;
|
|
26
|
+
updatedAt: string;
|
|
27
|
+
settledAt: string | null;
|
|
28
|
+
consumedAt: string | null;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export function workflowRequestId(runId: string, attemptId: string): string {
|
|
32
|
+
return `request-${createHash("sha256")
|
|
33
|
+
.update(JSON.stringify([runId, attemptId]))
|
|
34
|
+
.digest("hex")}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Immutable identity and payload; an accepted request is never reopened. */
|
|
38
|
+
export function ensureWorkflowRequest(
|
|
39
|
+
state: StateDatabase,
|
|
40
|
+
options: Pick<
|
|
41
|
+
InteractiveRequestRecord,
|
|
42
|
+
"requestId" | "runId" | "attemptId" | "targetSessionId" | "kind" | "contract"
|
|
43
|
+
>,
|
|
44
|
+
now = Date.now(),
|
|
45
|
+
): InteractiveRequestRecord {
|
|
46
|
+
return state.transaction(() => {
|
|
47
|
+
const existing = readWorkflowRequest(state, options.requestId);
|
|
48
|
+
if (existing !== undefined) {
|
|
49
|
+
if (
|
|
50
|
+
existing.runId !== options.runId ||
|
|
51
|
+
existing.attemptId !== options.attemptId ||
|
|
52
|
+
existing.targetSessionId !== options.targetSessionId ||
|
|
53
|
+
existing.kind !== options.kind ||
|
|
54
|
+
canonicalJson(existing.contract) !== canonicalJson(options.contract)
|
|
55
|
+
)
|
|
56
|
+
throw new Error(`Interactive request conflicts: ${options.requestId}`);
|
|
57
|
+
return existing;
|
|
58
|
+
}
|
|
59
|
+
const attempt = state.connection
|
|
60
|
+
.prepare("SELECT run_id AS runId FROM node_attempts WHERE attempt_id = ?")
|
|
61
|
+
.get(options.attemptId) as { runId: string } | undefined;
|
|
62
|
+
if (attempt?.runId !== options.runId)
|
|
63
|
+
throw new Error("Request does not match its run and attempt");
|
|
64
|
+
state.connection
|
|
65
|
+
.prepare(
|
|
66
|
+
`INSERT INTO interactive_requests(
|
|
67
|
+
request_id, run_id, attempt_id, target_session_id, kind, contract_hash,
|
|
68
|
+
revision, status, created_at, updated_at
|
|
69
|
+
) VALUES (?, ?, ?, ?, ?, ?, 1, 'pending', ?, ?)`,
|
|
70
|
+
)
|
|
71
|
+
.run(
|
|
72
|
+
options.requestId,
|
|
73
|
+
options.runId,
|
|
74
|
+
options.attemptId,
|
|
75
|
+
options.targetSessionId,
|
|
76
|
+
options.kind,
|
|
77
|
+
state.putJson(options.contract, now),
|
|
78
|
+
now,
|
|
79
|
+
now,
|
|
80
|
+
);
|
|
81
|
+
const created = readWorkflowRequest(state, options.requestId);
|
|
82
|
+
if (created === undefined) throw new Error("Workflow request was not saved");
|
|
83
|
+
return created;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
type RequestRow = {
|
|
88
|
+
requestId: string;
|
|
89
|
+
runId: string;
|
|
90
|
+
attemptId: string;
|
|
91
|
+
targetSessionId: string;
|
|
92
|
+
kind: WorkflowRequestKind;
|
|
93
|
+
contractHash: Buffer;
|
|
94
|
+
revision: number;
|
|
95
|
+
status: InteractiveRequestRecord["status"];
|
|
96
|
+
acceptedSubmissionId: string | null;
|
|
97
|
+
createdAt: number;
|
|
98
|
+
updatedAt: number;
|
|
99
|
+
settledAt: number | null;
|
|
100
|
+
consumedAt: number | null;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export function readWorkflowRequest(
|
|
104
|
+
state: StateDatabase,
|
|
105
|
+
requestId: string,
|
|
106
|
+
): InteractiveRequestRecord | undefined {
|
|
107
|
+
const row = state.connection
|
|
108
|
+
.prepare(
|
|
109
|
+
`SELECT request_id AS requestId, run_id AS runId, attempt_id AS attemptId,
|
|
110
|
+
target_session_id AS targetSessionId, kind, contract_hash AS contractHash,
|
|
111
|
+
revision, status,
|
|
112
|
+
accepted_submission_id AS acceptedSubmissionId, created_at AS createdAt,
|
|
113
|
+
updated_at AS updatedAt, settled_at AS settledAt, consumed_at AS consumedAt
|
|
114
|
+
FROM interactive_requests WHERE request_id = ?`,
|
|
115
|
+
)
|
|
116
|
+
.get(requestId) as RequestRow | undefined;
|
|
117
|
+
if (row === undefined) return undefined;
|
|
118
|
+
const { contractHash, createdAt, updatedAt, settledAt, consumedAt, ...request } = row;
|
|
119
|
+
return {
|
|
120
|
+
...request,
|
|
121
|
+
contract: state.readJson(contractHash),
|
|
122
|
+
createdAt: new Date(createdAt).toISOString(),
|
|
123
|
+
updatedAt: new Date(updatedAt).toISOString(),
|
|
124
|
+
settledAt: settledAt === null ? null : new Date(settledAt).toISOString(),
|
|
125
|
+
consumedAt: consumedAt === null ? null : new Date(consumedAt).toISOString(),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function requestForAttempt(
|
|
130
|
+
state: StateDatabase,
|
|
131
|
+
runId: string,
|
|
132
|
+
attemptId: string,
|
|
133
|
+
): InteractiveRequestRecord | undefined {
|
|
134
|
+
const row = state.connection
|
|
135
|
+
.prepare(
|
|
136
|
+
"SELECT request_id AS requestId FROM interactive_requests WHERE run_id = ? AND attempt_id = ?",
|
|
137
|
+
)
|
|
138
|
+
.get(runId, attemptId) as { requestId: string } | undefined;
|
|
139
|
+
return row === undefined ? undefined : readWorkflowRequest(state, row.requestId);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function acceptedRequestOutput(
|
|
143
|
+
state: StateDatabase,
|
|
144
|
+
request: InteractiveRequestRecord,
|
|
145
|
+
): JsonValue {
|
|
146
|
+
if (request.status !== "settled" || request.acceptedSubmissionId === null) {
|
|
147
|
+
throw new Error("Workflow request has no accepted output");
|
|
148
|
+
}
|
|
149
|
+
const row = state.connection
|
|
150
|
+
.prepare(
|
|
151
|
+
`SELECT payload_hash AS payloadHash FROM interactive_submissions
|
|
152
|
+
WHERE request_id = ? AND submission_id = ? AND outcome = 'accepted'`,
|
|
153
|
+
)
|
|
154
|
+
.get(request.requestId, request.acceptedSubmissionId) as { payloadHash: Buffer } | undefined;
|
|
155
|
+
if (row === undefined) throw new Error("Accepted workflow response is missing");
|
|
156
|
+
return state.readJson(row.payloadHash);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export type WorkflowSubmissionOptions = {
|
|
160
|
+
requestId: string;
|
|
161
|
+
submissionId: string;
|
|
162
|
+
idempotencyKey: string;
|
|
163
|
+
expectedRevision: number;
|
|
164
|
+
payload: JsonValue;
|
|
165
|
+
outcome: "validating" | "accepted" | "rejected" | "adopted";
|
|
166
|
+
settle: boolean;
|
|
167
|
+
receipt?: JsonValue;
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
/** Record one exact response candidate or winner under the request revision. */
|
|
171
|
+
export function recordWorkflowSubmission(
|
|
172
|
+
state: StateDatabase,
|
|
173
|
+
options: WorkflowSubmissionOptions,
|
|
174
|
+
): {
|
|
175
|
+
interaction: InteractiveRequestRecord;
|
|
176
|
+
submissionId: string;
|
|
177
|
+
outcome: "accepted" | "adopted";
|
|
178
|
+
receipt: JsonValue;
|
|
179
|
+
} {
|
|
180
|
+
return state.transaction(() => {
|
|
181
|
+
const request = readWorkflowRequest(state, options.requestId);
|
|
182
|
+
if (request === undefined) throw new Error("Workflow request is missing");
|
|
183
|
+
const payloadHash = createHash("sha256").update(canonicalJson(options.payload)).digest();
|
|
184
|
+
const existing = state.connection
|
|
185
|
+
.prepare(
|
|
186
|
+
`SELECT submission_id AS submissionId, payload_hash AS payloadHash, receipt_hash AS receiptHash
|
|
187
|
+
FROM interactive_submissions WHERE request_id = ? AND idempotency_key = ?`,
|
|
188
|
+
)
|
|
189
|
+
.get(options.requestId, options.idempotencyKey) as
|
|
190
|
+
| { submissionId: string; payloadHash: Buffer; receiptHash: Buffer | null }
|
|
191
|
+
| undefined;
|
|
192
|
+
if (existing !== undefined) {
|
|
193
|
+
if (!existing.payloadHash.equals(payloadHash))
|
|
194
|
+
throw new Error("Interactive submission idempotency key conflicts");
|
|
195
|
+
return {
|
|
196
|
+
interaction: request,
|
|
197
|
+
submissionId: existing.submissionId,
|
|
198
|
+
outcome: "adopted",
|
|
199
|
+
receipt:
|
|
200
|
+
existing.receiptHash === null
|
|
201
|
+
? { requestId: request.requestId, submissionId: existing.submissionId }
|
|
202
|
+
: state.readJson(existing.receiptHash),
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
if (request.revision !== options.expectedRevision || request.status !== "pending") {
|
|
206
|
+
throw new Error("Interactive request revision conflict");
|
|
207
|
+
}
|
|
208
|
+
if (
|
|
209
|
+
options.outcome === "validating" &&
|
|
210
|
+
state.connection
|
|
211
|
+
.prepare(
|
|
212
|
+
"SELECT 1 FROM interactive_submissions WHERE request_id = ? AND outcome = 'validating'",
|
|
213
|
+
)
|
|
214
|
+
.get(options.requestId) !== undefined
|
|
215
|
+
)
|
|
216
|
+
throw new Error("Interactive submission validation is already active");
|
|
217
|
+
if (options.settle && options.outcome !== "accepted")
|
|
218
|
+
throw new Error("Only accepted output can settle a request");
|
|
219
|
+
if (request.kind === "decision" && options.settle) {
|
|
220
|
+
const resolution = state.connection
|
|
221
|
+
.prepare(
|
|
222
|
+
`SELECT r.response_hash AS responseHash FROM human_decision_resolutions r
|
|
223
|
+
JOIN human_decisions d ON d.decision_id = r.decision_id
|
|
224
|
+
WHERE d.decision_id = ? AND d.run_id = ? AND d.attempt_id = ? AND r.outcome = 'accepted'`,
|
|
225
|
+
)
|
|
226
|
+
.get(request.requestId, request.runId, request.attemptId) as
|
|
227
|
+
| { responseHash: Buffer }
|
|
228
|
+
| undefined;
|
|
229
|
+
const decision =
|
|
230
|
+
resolution === undefined
|
|
231
|
+
? undefined
|
|
232
|
+
: (state.readJson(resolution.responseHash) as { response?: JsonValue });
|
|
233
|
+
if (
|
|
234
|
+
decision?.response === undefined ||
|
|
235
|
+
canonicalJson(decision.response) !== canonicalJson(options.payload)
|
|
236
|
+
) {
|
|
237
|
+
throw new Error("Checkpoint response does not match a verified human decision");
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const now = Date.now();
|
|
241
|
+
state.connection
|
|
242
|
+
.prepare(
|
|
243
|
+
`INSERT INTO interactive_submissions(
|
|
244
|
+
submission_id, request_id, idempotency_key, request_revision,
|
|
245
|
+
payload_hash, outcome, receipt_hash, submitted_at
|
|
246
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
247
|
+
)
|
|
248
|
+
.run(
|
|
249
|
+
options.submissionId,
|
|
250
|
+
request.requestId,
|
|
251
|
+
options.idempotencyKey,
|
|
252
|
+
options.expectedRevision,
|
|
253
|
+
state.putJson(options.payload, now),
|
|
254
|
+
options.outcome,
|
|
255
|
+
options.receipt === undefined ? null : state.putJson(options.receipt, now),
|
|
256
|
+
now,
|
|
257
|
+
);
|
|
258
|
+
if (options.settle) {
|
|
259
|
+
const changed = state.connection
|
|
260
|
+
.prepare(
|
|
261
|
+
`UPDATE interactive_requests SET status = 'settled', accepted_submission_id = ?,
|
|
262
|
+
revision = revision + 1, updated_at = ?, settled_at = ?
|
|
263
|
+
WHERE request_id = ? AND revision = ? AND status = 'pending'`,
|
|
264
|
+
)
|
|
265
|
+
.run(options.submissionId, now, now, request.requestId, options.expectedRevision);
|
|
266
|
+
if (changed.changes !== 1) throw new Error("Workflow response lost its request revision");
|
|
267
|
+
const messages = new WorkflowMessageStore(state);
|
|
268
|
+
messages.cancelPendingForSource(request.requestId, "step", now);
|
|
269
|
+
messages.cancelPendingForSource(request.requestId, "decision", now);
|
|
270
|
+
}
|
|
271
|
+
const interaction = readWorkflowRequest(state, request.requestId);
|
|
272
|
+
if (interaction === undefined) throw new Error("Workflow request disappeared after acceptance");
|
|
273
|
+
return {
|
|
274
|
+
interaction,
|
|
275
|
+
submissionId: options.submissionId,
|
|
276
|
+
outcome: "accepted",
|
|
277
|
+
receipt: options.receipt ?? {
|
|
278
|
+
requestId: request.requestId,
|
|
279
|
+
submissionId: options.submissionId,
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
});
|
|
283
|
+
}
|
package/src/workflows/schema.ts
CHANGED
|
@@ -317,12 +317,8 @@ export function assertValidWorkflowDefinitionShape(
|
|
|
317
317
|
) {
|
|
318
318
|
fail("workflow title must be a string or function");
|
|
319
319
|
}
|
|
320
|
-
if (
|
|
321
|
-
|
|
322
|
-
typeof definition.presentationPrompt !== "string" &&
|
|
323
|
-
typeof definition.presentationPrompt !== "function"
|
|
324
|
-
) {
|
|
325
|
-
fail("workflow presentationPrompt must be a string or function");
|
|
320
|
+
if ("presentationPrompt" in definition) {
|
|
321
|
+
fail("presentationPrompt is not supported; use an explicit assistant-response node");
|
|
326
322
|
}
|
|
327
323
|
if (typeof definition.startAt !== "string" || definition.startAt.length === 0) {
|
|
328
324
|
fail("workflow requires startAt");
|