@wichayutdew/pi-workflows 2.5.1 → 2.6.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 (95) hide show
  1. package/README.md +4 -1
  2. package/dist/index.js +1133 -2409
  3. package/examples/starter-kit/agents/planner.md +7 -0
  4. package/examples/starter-kit/agents/reviewer.md +6 -0
  5. package/examples/starter-kit/agents/scout.md +6 -0
  6. package/examples/starter-kit/agents/worker.md +7 -0
  7. package/examples/starter-kit/agents/workspace-preparer.md +6 -0
  8. package/examples/starter-kit/investigate.workflow.yaml +114 -0
  9. package/examples/starter-kit/mr-comment.workflow.yaml +114 -54
  10. package/examples/starter-kit/mr-review.workflow.yaml +77 -56
  11. package/examples/starter-kit/settings.yaml +3 -0
  12. package/examples/starter-kit/steps/investigate/investigate.md +77 -0
  13. package/examples/starter-kit/steps/investigate/retrieve.md +63 -0
  14. package/examples/starter-kit/steps/investigate/validate.md +46 -0
  15. package/examples/starter-kit/steps/mr-comment/checkout-source.md +67 -0
  16. package/examples/starter-kit/steps/mr-comment/fetch.md +34 -26
  17. package/examples/starter-kit/steps/mr-comment/implement.md +34 -27
  18. package/examples/starter-kit/steps/mr-comment/plan.md +54 -40
  19. package/examples/starter-kit/steps/mr-comment/publish.md +28 -27
  20. package/examples/starter-kit/steps/mr-comment/verify.md +42 -35
  21. package/examples/starter-kit/steps/mr-review/fetch.md +52 -22
  22. package/examples/starter-kit/steps/mr-review/publish-approved.md +49 -0
  23. package/examples/starter-kit/steps/mr-review/review-for-approval.md +142 -0
  24. package/examples/starter-kit/steps/mr-review/verify-published.md +37 -0
  25. package/examples/starter-kit/steps/shared/prepare-workspace.md +91 -73
  26. package/examples/starter-kit/steps/shared/publish-remote.md +45 -0
  27. package/examples/starter-kit/steps/ticket/implement.md +59 -25
  28. package/examples/starter-kit/steps/ticket/plan.md +145 -72
  29. package/examples/starter-kit/steps/ticket/verify.md +80 -45
  30. package/examples/starter-kit/steps/work/implement.md +60 -24
  31. package/examples/starter-kit/steps/work/plan.md +129 -57
  32. package/examples/starter-kit/steps/work/verify.md +58 -22
  33. package/examples/starter-kit/ticket.workflow.yaml +75 -36
  34. package/examples/starter-kit/work.workflow.yaml +63 -33
  35. package/package.json +3 -16
  36. package/schemas/workflow.schema.json +2 -15
  37. package/src/agents/profile.ts +98 -0
  38. package/src/config/ceiling.ts +0 -82
  39. package/src/config/types.ts +6 -53
  40. package/src/config/validation/settings.ts +2 -14
  41. package/src/config/validation/step.ts +12 -8
  42. package/src/config/validation/workflow.ts +1 -10
  43. package/src/engine/run-workflow-validation.ts +0 -3
  44. package/src/engine/state-types.ts +1 -1
  45. package/src/harness/action-context.ts +1 -13
  46. package/src/harness/delegation-control-actions.ts +4 -63
  47. package/src/harness/delegation-plan.ts +26 -80
  48. package/src/harness/delegation-response-actions.ts +22 -135
  49. package/src/harness/dependencies.ts +1 -12
  50. package/src/harness/status-actions.ts +1 -0
  51. package/src/harness/step-execution-actions.ts +2 -9
  52. package/src/harness/types.ts +2 -40
  53. package/src/harness.ts +2 -17
  54. package/src/index.ts +4 -9
  55. package/src/integrations/subagents/child-policy-validation.ts +6 -7
  56. package/src/integrations/subagents/child-runtime-dependencies.ts +1 -1
  57. package/src/integrations/subagents/child-runtime-policy.ts +1 -7
  58. package/src/integrations/subagents/child-runtime.ts +18 -9
  59. package/src/integrations/subagents/client.ts +240 -98
  60. package/src/integrations/subagents/protocol-events.ts +32 -15
  61. package/src/integrations/subagents/protocol.ts +1 -1
  62. package/src/preflight.ts +0 -8
  63. package/src/prompt/main-workflow-notice.ts +8 -15
  64. package/src/prompt/step-task.ts +7 -6
  65. package/src/workflow-status/format-status.ts +5 -1
  66. package/src/workflow-status/render-step-detail.ts +94 -0
  67. package/src/workflow-status/types.ts +1 -0
  68. package/src/workflow-status/view.ts +49 -14
  69. package/agents/step.md +0 -32
  70. package/examples/mr-comments.workflow.yaml +0 -125
  71. package/examples/prompts/mr-comments/implement.md +0 -17
  72. package/examples/prompts/mr-comments/inspect.md +0 -5
  73. package/examples/prompts/mr-comments/plan.md +0 -54
  74. package/examples/prompts/mr-comments/verify.md +0 -9
  75. package/examples/settings.yaml +0 -27
  76. package/examples/starter-kit/steps/mr-review/publish.md +0 -48
  77. package/examples/starter-kit/steps/mr-review/review.md +0 -76
  78. package/examples/starter-kit/steps/mr-review/verify.md +0 -35
  79. package/src/config/validation/subagent.ts +0 -288
  80. package/src/harness/delegation-failure.ts +0 -248
  81. package/src/harness/delegation-recovery-validation.ts +0 -161
  82. package/src/harness/delegation-retry-policy.ts +0 -120
  83. package/src/integrations/subagents/client-delegation.ts +0 -181
  84. package/src/integrations/subagents/client-messages.ts +0 -66
  85. package/src/integrations/subagents/client-types.ts +0 -36
  86. package/src/integrations/subagents/diagnostic-format.ts +0 -45
  87. package/src/integrations/subagents/diagnostic-text.ts +0 -114
  88. package/src/integrations/subagents/diagnostic-types.ts +0 -83
  89. package/src/integrations/subagents/diagnostics.ts +0 -26
  90. package/src/integrations/subagents/failure-correlation.ts +0 -285
  91. package/src/integrations/subagents/failure-transcript.ts +0 -252
  92. package/src/integrations/subagents/hidden-bash-failure.ts +0 -98
  93. package/src/integrations/subagents/replay-audit.ts +0 -146
  94. package/src/integrations/subagents/replay-safety.ts +0 -67
  95. package/src/integrations/subagents/session-diagnostics.ts +0 -357
