@wichayutdew/pi-workflows 2.5.1 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -1
- package/dist/index.js +1315 -2467
- package/examples/starter-kit/agents/planner.md +11 -0
- package/examples/starter-kit/agents/reviewer.md +10 -0
- package/examples/starter-kit/agents/scout.md +10 -0
- package/examples/starter-kit/agents/worker.md +11 -0
- package/examples/starter-kit/agents/workspace-preparer.md +10 -0
- package/examples/starter-kit/investigate.workflow.yaml +84 -0
- package/examples/starter-kit/jira.workflow.yaml +75 -0
- package/examples/starter-kit/mr-comment.workflow.yaml +86 -93
- package/examples/starter-kit/mr-review.workflow.yaml +52 -88
- package/examples/starter-kit/settings.yaml +4 -0
- package/examples/starter-kit/steps/investigate/investigate.md +40 -0
- package/examples/starter-kit/steps/investigate/retrieve.md +28 -0
- package/examples/starter-kit/steps/investigate/validate.md +20 -0
- package/examples/starter-kit/steps/jira/create.md +25 -0
- package/examples/starter-kit/steps/jira/draft.md +18 -0
- package/examples/starter-kit/steps/jira/plan.md +30 -0
- package/examples/starter-kit/steps/mr-comment/checkout-source.md +14 -0
- package/examples/starter-kit/steps/mr-comment/fetch.md +11 -28
- package/examples/starter-kit/steps/mr-comment/implement.md +9 -26
- package/examples/starter-kit/steps/mr-comment/plan.md +46 -55
- package/examples/starter-kit/steps/mr-comment/publish.md +11 -31
- package/examples/starter-kit/steps/mr-comment/verify.md +7 -34
- package/examples/starter-kit/steps/mr-review/fetch.md +13 -21
- package/examples/starter-kit/steps/mr-review/publish-approved.md +18 -0
- package/examples/starter-kit/steps/mr-review/review-for-approval.md +53 -0
- package/examples/starter-kit/steps/mr-review/verify-published.md +16 -0
- package/examples/starter-kit/steps/shared/prepare-workspace.md +11 -89
- package/examples/starter-kit/steps/shared/publish-remote.md +16 -0
- package/examples/starter-kit/steps/ticket/implement.md +10 -23
- package/examples/starter-kit/steps/ticket/plan.md +49 -98
- package/examples/starter-kit/steps/ticket/verify.md +14 -65
- package/examples/starter-kit/steps/work/implement.md +11 -22
- package/examples/starter-kit/steps/work/plan.md +43 -59
- package/examples/starter-kit/steps/work/verify.md +14 -25
- package/examples/starter-kit/ticket.workflow.yaml +57 -61
- package/examples/starter-kit/work.workflow.yaml +49 -57
- package/package.json +9 -19
- package/schemas/workflow.schema.json +63 -15
- package/scripts/patch-herdr-agent-state.mjs +36 -0
- package/src/agents/profile.ts +98 -0
- package/src/config/ceiling.ts +0 -82
- package/src/config/types.ts +15 -53
- package/src/config/validation/settings.ts +2 -14
- package/src/config/validation/step.ts +129 -8
- package/src/config/validation/workflow.ts +1 -10
- package/src/engine/run-workflow-validation.ts +0 -3
- package/src/engine/state-types.ts +1 -1
- package/src/harness/action-context.ts +1 -13
- package/src/harness/artifact-contract.ts +46 -0
- package/src/harness/delegation-control-actions.ts +4 -63
- package/src/harness/delegation-plan.ts +26 -80
- package/src/harness/delegation-response-actions.ts +22 -135
- package/src/harness/dependencies.ts +1 -12
- package/src/harness/gate-submission-action.ts +28 -0
- package/src/harness/status-actions.ts +20 -0
- package/src/harness/step-execution-actions.ts +2 -9
- package/src/harness/types.ts +2 -40
- package/src/harness.ts +2 -17
- package/src/herdr-workflow-state.ts +65 -0
- package/src/index.ts +4 -9
- package/src/integrations/subagents/child-policy-validation.ts +6 -7
- package/src/integrations/subagents/child-runtime-dependencies.ts +1 -1
- package/src/integrations/subagents/child-runtime-policy.ts +1 -7
- package/src/integrations/subagents/child-runtime.ts +18 -9
- package/src/integrations/subagents/client.ts +240 -98
- package/src/integrations/subagents/protocol-events.ts +32 -15
- package/src/integrations/subagents/protocol.ts +1 -1
- package/src/preflight.ts +0 -8
- package/src/prompt/main-workflow-notice.ts +8 -15
- package/src/prompt/step-task.ts +7 -6
- package/src/workflow-status/format-status.ts +5 -1
- package/src/workflow-status/render-step-detail.ts +94 -0
- package/src/workflow-status/types.ts +1 -0
- package/src/workflow-status/view.ts +49 -14
- package/agents/step.md +0 -32
- package/examples/mr-comments.workflow.yaml +0 -125
- package/examples/prompts/mr-comments/implement.md +0 -17
- package/examples/prompts/mr-comments/inspect.md +0 -5
- package/examples/prompts/mr-comments/plan.md +0 -54
- package/examples/prompts/mr-comments/verify.md +0 -9
- package/examples/settings.yaml +0 -27
- package/examples/starter-kit/steps/mr-review/publish.md +0 -48
- package/examples/starter-kit/steps/mr-review/review.md +0 -76
- package/examples/starter-kit/steps/mr-review/verify.md +0 -35
- package/src/config/validation/subagent.ts +0 -288
- package/src/harness/delegation-failure.ts +0 -248
- package/src/harness/delegation-recovery-validation.ts +0 -161
- package/src/harness/delegation-retry-policy.ts +0 -120
- package/src/integrations/subagents/client-delegation.ts +0 -181
- package/src/integrations/subagents/client-messages.ts +0 -66
- package/src/integrations/subagents/client-types.ts +0 -36
- package/src/integrations/subagents/diagnostic-format.ts +0 -45
- package/src/integrations/subagents/diagnostic-text.ts +0 -114
- package/src/integrations/subagents/diagnostic-types.ts +0 -83
- package/src/integrations/subagents/diagnostics.ts +0 -26
- package/src/integrations/subagents/failure-correlation.ts +0 -285
- package/src/integrations/subagents/failure-transcript.ts +0 -252
- package/src/integrations/subagents/hidden-bash-failure.ts +0 -98
- package/src/integrations/subagents/replay-audit.ts +0 -146
- package/src/integrations/subagents/replay-safety.ts +0 -67
- package/src/integrations/subagents/session-diagnostics.ts +0 -357
|
@@ -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 {
|
|
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) =>
|
package/src/harness/types.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import type { ExtensionContext } from '@earendil-works/pi-coding-agent';
|
|
2
|
-
import type {
|
|
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
|
-
|
|
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);
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import net from 'node:net';
|
|
2
|
+
import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
3
|
+
|
|
4
|
+
const source = 'herdr:pi-workflows';
|
|
5
|
+
|
|
6
|
+
type WorkflowState = {
|
|
7
|
+
state: 'working' | 'blocked' | 'completed' | 'interrupted';
|
|
8
|
+
workflowId?: string;
|
|
9
|
+
stepId?: string;
|
|
10
|
+
message?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default function herdrWorkflowState(pi: ExtensionAPI): void {
|
|
14
|
+
const socketPath = process.env.HERDR_SOCKET_PATH;
|
|
15
|
+
const paneId = process.env.HERDR_PANE_ID;
|
|
16
|
+
if (process.env.HERDR_ENV !== '1' || !socketPath || !paneId) return;
|
|
17
|
+
|
|
18
|
+
let seq = Date.now() * 1000;
|
|
19
|
+
let last = '';
|
|
20
|
+
pi.events.on('pi-workflows:state', (data: unknown) => {
|
|
21
|
+
if (!data || typeof data !== 'object') return;
|
|
22
|
+
const event = data as WorkflowState;
|
|
23
|
+
if (
|
|
24
|
+
!['working', 'blocked', 'completed', 'interrupted'].includes(event.state)
|
|
25
|
+
)
|
|
26
|
+
return;
|
|
27
|
+
const state =
|
|
28
|
+
event.state === 'working'
|
|
29
|
+
? 'working'
|
|
30
|
+
: event.state === 'blocked'
|
|
31
|
+
? 'blocked'
|
|
32
|
+
: 'idle';
|
|
33
|
+
const message =
|
|
34
|
+
event.message ??
|
|
35
|
+
(event.workflowId
|
|
36
|
+
? `Workflow "${event.workflowId}" ${event.state}`
|
|
37
|
+
: undefined);
|
|
38
|
+
const fingerprint = `${state}:${message ?? ''}`;
|
|
39
|
+
if (fingerprint === last) return;
|
|
40
|
+
last = fingerprint;
|
|
41
|
+
const request = {
|
|
42
|
+
id: `${source}:${Date.now()}:${++seq}`,
|
|
43
|
+
method: 'pane.report_agent',
|
|
44
|
+
params: {
|
|
45
|
+
pane_id: paneId,
|
|
46
|
+
source,
|
|
47
|
+
agent: 'pi-workflows',
|
|
48
|
+
state,
|
|
49
|
+
message,
|
|
50
|
+
seq,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
const socket = net.createConnection(socketPath);
|
|
54
|
+
const timeout = setTimeout(() => socket.destroy(), 1500);
|
|
55
|
+
timeout.unref();
|
|
56
|
+
socket.on('connect', () => socket.write(`${JSON.stringify(request)}\n`));
|
|
57
|
+
socket.on('data', () => socket.destroy());
|
|
58
|
+
socket.on('close', () => {
|
|
59
|
+
clearTimeout(timeout);
|
|
60
|
+
});
|
|
61
|
+
socket.on('error', () => {
|
|
62
|
+
clearTimeout(timeout);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}
|
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.
|
|
38
|
-
childAgent: process.env.
|
|
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
|
-
|
|
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
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { dirname, isAbsolute, resolve } from 'node:path';
|
|
2
|
-
import {
|
|
2
|
+
import { AGENT_PROFILE_NAME_PATTERN } from '../../config/types.ts';
|
|
3
3
|
import {
|
|
4
4
|
DEFAULT_CHILD_POLICY_ENVIRONMENT,
|
|
5
5
|
isSafeStepCapabilityPath,
|
|
@@ -61,11 +61,10 @@ const requiredString = (
|
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
63
|
* Returns whether a name follows the runtime naming contract used by
|
|
64
|
-
*
|
|
64
|
+
* workflow agent profiles.
|
|
65
65
|
*/
|
|
66
|
-
export const
|
|
67
|
-
name
|
|
68
|
-
): name is string => Boolean(name && SUBAGENT_RUNTIME_NAME_PATTERN.test(name));
|
|
66
|
+
export const isAgentProfileName = (name: string | undefined): name is string =>
|
|
67
|
+
Boolean(name && AGENT_PROFILE_NAME_PATTERN.test(name));
|
|
69
68
|
|
|
70
69
|
const rejectUnknownProperties = (
|
|
71
70
|
value: Readonly<Record<string, unknown>>,
|
|
@@ -115,8 +114,8 @@ const parseIdentityAndPaths = (
|
|
|
115
114
|
if (!POLICY_DIGEST_PATTERN.test(policyDigest)) {
|
|
116
115
|
throw new Error('child policy digest is invalid');
|
|
117
116
|
}
|
|
118
|
-
if (!
|
|
119
|
-
throw new Error('child policy agent is not a valid
|
|
117
|
+
if (!isAgentProfileName(agent)) {
|
|
118
|
+
throw new Error('child policy agent is not a valid agent profile name');
|
|
120
119
|
}
|
|
121
120
|
if (!CAPABILITY_TOKEN_PATTERN.test(capabilityToken)) {
|
|
122
121
|
throw new Error('child policy capability token is invalid');
|
|
@@ -41,7 +41,7 @@ export const DEFAULT_CHILD_RUNTIME_DEPENDENCIES = {
|
|
|
41
41
|
createUniqueId: randomUUID,
|
|
42
42
|
currentWorkingDirectory: () => process.cwd(),
|
|
43
43
|
environmentChildAgent: () =>
|
|
44
|
-
process.env.
|
|
44
|
+
process.env.PI_WORKFLOWS_CHILD_AGENT?.trim() || undefined,
|
|
45
45
|
temporaryDirectory: tmpdir,
|
|
46
46
|
tokensAreEqual,
|
|
47
47
|
} as const satisfies SubagentChildRuntimeDependencies;
|
|
@@ -8,13 +8,7 @@ import type { ChildStepPolicy } from './child-policy-types.ts';
|
|
|
8
8
|
export const childPolicyStep = (policy: ChildStepPolicy): WorkflowStep => ({
|
|
9
9
|
title: policy.stepTitle,
|
|
10
10
|
prompt: { inline: 'Delegated workflow step' },
|
|
11
|
-
|
|
12
|
-
agent: policy.agent,
|
|
13
|
-
context: 'fresh',
|
|
14
|
-
timeoutMs: 900_000,
|
|
15
|
-
artifacts: false,
|
|
16
|
-
retryToolFailures: false,
|
|
17
|
-
},
|
|
11
|
+
agent: { name: policy.agent },
|
|
18
12
|
permissions: policy.permissions,
|
|
19
13
|
requires: { tools: [], extensions: [], skills: [] },
|
|
20
14
|
transitions: {},
|
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
InputEvent,
|
|
4
4
|
InputEventResult,
|
|
5
5
|
} from '@earendil-works/pi-coding-agent';
|
|
6
|
+
import { Type } from 'typebox';
|
|
6
7
|
import { invalidCompletionCallIds } from '../../policy/completion-batch.ts';
|
|
7
8
|
import { freezeToolInput } from '../../policy/immutable-input.ts';
|
|
8
9
|
import { authorizeToolCall, resolveActiveTools } from '../../policy/tools.ts';
|
|
@@ -24,7 +25,6 @@ import type {
|
|
|
24
25
|
} from './child-runtime-types.ts';
|
|
25
26
|
import { extractChildPolicy } from './child-policy-envelope.ts';
|
|
26
27
|
import type { ChildStepPolicy } from './child-policy-types.ts';
|
|
27
|
-
import { isSubagentRuntimeName } from './child-policy-validation.ts';
|
|
28
28
|
|
|
29
29
|
export { CHILD_COMPLETION_TOOL } from './child-runtime-completion.ts';
|
|
30
30
|
export type {
|
|
@@ -85,6 +85,21 @@ export const registerSubagentChildRuntime = (
|
|
|
85
85
|
const childAgent = resolveChildAgent(options, dependencies);
|
|
86
86
|
let state = INITIAL_STATE;
|
|
87
87
|
|
|
88
|
+
pi.registerTool({
|
|
89
|
+
name: CHILD_COMPLETION_TOOL,
|
|
90
|
+
label: 'Complete Workflow Step',
|
|
91
|
+
description: 'Return the one structured result for this workflow step',
|
|
92
|
+
parameters: Type.Object({ value: Type.Any() }),
|
|
93
|
+
executionMode: 'sequential',
|
|
94
|
+
execute: async () => ({
|
|
95
|
+
content: [
|
|
96
|
+
{ type: 'text' as const, text: 'Captured workflow step result.' },
|
|
97
|
+
],
|
|
98
|
+
details: {},
|
|
99
|
+
terminate: true,
|
|
100
|
+
}),
|
|
101
|
+
});
|
|
102
|
+
|
|
88
103
|
pi.on('input', (event) => {
|
|
89
104
|
let extracted;
|
|
90
105
|
try {
|
|
@@ -104,11 +119,7 @@ export const registerSubagentChildRuntime = (
|
|
|
104
119
|
}
|
|
105
120
|
|
|
106
121
|
try {
|
|
107
|
-
if (!
|
|
108
|
-
throw new Error(
|
|
109
|
-
'child agent does not match the delegated workflow policy',
|
|
110
|
-
);
|
|
111
|
-
}
|
|
122
|
+
if (!childAgent) throw new Error('workflow worker agent is unavailable');
|
|
112
123
|
verifyChildWorkingDirectory(extracted.policy, dependencies);
|
|
113
124
|
verifyChildCapability({
|
|
114
125
|
policy: extracted.policy,
|
|
@@ -117,9 +128,7 @@ export const registerSubagentChildRuntime = (
|
|
|
117
128
|
});
|
|
118
129
|
const profileTools = new Set(pi.getActiveTools());
|
|
119
130
|
if (!profileTools.has(CHILD_COMPLETION_TOOL)) {
|
|
120
|
-
throw new Error(
|
|
121
|
-
'pi-subagents structured_output completion is unavailable',
|
|
122
|
-
);
|
|
131
|
+
throw new Error('workflow worker completion tool is unavailable');
|
|
123
132
|
}
|
|
124
133
|
const effectiveTools = new Set(
|
|
125
134
|
resolveActiveTools(
|