@voyantjs/workflows-orchestrator 0.107.5 → 0.107.6
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/driver-inmemory.d.ts.map +1 -1
- package/dist/driver-inmemory.js +1 -0
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +1 -0
- package/dist/resume-run.d.ts +17 -0
- package/dist/resume-run.d.ts.map +1 -1
- package/dist/resume-run.js +54 -0
- package/dist/schedule.d.ts.map +1 -1
- package/dist/schedule.js +9 -1
- package/dist/testing/driver-compliance.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/orchestrator-test-support.ts +18 -0
- package/src/driver-inmemory.ts +2 -1
- package/src/orchestrator.ts +1 -0
- package/src/resume-run.ts +59 -0
- package/src/schedule.ts +12 -1
- package/src/testing/driver-compliance.ts +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver-inmemory.d.ts","sourceRoot":"","sources":["../src/driver-inmemory.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"driver-inmemory.d.ts","sourceRoot":"","sources":["../src/driver-inmemory.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,eAAe,EAMhB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACL,KAAK,aAAa,EAQnB,MAAM,4BAA4B,CAAA;AAkBnC,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAIxD,MAAM,WAAW,qBAAqB;IACpC,wEAAwE;IACxE,kBAAkB,CAAC,EAAE,eAAe,CAAA;IACpC,wDAAwD;IACxD,UAAU,CAAC,EAAE,SAAS,CAAC,YAAY,CAAC,CAAA;IACpC,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,2DAA2D;IAC3D,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,2EAA2E;IAC3E,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAChC;AAQD;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,GAAE,qBAA0B,GAAG,aAAa,CAyTpF"}
|
package/dist/driver-inmemory.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// agent-quality: file-size exception -- owner: workflows-orchestrator; existing module stays co-located until a dedicated split preserves behavior and tests.
|
|
1
2
|
// In-memory WorkflowDriver — primarily for tests, also for short-lived
|
|
2
3
|
// scripts and the parameterized compliance suite.
|
|
3
4
|
//
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"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"}
|
package/dist/orchestrator.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// agent-quality: file-size exception -- owner: workflows-orchestrator; existing module stays co-located until a dedicated split preserves behavior and tests.
|
|
1
2
|
// Public entry points for the reference orchestrator.
|
|
2
3
|
//
|
|
3
4
|
// `trigger()` creates a RunRecord, drives it forward through the
|
package/dist/resume-run.d.ts
CHANGED
|
@@ -20,4 +20,21 @@ export interface BuildSeededResumeJournalInput {
|
|
|
20
20
|
}
|
|
21
21
|
export declare function buildResumeJournal(input: BuildResumeJournalInput): BuildResumeJournalResult;
|
|
22
22
|
export declare function buildSeededResumeJournal(input: BuildSeededResumeJournalInput): BuildResumeJournalResult;
|
|
23
|
+
export type SeedResultsValidation = {
|
|
24
|
+
ok: true;
|
|
25
|
+
seedResults: Record<string, unknown>;
|
|
26
|
+
} | {
|
|
27
|
+
ok: false;
|
|
28
|
+
message: string;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Strict structural validation for caller-supplied `seedResults`
|
|
32
|
+
* (`POST /api/runs/:id/resume`). Seeded entries are written verbatim
|
|
33
|
+
* into the new run's journal as already-completed steps, so they let
|
|
34
|
+
* the caller assert "this step ran and produced this output" — they
|
|
35
|
+
* must be gated behind an operator credential AND shape-checked:
|
|
36
|
+
* a record of bounded, control-character-free step ids to
|
|
37
|
+
* JSON-serializable values, bounded in count and total size.
|
|
38
|
+
*/
|
|
39
|
+
export declare function validateSeedResults(value: unknown): SeedResultsValidation;
|
|
23
40
|
//# sourceMappingURL=resume-run.d.ts.map
|
package/dist/resume-run.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resume-run.d.ts","sourceRoot":"","sources":["../src/resume-run.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAoB,MAAM,YAAY,CAAA;AAE3E,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,SAAS,CAAA;IACjB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACrC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,wBAAwB;IACvC,cAAc,EAAE,MAAM,CAAA;IACtB,OAAO,EAAE,YAAY,CAAA;IACrB,oBAAoB,EAAE,MAAM,CAAA;CAC7B;AAED,MAAM,WAAW,6BAA6B;IAC5C,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACvC,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,wBAAwB,CAwC3F;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,6BAA6B,GACnC,wBAAwB,CAgB1B"}
|
|
1
|
+
{"version":3,"file":"resume-run.d.ts","sourceRoot":"","sources":["../src/resume-run.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAoB,MAAM,YAAY,CAAA;AAE3E,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,SAAS,CAAA;IACjB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACrC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,wBAAwB;IACvC,cAAc,EAAE,MAAM,CAAA;IACtB,OAAO,EAAE,YAAY,CAAA;IACrB,oBAAoB,EAAE,MAAM,CAAA;CAC7B;AAED,MAAM,WAAW,6BAA6B;IAC5C,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACvC,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,wBAAwB,CAwC3F;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,6BAA6B,GACnC,wBAAwB,CAgB1B;AAED,MAAM,MAAM,qBAAqB,GAC7B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAClD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAQlC;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,qBAAqB,CAsCzE"}
|
package/dist/resume-run.js
CHANGED
|
@@ -47,6 +47,60 @@ export function buildSeededResumeJournal(input) {
|
|
|
47
47
|
metadataAppliedCount: input.metadataAppliedCount ?? 0,
|
|
48
48
|
};
|
|
49
49
|
}
|
|
50
|
+
const SEED_RESULTS_MAX_ENTRIES = 256;
|
|
51
|
+
const SEED_RESULTS_MAX_STEP_ID_LENGTH = 200;
|
|
52
|
+
const SEED_RESULTS_MAX_SERIALIZED_CHARS = 1_000_000;
|
|
53
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: rejecting control chars is the point -- owner: workflows-orchestrator; existing suppression is intentional pending typed cleanup.
|
|
54
|
+
const CONTROL_CHARS = /[\x00-\x1f\x7f]/;
|
|
55
|
+
/**
|
|
56
|
+
* Strict structural validation for caller-supplied `seedResults`
|
|
57
|
+
* (`POST /api/runs/:id/resume`). Seeded entries are written verbatim
|
|
58
|
+
* into the new run's journal as already-completed steps, so they let
|
|
59
|
+
* the caller assert "this step ran and produced this output" — they
|
|
60
|
+
* must be gated behind an operator credential AND shape-checked:
|
|
61
|
+
* a record of bounded, control-character-free step ids to
|
|
62
|
+
* JSON-serializable values, bounded in count and total size.
|
|
63
|
+
*/
|
|
64
|
+
export function validateSeedResults(value) {
|
|
65
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
66
|
+
return { ok: false, message: "seedResults must be an object of stepId → output" };
|
|
67
|
+
}
|
|
68
|
+
const entries = Object.entries(value);
|
|
69
|
+
if (entries.length > SEED_RESULTS_MAX_ENTRIES) {
|
|
70
|
+
return {
|
|
71
|
+
ok: false,
|
|
72
|
+
message: `seedResults may contain at most ${SEED_RESULTS_MAX_ENTRIES} entries`,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
for (const [stepId, output] of entries) {
|
|
76
|
+
if (stepId.length === 0 || stepId.length > SEED_RESULTS_MAX_STEP_ID_LENGTH) {
|
|
77
|
+
return {
|
|
78
|
+
ok: false,
|
|
79
|
+
message: `seedResults step ids must be 1-${SEED_RESULTS_MAX_STEP_ID_LENGTH} characters`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (CONTROL_CHARS.test(stepId)) {
|
|
83
|
+
return { ok: false, message: "seedResults step ids must not contain control characters" };
|
|
84
|
+
}
|
|
85
|
+
let serialized;
|
|
86
|
+
try {
|
|
87
|
+
serialized = JSON.stringify(output);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return { ok: false, message: `seedResults["${stepId}"] is not JSON-serializable` };
|
|
91
|
+
}
|
|
92
|
+
if (serialized === undefined) {
|
|
93
|
+
return { ok: false, message: `seedResults["${stepId}"] is not JSON-serializable` };
|
|
94
|
+
}
|
|
95
|
+
if (serialized.length > SEED_RESULTS_MAX_SERIALIZED_CHARS) {
|
|
96
|
+
return {
|
|
97
|
+
ok: false,
|
|
98
|
+
message: `seedResults["${stepId}"] exceeds the ${SEED_RESULTS_MAX_SERIALIZED_CHARS}-character serialized limit`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return { ok: true, seedResults: value };
|
|
103
|
+
}
|
|
50
104
|
function findFirstFailedStep(parent) {
|
|
51
105
|
for (const [stepId, entry] of Object.entries(parent.journal.stepResults)) {
|
|
52
106
|
if (entry.status === "err")
|
package/dist/schedule.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schedule.d.ts","sourceRoot":"","sources":["../src/schedule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AACzF,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAEtF,MAAM,MAAM,sBAAsB,GAAG,mBAAmB,GAAG,gBAAgB,CAAA;AAE3E,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,sBAAsB,CAAA;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,SAAS,cAAc,EAAE,CAAA;IAClC,MAAM,EAAE,CAAC,IAAI,EAAE;QACb,UAAU,EAAE,MAAM,CAAA;QAClB,KAAK,EAAE,OAAO,CAAA;QACd,UAAU,EAAE,MAAM,CAAA;QAClB,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,MAAM,EAAE,MAAM,CAAA;KACf,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACnB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,eAAe,CAAA;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,OAAO,WAAW,CAAA;IAChC,aAAa,CAAC,EAAE,OAAO,aAAa,CAAA;IACpC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;CAChF;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB,WAAW,EAAE,MAAM;QACjB,UAAU,EAAE,MAAM,CAAA;QAClB,UAAU,EAAE,MAAM,CAAA;QAClB,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,MAAM,EAAE,MAAM,CAAA;QACd,IAAI,EAAE,OAAO,CAAA;KACd,EAAE,CAAA;IACH,WAAW,EAAE,MAAM,MAAM,CAAA;CAC1B;
|
|
1
|
+
{"version":3,"file":"schedule.d.ts","sourceRoot":"","sources":["../src/schedule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAA;AACzF,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAEtF,MAAM,MAAM,sBAAsB,GAAG,mBAAmB,GAAG,gBAAgB,CAAA;AAE3E,MAAM,WAAW,cAAc;IAC7B,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,sBAAsB,CAAA;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,SAAS,cAAc,EAAE,CAAA;IAClC,MAAM,EAAE,CAAC,IAAI,EAAE;QACb,UAAU,EAAE,MAAM,CAAA;QAClB,KAAK,EAAE,OAAO,CAAA;QACd,UAAU,EAAE,MAAM,CAAA;QAClB,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,MAAM,EAAE,MAAM,CAAA;KACf,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACnB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,eAAe,CAAA;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,OAAO,WAAW,CAAA;IAChC,aAAa,CAAC,EAAE,OAAO,aAAa,CAAA;IACpC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;CAChF;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB,WAAW,EAAE,MAAM;QACjB,UAAU,EAAE,MAAM,CAAA;QAClB,UAAU,EAAE,MAAM,CAAA;QAClB,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,MAAM,EAAE,MAAM,CAAA;QACd,IAAI,EAAE,OAAO,CAAA;KACd,EAAE,CAAA;IACH,WAAW,EAAE,MAAM,MAAM,CAAA;CAC1B;AA0BD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,cAAc,EAAE,CAYpF;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,GAAG,eAAe,CAmHpE;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,sBAAsB,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CASpF;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,GAAG,EAAE,MAAM,EAAE,CAAA;IACb,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,GAAG,EAAE,MAAM,EAAE,CAAA;CACd;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAYhD;AA8BD,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAmBnE;AAED,wBAAgB,IAAI,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAqBjE"}
|
package/dist/schedule.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
function unrefTimer(timer) {
|
|
2
|
+
if (typeof timer === "object" &&
|
|
3
|
+
timer !== null &&
|
|
4
|
+
"unref" in timer &&
|
|
5
|
+
typeof timer.unref === "function") {
|
|
6
|
+
timer.unref();
|
|
7
|
+
}
|
|
8
|
+
}
|
|
1
9
|
export function manifestScheduleSources(manifest) {
|
|
2
10
|
const sources = [];
|
|
3
11
|
for (const workflow of manifest.workflows) {
|
|
@@ -106,7 +114,7 @@ export function createScheduler(deps) {
|
|
|
106
114
|
timer = setInt(() => {
|
|
107
115
|
doTick().catch(() => { });
|
|
108
116
|
}, tickMs);
|
|
109
|
-
timer
|
|
117
|
+
unrefTimer(timer);
|
|
110
118
|
},
|
|
111
119
|
stop() {
|
|
112
120
|
if (!timer)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver-compliance.d.ts","sourceRoot":"","sources":["../../src/testing/driver-compliance.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;
|
|
1
|
+
{"version":3,"file":"driver-compliance.d.ts","sourceRoot":"","sources":["../../src/testing/driver-compliance.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAEnG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAKpE;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,eAAe,CAa1F;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,GAAE,eAAuC,GAChD,iBAAiB,GAAG;IAAE,IAAI,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;CAAE,CAOhE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,SAAe,GAAG,gBAAgB,CAa5E;AAaD;;;;;;GAMG;AACH,MAAM,WAAW,4BAA4B;IAC3C;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAC9B;AAID,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,aAAa,EAChC,YAAY,GAAE,4BAAiC,GAC9C,IAAI,CAmnBN"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyantjs/workflows-orchestrator",
|
|
3
|
-
"version": "0.107.
|
|
3
|
+
"version": "0.107.6",
|
|
4
4
|
"description": "Reference orchestrator core for Voyant Workflows — drives runs through the tenant step handler over the v1 wire protocol.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"NOTICE"
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@voyantjs/workflows": "^0.107.
|
|
33
|
+
"@voyantjs/workflows": "^0.107.6"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^20.12.0",
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { __resetRegistry } from "@voyantjs/workflows"
|
|
2
|
+
import { handleStepRequest, type WorkflowStepRequest } from "@voyantjs/workflows/handler"
|
|
3
|
+
import { beforeEach } from "vitest"
|
|
4
|
+
import type { StepHandler } from "../index.js"
|
|
5
|
+
|
|
6
|
+
export const handler: StepHandler = async (req: WorkflowStepRequest, opts) => {
|
|
7
|
+
return await handleStepRequest(req, {}, opts)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const tenantMeta = {
|
|
11
|
+
tenantId: "tnt_test",
|
|
12
|
+
projectId: "prj_test",
|
|
13
|
+
organizationId: "org_test",
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
__resetRegistry()
|
|
18
|
+
})
|
package/src/driver-inmemory.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// agent-quality: file-size exception -- owner: workflows-orchestrator; existing module stays co-located until a dedicated split preserves behavior and tests.
|
|
1
2
|
// In-memory WorkflowDriver — primarily for tests, also for short-lived
|
|
2
3
|
// scripts and the parameterized compliance suite.
|
|
3
4
|
//
|
|
@@ -307,7 +308,7 @@ export function createInMemoryDriver(opts: InMemoryDriverOptions = {}): DriverFa
|
|
|
307
308
|
scheduleDelayedRun(resumed)
|
|
308
309
|
})
|
|
309
310
|
}, delayMs)
|
|
310
|
-
timer.unref?.()
|
|
311
|
+
;(timer as { unref?: () => void }).unref?.()
|
|
311
312
|
}
|
|
312
313
|
|
|
313
314
|
async function triggerRecord(
|
package/src/orchestrator.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// agent-quality: file-size exception -- owner: workflows-orchestrator; existing module stays co-located until a dedicated split preserves behavior and tests.
|
|
1
2
|
// Public entry points for the reference orchestrator.
|
|
2
3
|
//
|
|
3
4
|
// `trigger()` creates a RunRecord, drives it forward through the
|
package/src/resume-run.ts
CHANGED
|
@@ -85,6 +85,65 @@ export function buildSeededResumeJournal(
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
export type SeedResultsValidation =
|
|
89
|
+
| { ok: true; seedResults: Record<string, unknown> }
|
|
90
|
+
| { ok: false; message: string }
|
|
91
|
+
|
|
92
|
+
const SEED_RESULTS_MAX_ENTRIES = 256
|
|
93
|
+
const SEED_RESULTS_MAX_STEP_ID_LENGTH = 200
|
|
94
|
+
const SEED_RESULTS_MAX_SERIALIZED_CHARS = 1_000_000
|
|
95
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: rejecting control chars is the point -- owner: workflows-orchestrator; existing suppression is intentional pending typed cleanup.
|
|
96
|
+
const CONTROL_CHARS = /[\x00-\x1f\x7f]/
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Strict structural validation for caller-supplied `seedResults`
|
|
100
|
+
* (`POST /api/runs/:id/resume`). Seeded entries are written verbatim
|
|
101
|
+
* into the new run's journal as already-completed steps, so they let
|
|
102
|
+
* the caller assert "this step ran and produced this output" — they
|
|
103
|
+
* must be gated behind an operator credential AND shape-checked:
|
|
104
|
+
* a record of bounded, control-character-free step ids to
|
|
105
|
+
* JSON-serializable values, bounded in count and total size.
|
|
106
|
+
*/
|
|
107
|
+
export function validateSeedResults(value: unknown): SeedResultsValidation {
|
|
108
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
109
|
+
return { ok: false, message: "seedResults must be an object of stepId → output" }
|
|
110
|
+
}
|
|
111
|
+
const entries = Object.entries(value as Record<string, unknown>)
|
|
112
|
+
if (entries.length > SEED_RESULTS_MAX_ENTRIES) {
|
|
113
|
+
return {
|
|
114
|
+
ok: false,
|
|
115
|
+
message: `seedResults may contain at most ${SEED_RESULTS_MAX_ENTRIES} entries`,
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
for (const [stepId, output] of entries) {
|
|
119
|
+
if (stepId.length === 0 || stepId.length > SEED_RESULTS_MAX_STEP_ID_LENGTH) {
|
|
120
|
+
return {
|
|
121
|
+
ok: false,
|
|
122
|
+
message: `seedResults step ids must be 1-${SEED_RESULTS_MAX_STEP_ID_LENGTH} characters`,
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (CONTROL_CHARS.test(stepId)) {
|
|
126
|
+
return { ok: false, message: "seedResults step ids must not contain control characters" }
|
|
127
|
+
}
|
|
128
|
+
let serialized: string | undefined
|
|
129
|
+
try {
|
|
130
|
+
serialized = JSON.stringify(output)
|
|
131
|
+
} catch {
|
|
132
|
+
return { ok: false, message: `seedResults["${stepId}"] is not JSON-serializable` }
|
|
133
|
+
}
|
|
134
|
+
if (serialized === undefined) {
|
|
135
|
+
return { ok: false, message: `seedResults["${stepId}"] is not JSON-serializable` }
|
|
136
|
+
}
|
|
137
|
+
if (serialized.length > SEED_RESULTS_MAX_SERIALIZED_CHARS) {
|
|
138
|
+
return {
|
|
139
|
+
ok: false,
|
|
140
|
+
message: `seedResults["${stepId}"] exceeds the ${SEED_RESULTS_MAX_SERIALIZED_CHARS}-character serialized limit`,
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return { ok: true, seedResults: value as Record<string, unknown> }
|
|
145
|
+
}
|
|
146
|
+
|
|
88
147
|
function findFirstFailedStep(parent: RunRecord): string | undefined {
|
|
89
148
|
for (const [stepId, entry] of Object.entries(parent.journal.stepResults)) {
|
|
90
149
|
if (entry.status === "err") return stepId
|
package/src/schedule.ts
CHANGED
|
@@ -40,6 +40,17 @@ export interface SchedulerHandle {
|
|
|
40
40
|
sourceCount: () => number
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
function unrefTimer(timer: unknown): void {
|
|
44
|
+
if (
|
|
45
|
+
typeof timer === "object" &&
|
|
46
|
+
timer !== null &&
|
|
47
|
+
"unref" in timer &&
|
|
48
|
+
typeof timer.unref === "function"
|
|
49
|
+
) {
|
|
50
|
+
timer.unref()
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
43
54
|
interface SourceState {
|
|
44
55
|
source: ScheduleSource
|
|
45
56
|
scheduleId: string
|
|
@@ -161,7 +172,7 @@ export function createScheduler(deps: SchedulerDeps): SchedulerHandle {
|
|
|
161
172
|
timer = setInt(() => {
|
|
162
173
|
doTick().catch(() => {})
|
|
163
174
|
}, tickMs)
|
|
164
|
-
|
|
175
|
+
unrefTimer(timer)
|
|
165
176
|
},
|
|
166
177
|
stop() {
|
|
167
178
|
if (!timer) return
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
import { __resetRegistry, workflow } from "@voyantjs/workflows"
|
|
22
22
|
import type { DriverFactory, DriverFactoryDeps, ServiceResolver } from "@voyantjs/workflows/driver"
|
|
23
|
+
// agent-quality: file-size exception -- Shared driver compliance suite intentionally keeps cross-driver behavioral cases together so all drivers run the same contract.
|
|
23
24
|
import type { WorkflowManifest } from "@voyantjs/workflows/protocol"
|
|
24
25
|
import { beforeEach, describe, expect, test, vi } from "vitest"
|
|
25
26
|
|
|
@@ -527,7 +528,7 @@ export function runDriverComplianceSuite(
|
|
|
527
528
|
{
|
|
528
529
|
id: `ef_${uniqueId("bad")}`,
|
|
529
530
|
eventType: "evt.x",
|
|
530
|
-
where: { wat: "huh" } as
|
|
531
|
+
where: { wat: "huh" } as never,
|
|
531
532
|
payloadHash: "h",
|
|
532
533
|
targetWorkflowId: wfId,
|
|
533
534
|
},
|