@agwab/pi-workflow 0.1.1 → 0.2.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.
Files changed (70) hide show
  1. package/README.md +20 -15
  2. package/agents/researcher.md +17 -7
  3. package/dist/artifact-graph-runtime.js +1 -0
  4. package/dist/compiler.d.ts +2 -0
  5. package/dist/compiler.js +29 -4
  6. package/dist/dynamic-generated-task-runtime.js +4 -3
  7. package/dist/dynamic-runtime-bundle.js +3 -2
  8. package/dist/engine.d.ts +2 -0
  9. package/dist/engine.js +3 -2
  10. package/dist/extension.js +240 -16
  11. package/dist/store.js +1 -0
  12. package/dist/subagent-backend.js +82 -27
  13. package/dist/tool-metadata.d.ts +1 -0
  14. package/dist/tool-metadata.js +13 -1
  15. package/dist/types.d.ts +3 -0
  16. package/dist/workflow-artifact-extension.js +3 -2
  17. package/dist/workflow-artifact-tool.js +84 -4
  18. package/dist/workflow-progress-health.d.ts +37 -0
  19. package/dist/workflow-progress-health.js +296 -0
  20. package/dist/workflow-runtime.d.ts +6 -0
  21. package/dist/workflow-runtime.js +33 -10
  22. package/dist/workflow-view.d.ts +2 -0
  23. package/dist/workflow-view.js +97 -18
  24. package/dist/workflow-web-source-extension.d.ts +43 -0
  25. package/dist/workflow-web-source-extension.js +1194 -0
  26. package/dist/workflow-web-source.d.ts +171 -0
  27. package/dist/workflow-web-source.js +915 -0
  28. package/docs/usage.md +32 -18
  29. package/node_modules/@agwab/pi-subagent/package.json +1 -1
  30. package/node_modules/@agwab/pi-subagent/src/api.ts +245 -132
  31. package/node_modules/@agwab/pi-subagent/src/artifacts/result.ts +243 -163
  32. package/node_modules/@agwab/pi-subagent/src/core/constants.ts +117 -90
  33. package/node_modules/@agwab/pi-subagent/src/core/validation.ts +728 -475
  34. package/node_modules/@agwab/pi-subagent/src/orchestrate/run.ts +305 -209
  35. package/node_modules/@agwab/pi-subagent/src/runners/headless-model.ts +750 -439
  36. package/node_modules/@agwab/pi-subagent/src/runners/tmux.ts +422 -268
  37. package/package.json +7 -7
  38. package/skills/workflow-guide/scaffolds/object-tool-fallback/schemas/fetch-control.schema.json +1 -1
  39. package/skills/workflow-guide/scaffolds/object-tool-fallback/spec.json +4 -3
  40. package/src/artifact-graph-runtime.ts +1 -0
  41. package/src/compiler.ts +43 -3
  42. package/src/dynamic-generated-task-runtime.ts +4 -2
  43. package/src/dynamic-runtime-bundle.ts +3 -2
  44. package/src/engine.ts +7 -16
  45. package/src/extension.ts +299 -22
  46. package/src/store.ts +1 -0
  47. package/src/subagent-backend.ts +121 -37
  48. package/src/tool-metadata.ts +22 -1
  49. package/src/types.ts +4 -0
  50. package/src/workflow-artifact-extension.ts +3 -2
  51. package/src/workflow-artifact-tool.ts +96 -4
  52. package/src/workflow-progress-health.ts +461 -0
  53. package/src/workflow-runtime.ts +50 -13
  54. package/src/workflow-view.ts +186 -41
  55. package/src/workflow-web-source-extension.ts +1411 -0
  56. package/src/workflow-web-source.ts +1294 -0
  57. package/workflows/README.md +1 -1
  58. package/workflows/deep-research/helpers/claim-evidence-gate.mjs +552 -44
  59. package/workflows/deep-research/helpers/final-audit-packet.mjs +396 -0
  60. package/workflows/deep-research/helpers/normalize-input-packet.mjs +545 -0
  61. package/workflows/deep-research/helpers/render-executive.mjs +1199 -192
  62. package/workflows/deep-research/helpers/sanitize-verification-candidates.mjs +624 -0
  63. package/workflows/deep-research/schemas/deep-research-executive-render-control.schema.json +37 -8
  64. package/workflows/deep-research/schemas/deep-research-final-synthesis-control.schema.json +110 -0
  65. package/workflows/deep-research/schemas/deep-research-normalize-claims-control.schema.json +45 -4
  66. package/workflows/deep-research/schemas/deep-research-verify-claims-control.schema.json +0 -2
  67. package/workflows/deep-research/spec.json +71 -26
  68. package/workflows/deep-review/helpers/render-review-report.mjs +502 -0
  69. package/workflows/deep-review/schemas/deep-review-render-control.schema.json +50 -0
  70. package/workflows/deep-review/spec.json +22 -1
