@osolmaz/pi-workflows 0.12.0 → 0.12.1
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 +4 -3
- package/dist/builtins/autoimplement.workflow.d.ts +485 -126
- package/dist/builtins/autoimplement.workflow.js +17 -105
- package/dist/builtins/autoimplement.workflow.js.map +1 -1
- package/dist/builtins/catalog.js +4 -4
- package/dist/builtins/index.d.ts +2 -1
- package/dist/builtins/index.js +2 -1
- package/dist/builtins/index.js.map +1 -1
- package/dist/builtins/monitor.workflow.d.ts +2 -4
- package/dist/builtins/monitor.workflow.js +26 -128
- package/dist/builtins/monitor.workflow.js.map +1 -1
- package/dist/builtins/pi-agent-group.d.ts +72 -0
- package/dist/builtins/pi-agent-group.js +1087 -0
- package/dist/builtins/pi-agent-group.js.map +1 -0
- package/dist/builtins/plan-approval.workflow.d.ts +39 -5
- package/dist/builtins/plan-approval.workflow.js +92 -14
- package/dist/builtins/plan-approval.workflow.js.map +1 -1
- package/dist/builtins/plan-change.workflow.d.ts +301 -0
- package/dist/builtins/plan-change.workflow.js +256 -0
- package/dist/builtins/plan-change.workflow.js.map +1 -0
- package/dist/builtins/plan-presentation.js +2 -2
- package/dist/builtins/plan-presentation.js.map +1 -1
- package/dist/builtins/sanity-check.workflow.d.ts +5 -3
- package/dist/builtins/sanity-check.workflow.js +105 -21
- package/dist/builtins/sanity-check.workflow.js.map +1 -1
- package/dist/extension/decision-channels.d.ts +2 -2
- package/dist/extension/decision-channels.js +22 -28
- package/dist/extension/decision-channels.js.map +1 -1
- package/dist/extension/index.js +62 -33
- package/dist/extension/index.js.map +1 -1
- package/dist/extension/session-events.d.ts +2 -2
- package/dist/extension/widget.js +23 -3
- package/dist/extension/widget.js.map +1 -1
- package/dist/render/graph-render.js +1 -2
- package/dist/render/graph-render.js.map +1 -1
- package/dist/viewer/render.js +7 -6
- package/dist/viewer/render.js.map +1 -1
- package/dist/workflows/catalog.js +7 -2
- package/dist/workflows/catalog.js.map +1 -1
- package/dist/workflows/composition.js +8 -0
- package/dist/workflows/composition.js.map +1 -1
- package/dist/workflows/decision-presentation.d.ts +1 -1
- package/dist/workflows/decision-presentation.js +51 -38
- package/dist/workflows/decision-presentation.js.map +1 -1
- package/dist/workflows/engine.d.ts +2 -2
- package/dist/workflows/engine.js +14 -13
- package/dist/workflows/engine.js.map +1 -1
- package/dist/workflows/errors.d.ts +13 -0
- package/dist/workflows/errors.js +15 -0
- package/dist/workflows/errors.js.map +1 -1
- package/dist/workflows/human-decision.d.ts +16 -4
- package/dist/workflows/human-decision.js +175 -72
- package/dist/workflows/human-decision.js.map +1 -1
- package/dist/workflows/index.d.ts +2 -2
- package/dist/workflows/index.js +1 -1
- package/dist/workflows/index.js.map +1 -1
- package/dist/workflows/progress.d.ts +1 -0
- package/dist/workflows/progress.js +15 -3
- package/dist/workflows/progress.js.map +1 -1
- package/dist/workflows/schema.js +10 -0
- package/dist/workflows/schema.js.map +1 -1
- package/dist/workflows/store.js +5 -0
- package/dist/workflows/store.js.map +1 -1
- package/dist/workflows/types.d.ts +33 -45
- package/docs/HUMAN_DECISIONS.md +25 -35
- package/docs/HUMAN_DECISION_PRESENTATIONS.md +14 -24
- package/docs/MONITOR.md +5 -11
- package/docs/WORKFLOW_COMPOSITION.md +8 -7
- package/docs/plans/2026-08-21-plan-change-approval-policy-plan.md +322 -0
- package/docs/plans/2026-08-21-sanity-check-plan.md +202 -94
- package/docs/run-bundles.md +6 -6
- package/docs/workflows.md +26 -6
- package/examples/workflows/approved-plan.workflow.ts +19 -46
- package/herdr-plugin.toml +1 -1
- package/package.json +7 -7
- package/schemas/human-decision-accepted-v1.schema.json +15 -3
- package/schemas/human-decision-continuation-v1.schema.json +10 -1
- package/schemas/human-decision-delivery-v1.schema.json +8 -0
- package/schemas/human-decision-receipt-v1.schema.json +8 -0
- package/schemas/human-decision-request-v1.schema.json +24 -4
- package/skills/autoimplement/SKILL.md +27 -0
- package/skills/monitor/SKILL.md +31 -3
- package/skills/pi-workflows/SKILL.md +2 -1
- package/skills/sanity-check/SKILL.md +44 -0
- package/src/builtins/autoimplement.workflow.ts +19 -118
- package/src/builtins/catalog.ts +4 -4
- package/src/builtins/index.ts +11 -0
- package/src/builtins/monitor.workflow.ts +27 -150
- package/src/builtins/pi-agent-group.ts +1407 -0
- package/src/builtins/plan-approval.workflow.ts +157 -24
- package/src/builtins/plan-change.workflow.ts +321 -0
- package/src/builtins/plan-presentation.ts +2 -2
- package/src/builtins/sanity-check.workflow.ts +186 -41
- package/src/extension/decision-channels.ts +29 -59
- package/src/extension/index.ts +79 -41
- package/src/extension/session-events.ts +2 -2
- package/src/extension/widget.ts +24 -5
- package/src/render/graph-render.ts +1 -2
- package/src/viewer/render.ts +7 -6
- package/src/workflows/catalog.ts +7 -2
- package/src/workflows/composition.ts +9 -0
- package/src/workflows/decision-presentation.ts +56 -43
- package/src/workflows/engine.ts +17 -15
- package/src/workflows/errors.ts +24 -0
- package/src/workflows/human-decision.ts +218 -101
- package/src/workflows/index.ts +5 -11
- package/src/workflows/progress.ts +18 -3
- package/src/workflows/schema.ts +17 -0
- package/src/workflows/store.ts +5 -0
- package/src/workflows/types.ts +39 -56
- package/dist/builtins/sanity-check-session.d.ts +0 -17
- package/dist/builtins/sanity-check-session.js +0 -168
- package/dist/builtins/sanity-check-session.js.map +0 -1
- package/schemas/human-decision-accepted-v2.schema.json +0 -50
- package/schemas/human-decision-delivery-v2.schema.json +0 -36
- package/schemas/human-decision-receipt-v2.schema.json +0 -39
- package/schemas/human-decision-request-v2.schema.json +0 -69
- package/schemas/human-decision-resolution-v2.schema.json +0 -27
- package/src/builtins/sanity-check-session.ts +0 -205
|
@@ -4,8 +4,13 @@ import {
|
|
|
4
4
|
type CommandBatchItemResult,
|
|
5
5
|
} from "../workflows/command-batch.js";
|
|
6
6
|
import { action, compute, defineWorkflow, notify } from "../workflows/definition.js";
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
7
|
+
import { extractJsonValue } from "../workflows/json.js";
|
|
8
|
+
import type { WorkflowActionContext, WorkflowProgressStatus } from "../workflows/types.js";
|
|
9
|
+
import {
|
|
10
|
+
runPiAgentGroup,
|
|
11
|
+
type PiAgentLifecycleEvent,
|
|
12
|
+
type PiAgentRequest,
|
|
13
|
+
} from "./pi-agent-group.js";
|
|
9
14
|
|
|
10
15
|
const REVIEW_TIMEOUT_MS = 20 * 60_000;
|
|
11
16
|
const MAX_STRING_CHARS = 4_000;
|
|
@@ -237,21 +242,37 @@ export async function collectContributionEvidence(
|
|
|
237
242
|
};
|
|
238
243
|
}
|
|
239
244
|
|
|
245
|
+
type SanityCheckAgentPrompt = Pick<PiAgentRequest, "id" | "role" | "prompt">;
|
|
246
|
+
|
|
240
247
|
export function buildReviewRequests(
|
|
241
248
|
mode: SanityCheckMode,
|
|
242
249
|
evidence: ContributionEvidence,
|
|
243
|
-
):
|
|
250
|
+
): SanityCheckAgentPrompt[] {
|
|
244
251
|
if (mode === "serial") {
|
|
245
|
-
return [{ id: "review", prompt: reviewPrompt(reviewAreas, evidence) }];
|
|
252
|
+
return [{ id: "review", role: "Combined review", prompt: reviewPrompt(reviewAreas, evidence) }];
|
|
246
253
|
}
|
|
247
|
-
|
|
254
|
+
const roles: Record<SanityCheckArea, string> = {
|
|
255
|
+
necessity: "Necessity",
|
|
256
|
+
duplication: "Duplication and refactoring",
|
|
257
|
+
contracts: "Data models and public APIs",
|
|
258
|
+
scope_tests: "Scope and tests",
|
|
259
|
+
};
|
|
260
|
+
return reviewAreas.map((area) => ({
|
|
261
|
+
id: area,
|
|
262
|
+
role: roles[area],
|
|
263
|
+
prompt: reviewPrompt([area], evidence),
|
|
264
|
+
}));
|
|
248
265
|
}
|
|
249
266
|
|
|
250
267
|
export function buildVerificationRequest(
|
|
251
268
|
evidence: ContributionEvidence,
|
|
252
269
|
reviews: SanityCheckReview[],
|
|
253
|
-
):
|
|
254
|
-
return {
|
|
270
|
+
): SanityCheckAgentPrompt {
|
|
271
|
+
return {
|
|
272
|
+
id: "verification",
|
|
273
|
+
role: "Verification",
|
|
274
|
+
prompt: verificationPrompt(evidence, reviews),
|
|
275
|
+
};
|
|
255
276
|
}
|
|
256
277
|
|
|
257
278
|
export function parseReviewOutput(
|
|
@@ -321,53 +342,177 @@ async function runReviews(context: WorkflowActionContext): Promise<SanityCheckRe
|
|
|
321
342
|
const config = context.outputs.prepare as SanityCheckConfig;
|
|
322
343
|
const evidence = context.outputs.collectEvidence as ContributionEvidence;
|
|
323
344
|
const requests = buildReviewRequests(config.mode, evidence);
|
|
324
|
-
await
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
345
|
+
const progress = await createAgentProgress(context, "review", requests);
|
|
346
|
+
try {
|
|
347
|
+
const results = await runPiAgentGroup(agentRequests(requests, evidence.repository), {
|
|
348
|
+
maxConcurrency: config.mode === "parallel" ? 4 : 1,
|
|
349
|
+
signal: context.signal,
|
|
350
|
+
onLifecycle: progress.onLifecycle,
|
|
351
|
+
});
|
|
352
|
+
const reviews = results.map((result, index) =>
|
|
353
|
+
parseReviewOutput(
|
|
354
|
+
parseAgentJsonOutput(result.text, result.id),
|
|
355
|
+
config.mode === "serial" ? reviewAreas : [requests[index]!.id as SanityCheckArea],
|
|
356
|
+
),
|
|
357
|
+
);
|
|
358
|
+
await progress.complete();
|
|
359
|
+
return reviews;
|
|
360
|
+
} catch (error) {
|
|
361
|
+
await progress.fail();
|
|
362
|
+
throw error;
|
|
363
|
+
}
|
|
336
364
|
}
|
|
337
365
|
|
|
338
366
|
async function verifyReviews(context: WorkflowActionContext): Promise<SanityCheckResult> {
|
|
339
367
|
const evidence = context.outputs.collectEvidence as ContributionEvidence;
|
|
340
368
|
const reviews = context.outputs.review as SanityCheckReview[];
|
|
341
|
-
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
evidence.repository,
|
|
345
|
-
|
|
346
|
-
|
|
369
|
+
const requests = [buildVerificationRequest(evidence, reviews)];
|
|
370
|
+
const progress = await createAgentProgress(context, "verification", requests);
|
|
371
|
+
try {
|
|
372
|
+
const [result] = await runPiAgentGroup(agentRequests(requests, evidence.repository), {
|
|
373
|
+
maxConcurrency: 1,
|
|
374
|
+
signal: context.signal,
|
|
375
|
+
onLifecycle: progress.onLifecycle,
|
|
376
|
+
});
|
|
377
|
+
const parsed = parseSanityCheckResult(parseAgentJsonOutput(result!.text, result!.id));
|
|
378
|
+
await progress.complete();
|
|
379
|
+
return parsed;
|
|
380
|
+
} catch (error) {
|
|
381
|
+
await progress.fail();
|
|
382
|
+
throw error;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export function parseAgentJsonOutput(text: string, agentId: string): unknown {
|
|
387
|
+
try {
|
|
388
|
+
return extractJsonValue(text);
|
|
389
|
+
} catch {
|
|
390
|
+
throw new Error(`Sanity Check agent ${agentId} returned invalid JSON`);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function agentRequests(requests: SanityCheckAgentPrompt[], cwd: string): PiAgentRequest[] {
|
|
395
|
+
return requests.map((request) => ({
|
|
396
|
+
...request,
|
|
397
|
+
cwd,
|
|
398
|
+
tools: ["read", "grep", "find", "ls"],
|
|
399
|
+
timeoutMs: REVIEW_TIMEOUT_MS,
|
|
400
|
+
}));
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
type AgentProgress = {
|
|
404
|
+
onLifecycle(event: PiAgentLifecycleEvent): Promise<void>;
|
|
405
|
+
complete(): Promise<void>;
|
|
406
|
+
fail(): Promise<void>;
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
async function createAgentProgress(
|
|
410
|
+
context: WorkflowActionContext,
|
|
411
|
+
group: "review" | "verification",
|
|
412
|
+
requests: SanityCheckAgentPrompt[],
|
|
413
|
+
): Promise<AgentProgress> {
|
|
414
|
+
const aggregateKey = `agents/${group}`;
|
|
415
|
+
const settled = new Set<string>();
|
|
416
|
+
await safeProgress(context, aggregateKey, "running", group, 0, requests.length);
|
|
417
|
+
await Promise.all(
|
|
418
|
+
requests.map(
|
|
419
|
+
async (request) =>
|
|
420
|
+
await safeProgress(
|
|
421
|
+
context,
|
|
422
|
+
`${aggregateKey}/${request.id}`,
|
|
423
|
+
"pending",
|
|
424
|
+
"pending",
|
|
425
|
+
0,
|
|
426
|
+
1,
|
|
427
|
+
request.role,
|
|
428
|
+
),
|
|
429
|
+
),
|
|
347
430
|
);
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
431
|
+
let updateWork = Promise.resolve();
|
|
432
|
+
const enqueue = (update: () => Promise<void>) => {
|
|
433
|
+
updateWork = updateWork.then(update).catch(() => undefined);
|
|
434
|
+
return updateWork;
|
|
435
|
+
};
|
|
436
|
+
return {
|
|
437
|
+
async onLifecycle(event) {
|
|
438
|
+
await enqueue(async () => {
|
|
439
|
+
const terminal = event.state !== "running";
|
|
440
|
+
if (terminal) settled.add(event.id);
|
|
441
|
+
const label = event.model === undefined ? event.role : `${event.role} · ${event.model}`;
|
|
442
|
+
await safeProgress(
|
|
443
|
+
context,
|
|
444
|
+
`${aggregateKey}/${event.id}`,
|
|
445
|
+
event.state,
|
|
446
|
+
event.phase,
|
|
447
|
+
terminal ? 1 : 0,
|
|
448
|
+
1,
|
|
449
|
+
label,
|
|
450
|
+
);
|
|
451
|
+
if (terminal) {
|
|
452
|
+
await safeProgress(
|
|
453
|
+
context,
|
|
454
|
+
aggregateKey,
|
|
455
|
+
"running",
|
|
456
|
+
group,
|
|
457
|
+
settled.size,
|
|
458
|
+
requests.length,
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
},
|
|
463
|
+
async complete() {
|
|
464
|
+
await enqueue(
|
|
465
|
+
async () =>
|
|
466
|
+
await safeProgress(
|
|
467
|
+
context,
|
|
468
|
+
aggregateKey,
|
|
469
|
+
"completed",
|
|
470
|
+
group,
|
|
471
|
+
requests.length,
|
|
472
|
+
requests.length,
|
|
473
|
+
),
|
|
474
|
+
);
|
|
475
|
+
},
|
|
476
|
+
async fail() {
|
|
477
|
+
await enqueue(
|
|
478
|
+
async () =>
|
|
479
|
+
await safeProgress(
|
|
480
|
+
context,
|
|
481
|
+
aggregateKey,
|
|
482
|
+
context.signal.aborted ? "cancelled" : "failed",
|
|
483
|
+
group,
|
|
484
|
+
settled.size,
|
|
485
|
+
requests.length,
|
|
486
|
+
),
|
|
487
|
+
);
|
|
488
|
+
},
|
|
489
|
+
};
|
|
351
490
|
}
|
|
352
491
|
|
|
353
|
-
async function
|
|
492
|
+
async function safeProgress(
|
|
354
493
|
context: WorkflowActionContext,
|
|
494
|
+
key: string,
|
|
495
|
+
status: WorkflowProgressStatus,
|
|
355
496
|
phase: string,
|
|
356
497
|
completed: number,
|
|
357
498
|
total: number,
|
|
499
|
+
label?: string,
|
|
358
500
|
): Promise<void> {
|
|
359
|
-
await context
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
501
|
+
await context
|
|
502
|
+
.publishUpdate({
|
|
503
|
+
type: "progress",
|
|
504
|
+
key,
|
|
505
|
+
data: {
|
|
506
|
+
schema: "pi-workflows.progress.v1",
|
|
507
|
+
status,
|
|
508
|
+
phase,
|
|
509
|
+
completed,
|
|
510
|
+
total,
|
|
511
|
+
unit: "sessions",
|
|
512
|
+
...(label !== undefined ? { label: label.slice(0, 200) } : {}),
|
|
513
|
+
},
|
|
514
|
+
})
|
|
515
|
+
.catch(() => undefined);
|
|
371
516
|
}
|
|
372
517
|
|
|
373
518
|
function reviewPrompt(areas: readonly SanityCheckArea[], evidence: ContributionEvidence): string {
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
} from "../workflows/decision-presentation.js";
|
|
15
15
|
import { HumanDecisionStore, createHumanDecisionAttemptId } from "../workflows/human-decision.js";
|
|
16
16
|
import type {
|
|
17
|
-
|
|
17
|
+
ResolvedHumanDecision,
|
|
18
18
|
HumanDecisionAnswerSource,
|
|
19
19
|
HumanDecisionCancellationRecord,
|
|
20
20
|
HumanDecisionChannelRequest,
|
|
@@ -47,7 +47,7 @@ export type HumanDecisionDeliveryResult = {
|
|
|
47
47
|
errorCode?: string;
|
|
48
48
|
};
|
|
49
49
|
|
|
50
|
-
export type SettledHumanDecision =
|
|
50
|
+
export type SettledHumanDecision = ResolvedHumanDecision | HumanDecisionCancellationRecord;
|
|
51
51
|
|
|
52
52
|
export interface HumanDecisionChannel {
|
|
53
53
|
readonly id: string;
|
|
@@ -162,7 +162,7 @@ export class PiDecisionChannel implements HumanDecisionChannel {
|
|
|
162
162
|
await this.options.store.recordDelivery(
|
|
163
163
|
request,
|
|
164
164
|
this.id,
|
|
165
|
-
|
|
165
|
+
deliveryRecord(request, this.id, attemptId, "intent", "intent", createdAt),
|
|
166
166
|
);
|
|
167
167
|
const entries = Object.entries(request.choices);
|
|
168
168
|
const selectedChoice = await this.options.ui.custom<string | undefined>(
|
|
@@ -241,7 +241,7 @@ export class PiDecisionChannel implements HumanDecisionChannel {
|
|
|
241
241
|
await this.options.store.recordDelivery(
|
|
242
242
|
request,
|
|
243
243
|
this.id,
|
|
244
|
-
|
|
244
|
+
deliveryRecord(
|
|
245
245
|
request,
|
|
246
246
|
this.id,
|
|
247
247
|
`${attemptId}-cancelled`,
|
|
@@ -267,7 +267,7 @@ export class PiDecisionChannel implements HumanDecisionChannel {
|
|
|
267
267
|
await this.options.store.recordDelivery(
|
|
268
268
|
request,
|
|
269
269
|
this.id,
|
|
270
|
-
|
|
270
|
+
deliveryRecord(
|
|
271
271
|
request,
|
|
272
272
|
this.id,
|
|
273
273
|
`${attemptId}-cancelled`,
|
|
@@ -291,7 +291,7 @@ export class PiDecisionChannel implements HumanDecisionChannel {
|
|
|
291
291
|
await this.options.store.recordDelivery(
|
|
292
292
|
request,
|
|
293
293
|
this.id,
|
|
294
|
-
|
|
294
|
+
deliveryRecord(
|
|
295
295
|
request,
|
|
296
296
|
this.id,
|
|
297
297
|
`${attemptId}-confirmed`,
|
|
@@ -684,7 +684,7 @@ export class TelegramDecisionChannel implements HumanDecisionChannel {
|
|
|
684
684
|
await this.store.recordDelivery(
|
|
685
685
|
request,
|
|
686
686
|
channelPath,
|
|
687
|
-
|
|
687
|
+
deliveryRecord(request, this.id, attemptId, "intent", "intent", createdAt, {
|
|
688
688
|
partCount: parts.length,
|
|
689
689
|
}),
|
|
690
690
|
);
|
|
@@ -704,7 +704,6 @@ export class TelegramDecisionChannel implements HumanDecisionChannel {
|
|
|
704
704
|
);
|
|
705
705
|
const confirmed = prior.some(
|
|
706
706
|
(record) =>
|
|
707
|
-
record.schema === "pi-workflows.human-decision-delivery.v2" &&
|
|
708
707
|
record.phase === "part" &&
|
|
709
708
|
record.state === "confirmed" &&
|
|
710
709
|
record.recipientIndex === recipientIndex &&
|
|
@@ -724,7 +723,7 @@ export class TelegramDecisionChannel implements HumanDecisionChannel {
|
|
|
724
723
|
await this.store.recordDelivery(
|
|
725
724
|
request,
|
|
726
725
|
channelPath,
|
|
727
|
-
|
|
726
|
+
deliveryRecord(
|
|
728
727
|
request,
|
|
729
728
|
this.id,
|
|
730
729
|
`${attemptId}-r${recipientIndex}-p${partIndex}-unknown`,
|
|
@@ -740,15 +739,12 @@ export class TelegramDecisionChannel implements HumanDecisionChannel {
|
|
|
740
739
|
await this.store.recordDelivery(
|
|
741
740
|
request,
|
|
742
741
|
channelPath,
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
createdAt,
|
|
750
|
-
{ recipientIndex, partIndex, partCount: parts.length, contentDigest },
|
|
751
|
-
),
|
|
742
|
+
deliveryRecord(request, this.id, `${partAttemptId}-intent`, "part", "intent", createdAt, {
|
|
743
|
+
recipientIndex,
|
|
744
|
+
partIndex,
|
|
745
|
+
partCount: parts.length,
|
|
746
|
+
contentDigest,
|
|
747
|
+
}),
|
|
752
748
|
);
|
|
753
749
|
try {
|
|
754
750
|
const result = await this.call("sendMessage", {
|
|
@@ -769,7 +765,7 @@ export class TelegramDecisionChannel implements HumanDecisionChannel {
|
|
|
769
765
|
await this.store.recordDelivery(
|
|
770
766
|
request,
|
|
771
767
|
channelPath,
|
|
772
|
-
|
|
768
|
+
deliveryRecord(
|
|
773
769
|
request,
|
|
774
770
|
this.id,
|
|
775
771
|
`${partAttemptId}-confirmed`,
|
|
@@ -785,7 +781,7 @@ export class TelegramDecisionChannel implements HumanDecisionChannel {
|
|
|
785
781
|
await this.store.recordDelivery(
|
|
786
782
|
request,
|
|
787
783
|
channelPath,
|
|
788
|
-
|
|
784
|
+
deliveryRecord(
|
|
789
785
|
request,
|
|
790
786
|
this.id,
|
|
791
787
|
`${partAttemptId}-${state}`,
|
|
@@ -804,7 +800,7 @@ export class TelegramDecisionChannel implements HumanDecisionChannel {
|
|
|
804
800
|
await this.store.recordDelivery(
|
|
805
801
|
request,
|
|
806
802
|
channelPath,
|
|
807
|
-
|
|
803
|
+
deliveryRecord(
|
|
808
804
|
request,
|
|
809
805
|
this.id,
|
|
810
806
|
`${attemptId}-${state}`,
|
|
@@ -821,7 +817,7 @@ export class TelegramDecisionChannel implements HumanDecisionChannel {
|
|
|
821
817
|
await this.store.recordDelivery(
|
|
822
818
|
request,
|
|
823
819
|
channelPath,
|
|
824
|
-
|
|
820
|
+
deliveryRecord(
|
|
825
821
|
request,
|
|
826
822
|
this.id,
|
|
827
823
|
`${attemptId}-confirmed`,
|
|
@@ -1234,29 +1230,26 @@ function parseCredentialConfig(value: unknown): DecisionCredentialConfig {
|
|
|
1234
1230
|
return { schema: "pi-workflows.credentials.v1", telegram };
|
|
1235
1231
|
}
|
|
1236
1232
|
|
|
1237
|
-
type
|
|
1238
|
-
HumanDecisionDeliveryRecord,
|
|
1239
|
-
{ schema: "pi-workflows.human-decision-delivery.v2" }
|
|
1240
|
-
>;
|
|
1233
|
+
type DeliveryRecord = HumanDecisionDeliveryRecord;
|
|
1241
1234
|
|
|
1242
|
-
type
|
|
1235
|
+
type DeliveryRecordExtra = Partial<
|
|
1243
1236
|
Pick<
|
|
1244
|
-
|
|
1237
|
+
DeliveryRecord,
|
|
1245
1238
|
"recipientIndex" | "partIndex" | "partCount" | "contentDigest" | "messageCount" | "errorCode"
|
|
1246
1239
|
>
|
|
1247
1240
|
>;
|
|
1248
1241
|
|
|
1249
|
-
function
|
|
1242
|
+
function deliveryRecord(
|
|
1250
1243
|
request: HumanDecisionChannelRequest,
|
|
1251
1244
|
channel: string,
|
|
1252
1245
|
attemptId: string,
|
|
1253
|
-
phase:
|
|
1254
|
-
state:
|
|
1246
|
+
phase: DeliveryRecord["phase"],
|
|
1247
|
+
state: DeliveryRecord["state"],
|
|
1255
1248
|
createdAt: string,
|
|
1256
|
-
extra:
|
|
1257
|
-
):
|
|
1249
|
+
extra: DeliveryRecordExtra = {},
|
|
1250
|
+
): DeliveryRecord {
|
|
1258
1251
|
return {
|
|
1259
|
-
schema: "pi-workflows.human-decision-delivery.
|
|
1252
|
+
schema: "pi-workflows.human-decision-delivery.v1",
|
|
1260
1253
|
attemptId,
|
|
1261
1254
|
decisionId: request.decisionId,
|
|
1262
1255
|
requestDigest: request.requestDigest,
|
|
@@ -1271,37 +1264,14 @@ function v2DeliveryRecord(
|
|
|
1271
1264
|
}
|
|
1272
1265
|
|
|
1273
1266
|
function isCompleteDelivery(record: HumanDecisionDeliveryRecord): boolean {
|
|
1274
|
-
return
|
|
1275
|
-
record.state === "confirmed" &&
|
|
1276
|
-
(record.schema === "pi-workflows.human-decision-delivery.v1" || record.phase === "complete")
|
|
1277
|
-
);
|
|
1267
|
+
return record.state === "confirmed" && record.phase === "complete";
|
|
1278
1268
|
}
|
|
1279
1269
|
|
|
1280
1270
|
function hasUnsettledDeliveryIntent(records: HumanDecisionDeliveryRecord[]): boolean {
|
|
1281
|
-
const hasLegacyIntent = records.some(
|
|
1282
|
-
(record) =>
|
|
1283
|
-
record.schema === "pi-workflows.human-decision-delivery.v1" && record.state === "intent",
|
|
1284
|
-
);
|
|
1285
|
-
if (
|
|
1286
|
-
hasLegacyIntent &&
|
|
1287
|
-
!records.some(
|
|
1288
|
-
(record) =>
|
|
1289
|
-
record.schema === "pi-workflows.human-decision-delivery.v1" && record.state !== "intent",
|
|
1290
|
-
)
|
|
1291
|
-
) {
|
|
1292
|
-
return true;
|
|
1293
|
-
}
|
|
1294
1271
|
return records.some((record) => {
|
|
1295
|
-
if (
|
|
1296
|
-
record.schema !== "pi-workflows.human-decision-delivery.v2" ||
|
|
1297
|
-
record.phase !== "part" ||
|
|
1298
|
-
record.state !== "intent"
|
|
1299
|
-
) {
|
|
1300
|
-
return false;
|
|
1301
|
-
}
|
|
1272
|
+
if (record.phase !== "part" || record.state !== "intent") return false;
|
|
1302
1273
|
return !records.some(
|
|
1303
1274
|
(other) =>
|
|
1304
|
-
other.schema === "pi-workflows.human-decision-delivery.v2" &&
|
|
1305
1275
|
other.phase === "part" &&
|
|
1306
1276
|
other.state !== "intent" &&
|
|
1307
1277
|
other.recipientIndex === record.recipientIndex &&
|