@@ -1,19 +1,17 @@
1
1
  import type { ExtensionContext } from '@earendil-works/pi-coding-agent';
2
+ import { loadAgentProfile } from '../agents/profile.ts';
2
3
  import type { LoadedWorkflow, WorkflowStep } from '../config/types.ts';
3
4
  import type { WorkflowRun } from '../engine/state.ts';
4
5
  import { allowedOutcomes } from '../engine/transitions.ts';
5
6
  import { digest } from '../digest.ts';
6
- import { deriveSubagentSessionRoot } from '../integrations/subagents/diagnostics.ts';
7
7
  import {
8
8
  encodeChildPolicy,
9
9
  type ChildStepPolicy,
10
10
  type SubagentDelegationRequest,
11
11
  } from '../integrations/subagents/protocol.ts';
12
- import { automaticRecoveryTask, buildDelegatedStepTask } from '../prompt.ts';
13
- import { WORKFLOW_COMPLETION_PARAMETERS } from '../runtime/completion-tool.ts';
14
- import { MAX_DELEGATION_RECOVERY_ATTEMPTS } from './delegation-retry-policy.ts';
12
+ import { buildDelegatedStepTask } from '../prompt.ts';
15
13
  import type { WorkflowHarnessDependencies } from './dependencies.ts';
16
- import type { ActiveDelegation, DelegationRecovery } from './types.ts';
14
+ import type { ActiveDelegation } from './types.ts';
17
15
 
18
16
  type DelegationPlanInput = {
19
17
  workflow: LoadedWorkflow;
@@ -21,7 +19,6 @@ type DelegationPlanInput = {
21
19
  step: WorkflowStep;
22
20
  sessionEpoch: number;
23
21
  latestContext: ExtensionContext | undefined;
24
- recovery: DelegationRecovery | undefined;
25
22
  };
26
23
 
27
24
  export type DelegationPlan =
@@ -35,13 +32,6 @@ export type DelegationPlan =
35
32
  request: SubagentDelegationRequest;
36
33
  };
37
34
 
