@cat-factory/orchestration 0.155.0 → 0.156.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/dist/modules/execution/AgentContextBuilder.d.ts +16 -18
- package/dist/modules/execution/AgentContextBuilder.d.ts.map +1 -1
- package/dist/modules/execution/AgentContextBuilder.js +28 -33
- package/dist/modules/execution/AgentContextBuilder.js.map +1 -1
- package/dist/modules/execution/RalphController.d.ts +9 -3
- package/dist/modules/execution/RalphController.d.ts.map +1 -1
- package/dist/modules/execution/RalphController.js +43 -13
- package/dist/modules/execution/RalphController.js.map +1 -1
- package/dist/modules/execution/StepGraph.d.ts.map +1 -1
- package/dist/modules/execution/StepGraph.js +9 -0
- package/dist/modules/execution/StepGraph.js.map +1 -1
- package/dist/modules/execution/ralph.logic.d.ts +65 -4
- package/dist/modules/execution/ralph.logic.d.ts.map +1 -1
- package/dist/modules/execution/ralph.logic.js +89 -2
- package/dist/modules/execution/ralph.logic.js.map +1 -1
- package/dist/modules/execution/retry.logic.d.ts.map +1 -1
- package/dist/modules/execution/retry.logic.js +11 -0
- package/dist/modules/execution/retry.logic.js.map +1 -1
- package/dist/modules/execution/run-context-admission.d.ts +1 -1
- package/dist/modules/execution/run-context-admission.d.ts.map +1 -1
- package/dist/modules/execution/run-context-admission.js +1 -0
- package/dist/modules/execution/run-context-admission.js.map +1 -1
- package/dist/modules/execution/run-skills.d.ts +38 -0
- package/dist/modules/execution/run-skills.d.ts.map +1 -0
- package/dist/modules/execution/run-skills.js +92 -0
- package/dist/modules/execution/run-skills.js.map +1 -0
- package/dist/validation/validateRegistrations.d.ts.map +1 -1
- package/dist/validation/validateRegistrations.js +107 -1
- package/dist/validation/validateRegistrations.js.map +1 -1
- package/package.json +11 -11
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentConfigValues, RalphStepState, RalphVerdict } from '@cat-factory/kernel';
|
|
1
|
+
import type { AgentConfigValues, RalphAttempt, RalphStepState, RalphVerdict } from '@cat-factory/kernel';
|
|
2
2
|
import { RALPH_AGENT_KIND } from '@cat-factory/agents';
|
|
3
3
|
export { RALPH_AGENT_KIND };
|
|
4
4
|
/** Default repo-relative path of the append-only progress log the ralph agent maintains. */
|
|
@@ -8,6 +8,23 @@ export declare const RALPH_PROGRESS_PATH = ".cat-factory/ralph-progress.md";
|
|
|
8
8
|
* loop spin (near-)forever. Well above any sane hand-set budget; the default is much smaller.
|
|
9
9
|
*/
|
|
10
10
|
export declare const MAX_RALPH_ITERATIONS_CAP = 50;
|
|
11
|
+
/**
|
|
12
|
+
* How many consecutive FAILING iterations against an UNCHANGED work-branch HEAD end the loop
|
|
13
|
+
* early. The iteration budget alone is a poor runaway guard: a loop whose agent commits nothing
|
|
14
|
+
* is provably not converging, and every further pass costs a full model run to re-learn that.
|
|
15
|
+
* Two is the smallest value that can distinguish a stall from a single unlucky pass — one
|
|
16
|
+
* no-commit iteration happens (a pass that only investigated), two in a row does not.
|
|
17
|
+
*/
|
|
18
|
+
export declare const RALPH_NO_PROGRESS_LIMIT = 2;
|
|
19
|
+
/**
|
|
20
|
+
* How many iterations the step's inspectable {@link RalphStepState.attemptLog} keeps. The loop
|
|
21
|
+
* state rides the run's `detail` JSON blob, which is re-serialized on EVERY step-progress write,
|
|
22
|
+
* so an uncapped log of up to {@link MAX_RALPH_ITERATIONS_CAP} entries (each carrying an output
|
|
23
|
+
* tail and the iteration's prose summary) would bloat every write for the rest of the loop's
|
|
24
|
+
* life — the same reason the run's failure and output trails are capped. The newest iterations
|
|
25
|
+
* are the ones worth reading; what the cap drops is COUNTED, never silently discarded.
|
|
26
|
+
*/
|
|
27
|
+
export declare const MAX_RALPH_ATTEMPT_LOG = 20;
|
|
11
28
|
/** Whether a step's kind is the ralph-loop kind. */
|
|
12
29
|
export declare function isRalphKind(kind: string): boolean;
|
|
13
30
|
/** A block's resolved ralph config: the completion command + the iteration budget. */
|
|
@@ -27,6 +44,23 @@ export interface RalphConfig {
|
|
|
27
44
|
export declare function resolveRalphConfig(agentConfig: AgentConfigValues | undefined): RalphConfig;
|
|
28
45
|
/** Seed a fresh ralph step state from a resolved config (attempts start at 0, no history). */
|
|
29
46
|
export declare function seedRalphState(config: RalphConfig): RalphStepState;
|
|
47
|
+
/**
|
|
48
|
+
* Re-seed a ralph step's loop state for a RE-RUN (a retry, a restart-from-step, or a loop-back),
|
|
49
|
+
* keeping the config frozen at run start — the completion command, the budget, the progress-log
|
|
50
|
+
* path — while zeroing everything the previous attempt accumulated.
|
|
51
|
+
*
|
|
52
|
+
* Both halves matter and neither used to happen. A rebuild-from-scratch reset (the retry path)
|
|
53
|
+
* DROPPED the state entirely, and a ralph step with no `ralph` state dispatches with no
|
|
54
|
+
* validation block at all: the harness then runs a plain coding pass, returns no verdict, and
|
|
55
|
+
* the loop interceptor never fires — the step silently completes as an ungated one-shot coder.
|
|
56
|
+
* A preserve-everything reset (the loop-back path) kept `attempts` at the spent budget, so the
|
|
57
|
+
* very first verdict of the re-run went straight to `exhausted`. Re-seeding from the step's own
|
|
58
|
+
* frozen config is the one answer that is right for both, and needs no re-read of the block.
|
|
59
|
+
*
|
|
60
|
+
* Returns undefined for a step that carries no ralph state (every non-ralph kind), so callers
|
|
61
|
+
* can spread it unconditionally.
|
|
62
|
+
*/
|
|
63
|
+
export declare function restartRalphState(ralph: RalphStepState | null | undefined): RalphStepState | undefined;
|
|
30
64
|
/**
|
|
31
65
|
* Fold a ralph step's state into the container context's `ralphValidation` block: the command
|
|
32
66
|
* the harness runs, the progress-log path, and the 1-based iteration number about to run
|
|
@@ -38,14 +72,41 @@ export declare function buildRalphValidation(ralph: RalphStepState | null | unde
|
|
|
38
72
|
progressPath: string;
|
|
39
73
|
iteration: number;
|
|
40
74
|
} | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* The no-progress streak a just-finished iteration leaves behind: how many consecutive failing
|
|
77
|
+
* iterations have now run against an unchanged work-branch HEAD.
|
|
78
|
+
*
|
|
79
|
+
* FAILS OPEN by design. A verdict with no `headSha` — a self-hosted runner pool on an older
|
|
80
|
+
* harness image, or a pass whose head could not be read — resets the streak rather than
|
|
81
|
+
* extending it: the cost of a missed stall is a few wasted iterations the budget still bounds,
|
|
82
|
+
* while the cost of a false stall is killing a loop that was making progress the whole time.
|
|
83
|
+
*/
|
|
84
|
+
export declare function nextNoProgressStreak(ralph: RalphStepState, verdict: RalphVerdict | null, previousHeadSha: string | null | undefined): number;
|
|
85
|
+
/** The work-branch HEAD the most recent RECORDED iteration ran against, if it reported one. */
|
|
86
|
+
export declare function lastRecordedHeadSha(ralph: RalphStepState): string | null;
|
|
41
87
|
/** The engine's decision after one ralph iteration's verdict is recorded. */
|
|
42
|
-
export type RalphDecision = 'done' | 'retry' | 'exhausted';
|
|
88
|
+
export type RalphDecision = 'done' | 'retry' | 'exhausted' | 'stalled';
|
|
43
89
|
/**
|
|
44
90
|
* Decide the loop's next move from the step state (AFTER the just-finished iteration has been
|
|
45
|
-
* counted into `attempts`) and its verdict: the criterion
|
|
46
|
-
*
|
|
91
|
+
* counted into `attempts` and its no-progress streak folded in) and its verdict: the criterion
|
|
92
|
+
* passed ⇒ `done`; the loop has stopped making progress ⇒ `stalled`; else another iteration
|
|
93
|
+
* remains within the budget ⇒ `retry`; else the budget is spent ⇒ `exhausted`.
|
|
94
|
+
*
|
|
95
|
+
* `stalled` is checked BEFORE the budget so a stuck loop reports why it actually stopped. The
|
|
96
|
+
* two outcomes are terminal in the same way but mean different things to the human reading the
|
|
97
|
+
* notification: "the budget was not enough" invites raising it, "nothing changed for two
|
|
98
|
+
* iterations" says raising it will not help.
|
|
47
99
|
*/
|
|
48
100
|
export declare function decideRalphNext(ralph: RalphStepState, verdict: RalphVerdict | null): RalphDecision;
|
|
101
|
+
/**
|
|
102
|
+
* Append a finished iteration to the step's capped history, returning the new log plus how many
|
|
103
|
+
* entries have now been dropped in total. Pure so the cap (and its accounting) is asserted
|
|
104
|
+
* without the controller's ports.
|
|
105
|
+
*/
|
|
106
|
+
export declare function appendRalphAttempt(ralph: RalphStepState, entry: RalphAttempt): {
|
|
107
|
+
attemptLog: RalphAttempt[];
|
|
108
|
+
droppedAttempts: number;
|
|
109
|
+
};
|
|
49
110
|
/** One-line, human-readable summary of a verdict for notifications / failure messages. */
|
|
50
111
|
export declare function describeRalphVerdict(verdict: RalphVerdict | null): string;
|
|
51
112
|
//# sourceMappingURL=ralph.logic.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ralph.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/ralph.logic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"ralph.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/ralph.logic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACd,YAAY,EACb,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACL,gBAAgB,EAIjB,MAAM,qBAAqB,CAAA;AAQ5B,OAAO,EAAE,gBAAgB,EAAE,CAAA;AAE3B,4FAA4F;AAC5F,eAAO,MAAM,mBAAmB,mCAAmC,CAAA;AAEnE;;;GAGG;AACH,eAAO,MAAM,wBAAwB,KAAK,CAAA;AAE1C;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,IAAI,CAAA;AAExC;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,KAAK,CAAA;AAEvC,oDAAoD;AACpD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,sFAAsF;AACtF,MAAM,WAAW,WAAW;IAC1B,gGAAgG;IAChG,iBAAiB,EAAE,MAAM,CAAA;IACzB,4FAA4F;IAC5F,aAAa,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,iBAAiB,GAAG,SAAS,GAAG,WAAW,CAQ1F;AAED,8FAA8F;AAC9F,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,cAAc,CASlE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,GACvC,cAAc,GAAG,SAAS,CAU5B;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,GACvC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAO1E;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,YAAY,GAAG,IAAI,EAC5B,eAAe,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACzC,MAAM,CAKR;AAED,+FAA+F;AAC/F,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAExE;AAED,6EAA6E;AAC7E,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,OAAO,GAAG,WAAW,GAAG,SAAS,CAAA;AAEtE;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,YAAY,GAAG,IAAI,GAC3B,aAAa,CAIf;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,cAAc,EACrB,KAAK,EAAE,YAAY,GAClB;IAAE,UAAU,EAAE,YAAY,EAAE,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,CAOzD;AAED,0FAA0F;AAC1F,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,GAAG,MAAM,CAMzE"}
|
|
@@ -12,6 +12,23 @@ export const RALPH_PROGRESS_PATH = '.cat-factory/ralph-progress.md';
|
|
|
12
12
|
* loop spin (near-)forever. Well above any sane hand-set budget; the default is much smaller.
|
|
13
13
|
*/
|
|
14
14
|
export const MAX_RALPH_ITERATIONS_CAP = 50;
|
|
15
|
+
/**
|
|
16
|
+
* How many consecutive FAILING iterations against an UNCHANGED work-branch HEAD end the loop
|
|
17
|
+
* early. The iteration budget alone is a poor runaway guard: a loop whose agent commits nothing
|
|
18
|
+
* is provably not converging, and every further pass costs a full model run to re-learn that.
|
|
19
|
+
* Two is the smallest value that can distinguish a stall from a single unlucky pass — one
|
|
20
|
+
* no-commit iteration happens (a pass that only investigated), two in a row does not.
|
|
21
|
+
*/
|
|
22
|
+
export const RALPH_NO_PROGRESS_LIMIT = 2;
|
|
23
|
+
/**
|
|
24
|
+
* How many iterations the step's inspectable {@link RalphStepState.attemptLog} keeps. The loop
|
|
25
|
+
* state rides the run's `detail` JSON blob, which is re-serialized on EVERY step-progress write,
|
|
26
|
+
* so an uncapped log of up to {@link MAX_RALPH_ITERATIONS_CAP} entries (each carrying an output
|
|
27
|
+
* tail and the iteration's prose summary) would bloat every write for the rest of the loop's
|
|
28
|
+
* life — the same reason the run's failure and output trails are capped. The newest iterations
|
|
29
|
+
* are the ones worth reading; what the cap drops is COUNTED, never silently discarded.
|
|
30
|
+
*/
|
|
31
|
+
export const MAX_RALPH_ATTEMPT_LOG = 20;
|
|
15
32
|
/** Whether a step's kind is the ralph-loop kind. */
|
|
16
33
|
export function isRalphKind(kind) {
|
|
17
34
|
return kind === RALPH_AGENT_KIND;
|
|
@@ -42,6 +59,34 @@ export function seedRalphState(config) {
|
|
|
42
59
|
attemptLog: [],
|
|
43
60
|
};
|
|
44
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Re-seed a ralph step's loop state for a RE-RUN (a retry, a restart-from-step, or a loop-back),
|
|
64
|
+
* keeping the config frozen at run start — the completion command, the budget, the progress-log
|
|
65
|
+
* path — while zeroing everything the previous attempt accumulated.
|
|
66
|
+
*
|
|
67
|
+
* Both halves matter and neither used to happen. A rebuild-from-scratch reset (the retry path)
|
|
68
|
+
* DROPPED the state entirely, and a ralph step with no `ralph` state dispatches with no
|
|
69
|
+
* validation block at all: the harness then runs a plain coding pass, returns no verdict, and
|
|
70
|
+
* the loop interceptor never fires — the step silently completes as an ungated one-shot coder.
|
|
71
|
+
* A preserve-everything reset (the loop-back path) kept `attempts` at the spent budget, so the
|
|
72
|
+
* very first verdict of the re-run went straight to `exhausted`. Re-seeding from the step's own
|
|
73
|
+
* frozen config is the one answer that is right for both, and needs no re-read of the block.
|
|
74
|
+
*
|
|
75
|
+
* Returns undefined for a step that carries no ralph state (every non-ralph kind), so callers
|
|
76
|
+
* can spread it unconditionally.
|
|
77
|
+
*/
|
|
78
|
+
export function restartRalphState(ralph) {
|
|
79
|
+
if (!ralph)
|
|
80
|
+
return undefined;
|
|
81
|
+
return {
|
|
82
|
+
phase: 'iterating',
|
|
83
|
+
attempts: 0,
|
|
84
|
+
maxIterations: ralph.maxIterations,
|
|
85
|
+
validationCommand: ralph.validationCommand,
|
|
86
|
+
progressPath: ralph.progressPath ?? RALPH_PROGRESS_PATH,
|
|
87
|
+
attemptLog: [],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
45
90
|
/**
|
|
46
91
|
* Fold a ralph step's state into the container context's `ralphValidation` block: the command
|
|
47
92
|
* the harness runs, the progress-log path, and the 1-based iteration number about to run
|
|
@@ -57,16 +102,58 @@ export function buildRalphValidation(ralph) {
|
|
|
57
102
|
iteration: ralph.attempts + 1,
|
|
58
103
|
};
|
|
59
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* The no-progress streak a just-finished iteration leaves behind: how many consecutive failing
|
|
107
|
+
* iterations have now run against an unchanged work-branch HEAD.
|
|
108
|
+
*
|
|
109
|
+
* FAILS OPEN by design. A verdict with no `headSha` — a self-hosted runner pool on an older
|
|
110
|
+
* harness image, or a pass whose head could not be read — resets the streak rather than
|
|
111
|
+
* extending it: the cost of a missed stall is a few wasted iterations the budget still bounds,
|
|
112
|
+
* while the cost of a false stall is killing a loop that was making progress the whole time.
|
|
113
|
+
*/
|
|
114
|
+
export function nextNoProgressStreak(ralph, verdict, previousHeadSha) {
|
|
115
|
+
if (verdict?.validationPassed)
|
|
116
|
+
return 0;
|
|
117
|
+
const head = verdict?.headSha?.trim();
|
|
118
|
+
if (!head || !previousHeadSha || head !== previousHeadSha)
|
|
119
|
+
return 0;
|
|
120
|
+
return (ralph.noProgressStreak ?? 0) + 1;
|
|
121
|
+
}
|
|
122
|
+
/** The work-branch HEAD the most recent RECORDED iteration ran against, if it reported one. */
|
|
123
|
+
export function lastRecordedHeadSha(ralph) {
|
|
124
|
+
return ralph.attemptLog?.at(-1)?.headSha?.trim() || null;
|
|
125
|
+
}
|
|
60
126
|
/**
|
|
61
127
|
* Decide the loop's next move from the step state (AFTER the just-finished iteration has been
|
|
62
|
-
* counted into `attempts`) and its verdict: the criterion
|
|
63
|
-
*
|
|
128
|
+
* counted into `attempts` and its no-progress streak folded in) and its verdict: the criterion
|
|
129
|
+
* passed ⇒ `done`; the loop has stopped making progress ⇒ `stalled`; else another iteration
|
|
130
|
+
* remains within the budget ⇒ `retry`; else the budget is spent ⇒ `exhausted`.
|
|
131
|
+
*
|
|
132
|
+
* `stalled` is checked BEFORE the budget so a stuck loop reports why it actually stopped. The
|
|
133
|
+
* two outcomes are terminal in the same way but mean different things to the human reading the
|
|
134
|
+
* notification: "the budget was not enough" invites raising it, "nothing changed for two
|
|
135
|
+
* iterations" says raising it will not help.
|
|
64
136
|
*/
|
|
65
137
|
export function decideRalphNext(ralph, verdict) {
|
|
66
138
|
if (verdict?.validationPassed)
|
|
67
139
|
return 'done';
|
|
140
|
+
if ((ralph.noProgressStreak ?? 0) >= RALPH_NO_PROGRESS_LIMIT)
|
|
141
|
+
return 'stalled';
|
|
68
142
|
return ralph.attempts < ralph.maxIterations ? 'retry' : 'exhausted';
|
|
69
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* Append a finished iteration to the step's capped history, returning the new log plus how many
|
|
146
|
+
* entries have now been dropped in total. Pure so the cap (and its accounting) is asserted
|
|
147
|
+
* without the controller's ports.
|
|
148
|
+
*/
|
|
149
|
+
export function appendRalphAttempt(ralph, entry) {
|
|
150
|
+
const appended = [...(ralph.attemptLog ?? []), entry];
|
|
151
|
+
const overflow = Math.max(appended.length - MAX_RALPH_ATTEMPT_LOG, 0);
|
|
152
|
+
return {
|
|
153
|
+
attemptLog: overflow > 0 ? appended.slice(overflow) : appended,
|
|
154
|
+
droppedAttempts: (ralph.droppedAttempts ?? 0) + overflow,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
70
157
|
/** One-line, human-readable summary of a verdict for notifications / failure messages. */
|
|
71
158
|
export function describeRalphVerdict(verdict) {
|
|
72
159
|
if (!verdict)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ralph.logic.js","sourceRoot":"","sources":["../../../src/modules/execution/ralph.logic.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ralph.logic.js","sourceRoot":"","sources":["../../../src/modules/execution/ralph.logic.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/retry.logic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,eAAe,EAChB,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"retry.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/retry.logic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,eAAe,EAChB,MAAM,qBAAqB,CAAA;AAG5B;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,YAAY,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG;IACtF,KAAK,EAAE,YAAY,EAAE,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;CACpB,CASA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,KAAK,CAAA;AAErC;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,OAAO,CAAC,EAAE,YAAY,GAAG,IAAI,CAAA;IAC7B,cAAc,CAAC,EAAE,YAAY,EAAE,CAAA;CAChC,GAAG,YAAY,EAAE,CAIjB;AAED,2FAA2F;AAC3F,eAAO,MAAM,kBAAkB,KAAK,CAAA;AAEpC;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,OAAQ,CAAA;AAE7C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE;IAAE,KAAK,EAAE,YAAY,EAAE,CAAC;IAAC,aAAa,CAAC,EAAE,eAAe,EAAE,CAAA;CAAE,EAClE,cAAc,EAAE,MAAM,EACtB,GAAG,EAAE,MAAM,GACV,eAAe,EAAE,CAmBnB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE;IAAE,KAAK,EAAE,YAAY,EAAE,CAAA;CAAE,EAC/B,SAAS,EAAE,MAAM,GAChB;IAAE,KAAK,EAAE,YAAY,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAShD;AAwDD;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,0EAA0E;IAC1E,QAAQ,EAAE,iBAAiB,CAAA;IAC3B,iCAAiC;IACjC,EAAE,EAAE,MAAM,CAAA;IACV,mGAAmG;IACnG,IAAI,EAAE;QAAE,KAAK,EAAE,YAAY,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAA;IACpD,kGAAkG;IAClG,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAA;CACZ,GAAG,iBAAiB,CAuBpB"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { restartRalphState } from './ralph.logic.js';
|
|
1
2
|
/**
|
|
2
3
|
* Plan how a failed run resumes on retry: keep the steps that already completed
|
|
3
4
|
* and re-run from the one that actually failed, rather than restarting the whole
|
|
@@ -128,8 +129,17 @@ function planFromStep(prevSteps, resumeIndex) {
|
|
|
128
129
|
* fresh timing (`startStep` re-stamps `startedAt`). The structural fields the
|
|
129
130
|
* pipeline defined — `agentKind` and `requiresApproval` — are preserved so the
|
|
130
131
|
* approval gate still fires after the re-run.
|
|
132
|
+
*
|
|
133
|
+
* A `ralph` step's loop state is RE-SEEDED rather than dropped. Everything else here is
|
|
134
|
+
* re-derived at dispatch or lazily on the way back (`step.test` is seeded when the tester's
|
|
135
|
+
* report arrives), but a ralph loop's completion command is needed BEFORE the dispatch: it is
|
|
136
|
+
* what puts the `validation` block on the job body. Rebuilding this object without it left the
|
|
137
|
+
* retried step with no ralph state at all, so the harness ran a plain coding pass, returned no
|
|
138
|
+
* verdict, and the loop interceptor never fired — the step completed as an ungated one-shot
|
|
139
|
+
* coder. {@link restartRalphState} keeps the frozen config and zeroes the counters.
|
|
131
140
|
*/
|
|
132
141
|
function resetStep(step, state) {
|
|
142
|
+
const ralph = restartRalphState(step.ralph);
|
|
133
143
|
return {
|
|
134
144
|
agentKind: step.agentKind,
|
|
135
145
|
state,
|
|
@@ -146,6 +156,7 @@ function resetStep(step, state) {
|
|
|
146
156
|
startedAt: undefined,
|
|
147
157
|
finishedAt: undefined,
|
|
148
158
|
pausedAt: undefined,
|
|
159
|
+
...(ralph ? { ralph } : {}),
|
|
149
160
|
};
|
|
150
161
|
}
|
|
151
162
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retry.logic.js","sourceRoot":"","sources":["../../../src/modules/execution/retry.logic.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"retry.logic.js","sourceRoot":"","sources":["../../../src/modules/execution/retry.logic.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,7 +17,7 @@ import type { ExecutionServiceDependencies } from './ExecutionService.js';
|
|
|
17
17
|
* value the constructor passed inline, so the two collaborators are built from an identical
|
|
18
18
|
* input to before.
|
|
19
19
|
*/
|
|
20
|
-
export type RunContextAdmissionDeps = Pick<ExecutionServiceDependencies, 'workspaceRepository' | 'blockRepository' | 'executionRepository' | 'accountRepository' | 'agentKindRegistry' | 'initiativePresetRegistry' | 'documentRepository' | 'documentUrlResolver' | 'taskRepository' | 'requirementReviewRepository' | 'docInterviewRepository' | 'clarityReviewRepository' | 'brainstormSessionRepository' | 'initiativeRepository' | 'environmentProvisioning' | 'resolveTestSecretRefs' | 'resolveValidationChecks' | 'fragmentResolver' | 'skillResolver' | 'spendService' | 'workspaceSettingsService' | 'resolveBinaryArtifactStore' | 'resolveProviderCapabilities' | 'inlineHarnessRef' | 'resolveWorkspaceModelDefault' | 'assertAgentBackendConfigured'>;
|
|
20
|
+
export type RunContextAdmissionDeps = Pick<ExecutionServiceDependencies, 'workspaceRepository' | 'blockRepository' | 'executionRepository' | 'accountRepository' | 'agentKindRegistry' | 'initiativePresetRegistry' | 'documentRepository' | 'documentUrlResolver' | 'taskRepository' | 'requirementReviewRepository' | 'docInterviewRepository' | 'clarityReviewRepository' | 'brainstormSessionRepository' | 'initiativeRepository' | 'environmentProvisioning' | 'resolveTestSecretRefs' | 'resolveValidationChecks' | 'fragmentResolver' | 'skillResolver' | 'spendService' | 'workspaceSettingsService' | 'resolveBinaryArtifactStore' | 'resolveProviderCapabilities' | 'inlineHarnessRef' | 'resolveWorkspaceModelDefault' | 'assertAgentBackendConfigured' | 'logger'>;
|
|
21
21
|
export declare function buildRunContextAndAdmission(deps: RunContextAdmissionDeps): {
|
|
22
22
|
contextBuilder: AgentContextBuilder;
|
|
23
23
|
admission: RunAdmission;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-context-admission.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/run-context-admission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAA;AAEzE;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,IAAI,CACxC,4BAA4B,EAC1B,qBAAqB,GACrB,iBAAiB,GACjB,qBAAqB,GACrB,mBAAmB,GACnB,mBAAmB,GACnB,0BAA0B,GAC1B,oBAAoB,GACpB,qBAAqB,GACrB,gBAAgB,GAChB,6BAA6B,GAC7B,wBAAwB,GACxB,yBAAyB,GACzB,6BAA6B,GAC7B,sBAAsB,GACtB,yBAAyB,GACzB,uBAAuB,GACvB,yBAAyB,GACzB,kBAAkB,GAClB,eAAe,GACf,cAAc,GACd,0BAA0B,GAC1B,4BAA4B,GAC5B,6BAA6B,GAC7B,kBAAkB,GAClB,8BAA8B,GAC9B,8BAA8B,
|
|
1
|
+
{"version":3,"file":"run-context-admission.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/run-context-admission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAA;AAEzE;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,IAAI,CACxC,4BAA4B,EAC1B,qBAAqB,GACrB,iBAAiB,GACjB,qBAAqB,GACrB,mBAAmB,GACnB,mBAAmB,GACnB,0BAA0B,GAC1B,oBAAoB,GACpB,qBAAqB,GACrB,gBAAgB,GAChB,6BAA6B,GAC7B,wBAAwB,GACxB,yBAAyB,GACzB,6BAA6B,GAC7B,sBAAsB,GACtB,yBAAyB,GACzB,uBAAuB,GACvB,yBAAyB,GACzB,kBAAkB,GAClB,eAAe,GACf,cAAc,GACd,0BAA0B,GAC1B,4BAA4B,GAC5B,6BAA6B,GAC7B,kBAAkB,GAClB,8BAA8B,GAC9B,8BAA8B,GAC9B,QAAQ,CACX,CAAA;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,uBAAuB,GAAG;IAC1E,cAAc,EAAE,mBAAmB,CAAA;IACnC,SAAS,EAAE,YAAY,CAAA;CACxB,CAwCA"}
|
|
@@ -31,6 +31,7 @@ export function buildRunContextAndAdmission(deps) {
|
|
|
31
31
|
resolveValidationChecks: deps.resolveValidationChecks,
|
|
32
32
|
fragmentResolver: deps.fragmentResolver,
|
|
33
33
|
skillResolver: deps.skillResolver,
|
|
34
|
+
logger: deps.logger,
|
|
34
35
|
});
|
|
35
36
|
// The run-admission preflights (the shared start/retry/restart `assert*` gate family).
|
|
36
37
|
// The admission-only seams are forwarded here rather than stored on the engine.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-context-admission.js","sourceRoot":"","sources":["../../../src/modules/execution/run-context-admission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"run-context-admission.js","sourceRoot":"","sources":["../../../src/modules/execution/run-context-admission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAuChD,MAAM,UAAU,2BAA2B,CAAC,IAA6B;IAIvE,MAAM,cAAc,GAAG,IAAI,mBAAmB,CAAC;QAC7C,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;QAC7C,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;QACzC,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;QACzC,wBAAwB,EAAE,IAAI,CAAC,wBAAwB;QACvD,SAAS,EAAE,IAAI,CAAC,kBAAkB;QAClC,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;QAC7C,KAAK,EAAE,IAAI,CAAC,cAAc;QAC1B,kBAAkB,EAAE,IAAI,CAAC,2BAA2B;QACpD,aAAa,EAAE,IAAI,CAAC,sBAAsB;QAC1C,cAAc,EAAE,IAAI,CAAC,uBAAuB;QAC5C,kBAAkB,EAAE,IAAI,CAAC,2BAA2B;QACpD,WAAW,EAAE,IAAI,CAAC,oBAAoB;QACtC,uBAAuB,EAAE,IAAI,CAAC,uBAAuB;QACrD,qBAAqB,EAAE,IAAI,CAAC,qBAAqB;QACjD,uBAAuB,EAAE,IAAI,CAAC,uBAAuB;QACrD,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;QACvC,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC,CAAA;IACF,uFAAuF;IACvF,gFAAgF;IAChF,MAAM,SAAS,GAAG,IAAI,YAAY,CAAC;QACjC,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;QAC7C,eAAe,EAAE,IAAI,CAAC,eAAe;QACrC,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;QAC7C,cAAc;QACd,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;QACzC,KAAK,EAAE,IAAI,CAAC,YAAY;QACxB,uBAAuB,EAAE,IAAI,CAAC,uBAAuB;QACrD,wBAAwB,EAAE,IAAI,CAAC,wBAAwB;QACvD,0BAA0B,EAAE,IAAI,CAAC,0BAA0B;QAC3D,2BAA2B,EAAE,IAAI,CAAC,2BAA2B;QAC7D,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;QACvC,4BAA4B,EAAE,IAAI,CAAC,4BAA4B;QAC/D,4BAA4B,EAAE,IAAI,CAAC,4BAA4B;KAChE,CAAC,CAAA;IACF,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,CAAA;AACtC,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { AgentKindRegistry } from '@cat-factory/agents';
|
|
2
|
+
import type { PipelineStep } from '@cat-factory/contracts';
|
|
3
|
+
import type { AgentKind, Logger, ResolvedSkill, SkillVersionPin } from '@cat-factory/kernel';
|
|
4
|
+
import type { SkillResolver } from './AgentContextBuilder.js';
|
|
5
|
+
export interface ResolveRunSkillsInput {
|
|
6
|
+
workspaceId: string;
|
|
7
|
+
/** The EFFECTIVE dispatched kind (a gate helper dispatches its own kind, not the step's). */
|
|
8
|
+
agentKind: AgentKind;
|
|
9
|
+
/** The step being dispatched; its `skillVersions` pin is written here. */
|
|
10
|
+
step: PipelineStep;
|
|
11
|
+
agentKindRegistry: AgentKindRegistry;
|
|
12
|
+
/** Wired only when the skill library is configured; absent ⇒ no catalog skill can resolve. */
|
|
13
|
+
skillResolver?: SkillResolver;
|
|
14
|
+
logger?: Logger;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Resolve every skill this dispatch applies, in the order they should be applied: the kind's own
|
|
18
|
+
* declarations first (its standing playbooks), then the step's picked skill. Deduplicated by
|
|
19
|
+
* skill id, so a step that picks a skill its kind already declares runs it once.
|
|
20
|
+
*
|
|
21
|
+
* The failure policy differs by SOURCE, deliberately:
|
|
22
|
+
*
|
|
23
|
+
* - **The step's picked skill** is a hard failure when it cannot resolve (no resolver wired) —
|
|
24
|
+
* the whole point of that step is to run that skill, so a silent skip is a wrong run. This is
|
|
25
|
+
* the pre-existing `skill`-kind contract, unchanged.
|
|
26
|
+
* - **A kind's declared CATALOG skill** is a hard failure too unless it declared itself
|
|
27
|
+
* `optional`: a kind that names a skill by id is saying it needs it to do the work. Marking it
|
|
28
|
+
* optional is how a kind says "apply the house playbook if this deployment has one".
|
|
29
|
+
* - **A kind's declared BUNDLED skill** cannot fail: it ships in the deployment's own code.
|
|
30
|
+
*
|
|
31
|
+
* Returns the resolved skills plus the CATALOG version pins (a bundled skill has no pin — its
|
|
32
|
+
* version is the deployment's), which the caller records on the step.
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolveRunSkills(input: ResolveRunSkillsInput): Promise<{
|
|
35
|
+
skills: ResolvedSkill[];
|
|
36
|
+
versions: SkillVersionPin[];
|
|
37
|
+
}>;
|
|
38
|
+
//# sourceMappingURL=run-skills.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-skills.d.ts","sourceRoot":"","sources":["../../../src/modules/execution/run-skills.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAE5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAE5F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAY7D,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAA;IACnB,6FAA6F;IAC7F,SAAS,EAAE,SAAS,CAAA;IACpB,0EAA0E;IAC1E,IAAI,EAAE,YAAY,CAAA;IAClB,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,8FAA8F;IAC9F,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC;IAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IAAC,QAAQ,EAAE,eAAe,EAAE,CAAA;CAAE,CAAC,CAgDnE"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { bundledSkillToResolved, SKILL_AGENT_KIND } from '@cat-factory/agents';
|
|
2
|
+
import { ValidationError, noopLogger, runBestEffort } from '@cat-factory/kernel';
|
|
3
|
+
/**
|
|
4
|
+
* Resolve every skill this dispatch applies, in the order they should be applied: the kind's own
|
|
5
|
+
* declarations first (its standing playbooks), then the step's picked skill. Deduplicated by
|
|
6
|
+
* skill id, so a step that picks a skill its kind already declares runs it once.
|
|
7
|
+
*
|
|
8
|
+
* The failure policy differs by SOURCE, deliberately:
|
|
9
|
+
*
|
|
10
|
+
* - **The step's picked skill** is a hard failure when it cannot resolve (no resolver wired) —
|
|
11
|
+
* the whole point of that step is to run that skill, so a silent skip is a wrong run. This is
|
|
12
|
+
* the pre-existing `skill`-kind contract, unchanged.
|
|
13
|
+
* - **A kind's declared CATALOG skill** is a hard failure too unless it declared itself
|
|
14
|
+
* `optional`: a kind that names a skill by id is saying it needs it to do the work. Marking it
|
|
15
|
+
* optional is how a kind says "apply the house playbook if this deployment has one".
|
|
16
|
+
* - **A kind's declared BUNDLED skill** cannot fail: it ships in the deployment's own code.
|
|
17
|
+
*
|
|
18
|
+
* Returns the resolved skills plus the CATALOG version pins (a bundled skill has no pin — its
|
|
19
|
+
* version is the deployment's), which the caller records on the step.
|
|
20
|
+
*/
|
|
21
|
+
export async function resolveRunSkills(input) {
|
|
22
|
+
const declared = input.agentKindRegistry.skillsFor(input.agentKind);
|
|
23
|
+
const pickedSkillId = input.agentKind === SKILL_AGENT_KIND ? input.step.stepOptions?.skillId?.trim() : undefined;
|
|
24
|
+
if (!declared.bundled.length && !declared.catalog.length && !pickedSkillId) {
|
|
25
|
+
// Clear on this path too, not just the one below: a step re-dispatched after its pick was
|
|
26
|
+
// removed (or its kind's declaration dropped) lands HERE, and leaving the prior round's pin
|
|
27
|
+
// in place would report "this run executed that version" of a skill it never touched.
|
|
28
|
+
input.step.skillVersions = undefined;
|
|
29
|
+
return { skills: [], versions: [] };
|
|
30
|
+
}
|
|
31
|
+
// A registered id with no registration is a deployment typo. It is reported at BOOT
|
|
32
|
+
// (`validateRegistrations`), so by the time a run reaches here the loud channel has already
|
|
33
|
+
// fired — dropping it with a warning is right, because failing the run cannot fix the typo.
|
|
34
|
+
for (const id of declared.unknown) {
|
|
35
|
+
input.logger?.warn('agent kind declares an unregistered skill id; skipping it', {
|
|
36
|
+
agentKind: input.agentKind,
|
|
37
|
+
skillId: id,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const skills = declared.bundled.map(bundledSkillToResolved);
|
|
41
|
+
const versions = [];
|
|
42
|
+
const seen = new Set(skills.map((s) => s.skillId));
|
|
43
|
+
for (const ref of declared.catalog) {
|
|
44
|
+
if (seen.has(ref.skillId))
|
|
45
|
+
continue;
|
|
46
|
+
const resolved = await resolveCatalogSkill(input, ref.skillId, ref.optional);
|
|
47
|
+
if (!resolved)
|
|
48
|
+
continue;
|
|
49
|
+
seen.add(resolved.skill.skillId);
|
|
50
|
+
skills.push(resolved.skill);
|
|
51
|
+
versions.push(resolved.version);
|
|
52
|
+
}
|
|
53
|
+
if (pickedSkillId && !seen.has(pickedSkillId)) {
|
|
54
|
+
const resolved = await resolveCatalogSkill(input, pickedSkillId, false);
|
|
55
|
+
if (resolved) {
|
|
56
|
+
skills.push(resolved.skill);
|
|
57
|
+
versions.push(resolved.version);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Assigned unconditionally (cleared when nothing pinned) rather than only on success: a step
|
|
61
|
+
// re-dispatched after its skill was removed upstream would otherwise keep reporting the prior
|
|
62
|
+
// round's pin, which reads as "this run executed that version" when it did not.
|
|
63
|
+
input.step.skillVersions = versions.length ? versions : undefined;
|
|
64
|
+
return { skills, versions };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Resolve ONE account-catalog skill. An unwired resolver, or a resolver that throws (an unknown /
|
|
68
|
+
* tombstoned skill id), fails the dispatch unless the reference declared itself optional — in
|
|
69
|
+
* which case the skill is skipped with a logged reason, never in silence. A resource-fetch
|
|
70
|
+
* failure inside the resolver already degrades to a body-less reference and never throws, so a
|
|
71
|
+
* transient GitHub blip cannot reach this branch.
|
|
72
|
+
*/
|
|
73
|
+
async function resolveCatalogSkill(input, skillId, optional) {
|
|
74
|
+
if (!input.skillResolver) {
|
|
75
|
+
if (!optional) {
|
|
76
|
+
throw new ValidationError(`This pipeline step runs the skill '${skillId}', but the skill library is not configured for this deployment.`);
|
|
77
|
+
}
|
|
78
|
+
input.logger?.info('optional skill skipped: the skill library is not configured', { skillId });
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
const resolver = input.skillResolver;
|
|
82
|
+
if (optional) {
|
|
83
|
+
const resolved = await runBestEffort(input.logger ?? noopLogger, 'resolve optional agent-kind skill', async () => {
|
|
84
|
+
const { skill, version } = await resolver.resolveForRun(input.workspaceId, skillId);
|
|
85
|
+
return { skill: { ...skill, origin: 'catalog' }, version };
|
|
86
|
+
}, { skillId });
|
|
87
|
+
return resolved ?? null;
|
|
88
|
+
}
|
|
89
|
+
const { skill, version } = await resolver.resolveForRun(input.workspaceId, skillId);
|
|
90
|
+
return { skill: { ...skill, origin: 'catalog' }, version };
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=run-skills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-skills.js","sourceRoot":"","sources":["../../../src/modules/execution/run-skills.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateRegistrations.d.ts","sourceRoot":"","sources":["../../src/validation/validateRegistrations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAC5D,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"validateRegistrations.d.ts","sourceRoot":"","sources":["../../src/validation/validateRegistrations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAC5D,OAAO,KAAK,EAEV,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EACjB,MAAM,qBAAqB,CAAA;AAsC5B,4FAA4F;AAC5F,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAA;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,uFAAuF;AACvF,MAAM,WAAW,4BAA4B;IAC3C;;;OAGG;IACH,iBAAiB,EAAE,iBAAiB,CAAA;IACpC;;;;OAIG;IACH,YAAY,EAAE,YAAY,CAAA;IAC1B;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,qGAAqG;IACrG,kBAAkB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACxC,qGAAqG;IACrG,kBAAkB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACxC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IACrC;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAA;CAChD;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,4BAA4B,GACjC,mBAAmB,EAAE,CAwEvB;AAuOD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,4BAA4B,GAAG,IAAI,CAY9E;AAOD,yGAAyG;AACzG,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,4BAA4B,GAAG,IAAI,CASlF;AAED,uFAAuF;AACvF,wBAAgB,gCAAgC,IAAI,IAAI,CAEvD"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CI_FIXER_AGENT_KIND, CONFLICT_RESOLVER_AGENT_KIND, FIXER_AGENT_KIND, ON_CALL_AGENT_KIND, seedPipelines, stubGateContext, } from '@cat-factory/kernel';
|
|
1
|
+
import { CI_FIXER_AGENT_KIND, CONFLICT_RESOLVER_AGENT_KIND, FIXER_AGENT_KIND, ON_CALL_AGENT_KIND, isAllowedMcpHttpUrl, isValidMcpServerId, seedPipelines, stubGateContext, } from '@cat-factory/kernel';
|
|
2
2
|
import { isNamespacedId, isValidResultViewId, RESULT_VIEW_ID_SET } from '@cat-factory/contracts';
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
4
|
// Boot-time validation of the deployment's registered extensions (agent kinds, gates,
|
|
@@ -86,6 +86,112 @@ export function collectRegistrationProblems(opts) {
|
|
|
86
86
|
problems.push(...checkPipelineKinds(opts, registeredKindIds, gateKinds, builtInHelperKinds));
|
|
87
87
|
// 5. Custom task types (only when a task-type registry is supplied).
|
|
88
88
|
problems.push(...checkCustomTaskTypes(opts));
|
|
89
|
+
// 6. Agent capabilities: the skills + tool servers each kind declares.
|
|
90
|
+
problems.push(...checkAgentCapabilities(agentKinds, registry));
|
|
91
|
+
return problems;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Section 6 of {@link collectRegistrationProblems}: a kind's declared capabilities must be
|
|
95
|
+
* REACHABLE and COHERENT. Every check here covers something that otherwise fails invisibly at run
|
|
96
|
+
* time — the agent just quietly works without the playbook or the tool it was supposed to have,
|
|
97
|
+
* which is why boot is the right place to be loud. Split per capability; see each helper.
|
|
98
|
+
*/
|
|
99
|
+
function checkAgentCapabilities(agentKinds, registry) {
|
|
100
|
+
return agentKinds.flatMap((def) => [
|
|
101
|
+
...checkKindSkills(def.kind, registry),
|
|
102
|
+
...checkKindToolServers(def.kind, registry),
|
|
103
|
+
]);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* A kind's declared SKILLS:
|
|
107
|
+
*
|
|
108
|
+
* - an id with no registration (a typo, or a `registerSkill` call that never ran) is an ERROR;
|
|
109
|
+
* - skills on a NON-container kind is a WARNING, exactly as for tool servers below. Only the
|
|
110
|
+
* container executor renders `AgentRunContext.skills` into a dispatch, so an inline kind's
|
|
111
|
+
* declaration can never take effect — and a non-optional `{ catalogSkillId }` there is worse
|
|
112
|
+
* than inert, since it fails EVERY dispatch of that kind on a deployment with no skill library
|
|
113
|
+
* while never being able to reach the model.
|
|
114
|
+
*/
|
|
115
|
+
function checkKindSkills(kind, registry) {
|
|
116
|
+
const problems = [];
|
|
117
|
+
const skills = registry.skillsFor(kind);
|
|
118
|
+
for (const id of skills.unknown) {
|
|
119
|
+
problems.push({
|
|
120
|
+
severity: 'error',
|
|
121
|
+
code: 'unknown_bundled_skill',
|
|
122
|
+
message: `Agent kind "${kind}" declares skill "${id}", which is not registered. Call ` +
|
|
123
|
+
`registry.registerSkill({ id: '${id}', … }) before registering the kind, declare the ` +
|
|
124
|
+
`skill inline, or use { catalogSkillId } for a repo-synced skill.`,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
const declared = skills.bundled.length + skills.catalog.length;
|
|
128
|
+
if (declared && !registry.requiresContainer(kind)) {
|
|
129
|
+
problems.push({
|
|
130
|
+
severity: 'warn',
|
|
131
|
+
code: 'skills_without_container',
|
|
132
|
+
message: `Agent kind "${kind}" declares skills but does not run in a container — only a container ` +
|
|
133
|
+
`dispatch installs a skill and folds its instructions into the prompt, so an inline LLM ` +
|
|
134
|
+
`step will never apply them. Give the kind a container surface (agent.surface: ` +
|
|
135
|
+
`'container-explore' / 'container-coding') or drop the skills.`,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return problems;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* A kind's declared TOOL SERVERS:
|
|
142
|
+
*
|
|
143
|
+
* - an unregistered id is an ERROR, like an unregistered skill;
|
|
144
|
+
* - a malformed MCP server id is an ERROR, because it becomes both a tool-name fragment and a
|
|
145
|
+
* Codex TOML table key, so the CLI fails on it far from the registration that caused it;
|
|
146
|
+
* - a cleartext `http://` endpoint off loopback is an ERROR: a resolved credential rides that
|
|
147
|
+
* request as a header, and the harness refuses the same URL at the job boundary — so allowing
|
|
148
|
+
* it here only moves the failure to a place with no registration to point at;
|
|
149
|
+
* - tool servers on a NON-container kind is a WARNING: an inline LLM call has no CLI to wire them
|
|
150
|
+
* into, so they can never take effect. A warning rather than an error because a deployment may
|
|
151
|
+
* deliberately declare them ahead of moving the kind onto a container surface.
|
|
152
|
+
*/
|
|
153
|
+
function checkKindToolServers(kind, registry) {
|
|
154
|
+
const problems = [];
|
|
155
|
+
const tools = registry.toolServersFor(kind);
|
|
156
|
+
for (const id of tools.unknown) {
|
|
157
|
+
problems.push({
|
|
158
|
+
severity: 'error',
|
|
159
|
+
code: 'unknown_tool_server',
|
|
160
|
+
message: `Agent kind "${kind}" declares tool server "${id}", which is not registered. Call ` +
|
|
161
|
+
`registry.registerToolServer({ id: '${id}', … }) before registering the kind, or ` +
|
|
162
|
+
`declare the server inline.`,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
for (const server of tools.servers) {
|
|
166
|
+
if (!isValidMcpServerId(server.id)) {
|
|
167
|
+
problems.push({
|
|
168
|
+
severity: 'error',
|
|
169
|
+
code: 'invalid_tool_server_id',
|
|
170
|
+
message: `Tool server "${server.id}" (on agent kind "${kind}") has an invalid id. It ` +
|
|
171
|
+
`becomes part of the tool names the CLI exposes (mcp__<id>__<tool>) and a Codex ` +
|
|
172
|
+
`config key, so it must match [a-z0-9][a-z0-9_-]*.`,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
if (server.transport.kind === 'http' && !isAllowedMcpHttpUrl(server.transport.url)) {
|
|
176
|
+
problems.push({
|
|
177
|
+
severity: 'error',
|
|
178
|
+
code: 'insecure_tool_server_url',
|
|
179
|
+
message: `Tool server "${server.id}" (on agent kind "${kind}") has url ` +
|
|
180
|
+
`"${server.transport.url}". An HTTP tool server carries its resolved credential in a ` +
|
|
181
|
+
`request header, so the url must be https (plain http is accepted only on loopback).`,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (tools.servers.length && !registry.requiresContainer(kind)) {
|
|
186
|
+
problems.push({
|
|
187
|
+
severity: 'warn',
|
|
188
|
+
code: 'tool_servers_without_container',
|
|
189
|
+
message: `Agent kind "${kind}" declares tool servers but does not run in a container — an ` +
|
|
190
|
+
`inline LLM step has no agent CLI to wire them into, so they will never be available. ` +
|
|
191
|
+
`Give the kind a container surface (agent.surface: 'container-explore' / ` +
|
|
192
|
+
`'container-coding') or drop the tool servers.`,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
89
195
|
return problems;
|
|
90
196
|
}
|
|
91
197
|
/**
|