@cat-factory/orchestration 0.37.0 → 0.37.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/dist/modules/execution/ExecutionService.d.ts +2 -51
- package/dist/modules/execution/ExecutionService.d.ts.map +1 -1
- package/dist/modules/execution/ExecutionService.js +32 -131
- package/dist/modules/execution/ExecutionService.js.map +1 -1
- package/dist/modules/execution/StepGraph.d.ts +70 -0
- package/dist/modules/execution/StepGraph.d.ts.map +1 -0
- package/dist/modules/execution/StepGraph.js +124 -0
- package/dist/modules/execution/StepGraph.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Clock, ExecutionInstance, PipelineStep } from '@cat-factory/kernel';
|
|
2
|
+
/**
|
|
3
|
+
* The pure, synchronous step/cursor mutators of the execution engine — the dependency-free
|
|
4
|
+
* inner layer of the run state-machine spine. Every method operates on a passed
|
|
5
|
+
* {@link PipelineStep} / {@link ExecutionInstance} and mutates it in place; the only
|
|
6
|
+
* collaborator is the {@link Clock} the timing stamps come from. Lifted verbatim out of
|
|
7
|
+
* `ExecutionService` so the engine AND every gate controller share ONE definition of "what
|
|
8
|
+
* does it mean to start / finish / park / reset a step" instead of each receiving the
|
|
9
|
+
* mutators as a loose callback bag.
|
|
10
|
+
*
|
|
11
|
+
* Deliberately holds NO repositories, event publisher or runner — those async,
|
|
12
|
+
* instance-persisting concerns live in {@link RunStateMachine}, which composes this. Keeping
|
|
13
|
+
* the pure mutators separate is what lets a controller depend on the timing rules without
|
|
14
|
+
* pulling in the whole persistence/emission surface.
|
|
15
|
+
*/
|
|
16
|
+
export declare class StepGraph {
|
|
17
|
+
private readonly clock;
|
|
18
|
+
constructor(clock: Clock);
|
|
19
|
+
/** Transition a step into `working`, stamping its start time once, and resume its clock. */
|
|
20
|
+
startStep(step: PipelineStep): void;
|
|
21
|
+
/**
|
|
22
|
+
* Transition a step into `done`, stamping its finish time once. Set-once so the
|
|
23
|
+
* approval-gate flow (which re-asserts `done` after a human approves, long after
|
|
24
|
+
* the agent actually finished) keeps the agent's true completion time, and so a
|
|
25
|
+
* replay doesn't move it. With {@link startStep}'s `startedAt` this yields the
|
|
26
|
+
* step's execution duration. A step finished directly out of a parked approval
|
|
27
|
+
* stopped *working* when it parked, so its duration is billed to the pause instant
|
|
28
|
+
* ({@link pauseStepForInput}), not the (later) moment the human decided.
|
|
29
|
+
*/
|
|
30
|
+
finishStep(step: PipelineStep): void;
|
|
31
|
+
/**
|
|
32
|
+
* Park a step on a human decision and freeze its duration clock. Records when the
|
|
33
|
+
* step stopped working (`pausedAt`) so elapsed time no longer accrues while it waits
|
|
34
|
+
* for input — the symmetric counterpart of the terminal freeze on `finishedAt`.
|
|
35
|
+
* Set-once (a Workflows replay re-parking keeps the original instant); cleared when
|
|
36
|
+
* the step resumes ({@link startStep}) or finishes ({@link finishStep}).
|
|
37
|
+
*/
|
|
38
|
+
pauseStepForInput(step: PipelineStep): void;
|
|
39
|
+
/**
|
|
40
|
+
* Reset a step so the durable driver re-runs it from scratch: clear its live container
|
|
41
|
+
* job handle (so it dispatches FRESH work rather than re-attaching to a stale/evicted
|
|
42
|
+
* job), timings, approval, subtasks and prior output.
|
|
43
|
+
*/
|
|
44
|
+
resetStepForRerun(step: PipelineStep): void;
|
|
45
|
+
/**
|
|
46
|
+
* Loop a producer step back for rework and re-run every step from it up to and
|
|
47
|
+
* including the companion at `companionIndex`: each one is reset (crucially clearing
|
|
48
|
+
* stale container job handles so an intermediate container step re-dispatches fresh
|
|
49
|
+
* work instead of re-attaching to its evicted job), the producer is handed the
|
|
50
|
+
* `rework` feedback + started, and the instance cursor is moved back to the producer.
|
|
51
|
+
* Shared by the automatic companion loop and the human "request changes" path.
|
|
52
|
+
*/
|
|
53
|
+
rerunProducerThrough(instance: ExecutionInstance, producerIndex: number, companionIndex: number, rework: NonNullable<PipelineStep['rework']>): void;
|
|
54
|
+
/**
|
|
55
|
+
* The index of the nearest preceding step a companion grades (one of its target
|
|
56
|
+
* producer kinds), or -1 when none precedes it. The single producer-search used by the
|
|
57
|
+
* automatic companion loop, the human "request changes" redirect, and the iteration-cap
|
|
58
|
+
* extra-round resolution.
|
|
59
|
+
*/
|
|
60
|
+
companionProducerIndex(instance: ExecutionInstance, companionIndex: number): number;
|
|
61
|
+
/**
|
|
62
|
+
* Loop a companion's producer back for one more automatic rework cycle: charge one
|
|
63
|
+
* attempt against the budget, then re-run the producer (and any intermediate steps) up
|
|
64
|
+
* to and including the companion so it re-grades. Shared by the automatic
|
|
65
|
+
* below-threshold loop and the human-granted extra round, so both consume the budget
|
|
66
|
+
* identically.
|
|
67
|
+
*/
|
|
68
|
+
loopCompanionProducer(instance: ExecutionInstance, companionIndex: number, rework: NonNullable<PipelineStep['rework']>): void;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=StepGraph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StepGraph.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/StepGraph.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAGjF;;;;;;;;;;;;;GAaG;AACH,qBAAa,SAAS;IACR,OAAO,CAAC,QAAQ,CAAC,KAAK;IAAlC,YAA6B,KAAK,EAAE,KAAK,EAAI;IAE7C,4FAA4F;IAC5F,SAAS,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAMlC;IAED;;;;;;;;OAQG;IACH,UAAU,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAInC;IAED;;;;;;OAMG;IACH,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAG1C;IAED;;;;OAIG;IACH,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAc1C;IAED;;;;;;;OAOG;IACH,oBAAoB,CAClB,QAAQ,EAAE,iBAAiB,EAC3B,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,WAAW,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,GAC1C,IAAI,CAQN;IAED;;;;;OAKG;IACH,sBAAsB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAMlF;IAED;;;;;;OAMG;IACH,qBAAqB,CACnB,QAAQ,EAAE,iBAAiB,EAC3B,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,WAAW,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,GAC1C,IAAI,CAMN;CACF"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { companionTargets } from '@cat-factory/agents';
|
|
2
|
+
/**
|
|
3
|
+
* The pure, synchronous step/cursor mutators of the execution engine — the dependency-free
|
|
4
|
+
* inner layer of the run state-machine spine. Every method operates on a passed
|
|
5
|
+
* {@link PipelineStep} / {@link ExecutionInstance} and mutates it in place; the only
|
|
6
|
+
* collaborator is the {@link Clock} the timing stamps come from. Lifted verbatim out of
|
|
7
|
+
* `ExecutionService` so the engine AND every gate controller share ONE definition of "what
|
|
8
|
+
* does it mean to start / finish / park / reset a step" instead of each receiving the
|
|
9
|
+
* mutators as a loose callback bag.
|
|
10
|
+
*
|
|
11
|
+
* Deliberately holds NO repositories, event publisher or runner — those async,
|
|
12
|
+
* instance-persisting concerns live in {@link RunStateMachine}, which composes this. Keeping
|
|
13
|
+
* the pure mutators separate is what lets a controller depend on the timing rules without
|
|
14
|
+
* pulling in the whole persistence/emission surface.
|
|
15
|
+
*/
|
|
16
|
+
export class StepGraph {
|
|
17
|
+
clock;
|
|
18
|
+
constructor(clock) {
|
|
19
|
+
this.clock = clock;
|
|
20
|
+
}
|
|
21
|
+
/** Transition a step into `working`, stamping its start time once, and resume its clock. */
|
|
22
|
+
startStep(step) {
|
|
23
|
+
step.state = 'working';
|
|
24
|
+
if (step.startedAt == null)
|
|
25
|
+
step.startedAt = this.clock.now();
|
|
26
|
+
// (Re)entering `working` means the step is no longer parked on a human: resume
|
|
27
|
+
// its duration clock (see {@link pauseStepForInput}).
|
|
28
|
+
step.pausedAt = null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Transition a step into `done`, stamping its finish time once. Set-once so the
|
|
32
|
+
* approval-gate flow (which re-asserts `done` after a human approves, long after
|
|
33
|
+
* the agent actually finished) keeps the agent's true completion time, and so a
|
|
34
|
+
* replay doesn't move it. With {@link startStep}'s `startedAt` this yields the
|
|
35
|
+
* step's execution duration. A step finished directly out of a parked approval
|
|
36
|
+
* stopped *working* when it parked, so its duration is billed to the pause instant
|
|
37
|
+
* ({@link pauseStepForInput}), not the (later) moment the human decided.
|
|
38
|
+
*/
|
|
39
|
+
finishStep(step) {
|
|
40
|
+
step.state = 'done';
|
|
41
|
+
if (step.finishedAt == null)
|
|
42
|
+
step.finishedAt = step.pausedAt ?? this.clock.now();
|
|
43
|
+
step.pausedAt = null;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Park a step on a human decision and freeze its duration clock. Records when the
|
|
47
|
+
* step stopped working (`pausedAt`) so elapsed time no longer accrues while it waits
|
|
48
|
+
* for input — the symmetric counterpart of the terminal freeze on `finishedAt`.
|
|
49
|
+
* Set-once (a Workflows replay re-parking keeps the original instant); cleared when
|
|
50
|
+
* the step resumes ({@link startStep}) or finishes ({@link finishStep}).
|
|
51
|
+
*/
|
|
52
|
+
pauseStepForInput(step) {
|
|
53
|
+
step.state = 'waiting_decision';
|
|
54
|
+
if (step.pausedAt == null)
|
|
55
|
+
step.pausedAt = this.clock.now();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Reset a step so the durable driver re-runs it from scratch: clear its live container
|
|
59
|
+
* job handle (so it dispatches FRESH work rather than re-attaching to a stale/evicted
|
|
60
|
+
* job), timings, approval, subtasks and prior output.
|
|
61
|
+
*/
|
|
62
|
+
resetStepForRerun(step) {
|
|
63
|
+
step.state = 'pending';
|
|
64
|
+
step.startedAt = null;
|
|
65
|
+
step.finishedAt = null;
|
|
66
|
+
step.pausedAt = null;
|
|
67
|
+
step.jobId = undefined;
|
|
68
|
+
step.approval = null;
|
|
69
|
+
step.subtasks = undefined;
|
|
70
|
+
step.progress = 0;
|
|
71
|
+
step.output = undefined;
|
|
72
|
+
// Drop the prior run's structured output too, so a re-run that produces no `custom`
|
|
73
|
+
// doesn't leave stale JSON for the `generic-structured` result view to render.
|
|
74
|
+
step.custom = undefined;
|
|
75
|
+
step.rework = undefined;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Loop a producer step back for rework and re-run every step from it up to and
|
|
79
|
+
* including the companion at `companionIndex`: each one is reset (crucially clearing
|
|
80
|
+
* stale container job handles so an intermediate container step re-dispatches fresh
|
|
81
|
+
* work instead of re-attaching to its evicted job), the producer is handed the
|
|
82
|
+
* `rework` feedback + started, and the instance cursor is moved back to the producer.
|
|
83
|
+
* Shared by the automatic companion loop and the human "request changes" path.
|
|
84
|
+
*/
|
|
85
|
+
rerunProducerThrough(instance, producerIndex, companionIndex, rework) {
|
|
86
|
+
for (let i = producerIndex; i <= companionIndex; i++) {
|
|
87
|
+
this.resetStepForRerun(instance.steps[i]);
|
|
88
|
+
}
|
|
89
|
+
const producer = instance.steps[producerIndex];
|
|
90
|
+
producer.rework = rework;
|
|
91
|
+
this.startStep(producer);
|
|
92
|
+
instance.currentStep = producerIndex;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The index of the nearest preceding step a companion grades (one of its target
|
|
96
|
+
* producer kinds), or -1 when none precedes it. The single producer-search used by the
|
|
97
|
+
* automatic companion loop, the human "request changes" redirect, and the iteration-cap
|
|
98
|
+
* extra-round resolution.
|
|
99
|
+
*/
|
|
100
|
+
companionProducerIndex(instance, companionIndex) {
|
|
101
|
+
const targets = companionTargets(instance.steps[companionIndex].agentKind);
|
|
102
|
+
for (let i = companionIndex - 1; i >= 0; i--) {
|
|
103
|
+
if (targets.includes(instance.steps[i].agentKind))
|
|
104
|
+
return i;
|
|
105
|
+
}
|
|
106
|
+
return -1;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Loop a companion's producer back for one more automatic rework cycle: charge one
|
|
110
|
+
* attempt against the budget, then re-run the producer (and any intermediate steps) up
|
|
111
|
+
* to and including the companion so it re-grades. Shared by the automatic
|
|
112
|
+
* below-threshold loop and the human-granted extra round, so both consume the budget
|
|
113
|
+
* identically.
|
|
114
|
+
*/
|
|
115
|
+
loopCompanionProducer(instance, companionIndex, rework) {
|
|
116
|
+
const companionStep = instance.steps[companionIndex];
|
|
117
|
+
const producerIndex = this.companionProducerIndex(instance, companionIndex);
|
|
118
|
+
companionStep.companion.attempts += 1;
|
|
119
|
+
this.rerunProducerThrough(instance, producerIndex, companionIndex, rework);
|
|
120
|
+
if (instance.status === 'blocked')
|
|
121
|
+
instance.status = 'running';
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=StepGraph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StepGraph.js","sourceRoot":"","sources":["../../../src/modules/execution/StepGraph.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/orchestration",
|
|
3
|
-
"version": "0.37.
|
|
3
|
+
"version": "0.37.1",
|
|
4
4
|
"description": "Delivery-workflow engine for the Agent Architecture Board (execution, bootstrap, pipelines, board, boardScan, requirements, and composition root).",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|