38
- function delegationTranscriptBinding(
39
- requestId: string,
40
- policyDigest: string,
41
- ): string {
42
- return `<pi-workflows-delegation-binding-v1>${requestId}:${policyDigest}</pi-workflows-delegation-binding-v1>`;
43
- }
44
-
45
35
  /**
46
36
  * Creates one immutable subagent request from workflow state and injected
47
37
  * identity/workspace effects.
@@ -55,12 +45,21 @@ export function createDelegationPlan(
55
45
  | 'resolveWorkspaceDirectory'
56
46
  >,
57
47
  ): DelegationPlan {
58
- const { workflow, run, step, latestContext, recovery } = input;
59
- const subagent = step.subagent;
60
- if (!subagent) {
48
+ const { workflow, run, step, latestContext } = input;
49
+ const agent = step.agent?.name;
50
+ if (!agent) {
51
+ return {
52
+ kind: 'invalid',
53
+ reason: `Step "${run.currentStepId}" has no agent profile`,
54
+ };
55
+ }
56
+ let agentProfile;
57
+ try {
58
+ agentProfile = loadAgentProfile(agent);
59
+ } catch (error) {
61
60
  return {
62
61
  kind: 'invalid',
63
- reason: `Step "${run.currentStepId}" has no subagent configuration`,
62
+ reason: error instanceof Error ? error.message : String(error),
64
63
  };
65
64
  }
66
65
  if (!run.cwd) {
@@ -160,7 +159,7 @@ export function createDelegationPlan(
160
159
  const policyDigest = digest({
161
160
  version: 1,
162
161
  requestId,
163
- agent: subagent.agent,
162
+ agent,
164
163
  runId: run.runId,
165
164
  stepId: run.currentStepId,
166
165
  stepDigest: run.currentStepDigest,
@@ -174,7 +173,7 @@ export function createDelegationPlan(
174
173
  const policy: ChildStepPolicy = {
175
174
  version: 1,
176
175
  requestId,
177
- agent: subagent.agent,
176
+ agent,
178
177
  workflowId: workflow.definition.id,
179
178
  runId: run.runId,
180
179
  stepId: run.currentStepId,
@@ -195,22 +194,7 @@ export function createDelegationPlan(
195
194
  ...(step.gate ? { gateSubmitOutcome: step.gate.submitOutcome } : {}),
196
195
  ...(step.workspace ? { workspace: structuredClone(step.workspace) } : {}),
197
196
  };
198
- const trustedSessionRoot = deriveSubagentSessionRoot(
199
- latestContext.sessionManager.getSessionFile(),
200
- );
201
- const transcriptTask = [
202
- buildDelegatedStepTask(workflow, run, ''),
203
- delegationTranscriptBinding(requestId, policyDigest),
204
- ...(recovery
205
- ? [
206
- automaticRecoveryTask(
207
- recovery.failures.map(({ reason }) => reason),
208
- recovery.attempt,
209
- MAX_DELEGATION_RECOVERY_ATTEMPTS,
210
- ),
211
- ]
212
- : []),
213
- ].join('\n\n');
197
+ const task = buildDelegatedStepTask(workflow, run, '');
214
198
  const active: ActiveDelegation = {
215
199
  requestId,
216
200
  runId: run.runId,
@@ -219,56 +203,18 @@ export function createDelegationPlan(
219
203
  sessionEpoch: input.sessionEpoch,
220
204
  resultDirectory: workspace.resultDirectory,
221
205
  policy,
222
- transcriptTask,
223
- agent: subagent.agent,
224
- ...(trustedSessionRoot ? { trustedSessionRoot } : {}),
225
- broadRecoveryAuthorized: subagent.retryToolFailures,
226
- recoveryAttemptCount: recovery?.attempt ?? 0,
227
- recoveryFailures: recovery?.failures ?? [],
206
+ transcriptTask: task,
207
+ agent,
228
208
  };
229
209
  const request: SubagentDelegationRequest = {
230
210
  version: 1,
231
211
  requestId,
232
- agent: subagent.agent,
233
- task: `${encodeChildPolicy(policy)}\n\n${transcriptTask}`,
234
- // Workflow steps are isolation boundaries. Parent/sibling transcripts are
235
- // replaced by the explicit workflow handoff.
236
- context: 'fresh',
212
+ agent,
213
+ task: `${encodeChildPolicy(policy)}\n\n${task}`,
237
214
  cwd: delegationCwd,
238
- timeoutMs: subagent.timeoutMs,
239
- skill:
240
- step.permissions.skills.length > 0 ? [...step.permissions.skills] : false,
241
- output: false,
242
- // TypeBox schemas are structurally JSON objects, but the upstream contract
243
- // exposes a generic record.
244
- outputSchema: WORKFLOW_COMPLETION_PARAMETERS as unknown as Record<
245
- string,
246
- unknown
247
- >,
248
- agentContract: { version: 1 },
249
- artifacts: subagent.artifacts,
250
- ...(subagent.model ? { model: subagent.model } : {}),
251
- ...(subagent.turnBudget
252
- ? { turnBudget: structuredClone(subagent.turnBudget) }
253
- : {}),
254
- ...(subagent.toolBudget
255
- ? {
256
- toolBudget: {
257
- hard: subagent.toolBudget.hard,
258
- ...(subagent.toolBudget.soft === undefined
259
- ? {}
260
- : { soft: subagent.toolBudget.soft }),
261
- ...(subagent.toolBudget.block === undefined
262
- ? {}
263
- : {
264
- block:
265
- subagent.toolBudget.block === '*'
266
- ? '*'
267
- : [...subagent.toolBudget.block],
268
- }),
269
- },
270
- }
271
- : {}),
215
+ timeoutMs: 900_000,
216
+ ...(agentProfile.model ? { model: agentProfile.model } : {}),
217
+ ...(agentProfile.thinking ? { thinking: agentProfile.thinking } : {}),
272
218
  };
273
219
 
274
220
  return { kind: 'ready', active, request };
@@ -4,13 +4,10 @@ import {
4
4
  type SubagentDelegationUpdate,
5
5
  } from '../integrations/subagents/protocol.ts';
6
6
  import { advanceRun } from '../engine/transitions.ts';
7
- import {
8
- attachSubagentTranscript,
9
- recordCurrentStepResult,
10
- } from '../engine/step-trace.ts';
7
+ import { recordCurrentStepResult } from '../engine/step-trace.ts';
11
8
  import type { WorkflowStepResult } from '../runtime/step-result.ts';
12
9
  import type { HarnessActionContext as FullHarnessActionContext } from './action-context.ts';
13
- import type { ActiveDelegation, DelegationFailureDetails } from './types.ts';
10
+ import type { ActiveDelegation } from './types.ts';
14
11
  import { resolveStepEffects } from './step-effects.ts';
15
12
 
16
13
  type HarnessActionContext = Pick<
@@ -18,7 +15,6 @@ type HarnessActionContext = Pick<
18
15
  | 'activeDelegation'
19
16
  | 'catalog'
20
17
  | 'cleanupDelegation'
21
- | 'delegationFailures'
22
18
  | 'dependencies'
23
19
  | 'finishDelegation'
24
20
  | 'isSessionActive'
@@ -27,7 +23,6 @@ type HarnessActionContext = Pick<
27
23
  | 'pauseForDelegationFailure'
28
24
  | 'releaseMainAfterCancellation'
29
25
  | 'retainUnconfirmedDelegation'
30
- | 'retryDelegationAfterFailure'
31
26
  | 'run'
32
27
  | 'sessionEpoch'
33
28
  | 'settleAfterTransition'
@@ -70,11 +65,22 @@ function handleDelegationUpdate(
70
65
  ): void {
71
66
  if (this.activeDelegation !== active) return;
72
67
  const progress = [
68
+ update.activity,
73
69
  update.currentTool ? `tool ${update.currentTool}` : undefined,
74
70
  update.toolCount !== undefined ? `${update.toolCount} calls` : undefined,
75
71
  update.tokens !== undefined ? `${update.tokens} tokens` : undefined,
76
72
  ].filter((part): part is string => part !== undefined);
77
73
  active.progress = progress.join(', ') || 'running';
74
+ if (update.detail) {
75
+ const previous = active.activityLog ?? [];
76
+ const replacesPreviousResponse =
77
+ update.detail.startsWith('response: ') &&
78
+ previous.at(-1)?.startsWith('response: ');
79
+ active.activityLog = [
80
+ ...(replacesPreviousResponse ? previous.slice(0, -1) : previous),
81
+ update.detail,
82
+ ].slice(-8);
83
+ }
78
84
  this.updateStatus();
79
85
  }
80
86
 
@@ -128,7 +134,6 @@ async function finishDelegation(
128
134
  return;
129
135
  }
130
136
  this.activeDelegation = undefined;
131
- let terminalFailure: DelegationFailureDetails | undefined;
132
137
  let cleanupAttempted = false;
133
138
 
134
139
  try {
@@ -144,80 +149,15 @@ async function finishDelegation(
144
149
  return;
145
150
  }
146
151
  const terminalAt = this.dependencies.now();
147
- if (
148
- response.requestId === active.requestId &&
149
- (response.agent === undefined || response.agent === active.agent) &&
150
- response.sessionFile &&
151
- active.trustedSessionRoot &&
152
- typeof response.runId === 'string' &&
153
- response.runId &&
154
- response.childIndex === 0
155
- ) {
156
- try {
157
- this.run = attachSubagentTranscript(
158
- this.run,
159
- active.requestId,
160
- {
161
- trustedRoot: active.trustedSessionRoot,
162
- sessionFile: response.sessionFile,
163
- runId: response.runId,
164
- childIndex: response.childIndex,
165
- },
166
- terminalAt,
167
- );
168
- } catch {
169
- // Status evidence is best-effort and cannot alter terminal handling.
170
- }
171
- }
172
152
  const workflow = this.catalog.workflows.get(this.run.workflowId);
173
153
  const step = workflow?.definition.steps[this.run.currentStepId];
174
154
  if (!workflow || !step) {
175
155
  throw new Error('Active workflow configuration is unavailable');
176
156
  }
177
- if (response.status === 'completed') {
178
- const transcriptAudit =
179
- await this.delegationFailures.completedResponseAudit(active, response);
180
- if (!transcriptAudit.verified) {
181
- throw new Error(
182
- `Subagent "${active.agent}" completed without a verifiable terminal transcript: ${transcriptAudit.reason}`,
183
- );
184
- }
185
- if (transcriptAudit.warning) {
186
- throw new Error(
187
- `Subagent "${active.agent}" completed with an unresolved post-completion watchdog warning: ${transcriptAudit.warning}`,
188
- );
189
- }
190
- }
191
- let recoveredTerminalFailure: DelegationFailureDetails | undefined;
192
- if (
193
- response.status !== 'completed' ||
194
- this.delegationFailures.hasContradictoryCompletion(response)
195
- ) {
196
- const failure = await this.delegationFailures.describeDelegationFailure(
197
- active,
198
- response,
199
- );
200
- terminalFailure = failure;
201
- if (
202
- response.status !== 'failed' ||
203
- failure.diagnostic?.completionAfterFailure !== true
204
- ) {
205
- throw new Error(failure.reason);
206
- }
207
- const projectionError = this.delegationFailures.recoveredProjectionError(
208
- active,
209
- response,
210
- failure.diagnostic,
157
+ if (response.status !== 'completed') {
158
+ throw new Error(
159
+ `Workflow worker "${active.agent}" ${response.status.replaceAll('_', ' ')}${response.error ? `: ${response.error}` : ''}`,
211
160
  );
212
- if (projectionError) {
213
- throw new Error(
214
- this.delegationFailures.rejectedRecoveryReason(
215
- failure,
216
- projectionError,
217
- ),
218
- );
219
- }
220
- recoveredTerminalFailure = failure;
221
161
  }
222
162
  const requiredSkillWarning =
223
163
  step.requires.skills.length > 0
@@ -233,15 +173,6 @@ async function finishDelegation(
233
173
  try {
234
174
  serializedResult = await this.dependencies.readDelegatedResult(active);
235
175
  } catch (error) {
236
- if (recoveredTerminalFailure) {
237
- throw new Error(
238
- this.delegationFailures.rejectedRecoveryReason(
239
- recoveredTerminalFailure,
240
- error,
241
- ),
242
- { cause: error },
243
- );
244
- }
245
176
  if (hasErrorCode(error, 'ENOENT')) {
246
177
  throw new Error(
247
178
  `Subagent "${active.agent}" completed without producing the required correlated structured_output result`,
@@ -251,49 +182,12 @@ async function finishDelegation(
251
182
  throw error;
252
183
  }
253
184
 
254
- let result: WorkflowStepResult;
255
- try {
256
- const rawResult: unknown = JSON.parse(serializedResult);
257
- result = parseDelegatedStepResult(rawResult, active.policy);
258
- } catch (error) {
259
- if (recoveredTerminalFailure) {
260
- throw new Error(
261
- this.delegationFailures.rejectedRecoveryReason(
262
- recoveredTerminalFailure,
263
- error,
264
- ),
265
- { cause: error },
266
- );
267
- }
268
- throw error;
269
- }
270
- if (
271
- recoveredTerminalFailure?.diagnostic &&
272
- !this.delegationFailures.completionMatchesResult(
273
- recoveredTerminalFailure.diagnostic,
274
- result,
275
- active.policy,
276
- )
277
- ) {
278
- throw new Error(
279
- this.delegationFailures.rejectedRecoveryReason(
280
- recoveredTerminalFailure,
281
- 'structured_output transcript value does not match the correlated result',
282
- ),
283
- );
284
- }
185
+ const rawResult: unknown = JSON.parse(serializedResult);
186
+ const result: WorkflowStepResult = parseDelegatedStepResult(
187
+ rawResult,
188
+ active.policy,
189
+ );
285
190
  const acceptedAt = terminalAt;
286
- if (recoveredTerminalFailure) {
287
- const isFalsePositive =
288
- recoveredTerminalFailure.diagnostic?.correlation ===
289
- 'successful-output-before-completion';
290
- this.latestContext?.ui.notify(
291
- isFalsePositive
292
- ? `Accepted "${active.stepId}" because the trusted child transcript proved the terminal tool error was a false positive and produced a matching structured result`
293
- : `Accepted "${active.stepId}" because the child resolved an earlier tool failure and produced a valid structured result`,
294
- 'warning',
295
- );
296
- }
297
191
  if (step.gate?.submitOutcome === result.outcome) {
298
192
  this.run = recordCurrentStepResult(this.run, result, acceptedAt);
299
193
  await this.submitGate(
@@ -335,14 +229,7 @@ async function finishDelegation(
335
229
  const reason = error instanceof Error ? error.message : String(error);
336
230
  cleanupAttempted = true;
337
231
  await this.cleanupDelegation(active);
338
- if (!this.retryDelegationAfterFailure(active, terminalFailure, reason)) {
339
- const failureSummary = terminalFailure?.error
340
- ? `Subagent ${terminalFailure.status.replaceAll('_', ' ')}: ${terminalFailure.error}`
341
- : terminalFailure
342
- ? `Subagent ${terminalFailure.status.replaceAll('_', ' ')}`
343
- : reason;
344
- this.pauseForDelegationFailure(reason, failureSummary);
345
- }
232
+ this.pauseForDelegationFailure(reason);
346
233
  } finally {
347
234
  try {
348
235
  if (!cleanupAttempted) await this.cleanupDelegation(active);
@@ -14,11 +14,6 @@ import {
14
14
  createSubagentDelegationClient,
15
15
  type SubagentDelegationClientController,
16
16
  } from '../integrations/subagents/client.ts';
17
- import {
18
- auditCompletedDelegationTranscript,
19
- readDelegationReplayAudit,
20
- readToolFailureDiagnostic,
21
- } from '../integrations/subagents/diagnostics.ts';
22
17
  import {
23
18
  createMainStepRuntime,
24
19
  type MainStepRuntimeController,
@@ -61,9 +56,6 @@ export type WorkflowHarnessDependencies = {
61
56
  readonly requestPlannotatorReview: typeof requestPlannotatorReview;
62
57
  readonly requestPlannotatorReviewStatus: typeof requestPlannotatorReviewStatus;
63
58
  readonly requestPromptGateReview: typeof requestPromptGateReview;
64
- readonly readDelegationReplayAudit: typeof readDelegationReplayAudit;
65
- readonly readToolFailureDiagnostic: typeof readToolFailureDiagnostic;
66
- readonly auditCompletedDelegationTranscript: typeof auditCompletedDelegationTranscript;
67
59
  readonly showWorkflowStatus: typeof showWorkflowStatus;
68
60
  readonly createSubagentClient: (
69
61
  pi: ExtensionAPI,
@@ -150,11 +142,8 @@ const DEFAULT_DEPENDENCIES: WorkflowHarnessDependencies = {
150
142
  requestPlannotatorReview,
151
143
  requestPlannotatorReviewStatus,
152
144
  requestPromptGateReview,
153
- readDelegationReplayAudit,
154
- readToolFailureDiagnostic,
155
- auditCompletedDelegationTranscript,
156
145
  showWorkflowStatus,
157
- createSubagentClient: (pi) => createSubagentDelegationClient(pi.events),
146
+ createSubagentClient: () => createSubagentDelegationClient(),
158
147
  createMainStepRuntime: (pi) => createMainStepRuntime({ pi }),
159
148
  createMutationQueue: createSerialTaskQueue,
160
149
  flushUnwrittenSession,
@@ -63,6 +63,7 @@ function workflowStatusSnapshot(
63
63
  agent: this.activeDelegation.agent,
64
64
  requestId: this.activeDelegation.requestId,
65
65
  progress: this.activeDelegation.progress ?? 'starting',
66
+ activityLog: this.activeDelegation.activityLog ?? [],
66
67
  };
67
68
  } else if (this.mainSteps.activeStepId) {
68
69
  execution = { kind: 'main' };
@@ -15,7 +15,7 @@ import type { MainStepExecution } from '../runtime/main-step-runtime.ts';
15
15
  import type { WorkflowStepResult } from '../runtime/step-result.ts';
16
16
  import type { HarnessActionContext as FullHarnessActionContext } from './action-context.ts';
17
17
  import { createDelegationPlan } from './delegation-plan.ts';
18
- import type { DelegationRecovery, MainStepIdentity } from './types.ts';
18
+ import type { MainStepIdentity } from './types.ts';
19
19
  import { resolveStepEffects } from './step-effects.ts';
20
20
 
21
21
  type HarnessActionContext = Pick<
@@ -50,7 +50,6 @@ export type StepExecutionActions = {
50
50
  launchCurrentStep: (
51
51
  this: HarnessActionContext,
52
52
  workflow: LoadedWorkflow,
53
- recovery?: DelegationRecovery,
54
53
  ) => void;
55
54
  launchMainStep: (
56
55
  this: HarnessActionContext,
@@ -87,7 +86,6 @@ export type StepExecutionActions = {
87
86
  function launchCurrentStep(
88
87
  this: HarnessActionContext,
89
88
  workflow: LoadedWorkflow,
90
- recovery?: DelegationRecovery,
91
89
  ): void {
92
90
  const run = this.run;
93
91
  if (
@@ -106,11 +104,6 @@ function launchCurrentStep(
106
104
  );
107
105
  return;
108
106
  }
109
- if (!step.subagent) {
110
- this.launchMainStep(workflow, run, step);
111
- return;
112
- }
113
-
114
107
  const plan = createDelegationPlan(
115
108
  {
116
109
  workflow,
@@ -118,7 +111,6 @@ function launchCurrentStep(
118
111
  step,
119
112
  sessionEpoch: this.sessionEpoch,
120
113
  latestContext: this.latestContext,
121
- recovery,
122
114
  },
123
115
  this.dependencies,
124
116
  );
@@ -243,6 +235,7 @@ function launchMainStep(
243
235
  outcomes: allowedOutcomes(workflow, run),
244
236
  summaryMaxChars: workflow.definition.summaryMaxChars,
245
237
  ...(step.gate ? { gateSubmitOutcome: step.gate.submitOutcome } : {}),
238
+ ...(step.workspace ? { workspace: structuredClone(step.workspace) } : {}),
246
239
  onTrace: (lines, context) =>
247
240
  this.queueMainStepLog(identity, lines, context),
248
241
  onSettled: (result, context) =>
@@ -1,10 +1,5 @@
1
1
  import type { ExtensionContext } from '@earendil-works/pi-coding-agent';
2
- import type { DelegationReplayAudit } from '../integrations/subagents/diagnostics.ts';
3
- import type {
4
- ChildStepPolicy,
5
- SubagentDelegationStatus,
6
- } from '../integrations/subagents/protocol.ts';
7
- import type { WorkflowHarnessDependencies } from './dependencies.ts';
2
+ import type { ChildStepPolicy } from '../integrations/subagents/protocol.ts';
8
3
 
9
4
  export type ActiveDelegation = {
10
5
  requestId: string;
@@ -16,34 +11,11 @@ export type ActiveDelegation = {
16
11
  policy: ChildStepPolicy;
17
12
  transcriptTask: string;
18
13
  agent: string;
19
- trustedSessionRoot?: string;
20
- broadRecoveryAuthorized: boolean;
21
- recoveryAttemptCount: number;
22
- recoveryFailures: ReadonlyArray<DelegationRecoveryFailure>;
23
14
  progress?: string;
15
+ activityLog?: Array<string>;
24
16
  cancelling?: boolean;
25
17
  };
26
18
 
27
- export type DelegationRecoveryBlocker =
28
- | 'cancelled'
29
- | 'detached'
30
- | 'inconsistent-timeout'
31
- | 'interrupted'
32
- | 'reported-mutation'
33
- | 'stopped';
34
-
35
- export type DelegationFailureDetails = {
36
- reason: string;
37
- status: SubagentDelegationStatus;
38
- error?: string;
39
- exitCode?: number;
40
- recoveryBlocker?: DelegationRecoveryBlocker;
41
- diagnostic?: Awaited<
42
- ReturnType<WorkflowHarnessDependencies['readToolFailureDiagnostic']>
43
- >;
44
- replayAudit?: DelegationReplayAudit;
45
- };
46
-
47
19
  export type MainStepIdentity = {
48
20
  requestId: string;
49
21
  runId: string;
@@ -65,13 +37,3 @@ export type WorkflowStartContext = {
65
37
  skills: () => ReadonlyArray<{ name: string }> | undefined;
66
38
  waitForIdle: () => Promise<void>;
67
39
  };
68
-
69
- export type DelegationRecoveryFailure = {
70
- readonly fingerprint: string;
71
- readonly reason: string;
72
- };
73
-
74
- export type DelegationRecovery = {
75
- readonly attempt: number;
76
- readonly failures: ReadonlyArray<DelegationRecoveryFailure>;
77
- };
package/src/harness.ts CHANGED
@@ -24,10 +24,6 @@ import {
24
24
  import type { MainStepRuntimeController } from './runtime/main-step-runtime.ts';
25
25
  import type { SerialTaskQueueController } from './runtime/serial-task-queue.ts';
26
26
  import type { WorkflowStepResult } from './runtime/step-result.ts';
27
- import {
28
- createDelegationFailureActions,
29
- type DelegationFailureActions,
30
- } from './harness/delegation-failure.ts';
31
27
  import { createEmptyCatalog } from './harness/catalog.ts';
32
28
  import {
33
29
  createWorkflowHarnessDependencies,
@@ -36,8 +32,6 @@ import {
36
32
  import type {
37
33
  ActiveDelegation,
38
34
  ActivePromptReview,
39
- DelegationRecovery,
40
- DelegationFailureDetails,
41
35
  MainStepIdentity,
42
36
  WorkflowStartContext,
43
37
  } from './harness/types.ts';
@@ -79,7 +73,6 @@ const CORE_ACTIONS = createCoreActions();
79
73
  export class WorkflowHarness implements WorkflowCommandController {
80
74
  private readonly pi: ExtensionAPI;
81
75
  private readonly dependencies: WorkflowHarnessDependencies;
82
- private readonly delegationFailures: DelegationFailureActions;
83
76
  private readonly subagents: SubagentDelegationClientController;
84
77
  private readonly mainSteps: MainStepRuntimeController;
85
78
  private catalog: WorkflowCatalog = createEmptyCatalog();
@@ -149,10 +142,8 @@ export class WorkflowHarness implements WorkflowCommandController {
149
142
  LIFECYCLE_ACTIONS.registerLifecycle;
150
143
  private readonly registerPolicy: () => void =
151
144
  LIFECYCLE_ACTIONS.registerPolicy;
152
- private readonly launchCurrentStep: (
153
- workflow: LoadedWorkflow,
154
- recovery?: DelegationRecovery,
155
- ) => void = STEP_EXECUTION_ACTIONS.launchCurrentStep;
145
+ private readonly launchCurrentStep: (workflow: LoadedWorkflow) => void =
146
+ STEP_EXECUTION_ACTIONS.launchCurrentStep;
156
147
  private readonly launchMainStep: (
157
148
  workflow: LoadedWorkflow,
158
149
  run: WorkflowRun,
@@ -200,11 +191,6 @@ export class WorkflowHarness implements WorkflowCommandController {
200
191
  private readonly cleanupDelegation: (
201
192
  active: ActiveDelegation,
202
193
  ) => Promise<void> = DELEGATION_CONTROL_ACTIONS.cleanupDelegation;
203
- private readonly retryDelegationAfterFailure: (
204
- active: ActiveDelegation,
205
- failure: DelegationFailureDetails | undefined,
206
- reason: string,
207
- ) => boolean = DELEGATION_CONTROL_ACTIONS.retryDelegationAfterFailure;
208
194
  private readonly pauseForDelegationFailure: (
209
195
  reason: string,
210
196
  failureSummary?: string,
@@ -298,7 +284,6 @@ export class WorkflowHarness implements WorkflowCommandController {
298
284
  ) {
299
285
  this.pi = pi;
300
286
  this.dependencies = createWorkflowHarnessDependencies(dependencyOverrides);
301
- this.delegationFailures = createDelegationFailureActions(this.dependencies);
302
287
  this.statusShortcut = statusShortcut;
303
288
  this.statusShortcutLabel = formatShortcutLabel(statusShortcut);
304
289
  this.subagents = this.dependencies.createSubagentClient(pi);
package/src/index.ts CHANGED
@@ -3,7 +3,6 @@ import type { KeyId } from '@earendil-works/pi-tui';
3
3
  import { defaultUserWorkflowDirectory, loadSettings } from './config/load.ts';
4
4
  import { WorkflowHarness } from './harness.ts';
5
5
  import { registerSubagentChildRuntime } from './integrations/subagents/child-runtime.ts';
6
- import { isSubagentRuntimeName } from './integrations/subagents/protocol.ts';
7
6
 
8
7
  /**
9
8
  * Asynchronous entry point accepted by Pi's extension loader.
@@ -25,7 +24,6 @@ export type PiWorkflowsExtensionDependencies = {
25
24
  readonly loadSettings: typeof loadSettings;
26
25
  readonly userWorkflowDirectory: () => string;
27
26
  readonly runtimeEnvironment: () => PiWorkflowsRuntimeEnvironment;
28
- readonly isSubagentRuntimeName: typeof isSubagentRuntimeName;
29
27
  readonly registerChildRuntime: (pi: ExtensionAPI, childAgent: string) => void;
30
28
  readonly createHarness: (pi: ExtensionAPI, statusShortcut: KeyId) => void;
31
29
  };
@@ -34,10 +32,9 @@ const DEFAULT_DEPENDENCIES = {
34
32
  loadSettings,
35
33
  userWorkflowDirectory: defaultUserWorkflowDirectory,
36
34
  runtimeEnvironment: (): PiWorkflowsRuntimeEnvironment => ({
37
- isSubagentChild: process.env.PI_SUBAGENT_CHILD === '1',
38
- childAgent: process.env.PI_SUBAGENT_CHILD_AGENT?.trim(),
35
+ isSubagentChild: process.env.PI_WORKFLOWS_CHILD === '1',
36
+ childAgent: process.env.PI_WORKFLOWS_CHILD_AGENT?.trim(),
39
37
  }),
40
- isSubagentRuntimeName,
41
38
  registerChildRuntime: (pi, childAgent): void => {
42
39
  registerSubagentChildRuntime(pi, { childAgent });
43
40
  },
@@ -59,10 +56,8 @@ export function createPiWorkflowsExtension(
59
56
  return async (pi): Promise<void> => {
60
57
  const environment = dependencies.runtimeEnvironment();
61
58
 
62
- if (environment.isSubagentChild) {
63
- if (dependencies.isSubagentRuntimeName(environment.childAgent)) {
64
- dependencies.registerChildRuntime(pi, environment.childAgent);
65
- }
59
+ if (environment.isSubagentChild && environment.childAgent) {
60
+ dependencies.registerChildRuntime(pi, environment.childAgent);
66
61
  return;
67
62
  }
68
63