@oisincoveney/pipeline 1.27.10 → 1.27.12
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/config.d.ts
CHANGED
|
@@ -485,8 +485,8 @@ declare const configSchema: z.ZodObject<{
|
|
|
485
485
|
rules: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
486
486
|
path: z.ZodString;
|
|
487
487
|
source_root: z.ZodDefault<z.ZodEnum<{
|
|
488
|
-
project: "project";
|
|
489
488
|
package: "package";
|
|
489
|
+
project: "project";
|
|
490
490
|
}>>;
|
|
491
491
|
}, z.core.$strict>>>;
|
|
492
492
|
runners: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
@@ -613,8 +613,8 @@ declare const configSchema: z.ZodObject<{
|
|
|
613
613
|
schedules: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
614
614
|
description: z.ZodOptional<z.ZodString>;
|
|
615
615
|
baseline: z.ZodEnum<{
|
|
616
|
-
quick: "quick";
|
|
617
616
|
execute: "execute";
|
|
617
|
+
quick: "quick";
|
|
618
618
|
}>;
|
|
619
619
|
max_parallel_nodes: z.ZodOptional<z.ZodNumber>;
|
|
620
620
|
node_catalog: z.ZodOptional<z.ZodString>;
|
|
@@ -626,8 +626,8 @@ declare const configSchema: z.ZodObject<{
|
|
|
626
626
|
skills: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
627
627
|
path: z.ZodString;
|
|
628
628
|
source_root: z.ZodDefault<z.ZodEnum<{
|
|
629
|
-
project: "project";
|
|
630
629
|
package: "package";
|
|
630
|
+
project: "project";
|
|
631
631
|
}>>;
|
|
632
632
|
}, z.core.$strict>>>;
|
|
633
633
|
task_context: z.ZodOptional<z.ZodObject<{
|
package/dist/moka-submit.d.ts
CHANGED
|
@@ -160,8 +160,8 @@ declare const mokaSubmitOptionsSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
160
160
|
}, z.core.$strict>>;
|
|
161
161
|
serviceAccountName: z.ZodDefault<z.ZodString>;
|
|
162
162
|
mode: z.ZodEnum<{
|
|
163
|
-
full: "full";
|
|
164
163
|
quick: "quick";
|
|
164
|
+
full: "full";
|
|
165
165
|
}>;
|
|
166
166
|
schedulePath: z.ZodOptional<z.ZodString>;
|
|
167
167
|
scheduleYaml: z.ZodOptional<z.ZodString>;
|
|
@@ -43,8 +43,8 @@ declare const runnerDeliverySchema: z.ZodObject<{
|
|
|
43
43
|
declare const mokaSubmissionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
44
44
|
kind: z.ZodLiteral<"graph">;
|
|
45
45
|
mode: z.ZodEnum<{
|
|
46
|
-
full: "full";
|
|
47
46
|
quick: "quick";
|
|
47
|
+
full: "full";
|
|
48
48
|
}>;
|
|
49
49
|
}, z.core.$strict>, z.ZodObject<{
|
|
50
50
|
argv: z.ZodArray<z.ZodString>;
|
|
@@ -104,8 +104,8 @@ declare const runnerCommandPayloadSchema: z.ZodObject<{
|
|
|
104
104
|
submission: z.ZodDefault<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
105
105
|
kind: z.ZodLiteral<"graph">;
|
|
106
106
|
mode: z.ZodEnum<{
|
|
107
|
-
full: "full";
|
|
108
107
|
quick: "quick";
|
|
108
|
+
full: "full";
|
|
109
109
|
}>;
|
|
110
110
|
}, z.core.$strict>, z.ZodObject<{
|
|
111
111
|
argv: z.ZodArray<z.ZodString>;
|
|
@@ -4,7 +4,7 @@ import { normalizeRunnerOutput, runnerTextCandidates } from "../../runner-output
|
|
|
4
4
|
import { gatewayServerForProfile } from "../../mcp/gateway.js";
|
|
5
5
|
import { selectNodeModel } from "../../model-resolver.js";
|
|
6
6
|
import { resolvePackageAssetPath } from "../../package-assets.js";
|
|
7
|
-
import { readJsonSchemaSource, validateJsonSchemaSource } from "../json-validation/json-validation.js";
|
|
7
|
+
import { normalizeJsonSource, readJsonSchemaSource, validateJsonSchemaSource } from "../json-validation/json-validation.js";
|
|
8
8
|
import "../json-validation/index.js";
|
|
9
9
|
import { emit, emitAgentFinish, emitAgentStart } from "../events/events.js";
|
|
10
10
|
import "../events/index.js";
|
|
@@ -54,22 +54,33 @@ async function executeAgentNode(node, context, attempt) {
|
|
|
54
54
|
}
|
|
55
55
|
async function finalizeAgentOutput(inputs) {
|
|
56
56
|
const { attempt, context, node, normalized, plan, result } = inputs;
|
|
57
|
-
const validStructuredOutput = selectValidStructuredOutput(context, node, plan, result.stdout);
|
|
57
|
+
const validStructuredOutput = selectValidStructuredOutput(context, node, normalized, plan, result.stdout);
|
|
58
58
|
if (validStructuredOutput) return validStructuredOutput;
|
|
59
59
|
const repairContext = outputRepairContext(context, node, normalized, result);
|
|
60
60
|
if (!repairContext) return normalized;
|
|
61
61
|
return await runOutputRepair(context, node, normalized, repairContext, attempt);
|
|
62
62
|
}
|
|
63
|
-
function selectValidStructuredOutput(context, node, plan, stdout) {
|
|
63
|
+
function selectValidStructuredOutput(context, node, normalized, plan, stdout) {
|
|
64
64
|
const output = (node.profile ? context.config.profiles[node.profile] : void 0)?.output;
|
|
65
65
|
if (output?.format !== "json_schema" || !output.schema_path) return null;
|
|
66
|
-
const candidates =
|
|
67
|
-
for (const candidate of
|
|
68
|
-
|
|
69
|
-
output
|
|
70
|
-
|
|
66
|
+
const candidates = structuredOutputCandidates(plan, stdout, normalized);
|
|
67
|
+
for (const candidate of candidates) {
|
|
68
|
+
const candidateOutput = normalizeJsonSource(candidate.output);
|
|
69
|
+
if (validateJsonSchemaSource(candidateOutput, output.schema_path, context.worktreePath).passed) return {
|
|
70
|
+
evidence: [candidate.evidence, `selected valid structured output for ${node.id}`],
|
|
71
|
+
output: candidateOutput
|
|
72
|
+
};
|
|
73
|
+
}
|
|
71
74
|
return null;
|
|
72
75
|
}
|
|
76
|
+
function structuredOutputCandidates(plan, stdout, normalized) {
|
|
77
|
+
const candidates = runnerTextCandidates(plan, stdout);
|
|
78
|
+
if (candidates.length > 0) return [...candidates].reverse();
|
|
79
|
+
return [{
|
|
80
|
+
evidence: normalized.evidence.join("; ") || "selected runner stdout",
|
|
81
|
+
output: normalized.output
|
|
82
|
+
}];
|
|
83
|
+
}
|
|
73
84
|
function outputRepairContext(context, node, normalized, result) {
|
|
74
85
|
if (result.exitCode !== 0 || result.timedOut) return null;
|
|
75
86
|
const profile = node.profile ? context.config.profiles[node.profile] : void 0;
|
|
@@ -110,14 +121,15 @@ async function runOutputRepair(context, node, normalized, repairContext, nodeAtt
|
|
|
110
121
|
const repairResult = await context.executor(repairPlan, { signal: context.signal });
|
|
111
122
|
emitAgentFinish(context, repairPlan, nodeAttempt, repairResult);
|
|
112
123
|
const repaired = normalizeAgentOutput(repairPlan, repairResult.stdout);
|
|
113
|
-
const
|
|
124
|
+
const repairedOutput = normalizeJsonSource(repaired.output);
|
|
125
|
+
const repairedValidation = validateJsonSchemaSource(repairedOutput, repairContext.schemaPath, context.worktreePath);
|
|
114
126
|
latest = {
|
|
115
127
|
evidence: [
|
|
116
128
|
...repaired.evidence,
|
|
117
129
|
...repairResult.stderr ? [`repair stderr: ${repairResult.stderr}`] : [],
|
|
118
130
|
...repairResult.timedOut ? ["output repair timed out"] : []
|
|
119
131
|
],
|
|
120
|
-
output:
|
|
132
|
+
output: repairedOutput
|
|
121
133
|
};
|
|
122
134
|
latestValidation = repairedValidation;
|
|
123
135
|
const passed = repairResult.exitCode === 0 && repairedValidation.passed;
|
|
@@ -131,7 +143,7 @@ async function runOutputRepair(context, node, normalized, repairContext, nodeAtt
|
|
|
131
143
|
});
|
|
132
144
|
if (passed) return {
|
|
133
145
|
evidence,
|
|
134
|
-
output:
|
|
146
|
+
output: repairedOutput
|
|
135
147
|
};
|
|
136
148
|
}
|
|
137
149
|
return {
|
|
@@ -6,6 +6,7 @@ import Ajv from "ajv";
|
|
|
6
6
|
import addFormats from "ajv-formats";
|
|
7
7
|
//#region src/runtime/json-validation/json-validation.ts
|
|
8
8
|
const LINE_RE = /\r?\n/;
|
|
9
|
+
const MARKDOWN_JSON_FENCE_RE = /^\s*```(?:json)?\s*\r?\n([\s\S]*?)\r?\n```\s*$/i;
|
|
9
10
|
const jsonSchemaValidator = addFormats(new Ajv({
|
|
10
11
|
allErrors: true,
|
|
11
12
|
strict: false
|
|
@@ -15,7 +16,7 @@ function parseRuntimeOutput(format, output) {
|
|
|
15
16
|
if (!(format === "json" || format === "json_schema" || format === "jsonl")) return { output };
|
|
16
17
|
try {
|
|
17
18
|
if (format === "jsonl") return { output: output.split(LINE_RE).filter((line) => line.trim().length > 0).map((line) => parseJson(line, "runtime JSONL line")) };
|
|
18
|
-
return { output: parseJson(output, "runtime JSON output") };
|
|
19
|
+
return { output: parseJson(normalizeJsonSource(output), "runtime JSON output") };
|
|
19
20
|
} catch (err) {
|
|
20
21
|
return {
|
|
21
22
|
error: err instanceof Error ? err.message : "failed to parse output",
|
|
@@ -26,7 +27,7 @@ function parseRuntimeOutput(format, output) {
|
|
|
26
27
|
function validateJsonSchemaSource(source, schemaPath, worktreePath) {
|
|
27
28
|
try {
|
|
28
29
|
const schemaSource = readJsonSchemaSource(schemaPath, worktreePath);
|
|
29
|
-
const value = parseJson(source, "JSON schema gate value");
|
|
30
|
+
const value = parseJson(normalizeJsonSource(source), "JSON schema gate value");
|
|
30
31
|
const validate = compiledJsonSchemaValidator(schemaPath, schemaSource);
|
|
31
32
|
const errors = validate(value) ? [] : formatJsonSchemaErrors(validate.errors ?? []);
|
|
32
33
|
return {
|
|
@@ -42,6 +43,10 @@ function validateJsonSchemaSource(source, schemaPath, worktreePath) {
|
|
|
42
43
|
};
|
|
43
44
|
}
|
|
44
45
|
}
|
|
46
|
+
function normalizeJsonSource(source) {
|
|
47
|
+
const trimmed = source.trim();
|
|
48
|
+
return MARKDOWN_JSON_FENCE_RE.exec(trimmed)?.[1].trim() ?? trimmed;
|
|
49
|
+
}
|
|
45
50
|
function readJsonSchemaSource(schemaPath, worktreePath) {
|
|
46
51
|
const standardName = standardOutputSchemaNameFromPath(schemaPath);
|
|
47
52
|
if (standardName) return standardOutputSchemaJson(standardName);
|
|
@@ -82,4 +87,4 @@ function parseJsonObject(value) {
|
|
|
82
87
|
}
|
|
83
88
|
}
|
|
84
89
|
//#endregion
|
|
85
|
-
export { parseJsonObject, parseRuntimeOutput, readJsonSchemaSource, readOptionalFile, validateJsonSchemaSource };
|
|
90
|
+
export { normalizeJsonSource, parseJsonObject, parseRuntimeOutput, readJsonSchemaSource, readOptionalFile, validateJsonSchemaSource };
|
package/dist/schedule-planner.js
CHANGED
|
@@ -485,35 +485,71 @@ function executeBaselineWorkflow() {
|
|
|
485
485
|
} };
|
|
486
486
|
}
|
|
487
487
|
async function planScheduleArtifact(baseline, plannerProfile, options, planningContext) {
|
|
488
|
-
|
|
489
|
-
const source = await runSchedulePlanner(
|
|
490
|
-
if (!source) throw new ScheduleArtifactError("schedule planner returned empty output");
|
|
488
|
+
const requiredPlannerProfile = requireSchedulePlannerProfile(plannerProfile, options.entrypointId);
|
|
489
|
+
const source = requireSchedulePlannerSource(await runSchedulePlanner(requiredPlannerProfile, plannerPrompt(options.entrypointId, options.task, baseline, options.config, planningContext), options));
|
|
491
490
|
const initial = acceptedGeneratedSchedule(parseGeneratedSchedule(source, "planner output"));
|
|
492
491
|
if (initial.ok) return initial.artifact;
|
|
493
|
-
|
|
494
|
-
|
|
492
|
+
return scheduleArtifactAfterRepair(await repairInvalidScheduleArtifact({
|
|
493
|
+
baseline,
|
|
494
|
+
initialFailure: initial.error,
|
|
495
|
+
initialSource: source,
|
|
496
|
+
options,
|
|
497
|
+
plannerProfile: requiredPlannerProfile
|
|
498
|
+
}), baseline, initial.error, source);
|
|
499
|
+
}
|
|
500
|
+
function requireSchedulePlannerProfile(plannerProfile, entrypointId) {
|
|
501
|
+
if (plannerProfile) return plannerProfile;
|
|
502
|
+
throw new ScheduleArtifactError(`schedule '${entrypointId}' requires planner_profile`);
|
|
503
|
+
}
|
|
504
|
+
function requireSchedulePlannerSource(source) {
|
|
505
|
+
if (source) return source;
|
|
506
|
+
throw new ScheduleArtifactError("schedule planner returned empty output");
|
|
507
|
+
}
|
|
508
|
+
function scheduleArtifactAfterRepair(repair, baseline, initialFailure, initialSource) {
|
|
509
|
+
if (repair.kind === "accepted") return repair.artifact;
|
|
510
|
+
if (repair.kind === "fallback") return baseline;
|
|
511
|
+
throw new ScheduleArtifactError([
|
|
512
|
+
"Schedule planner produced invalid output after repair.",
|
|
513
|
+
initialFailure.message,
|
|
514
|
+
"Original planner output:",
|
|
515
|
+
initialSource,
|
|
516
|
+
repair.latestFailure.message,
|
|
517
|
+
"Planner repair output:",
|
|
518
|
+
repair.latestSource
|
|
519
|
+
].join("\n"));
|
|
520
|
+
}
|
|
521
|
+
async function repairInvalidScheduleArtifact(input) {
|
|
522
|
+
let latestFailure = input.initialFailure;
|
|
523
|
+
let latestSource = input.initialSource;
|
|
495
524
|
for (let attempt = 1; attempt <= SCHEDULE_PLANNER_REPAIR_ATTEMPTS; attempt += 1) {
|
|
496
|
-
const repairedSource = await
|
|
497
|
-
|
|
498
|
-
baseline,
|
|
499
|
-
error: latestFailure,
|
|
500
|
-
source: latestSource
|
|
501
|
-
}), options, "schedule-plan-repair");
|
|
502
|
-
if (!repairedSource) throw new ScheduleArtifactError(`schedule planner repair returned empty output after invalid schedule\n${latestFailure.message}\nPlanner output:\n${latestSource}`);
|
|
525
|
+
const repairedSource = await runScheduleRepair(input, latestFailure, latestSource, attempt);
|
|
526
|
+
if (!repairedSource) return { kind: "fallback" };
|
|
503
527
|
const repaired = acceptedGeneratedSchedule(parseGeneratedSchedule(repairedSource, "planner repair output"));
|
|
504
|
-
if (repaired.ok) return
|
|
528
|
+
if (repaired.ok) return {
|
|
529
|
+
artifact: repaired.artifact,
|
|
530
|
+
kind: "accepted"
|
|
531
|
+
};
|
|
505
532
|
latestFailure = repaired.error;
|
|
506
533
|
latestSource = repairedSource;
|
|
507
534
|
}
|
|
508
|
-
|
|
509
|
-
"
|
|
510
|
-
|
|
511
|
-
"Original planner output:",
|
|
512
|
-
source,
|
|
513
|
-
latestFailure.message,
|
|
514
|
-
"Planner repair output:",
|
|
535
|
+
return {
|
|
536
|
+
kind: "invalid",
|
|
537
|
+
latestFailure,
|
|
515
538
|
latestSource
|
|
516
|
-
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
async function runScheduleRepair(input, latestFailure, latestSource, attempt) {
|
|
542
|
+
try {
|
|
543
|
+
return await runSchedulePlanner(input.plannerProfile, plannerRepairPrompt({
|
|
544
|
+
attempt,
|
|
545
|
+
baseline: input.baseline,
|
|
546
|
+
error: latestFailure,
|
|
547
|
+
source: latestSource
|
|
548
|
+
}), input.options, "schedule-plan-repair");
|
|
549
|
+
} catch (err) {
|
|
550
|
+
if (err instanceof ScheduleArtifactError) return;
|
|
551
|
+
throw err;
|
|
552
|
+
}
|
|
517
553
|
}
|
|
518
554
|
function parseGeneratedSchedule(source, sourcePath) {
|
|
519
555
|
const parseableSource = normalizeGeneratedScheduleSource(source);
|
|
@@ -644,18 +680,43 @@ function plannerRepairPrompt(inputs) {
|
|
|
644
680
|
function allowedProfilePromptLine(config, id) {
|
|
645
681
|
const profile = config.profiles[id];
|
|
646
682
|
const runner = config.runners[profile.runner];
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
683
|
+
return `- ${id} (${profilePromptFields(config, id, profile, runner).join("; ")})`;
|
|
684
|
+
}
|
|
685
|
+
function profilePromptFields(config, id, profile, runner) {
|
|
686
|
+
return definedProfilePromptFields([
|
|
687
|
+
requiredProfilePromptField("runner", profile.runner),
|
|
688
|
+
optionalProfilePromptField("model", profileModel(profile, runner)),
|
|
689
|
+
optionalProfilePromptField("scheduling_roles", effectiveSchedulingRoles(config, id).join(", ")),
|
|
690
|
+
optionalProfilePromptField("description", profile.description),
|
|
691
|
+
optionalProfilePromptField("tools", profileTools(profile)),
|
|
692
|
+
optionalProfilePromptField("filesystem", profileFilesystemMode(profile)),
|
|
693
|
+
optionalProfilePromptField("network", profileNetworkMode(profile)),
|
|
694
|
+
requiredProfilePromptField("output", profileOutputFormat(profile))
|
|
695
|
+
]);
|
|
696
|
+
}
|
|
697
|
+
function profileModel(profile, runner) {
|
|
698
|
+
return profile.model ?? runner?.model;
|
|
699
|
+
}
|
|
700
|
+
function profileTools(profile) {
|
|
701
|
+
return profile.tools?.join(", ");
|
|
702
|
+
}
|
|
703
|
+
function profileFilesystemMode(profile) {
|
|
704
|
+
return profile.filesystem?.mode;
|
|
705
|
+
}
|
|
706
|
+
function profileNetworkMode(profile) {
|
|
707
|
+
return profile.network?.mode;
|
|
708
|
+
}
|
|
709
|
+
function profileOutputFormat(profile) {
|
|
710
|
+
return profile.output?.format ?? "text";
|
|
711
|
+
}
|
|
712
|
+
function requiredProfilePromptField(label, value) {
|
|
713
|
+
return `${label}: ${value}`;
|
|
714
|
+
}
|
|
715
|
+
function optionalProfilePromptField(label, value) {
|
|
716
|
+
return value ? requiredProfilePromptField(label, value) : void 0;
|
|
717
|
+
}
|
|
718
|
+
function definedProfilePromptFields(fields) {
|
|
719
|
+
return fields.filter((field) => Boolean(field));
|
|
659
720
|
}
|
|
660
721
|
function schedulerCatalogPrompt(config, entrypointId) {
|
|
661
722
|
const catalog = resolveSchedulerCatalog(config, entrypointId);
|
|
@@ -837,16 +898,7 @@ function nodesByAssignedWorkUnit(nodes) {
|
|
|
837
898
|
return grouped;
|
|
838
899
|
}
|
|
839
900
|
function hasPathToNode(sourceId, targetId, dependentsByNeed) {
|
|
840
|
-
|
|
841
|
-
const seen = /* @__PURE__ */ new Set();
|
|
842
|
-
while (queue.length > 0) {
|
|
843
|
-
const node = queue.shift();
|
|
844
|
-
if (!node || seen.has(node.id)) continue;
|
|
845
|
-
if (node.id === targetId) return true;
|
|
846
|
-
seen.add(node.id);
|
|
847
|
-
queue.push(...dependentsByNeed.get(node.id) ?? []);
|
|
848
|
-
}
|
|
849
|
-
return false;
|
|
901
|
+
return hasReachableDependent(sourceId, dependentsByNeed, (node) => node.id === targetId);
|
|
850
902
|
}
|
|
851
903
|
function unsupportedGeneratedBuiltinIssues(artifact) {
|
|
852
904
|
const allowed = new Set(SCHEDULE_BUILTINS);
|
package/package.json
CHANGED
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
"prepack": "bun run build:cli"
|
|
121
121
|
},
|
|
122
122
|
"type": "module",
|
|
123
|
-
"version": "1.27.
|
|
123
|
+
"version": "1.27.12",
|
|
124
124
|
"description": "Config-driven multi-agent pipeline runner for repository work",
|
|
125
125
|
"main": "./dist/index.js",
|
|
126
126
|
"types": "./dist/index.d.ts",
|