@@ -0,0 +1,396 @@
1
+ // Deterministic compact input packet for deep-research final-audit.
2
+ //
3
+ // This helper performs mechanical joins only: it copies plan metadata,
4
+ // normalize-claims ledgers, and audit-claims verdict partitions into a compact
5
+ // packet. It does not choose truth, promote/downgrade claims, or write final
6
+ // recommendations. The final-audit LLM remains responsible for synthesis while
7
+ // consuming these code-computed ledgers as ground truth for counts and buckets.
8
+
9
+ const SCHEMA = "deep-research-final-audit-packet-v1";
10
+
11
+ function findSource(sources, stageId) {
12
+ for (const [specId, source] of Object.entries(sources ?? {})) {
13
+ if (specId === stageId || specId.startsWith(`${stageId}.`)) return source;
14
+ }
15
+ return null;
16
+ }
17
+
18
+ function asArray(value) {
19
+ return Array.isArray(value) ? value : [];
20
+ }
21
+
22
+ function asObject(value) {
23
+ return value && typeof value === "object" && !Array.isArray(value)
24
+ ? value
25
+ : {};
26
+ }
27
+
28
+ function stringOf(value) {
29
+ return typeof value === "string" ? value : undefined;
30
+ }
31
+
32
+ function idOf(value) {
33
+ return stringOf(value?.id) ?? stringOf(value?.claimId) ?? null;
34
+ }
35
+
36
+ function compactStrings(values, limit = 5) {
37
+ if (!Array.isArray(values)) return [];
38
+ const seen = new Set();
39
+ const out = [];
40
+ for (const value of values) {
41
+ if (typeof value !== "string") continue;
42
+ const text = value.trim();
43
+ if (!text || seen.has(text)) continue;
44
+ seen.add(text);
45
+ out.push(text);
46
+ if (out.length >= limit) break;
47
+ }
48
+ return out;
49
+ }
50
+
51
+ function truncateText(value, limit = 240) {
52
+ const text = stringOf(value);
53
+ if (!text) return undefined;
54
+ const normalized = text.replace(/\s+/g, " ").trim();
55
+ if (normalized.length <= limit) return normalized;
56
+ return `${normalized.slice(0, Math.max(0, limit - 1)).trimEnd()}…`;
57
+ }
58
+
59
+ function compactClaimDigest(claim) {
60
+ const digest = asObject(claim);
61
+ return {
62
+ id: idOf(digest),
63
+ claim: stringOf(digest.claim),
64
+ status: stringOf(digest.status ?? digest.verdict),
65
+ confidence: stringOf(digest.confidence),
66
+ factSlotIds: compactStrings(digest.factSlotIds, 12),
67
+ sourceRefs: compactStrings(digest.sourceRefs, 8),
68
+ sourceUrls: compactStrings(digest.sourceUrls, 8),
69
+ support: stringOf(
70
+ digest.verdictDigest?.support ??
71
+ digest.verdictDigest?.summary ??
72
+ digest.verdictDigest,
73
+ ),
74
+ caveat: stringOf(digest.verdictDigest?.caveat ?? digest.caveat),
75
+ correctionOrCounterclaim: stringOf(digest.correctionOrCounterclaim),
76
+ ...(digest.evidenceGate ? { evidenceGate: digest.evidenceGate } : {}),
77
+ };
78
+ }
79
+
80
+ function compactSlot(slot) {
81
+ const item = asObject(slot);
82
+ return {
83
+ slotId: stringOf(item.slotId ?? item.id),
84
+ label: stringOf(item.label),
85
+ status: stringOf(item.status),
86
+ bestValue: item.bestValue,
87
+ sourceUrls: compactStrings(item.sourceUrls, 6),
88
+ sourceQuality: stringOf(item.sourceQuality),
89
+ verificationCandidateIds: compactStrings(item.verificationCandidateIds, 8),
90
+ gapReason: stringOf(item.gapReason),
91
+ parentImpact: stringOf(item.parentImpact),
92
+ };
93
+ }
94
+
95
+ function compactGap(gap) {
96
+ const item = asObject(gap);
97
+ return {
98
+ id: stringOf(item.id ?? item.gapId),
99
+ claimId: stringOf(item.claimId),
100
+ slotId: stringOf(item.slotId),
101
+ evidenceState: stringOf(item.evidenceState),
102
+ reason: stringOf(item.reason ?? item.gapReason),
103
+ nextStep: stringOf(item.nextStep),
104
+ sourceUrls: compactStrings(item.sourceUrls, 6),
105
+ relatedFactSlotIds: compactStrings(item.relatedFactSlotIds, 8),
106
+ scopeItem: stringOf(item.scopeItem),
107
+ whyItMatters: stringOf(item.whyItMatters),
108
+ };
109
+ }
110
+
111
+ function compactVerifierIssue(issue) {
112
+ const item = asObject(issue);
113
+ return {
114
+ sourceId: stringOf(item.sourceId),
115
+ claimId: stringOf(item.claimId),
116
+ reason: stringOf(item.reason),
117
+ status: stringOf(item.status),
118
+ nextStep: stringOf(item.nextStep),
119
+ };
120
+ }
121
+
122
+ function compactDuplicateVerifierRow(row) {
123
+ const item = asObject(row);
124
+ return {
125
+ claimId: stringOf(item.claimId),
126
+ rowCount: Number.isFinite(Number(item.rowCount))
127
+ ? Number(item.rowCount)
128
+ : undefined,
129
+ sourceIds: compactStrings(item.sourceIds, 8),
130
+ statusInputs: compactStrings(item.statusInputs, 8),
131
+ selectedStatus: stringOf(item.selectedStatus),
132
+ statusConflict: item.statusConflict === true,
133
+ action: stringOf(item.action),
134
+ };
135
+ }
136
+
137
+ function countByStatus(slots) {
138
+ const counts = {};
139
+ for (const slot of slots) {
140
+ const status = stringOf(slot.status) ?? "unknown";
141
+ counts[status] = (counts[status] ?? 0) + 1;
142
+ }
143
+ return counts;
144
+ }
145
+
146
+ function withGeneratedIds(items, prefix) {
147
+ return items.map((item, index) => ({
148
+ ...item,
149
+ id: stringOf(item.id) ?? `${prefix}-${String(index + 1).padStart(3, "0")}`,
150
+ }));
151
+ }
152
+
153
+ function synthesisClaimDigest(claim) {
154
+ const item = compactClaimDigest(claim);
155
+ return {
156
+ id: item.id,
157
+ claim: truncateText(item.claim, 260),
158
+ status: item.status,
159
+ confidence: item.confidence,
160
+ factSlotIds: compactStrings(item.factSlotIds, 8),
161
+ support: truncateText(item.support, 240),
162
+ caveat: truncateText(item.caveat, 180),
163
+ correctionOrCounterclaim: truncateText(item.correctionOrCounterclaim, 180),
164
+ hasSourceUrls: compactStrings(item.sourceUrls, 1).length > 0,
165
+ hasSourceRefs: compactStrings(item.sourceRefs, 1).length > 0,
166
+ };
167
+ }
168
+
169
+ function synthesisFactSlot(slot) {
170
+ const item = asObject(slot);
171
+ return {
172
+ slotId: stringOf(item.slotId),
173
+ label: truncateText(item.label, 120),
174
+ status: stringOf(item.status),
175
+ gapReason: truncateText(item.gapReason, 120),
176
+ parentImpact: truncateText(item.parentImpact, 120),
177
+ };
178
+ }
179
+
180
+ function synthesisGap(gap) {
181
+ const item = asObject(gap);
182
+ return {
183
+ id: stringOf(item.id),
184
+ kind: stringOf(item.kind),
185
+ claimId: stringOf(item.claimId),
186
+ slotId: stringOf(item.slotId),
187
+ evidenceState: stringOf(item.evidenceState),
188
+ reason: truncateText(item.reason, 220),
189
+ nextStep: truncateText(item.nextStep, 180),
190
+ scopeItem: truncateText(item.scopeItem, 160),
191
+ whyItMatters: truncateText(item.whyItMatters, 180),
192
+ };
193
+ }
194
+
195
+ function synthesisScopeCoverage(row) {
196
+ const item = asObject(row);
197
+ return {
198
+ scopeItem: truncateText(item.scopeItem ?? item.item ?? item.topic, 160),
199
+ status: stringOf(item.status ?? item.coverageStatus),
200
+ evidenceState: stringOf(item.evidenceState),
201
+ summary: truncateText(item.summary ?? item.reason, 220),
202
+ whyItMatters: truncateText(item.whyItMatters, 180),
203
+ };
204
+ }
205
+
206
+ function buildSynthesisInput({
207
+ plan,
208
+ factSlotCoverage,
209
+ claimDigests,
210
+ preservedClaims,
211
+ coverageGaps,
212
+ remainingGaps,
213
+ sourceRefJoinFailures,
214
+ researchScopeCoverage,
215
+ integritySummary,
216
+ audit,
217
+ }) {
218
+ return {
219
+ researchMetadata: {
220
+ depth: stringOf(plan.depth),
221
+ taskType: stringOf(plan.taskType),
222
+ expectedFinalShape: stringOf(plan.expectedFinalShape),
223
+ researchQuestions: asArray(plan.researchQuestions).length,
224
+ plannedFactSlots: asArray(plan.factSlots).length,
225
+ },
226
+ verdictCounts: asObject(audit.verdictCounts),
227
+ factSlotStatusCounts: countByStatus(factSlotCoverage),
228
+ integritySummary,
229
+ researchScopeCoverage: asArray(researchScopeCoverage)
230
+ .slice(0, 24)
231
+ .map(synthesisScopeCoverage),
232
+ factSlots: factSlotCoverage.map(synthesisFactSlot),
233
+ claims: claimDigests.map(synthesisClaimDigest),
234
+ preservedClaims: preservedClaims.slice(0, 12).map((claim) => ({
235
+ id: idOf(claim),
236
+ claim: truncateText(claim.claim, 240),
237
+ factSlotIds: compactStrings(claim.factSlotIds, 8),
238
+ whyItMatters: truncateText(claim.whyItMatters ?? claim.reason, 180),
239
+ })),
240
+ gaps: [
241
+ ...remainingGaps.map((gap) =>
242
+ synthesisGap({ ...gap, kind: "remaining" }),
243
+ ),
244
+ ...coverageGaps.map((gap) => synthesisGap({ ...gap, kind: "coverage" })),
245
+ ...sourceRefJoinFailures.map((gap) =>
246
+ synthesisGap({ ...gap, kind: "sourceRefJoinFailure" }),
247
+ ),
248
+ ],
249
+ };
250
+ }
251
+
252
+ export default async function finalAuditPacket({ sources }) {
253
+ const plan = asObject(findSource(sources, "plan"));
254
+ const normalizeClaims = asObject(findSource(sources, "normalize-claims"));
255
+ const sanitizedCandidates = asObject(
256
+ findSource(sources, "sanitize-claims") ??
257
+ findSource(sources, "sanitize-verification-candidates"),
258
+ );
259
+ const normalized =
260
+ Object.keys(sanitizedCandidates).length > 0
261
+ ? sanitizedCandidates
262
+ : normalizeClaims;
263
+ const sanitizerDiagnostics = asObject(normalized.sanitizerDiagnostics);
264
+ const audit = asObject(findSource(sources, "audit-claims"));
265
+ const claimInventory = asObject(normalized.claimInventory);
266
+ const verificationCandidates = asArray(claimInventory.verificationCandidates);
267
+ const preservedClaims = asArray(claimInventory.preservedClaims);
268
+ const claimDigests = asArray(audit.claimDigests);
269
+ const auditedIds = new Set(claimDigests.map(idOf).filter(Boolean));
270
+ const candidateIds = verificationCandidates.map(idOf).filter(Boolean);
271
+ const omittedCandidateIds = candidateIds.filter((id) => !auditedIds.has(id));
272
+ const factSlotCoverage = asArray(normalized.factSlotCoverage).map(
273
+ compactSlot,
274
+ );
275
+ const coverageGaps = withGeneratedIds(
276
+ asArray(normalized.coverageGaps).map(compactGap),
277
+ "gap-coverage",
278
+ );
279
+ const remainingGaps = withGeneratedIds(
280
+ asArray(audit.remainingGaps).map(compactGap),
281
+ "gap-remaining",
282
+ );
283
+ const sourceRefJoinFailures = withGeneratedIds(
284
+ asArray(audit.sourceRefJoinFailures).map(compactGap),
285
+ "gap-source-ref",
286
+ );
287
+ const invalidVerifierRows = asArray(audit.invalidVerifierRows).map(
288
+ compactVerifierIssue,
289
+ );
290
+ const duplicateVerifierRows = asArray(audit.duplicateVerifierRows).map(
291
+ compactDuplicateVerifierRow,
292
+ );
293
+ const gateSummary = asObject(audit.gateSummary);
294
+ const precisionGuardDiagnostics = asObject(audit.precisionGuardDiagnostics);
295
+ const sourceRefCoverage = {
296
+ verificationCandidatesWithSourceRefs: verificationCandidates.filter(
297
+ (candidate) => compactStrings(candidate?.sourceRefs, 1).length > 0,
298
+ ).length,
299
+ auditedClaimsWithSourceRefs: claimDigests.filter(
300
+ (claim) => compactStrings(claim?.sourceRefs, 1).length > 0,
301
+ ).length,
302
+ sourceRefJoinFailures: sourceRefJoinFailures.length,
303
+ };
304
+ const integritySummary = {
305
+ omittedVerificationCandidateCount: omittedCandidateIds.length,
306
+ sourceRefJoinFailures: sourceRefJoinFailures.length,
307
+ invalidVerifierRows: invalidVerifierRows.length,
308
+ duplicateVerifierRows: duplicateVerifierRows.length,
309
+ missingVerifierResults: Number(gateSummary.missingVerifierResults ?? 0),
310
+ sourceRefCoverage,
311
+ };
312
+ const synthesisInput = buildSynthesisInput({
313
+ plan,
314
+ factSlotCoverage,
315
+ claimDigests,
316
+ preservedClaims,
317
+ coverageGaps,
318
+ remainingGaps,
319
+ sourceRefJoinFailures,
320
+ researchScopeCoverage: normalized.researchScopeCoverage,
321
+ integritySummary,
322
+ audit,
323
+ });
324
+
325
+ return {
326
+ schema: SCHEMA,
327
+ packet: {
328
+ synthesisInput,
329
+ researchMetadataSeed: {
330
+ depth: stringOf(plan.depth),
331
+ taskType: stringOf(plan.taskType),
332
+ expectedFinalShape: stringOf(plan.expectedFinalShape),
333
+ researchQuestions: asArray(plan.researchQuestions).length,
334
+ sourcePolicy: asObject(plan.sourcePolicy),
335
+ plannedFactSlots: asArray(plan.factSlots).length,
336
+ filledFactSlots: factSlotCoverage.filter(
337
+ (slot) => slot.status === "filled",
338
+ ).length,
339
+ partialFactSlots: factSlotCoverage.filter(
340
+ (slot) => slot.status === "partial",
341
+ ).length,
342
+ missingFactSlots: factSlotCoverage.filter(
343
+ (slot) => slot.status === "missing",
344
+ ).length,
345
+ },
346
+ verdictCounts: asObject(audit.verdictCounts),
347
+ statusPartitions: asObject(audit.statusPartitions),
348
+ factSlotCoverage,
349
+ factSlotStatusCounts: countByStatus(factSlotCoverage),
350
+ coverageGaps,
351
+ remainingGaps,
352
+ sourceRefJoinFailures,
353
+ claimVerdictLedger: claimDigests.map(compactClaimDigest),
354
+ verifierIntegrity: {
355
+ gateSummary,
356
+ invalidVerifierRows,
357
+ duplicateVerifierRows,
358
+ },
359
+ normalizerDiagnostics: {
360
+ precisionGuard: precisionGuardDiagnostics,
361
+ sanitizer: sanitizerDiagnostics,
362
+ },
363
+ preservedClaims: preservedClaims.map((claim) => ({
364
+ id: idOf(claim),
365
+ claim: stringOf(claim.claim),
366
+ factSlotIds: compactStrings(claim.factSlotIds, 8),
367
+ sourceRefs: compactStrings(claim.sourceRefs, 6),
368
+ sourceUrls: compactStrings(claim.sourceUrls, 6),
369
+ whyItMatters: stringOf(claim.whyItMatters ?? claim.reason),
370
+ })),
371
+ researchScopeCoverage: asArray(normalized.researchScopeCoverage),
372
+ invariantChecks: {
373
+ candidateCount: verificationCandidates.length,
374
+ auditedClaimCount: claimDigests.length,
375
+ omittedCandidateIds,
376
+ droppedSlotIds: asArray(audit.slotCoverageCheck?.droppedSlotIds),
377
+ sourceRefCoverage,
378
+ verifierIntegrity: {
379
+ invalidVerifierRows: invalidVerifierRows.length,
380
+ duplicateVerifierRows: duplicateVerifierRows.length,
381
+ missingVerifierResults: Number(
382
+ gateSummary.missingVerifierResults ?? 0,
383
+ ),
384
+ },
385
+ },
386
+ overflowLedger: {
387
+ preservedClaimCount: preservedClaims.length,
388
+ coverageGapCount: coverageGaps.length,
389
+ remainingGapCount: remainingGaps.length,
390
+ omittedVerificationCandidateCount: omittedCandidateIds.length,
391
+ invalidVerifierRowCount: invalidVerifierRows.length,
392
+ duplicateVerifierRowCount: duplicateVerifierRows.length,
393
+ },
394
+ },
395
+ };
396
+ }