@automatalabs/workflows 0.58.0 → 0.58.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/mcp-server.js +400 -45
- package/package.json +3 -3
package/dist/mcp-server.js
CHANGED
|
@@ -30667,6 +30667,9 @@ var permissionResponseSchema = external_exports.object({
|
|
|
30667
30667
|
external_exports.object({ outcome: external_exports.literal("selected"), optionId: external_exports.string().min(1).max(512) }).strict()
|
|
30668
30668
|
])
|
|
30669
30669
|
}).strict();
|
|
30670
|
+
var WORKFLOW_RESULT_CHUNK_BYTES_DEFAULT = 16384;
|
|
30671
|
+
var WORKFLOW_RESULT_CHUNK_BYTES_MAX = 16384;
|
|
30672
|
+
var WORKFLOW_RESULT_CHUNK_BYTES_MIN = 4;
|
|
30670
30673
|
var checkpointRepliesSchema = external_exports.record(
|
|
30671
30674
|
external_exports.string().refine(
|
|
30672
30675
|
(key) => {
|
|
@@ -30678,17 +30681,17 @@ var checkpointRepliesSchema = external_exports.record(
|
|
|
30678
30681
|
external_exports.unknown()
|
|
30679
30682
|
);
|
|
30680
30683
|
var workflowToolInputShape = {
|
|
30681
|
-
action: external_exports.enum(["run", "config", "inspect", "await", "stop", "permissions-response"]).optional().describe(
|
|
30682
|
-
"Operation. Omit or use run to validate then execute; config discovers live backend/model/mode/config options; inspect/await expose
|
|
30684
|
+
action: external_exports.enum(["run", "config", "inspect", "await", "result", "stop", "permissions-response"]).optional().describe(
|
|
30685
|
+
"Operation. Omit or use run to validate then execute; config discovers live backend/model/mode/config options; inspect/await expose lifecycle and action requirements; result pages the exact completed JSON result; permissions-response resolves one pending ACP permission; stop aborts a run or one in-flight agent."
|
|
30683
30686
|
),
|
|
30684
30687
|
script: external_exports.string().min(1).optional().describe(
|
|
30685
|
-
"Raw JavaScript workflow script (no Markdown fences). Exactly one of script or scriptPath is required for run; both are forbidden for config/inspect/await/stop/permissions-response. First statement MUST be `export const meta = { name, description, phases? }`. When present, phases MUST be an array of objects shaped `{ title: string, detail?: string, model?: string }`, never an array of strings."
|
|
30688
|
+
"Raw JavaScript workflow script (no Markdown fences). Exactly one of script or scriptPath is required for run; both are forbidden for config/inspect/await/result/stop/permissions-response. First statement MUST be `export const meta = { name, description, phases? }`. When present, phases MUST be an array of objects shaped `{ title: string, detail?: string, model?: string }`, never an array of strings."
|
|
30686
30689
|
),
|
|
30687
30690
|
scriptPath: external_exports.string().min(1).refine((value) => isAbsolute(value), "scriptPath must be an absolute path").optional().describe(
|
|
30688
|
-
"Absolute path, on the server's filesystem, to a workflow script file read once at admission. Exactly one of script or scriptPath is required for run; both are forbidden for config/inspect/await/stop/permissions-response. Relative paths are rejected."
|
|
30691
|
+
"Absolute path, on the server's filesystem, to a workflow script file read once at admission. Exactly one of script or scriptPath is required for run; both are forbidden for config/inspect/await/result/stop/permissions-response. Relative paths are rejected."
|
|
30689
30692
|
),
|
|
30690
30693
|
projectDir: external_exports.string().min(1).refine((value) => isAbsolute(value), "projectDir must be an absolute path").optional().describe(
|
|
30691
|
-
"Absolute project directory used as the cwd for config discovery and, for run, the project-scoped store (where the runId, journal, and resume state live) plus default execution cwd. Required for run and config on the shared workflow daemon; on a single-project (in-process) server it defaults to that server's own project. Forbidden for inspect/await/stop/permissions-response \u2014 a runId locates its project."
|
|
30694
|
+
"Absolute project directory used as the cwd for config discovery and, for run, the project-scoped store (where the runId, journal, and resume state live) plus default execution cwd. Required for run and config on the shared workflow daemon; on a single-project (in-process) server it defaults to that server's own project. Forbidden for inspect/await/result/stop/permissions-response \u2014 a runId locates its project."
|
|
30692
30695
|
),
|
|
30693
30696
|
harnesses: external_exports.array(external_exports.string().regex(/^[a-z][a-z0-9._-]*$/i, "invalid backend name")).min(1).max(16).optional().describe('With action="config", backend names to probe. Omit to probe every backend registered on this server.'),
|
|
30694
30697
|
modelSpecs: external_exports.array(external_exports.string().min(1).max(256)).min(1).max(16).optional().describe(
|
|
@@ -30710,7 +30713,7 @@ var workflowToolInputShape = {
|
|
|
30710
30713
|
resumePolicy: external_exports.enum(["auto", "positional"]).optional().describe('Resume matching policy. Default "auto"; requires resumeFromRunId.'),
|
|
30711
30714
|
checkpointReplies: checkpointRepliesSchema.optional().describe("With resumeFromRunId, durable-checkpoint decisions keyed by checkpointContext.callIndex."),
|
|
30712
30715
|
background: external_exports.boolean().optional().describe("Default false. True acknowledges after admission and executes in this server process."),
|
|
30713
|
-
runId: external_exports.string().max(128).regex(/^[a-z0-9]+-[a-z0-9]+$/, "runId must be an engine-generated run ID").optional().describe("Project-scoped workflow run ID. Required for inspect/await/stop/permissions-response; forbidden for config/run."),
|
|
30716
|
+
runId: external_exports.string().max(128).regex(/^[a-z0-9]+-[a-z0-9]+$/, "runId must be an engine-generated run ID").optional().describe("Project-scoped workflow run ID. Required for inspect/await/result/stop/permissions-response; forbidden for config/run."),
|
|
30714
30717
|
permissionId: external_exports.string().uuid().optional().describe('With action="permissions-response", the opaque pending permission id returned by inspect/await.'),
|
|
30715
30718
|
response: permissionResponseSchema.optional().describe('With action="permissions-response", an exact ACP selected optionId or cancelled outcome.'),
|
|
30716
30719
|
callIndex: external_exports.number().int().nonnegative().safe().optional().describe(
|
|
@@ -30724,7 +30727,9 @@ var workflowToolInputShape = {
|
|
|
30724
30727
|
message: "labelGlob must contain from 1 through 128 Unicode code points"
|
|
30725
30728
|
}).optional().describe("Case-sensitive whole-label glob using *, ?, and backslash escaping."),
|
|
30726
30729
|
logLines: external_exports.number().int().min(0).max(50).optional().describe("Latest run-log lines. Default 20; range 0..50."),
|
|
30727
|
-
waitMs: external_exports.number().int().min(0).max(25e3).optional().describe("Await duration in milliseconds. Default 20000; range 0..25000. Zero reads without blocking.")
|
|
30730
|
+
waitMs: external_exports.number().int().min(0).max(25e3).optional().describe("Await duration in milliseconds. Default 20000; range 0..25000. Zero reads without blocking."),
|
|
30731
|
+
offset: external_exports.number().int().nonnegative().safe().optional().describe('With action="result", UTF-8 byte offset into the exact serialized JSON. Default 0; use the previous endOffset.'),
|
|
30732
|
+
maxBytes: external_exports.number().int().min(WORKFLOW_RESULT_CHUNK_BYTES_MIN).max(WORKFLOW_RESULT_CHUNK_BYTES_MAX).optional().describe(`With action="result", maximum UTF-8 bytes returned. Default and maximum ${WORKFLOW_RESULT_CHUNK_BYTES_DEFAULT}.`)
|
|
30728
30733
|
};
|
|
30729
30734
|
function hasConfigFields(raw) {
|
|
30730
30735
|
return raw.harnesses !== void 0 || raw.modelSpecs !== void 0 || raw.modelFilter !== void 0 || raw.probeTimeoutMs !== void 0;
|
|
@@ -30732,6 +30737,9 @@ function hasConfigFields(raw) {
|
|
|
30732
30737
|
function hasPermissionFields(raw) {
|
|
30733
30738
|
return raw.permissionId !== void 0 || raw.response !== void 0;
|
|
30734
30739
|
}
|
|
30740
|
+
function hasResultFields(raw) {
|
|
30741
|
+
return raw.offset !== void 0 || raw.maxBytes !== void 0;
|
|
30742
|
+
}
|
|
30735
30743
|
function hasExecutionFields(raw) {
|
|
30736
30744
|
return raw.script !== void 0 || raw.scriptPath !== void 0 || raw.projectDir !== void 0 || raw.args !== void 0 || raw.maxAgents !== void 0 || raw.concurrency !== void 0 || raw.agentRetries !== void 0 || raw.agentTimeoutMs !== void 0 || raw.agentIdleTimeoutMs !== void 0 || raw.resumeFromRunId !== void 0 || raw.resumePolicy !== void 0 || raw.checkpointReplies !== void 0 || raw.background !== void 0;
|
|
30737
30745
|
}
|
|
@@ -30740,7 +30748,7 @@ function invalid(message) {
|
|
|
30740
30748
|
}
|
|
30741
30749
|
function parseWorkflowToolInput(raw, options = {}) {
|
|
30742
30750
|
if (raw.action === "config") {
|
|
30743
|
-
if (raw.script !== void 0 || raw.scriptPath !== void 0 || raw.args !== void 0 || raw.maxAgents !== void 0 || raw.concurrency !== void 0 || raw.agentRetries !== void 0 || raw.agentTimeoutMs !== void 0 || raw.agentIdleTimeoutMs !== void 0 || raw.resumeFromRunId !== void 0 || raw.resumePolicy !== void 0 || raw.checkpointReplies !== void 0 || raw.background !== void 0 || raw.runId !== void 0 || hasPermissionFields(raw) || raw.callIndex !== void 0 || raw.forceOwner !== void 0 || raw.waitMs !== void 0 || raw.lastN !== void 0 || raw.labelGlob !== void 0 || raw.logLines !== void 0) {
|
|
30751
|
+
if (raw.script !== void 0 || raw.scriptPath !== void 0 || raw.args !== void 0 || raw.maxAgents !== void 0 || raw.concurrency !== void 0 || raw.agentRetries !== void 0 || raw.agentTimeoutMs !== void 0 || raw.agentIdleTimeoutMs !== void 0 || raw.resumeFromRunId !== void 0 || raw.resumePolicy !== void 0 || raw.checkpointReplies !== void 0 || raw.background !== void 0 || raw.runId !== void 0 || hasPermissionFields(raw) || raw.callIndex !== void 0 || raw.forceOwner !== void 0 || raw.waitMs !== void 0 || raw.lastN !== void 0 || raw.labelGlob !== void 0 || raw.logLines !== void 0 || hasResultFields(raw)) {
|
|
30744
30752
|
invalid('action="config" accepts only projectDir, harnesses, modelSpecs, modelFilter, and probeTimeoutMs');
|
|
30745
30753
|
}
|
|
30746
30754
|
if (options.requireProjectDir === true && raw.projectDir === void 0) {
|
|
@@ -30757,12 +30765,24 @@ function parseWorkflowToolInput(raw, options = {}) {
|
|
|
30757
30765
|
probeTimeoutMs: raw.probeTimeoutMs
|
|
30758
30766
|
};
|
|
30759
30767
|
}
|
|
30768
|
+
if (raw.action === "result") {
|
|
30769
|
+
if (!raw.runId) invalid('action="result" requires runId');
|
|
30770
|
+
if (hasExecutionFields(raw) || hasConfigFields(raw) || hasPermissionFields(raw) || raw.waitMs !== void 0 || raw.callIndex !== void 0 || raw.forceOwner !== void 0 || raw.lastN !== void 0 || raw.labelGlob !== void 0 || raw.logLines !== void 0) {
|
|
30771
|
+
invalid('action="result" accepts only runId, offset, and maxBytes');
|
|
30772
|
+
}
|
|
30773
|
+
return {
|
|
30774
|
+
action: "result",
|
|
30775
|
+
runId: raw.runId,
|
|
30776
|
+
offset: raw.offset ?? 0,
|
|
30777
|
+
maxBytes: raw.maxBytes ?? WORKFLOW_RESULT_CHUNK_BYTES_DEFAULT
|
|
30778
|
+
};
|
|
30779
|
+
}
|
|
30760
30780
|
if (raw.action === "permissions-response") {
|
|
30761
30781
|
if (!raw.runId) invalid('action="permissions-response" requires runId');
|
|
30762
30782
|
if (!raw.permissionId || raw.response === void 0) {
|
|
30763
30783
|
invalid('action="permissions-response" requires permissionId and response');
|
|
30764
30784
|
}
|
|
30765
|
-
if (hasExecutionFields(raw) || hasConfigFields(raw) || raw.waitMs !== void 0 || raw.callIndex !== void 0 || raw.forceOwner !== void 0 || raw.lastN !== void 0 || raw.labelGlob !== void 0 || raw.logLines !== void 0) {
|
|
30785
|
+
if (hasExecutionFields(raw) || hasConfigFields(raw) || raw.waitMs !== void 0 || raw.callIndex !== void 0 || raw.forceOwner !== void 0 || raw.lastN !== void 0 || raw.labelGlob !== void 0 || raw.logLines !== void 0 || hasResultFields(raw)) {
|
|
30766
30786
|
invalid('action="permissions-response" accepts only runId, permissionId, and response');
|
|
30767
30787
|
}
|
|
30768
30788
|
return {
|
|
@@ -30774,7 +30794,7 @@ function parseWorkflowToolInput(raw, options = {}) {
|
|
|
30774
30794
|
}
|
|
30775
30795
|
if (raw.action === "inspect") {
|
|
30776
30796
|
if (!raw.runId) invalid('action="inspect" requires runId');
|
|
30777
|
-
if (hasExecutionFields(raw) || hasConfigFields(raw) || hasPermissionFields(raw) || raw.waitMs !== void 0 || raw.callIndex !== void 0 || raw.forceOwner !== void 0) {
|
|
30797
|
+
if (hasExecutionFields(raw) || hasConfigFields(raw) || hasPermissionFields(raw) || hasResultFields(raw) || raw.waitMs !== void 0 || raw.callIndex !== void 0 || raw.forceOwner !== void 0) {
|
|
30778
30798
|
invalid('action="inspect" cannot include execution fields');
|
|
30779
30799
|
}
|
|
30780
30800
|
return {
|
|
@@ -30787,7 +30807,7 @@ function parseWorkflowToolInput(raw, options = {}) {
|
|
|
30787
30807
|
}
|
|
30788
30808
|
if (raw.action === "await") {
|
|
30789
30809
|
if (!raw.runId) invalid('action="await" requires runId');
|
|
30790
|
-
if (hasExecutionFields(raw) || hasConfigFields(raw) || hasPermissionFields(raw) || raw.callIndex !== void 0 || raw.forceOwner !== void 0) {
|
|
30810
|
+
if (hasExecutionFields(raw) || hasConfigFields(raw) || hasPermissionFields(raw) || hasResultFields(raw) || raw.callIndex !== void 0 || raw.forceOwner !== void 0) {
|
|
30791
30811
|
invalid('action="await" cannot include execution fields');
|
|
30792
30812
|
}
|
|
30793
30813
|
return {
|
|
@@ -30801,7 +30821,7 @@ function parseWorkflowToolInput(raw, options = {}) {
|
|
|
30801
30821
|
}
|
|
30802
30822
|
if (raw.action === "stop") {
|
|
30803
30823
|
if (!raw.runId) invalid('action="stop" requires runId');
|
|
30804
|
-
if (hasExecutionFields(raw) || hasConfigFields(raw) || hasPermissionFields(raw) || raw.waitMs !== void 0) {
|
|
30824
|
+
if (hasExecutionFields(raw) || hasConfigFields(raw) || hasPermissionFields(raw) || hasResultFields(raw) || raw.waitMs !== void 0) {
|
|
30805
30825
|
invalid('action="stop" cannot include execution fields or waitMs');
|
|
30806
30826
|
}
|
|
30807
30827
|
if (raw.callIndex !== void 0 && raw.forceOwner !== void 0) {
|
|
@@ -30817,7 +30837,7 @@ function parseWorkflowToolInput(raw, options = {}) {
|
|
|
30817
30837
|
logLines: raw.logLines
|
|
30818
30838
|
};
|
|
30819
30839
|
}
|
|
30820
|
-
if (raw.runId !== void 0 || hasPermissionFields(raw) || raw.callIndex !== void 0 || raw.forceOwner !== void 0 || raw.waitMs !== void 0 || raw.lastN !== void 0 || raw.labelGlob !== void 0 || raw.logLines !== void 0 || hasConfigFields(raw)) {
|
|
30840
|
+
if (raw.runId !== void 0 || hasPermissionFields(raw) || raw.callIndex !== void 0 || raw.forceOwner !== void 0 || raw.waitMs !== void 0 || raw.lastN !== void 0 || raw.labelGlob !== void 0 || raw.logLines !== void 0 || hasConfigFields(raw) || hasResultFields(raw)) {
|
|
30821
30841
|
invalid("run inputs cannot include inspection fields");
|
|
30822
30842
|
}
|
|
30823
30843
|
const hasScript = raw.script !== void 0;
|
|
@@ -31916,6 +31936,7 @@ var scriptLineageEntrySchema = external_exports.object({
|
|
|
31916
31936
|
});
|
|
31917
31937
|
var inspectionScriptResourceShape = {
|
|
31918
31938
|
scriptUri: external_exports.string(),
|
|
31939
|
+
resultUri: external_exports.string().optional(),
|
|
31919
31940
|
lineage: external_exports.array(scriptLineageEntrySchema)
|
|
31920
31941
|
};
|
|
31921
31942
|
var runStatusShape = {
|
|
@@ -31983,8 +32004,24 @@ var executionResultSchema = external_exports.object({
|
|
|
31983
32004
|
runId: external_exports.string(),
|
|
31984
32005
|
status: external_exports.enum(["paused", "completed", "failed", "aborted"]),
|
|
31985
32006
|
...executionDetailsShape,
|
|
31986
|
-
scriptUri: external_exports.string()
|
|
31987
|
-
|
|
32007
|
+
scriptUri: external_exports.string(),
|
|
32008
|
+
resultUri: external_exports.string().optional()
|
|
32009
|
+
}).strict().superRefine((value, context) => {
|
|
32010
|
+
if (value.resultUri !== void 0 && value.status !== "completed") {
|
|
32011
|
+
context.addIssue({
|
|
32012
|
+
code: "custom",
|
|
32013
|
+
path: ["resultUri"],
|
|
32014
|
+
message: "resultUri is available only for completed workflow outcomes"
|
|
32015
|
+
});
|
|
32016
|
+
}
|
|
32017
|
+
}).meta({
|
|
32018
|
+
allOf: [
|
|
32019
|
+
{
|
|
32020
|
+
if: { required: ["resultUri"] },
|
|
32021
|
+
then: { required: ["status"], properties: { status: { const: "completed" } } }
|
|
32022
|
+
}
|
|
32023
|
+
]
|
|
32024
|
+
});
|
|
31988
32025
|
var waitSchema = external_exports.object({
|
|
31989
32026
|
requestedMs: external_exports.number().int().nonnegative(),
|
|
31990
32027
|
elapsedMs: external_exports.number().int().nonnegative(),
|
|
@@ -32067,7 +32104,7 @@ var inspectionRequired = [
|
|
|
32067
32104
|
];
|
|
32068
32105
|
var terminalStatuses = ["paused", "completed", "failed", "aborted"];
|
|
32069
32106
|
var nonterminalStatuses = ["pending", "running"];
|
|
32070
|
-
var commonOutputFields = ["runId", "status", "scriptUri", "limits", "replayEligibility"];
|
|
32107
|
+
var commonOutputFields = ["runId", "status", "scriptUri", "resultUri", "limits", "replayEligibility"];
|
|
32071
32108
|
var runOutputRequired = ["runId", "status", "scriptUri"];
|
|
32072
32109
|
var executionDetailFields = [
|
|
32073
32110
|
"result",
|
|
@@ -32094,6 +32131,15 @@ var discoveryOutputFields = [
|
|
|
32094
32131
|
"omittedHarnesses",
|
|
32095
32132
|
"models"
|
|
32096
32133
|
];
|
|
32134
|
+
var resultRetrievalFields = [
|
|
32135
|
+
"mimeType",
|
|
32136
|
+
"encoding",
|
|
32137
|
+
"totalBytes",
|
|
32138
|
+
"offset",
|
|
32139
|
+
"endOffset",
|
|
32140
|
+
"hasMore",
|
|
32141
|
+
"chunk"
|
|
32142
|
+
];
|
|
32097
32143
|
var stopControlSchema = external_exports.object({
|
|
32098
32144
|
state: external_exports.literal("pending"),
|
|
32099
32145
|
operationId: external_exports.string(),
|
|
@@ -32119,6 +32165,7 @@ var variantOutputFields = [
|
|
|
32119
32165
|
"pendingPermissions",
|
|
32120
32166
|
"interaction",
|
|
32121
32167
|
"permissionResponse",
|
|
32168
|
+
...resultRetrievalFields,
|
|
32122
32169
|
...discoveryOutputFields
|
|
32123
32170
|
];
|
|
32124
32171
|
var forbidsRequired = (...fields) => ({
|
|
@@ -32137,7 +32184,7 @@ function hasOnlyFields(value, allowed) {
|
|
|
32137
32184
|
return Object.entries(value).every(([field, fieldValue]) => fieldValue === void 0 || allowedFields.has(field));
|
|
32138
32185
|
}
|
|
32139
32186
|
var workflowToolOutputShape = external_exports.object({
|
|
32140
|
-
action: external_exports.enum(["run", "config"]).optional(),
|
|
32187
|
+
action: external_exports.enum(["run", "config", "result"]).optional(),
|
|
32141
32188
|
ok: external_exports.boolean().optional(),
|
|
32142
32189
|
validation: validationSummarySchema.optional(),
|
|
32143
32190
|
harnessOptions: external_exports.array(harnessDiagnosticSchema).optional(),
|
|
@@ -32148,6 +32195,7 @@ var workflowToolOutputShape = external_exports.object({
|
|
|
32148
32195
|
...executionDetailsShape,
|
|
32149
32196
|
scriptSource: scriptSourceSchema.optional(),
|
|
32150
32197
|
scriptUri: external_exports.string().optional(),
|
|
32198
|
+
resultUri: external_exports.string().optional(),
|
|
32151
32199
|
lineage: inspectionScriptResourceShape.lineage.optional(),
|
|
32152
32200
|
workflowName: runStatusShape.workflowName.optional(),
|
|
32153
32201
|
phases: runStatusShape.phases.optional(),
|
|
@@ -32164,14 +32212,23 @@ var workflowToolOutputShape = external_exports.object({
|
|
|
32164
32212
|
control: stopControlSchema.optional(),
|
|
32165
32213
|
pendingPermissions: external_exports.array(pendingPermissionSchema).optional(),
|
|
32166
32214
|
interaction: permissionInteractionSchema.optional(),
|
|
32167
|
-
permissionResponse: permissionAcknowledgementSchema.optional()
|
|
32215
|
+
permissionResponse: permissionAcknowledgementSchema.optional(),
|
|
32216
|
+
mimeType: external_exports.literal("application/json").optional(),
|
|
32217
|
+
encoding: external_exports.literal("utf-8").optional(),
|
|
32218
|
+
totalBytes: external_exports.number().int().nonnegative().optional(),
|
|
32219
|
+
offset: external_exports.number().int().nonnegative().optional(),
|
|
32220
|
+
endOffset: external_exports.number().int().nonnegative().optional(),
|
|
32221
|
+
hasMore: external_exports.boolean().optional(),
|
|
32222
|
+
chunk: external_exports.string().optional()
|
|
32168
32223
|
}).superRefine((value, context) => {
|
|
32169
32224
|
const has = (field) => value[field] !== void 0;
|
|
32170
32225
|
const inspectionComplete = inspectionRequired.every((field) => has(field));
|
|
32171
32226
|
const runCommonComplete = has("runId") && has("status") && has("scriptUri");
|
|
32172
32227
|
const terminal2 = terminalStatuses.includes(value.status);
|
|
32173
32228
|
let valid;
|
|
32174
|
-
if (value.action === "
|
|
32229
|
+
if (value.action === "result") {
|
|
32230
|
+
valid = value.status === "completed" && has("runId") && has("resultUri") && resultRetrievalFields.every((field) => has(field)) && hasOnlyExactFields(value, ["action", "runId", "status", "resultUri", ...resultRetrievalFields]);
|
|
32231
|
+
} else if (value.action === "config") {
|
|
32175
32232
|
valid = has("ok") && has("harnessOptions") && has("omittedHarnesses") && has("models") && hasOnlyExactFields(value, ["action", "ok", "harnessOptions", "omittedHarnesses", "models"]);
|
|
32176
32233
|
} else if (value.action === "run") {
|
|
32177
32234
|
valid = value.status === "rejected" && has("validation") && hasOnlyExactFields(value, ["action", "status", "validation"]);
|
|
@@ -32188,11 +32245,45 @@ var workflowToolOutputShape = external_exports.object({
|
|
|
32188
32245
|
} else {
|
|
32189
32246
|
valid = runCommonComplete && inspectionComplete && hasOnlyFields(value, [...inspectionFields, "pendingPermissions", "interaction"]);
|
|
32190
32247
|
}
|
|
32248
|
+
if (has("resultUri") && value.status !== "completed") valid = false;
|
|
32191
32249
|
if (!valid) {
|
|
32192
32250
|
context.addIssue({ code: "custom", message: "output does not match a workflow result variant" });
|
|
32193
32251
|
}
|
|
32194
32252
|
}).meta({
|
|
32253
|
+
allOf: [
|
|
32254
|
+
{
|
|
32255
|
+
if: { required: ["resultUri"] },
|
|
32256
|
+
then: { required: ["status"], properties: { status: { const: "completed" } } }
|
|
32257
|
+
}
|
|
32258
|
+
],
|
|
32195
32259
|
oneOf: [
|
|
32260
|
+
{
|
|
32261
|
+
title: "Workflow result retrieval",
|
|
32262
|
+
required: ["action", "runId", "status", "resultUri", ...resultRetrievalFields],
|
|
32263
|
+
properties: { action: { const: "result" }, status: { const: "completed" } },
|
|
32264
|
+
...forbidsRequired(
|
|
32265
|
+
"ok",
|
|
32266
|
+
"validation",
|
|
32267
|
+
"harnessOptions",
|
|
32268
|
+
"omittedHarnesses",
|
|
32269
|
+
"models",
|
|
32270
|
+
"scriptUri",
|
|
32271
|
+
"scriptSource",
|
|
32272
|
+
"limits",
|
|
32273
|
+
"replayEligibility",
|
|
32274
|
+
...executionDetailFields,
|
|
32275
|
+
...inspectionFields,
|
|
32276
|
+
"lineage",
|
|
32277
|
+
"wait",
|
|
32278
|
+
"outcome",
|
|
32279
|
+
"stopped",
|
|
32280
|
+
"alreadyTerminal",
|
|
32281
|
+
"control",
|
|
32282
|
+
"pendingPermissions",
|
|
32283
|
+
"interaction",
|
|
32284
|
+
"permissionResponse"
|
|
32285
|
+
)
|
|
32286
|
+
},
|
|
32196
32287
|
{
|
|
32197
32288
|
title: "Workflow config discovery",
|
|
32198
32289
|
required: ["action", "ok", "harnessOptions", "omittedHarnesses", "models"],
|
|
@@ -32319,7 +32410,8 @@ function toWorkflowExecutionOutcome(run, resources) {
|
|
|
32319
32410
|
...run.fallbacks === void 0 ? {} : { fallbacks: run.fallbacks },
|
|
32320
32411
|
...run.checkpointsTaken === void 0 ? {} : { checkpointsTaken: run.checkpointsTaken },
|
|
32321
32412
|
...run.resumeReport === void 0 ? {} : { resumeReport: run.resumeReport },
|
|
32322
|
-
|
|
32413
|
+
scriptUri: resources.scriptUri,
|
|
32414
|
+
...run.status === "completed" && resources.resultUri !== void 0 ? { resultUri: resources.resultUri } : {}
|
|
32323
32415
|
};
|
|
32324
32416
|
}
|
|
32325
32417
|
function toWorkflowToolResult(run, resources) {
|
|
@@ -32565,9 +32657,9 @@ var AUTHORING_DOC_TOPICS = [
|
|
|
32565
32657
|
"workflow/determinism-and-resume",
|
|
32566
32658
|
"workflow/models-and-config"
|
|
32567
32659
|
],
|
|
32568
|
-
"bytes":
|
|
32569
|
-
"sha256": "
|
|
32570
|
-
"text": '## Running workflows \u2014 the MCP `workflow` tool\n\n**Context:** JavaScript passed to the MCP `workflow` tool. Workflow scripts use `agent(prompt, options?)`; REPL evals use a different API.\n\nUse the connected `workflow` tool for deterministic batch orchestration. The shared server daemon owns execution, so admitted runs survive MCP client session churn and tool-request timeouts. During a version upgrade, the successor becomes the front door while a predecessor may remain the execution owner; signed run-control forwarding keeps later-session stop/cancel operations location-independent. Owner-process exit can still interrupt in-flight work. Any later session can await, inspect, or stop a run. Runs, journals, logs, and outstanding whole-stop intents persist per project namespace.\n\nEvery `config` and `run` call on the shared daemon names its project with the required `projectDir` argument \u2014 an absolute path, normally the workspace root. `inspect`/`await`/`stop` take only a `runId`; the run ID locates its project store automatically. In a single-project server, `projectDir` defaults to that server\'s project.\n\n### The `workflow` tool, by action\n\n- **Config** (`{ action: "config", projectDir, harnesses?, modelSpecs?, modelFilter? }`): discover live model, mode, effort, and `configOptions` values from no-prompt backend sessions. Use `harnesses` plus `modelFilter` to find ids, then `modelSpecs` to select exact models and read their model-specific option domains. Each successful entry preserves every harness-advertised mode id, name, description, and `_meta`, and reports `defaultModeId`. When a call omits mode, AgentPrism applies Claude `auto`, Codex `agent`, OpenCode `build`, or no mode for Pi; authored and default ids must appear in `modes.availableModes`. It starts no workflow and spends zero tokens. Use it only when pinning those values; an omitted model or backend-only model uses configured defaults without discovery.\n- **Run** (default, no `action`): supply exactly one of `script` (the raw source string, no Markdown fences) or `scriptPath` (an absolute path on the server\'s filesystem), plus `projectDir`. The tool automatically performs static validation, a mocked dry run, and routed config checks before admission. Invalid scripts return bounded `status:"rejected"` diagnostics with no run ID, background slot, or token spend. A path is read once at admission and its content snapshotted; later edits affect only a new run. `args` arrives in the script as the `args` global; the run\'s base directory is the `cwd` global. Some hosts hand `args` through as a JSON **string** \u2014 tolerate both shapes (`typeof args === "string" ? JSON.parse(args) : args`). Foreground streams progress but is bound to the request and its timeout. Pass `background: true` for anything that may outlive one request; it acknowledges after durable admission with a `runId`.\n- **Await** (`{ action: "await", runId, waitMs }`): bounded collection for background runs. A timeout is progress, not failure. Await returns early with `wait.returnedBecause:"action-required"` when an ACP permission is pending. At terminal status the response adds `outcome`: the authored result or pause context, plus replay diagnostics.\n- **Inspect** (`{ action: "inspect", runId, lastN, labelGlob, logLines }`): a bounded snapshot \u2014 the latest matching calls, newest log lines, and any live `pendingPermissions`. Elicitation-capable clients present one request\'s exact backend options during inspect/await. Permission diagnostics omit the private ACP session id, are credential-redacted and bounded, and retain the complete ordered exact option-id list or fail closed.\n- **Permission response** (`{ action:"permissions-response", runId, permissionId, response }`): for clients without elicitation, resolve one pending request with `{ outcome:{ outcome:"selected", optionId } }` using an exact advertised id, or `{ outcome:{ outcome:"cancelled" } }`. Caller-supplied response `_meta` is forbidden; provider effects come only from the selected advertised option. The request belongs to the live execution owner and cannot be answered after owner loss.\n- **Stop**: `{ action: "stop", runId }` durably aborts the whole run and normally returns its final snapshot; stopping a terminal run is a successful no-op. Across a daemon upgrade, the successor persists an idempotent stop intent and forwards to the predecessor that owns execution. If that owner does not settle within the bounded control wait, the successful response remains nonterminal with `control:{ state:"pending", operationId, requestedAt, owner? }`; retry stop, inspect, or await to observe settlement. `{ action: "stop", runId, callIndex }` synchronously routes to the live owner and cancels exactly that in-flight agent: its slot settles to `null` with `AGENT_CANCELLED` and the run stays live; call cancellation is never reconstructed after owner loss. Whole-run `{ action:"stop", runId, forceOwner:true }` explicitly authorizes terminating a superseded owner daemon when graceful control cannot settle and may interrupt sibling runs in that process; it is forbidden with `callIndex`. `labelGlob` only filters the returned snapshot; it never selects what to cancel.\n- **Resume**: a NEW run with `resumeFromRunId` plus the script content re-sent (the same `script` or `scriptPath`) and the desired `args` (+ `checkpointReplies` when answering a durable checkpoint). Read the returned `replayEligibility` for the predicted and observed replay prefix; never assume a prefix hit. Full semantics: **Determinism and resume**.\n\n### Operating rules\n\n- **Always retain the returned `runId`.** A paused, failed, or aborted response carries a redacted final-20 `logTail`. Read it before you change anything. Every admitted script is also an immutable resource at `workflow://runs/{runId}/script`, so a later session can recover a lost inline script.\n- **Two fingerprints control replay.** The identity hash covers the prompt, the resolved model, `mode` when set, non-empty sorted `configOptions`, `tier`, `phase`, `agentType`, the resolved agent definition, and the schema. The input fingerprint covers the resolved label, per-call `cwd` and isolation, `keepSession`, images, MCP servers, session/prompt metadata, and the approved script-backend digest.\n- **Operational bounds are not replay inputs.** Host `concurrency`, `agentRetries`, `agentTimeoutMs`, and `agentIdleTimeoutMs`, plus per-call `timeoutMs`, `idleTimeoutMs`, and `retries`, enter neither fingerprint. A resume does not inherit them from its source run; pass the values you want on every run. `agentTimeoutMs` caps total wall time and is not an idle timer. The separate opt-in `agentIdleTimeoutMs` fires after that long without real backend activity; ACP `session/update` re-arms it and synthetic progress heartbeats do not. Per-call values can tighten but cannot escape finite host ceilings. Every retry gets fresh clocks.\n- **Old journals stay usable.** Input formats below 2 replay positionally with `fallbackReason: "inputs-format-legacy"`. A current-format crash snapshot uses identity matching even without terminal-environment capture. Ancestor-scoped rows carried from \u22640.23 resume chains replay only while that ancestor run is still persisted. Journals resume across filesystem, environment, engine, Node, and V8 changes; `replayEligibility` reports those differences as diagnostics, never as gates.\n- **A background start returns immediately.** It sends no progress after it returns; collect progress with later bounded awaits. Its `interaction` block explains that ACP permissions may block an agent and names await/inspect plus `permissions-response` as the control path. Background runs have no live checkpoint channel, so authored `headless` checkpoint modes apply. When a run\'s owner process dies, a pending whole-stop intent is applied under the reclaimed lease; otherwise cold preflights reconcile stale `pending`/`running` state to `paused` with `pauseReason:"interrupted"`. A live owner lease is never stolen because of a timeout.\n- A run paused with `reason: "auth_required"` resumes as a new run after that backend\'s credentials are configured.\n\n### Execution logs \u2014 the events resource\n\nEvery journaling run publishes an MCP resource at `workflow://runs/{runId}/events`. Subscribe to the canonical URI for advisory `resources/updated` hints, then read and paginate with `after`, `limit`, and `streamId`. Progress is coarse and redacted: `agentTranscript` rows are assistant/tool upserts partitioned by `(scope, callIndex, executionStartSeq)` and reduced by greatest revision per entry index. The durable cursor is authoritative when hints coalesce or a subscriber falls behind.\n\nEmbedding hosts can drive the same contract with `runDynamicWorkflow` / `WorkflowManager` from `@automatalabs/workflows`; the script contract is identical either way.\n'
|
|
32660
|
+
"bytes": 9965,
|
|
32661
|
+
"sha256": "1143d846d50a7c2833ab58d0d88131dde8557770a6f818f2b8747c79f791ace7",
|
|
32662
|
+
"text": '## Running workflows \u2014 the MCP `workflow` tool\n\n**Context:** JavaScript passed to the MCP `workflow` tool. Workflow scripts use `agent(prompt, options?)`; REPL evals use a different API.\n\nUse the connected `workflow` tool for deterministic batch orchestration. The shared server daemon owns execution, so admitted runs survive MCP client session churn and tool-request timeouts. During a version upgrade, the successor becomes the front door while a predecessor may remain the execution owner; signed run-control forwarding keeps later-session stop/cancel operations location-independent. Owner-process exit can still interrupt in-flight work. Any later session can await, inspect, or stop a run. Runs, journals, logs, and outstanding whole-stop intents persist per project namespace.\n\nEvery `config` and `run` call on the shared daemon names its project with the required `projectDir` argument \u2014 an absolute path, normally the workspace root. `inspect`/`await`/`result`/`stop` take only a `runId`; the run ID locates its project store automatically. In a single-project server, `projectDir` defaults to that server\'s project.\n\n### The `workflow` tool, by action\n\n- **Config** (`{ action: "config", projectDir, harnesses?, modelSpecs?, modelFilter? }`): discover live model, mode, effort, and `configOptions` values from no-prompt backend sessions. Use `harnesses` plus `modelFilter` to find ids, then `modelSpecs` to select exact models and read their model-specific option domains. Each successful entry preserves every harness-advertised mode id, name, description, and `_meta`, and reports `defaultModeId`. When a call omits mode, AgentPrism applies Claude `auto`, Codex `agent`, OpenCode `build`, or no mode for Pi; authored and default ids must appear in `modes.availableModes`. It starts no workflow and spends zero tokens. Use it only when pinning those values; an omitted model or backend-only model uses configured defaults without discovery.\n- **Run** (default, no `action`): supply exactly one of `script` (the raw source string, no Markdown fences) or `scriptPath` (an absolute path on the server\'s filesystem), plus `projectDir`. The tool automatically performs static validation, a mocked dry run, and routed config checks before admission. Invalid scripts return bounded `status:"rejected"` diagnostics with no run ID, background slot, or token spend. A path is read once at admission and its content snapshotted; later edits affect only a new run. `args` arrives in the script as the `args` global; the run\'s base directory is the `cwd` global. Some hosts hand `args` through as a JSON **string** \u2014 tolerate both shapes (`typeof args === "string" ? JSON.parse(args) : args`). Foreground streams progress but is bound to the request and its timeout. Pass `background: true` for anything that may outlive one request; it acknowledges after durable admission with a `runId`.\n- **Await** (`{ action: "await", runId, waitMs }`): bounded collection for background runs. A timeout is progress, not failure. Await returns early with `wait.returnedBecause:"action-required"` when an ACP permission is pending. At terminal status the response adds `outcome`: the authored result or pause context, plus replay diagnostics.\n- **Inspect** (`{ action: "inspect", runId, lastN, labelGlob, logLines }`): a bounded snapshot \u2014 the latest matching calls, newest log lines, and any live `pendingPermissions`. A completed run also exposes `resultUri` and an exact-result resource link, without putting a large result into the bounded status projection. Elicitation-capable clients present one request\'s exact backend options during inspect/await. Permission diagnostics omit the private ACP session id, are credential-redacted and bounded, and retain the complete ordered exact option-id list or fail closed.\n- **Result** (`{ action: "result", runId, offset?, maxBytes? }`): bounded exact retrieval for a completed authored result. It returns at most 16,384 UTF-8 bytes plus `totalBytes`, `endOffset`, and `hasMore`; continue at the prior `endOffset`. The default offset is zero. UTF-8 code points are never split, and arbitrary offsets inside one fail closed. Running, paused, failed, aborted, unknown, deleted, and completed-without-value runs have no result page.\n- **Permission response** (`{ action:"permissions-response", runId, permissionId, response }`): for clients without elicitation, resolve one pending request with `{ outcome:{ outcome:"selected", optionId } }` using an exact advertised id, or `{ outcome:{ outcome:"cancelled" } }`. Caller-supplied response `_meta` is forbidden; provider effects come only from the selected advertised option. The request belongs to the live execution owner and cannot be answered after owner loss.\n- **Stop**: `{ action: "stop", runId }` durably aborts the whole run and normally returns its final snapshot; stopping a terminal run is a successful no-op. Across a daemon upgrade, the successor persists an idempotent stop intent and forwards to the predecessor that owns execution. If that owner does not settle within the bounded control wait, the successful response remains nonterminal with `control:{ state:"pending", operationId, requestedAt, owner? }`; retry stop, inspect, or await to observe settlement. `{ action: "stop", runId, callIndex }` synchronously routes to the live owner and cancels exactly that in-flight agent: its slot settles to `null` with `AGENT_CANCELLED` and the run stays live; call cancellation is never reconstructed after owner loss. Whole-run `{ action:"stop", runId, forceOwner:true }` explicitly authorizes terminating a superseded owner daemon when graceful control cannot settle and may interrupt sibling runs in that process; it is forbidden with `callIndex`. `labelGlob` only filters the returned snapshot; it never selects what to cancel.\n- **Resume**: a NEW run with `resumeFromRunId` plus the script content re-sent (the same `script` or `scriptPath`) and the desired `args` (+ `checkpointReplies` when answering a durable checkpoint). Read the returned `replayEligibility` for the predicted and observed replay prefix; never assume a prefix hit. Full semantics: **Determinism and resume**.\n\n### Operating rules\n\n- **Always retain the returned `runId`.** A paused, failed, or aborted response carries a redacted final-20 `logTail`. Read it before you change anything. Every admitted script is an immutable resource at `workflow://runs/{runId}/script`, so a later session can recover a lost inline script. A completed JSON result is independently durable at `workflow://runs/{runId}/result`. Completed foreground/await responses copy exact JSON up to 4,096 UTF-8 bytes into model-visible text; larger results stay out of summary text and point to the resource plus `action:"result"` paging. Script and result links are labelled separately.\n- **Two fingerprints control replay.** The identity hash covers the prompt, the resolved model, `mode` when set, non-empty sorted `configOptions`, `tier`, `phase`, `agentType`, the resolved agent definition, and the schema. The input fingerprint covers the resolved label, per-call `cwd` and isolation, `keepSession`, images, MCP servers, session/prompt metadata, and the approved script-backend digest.\n- **Operational bounds are not replay inputs.** Host `concurrency`, `agentRetries`, `agentTimeoutMs`, and `agentIdleTimeoutMs`, plus per-call `timeoutMs`, `idleTimeoutMs`, and `retries`, enter neither fingerprint. A resume does not inherit them from its source run; pass the values you want on every run. `agentTimeoutMs` caps total wall time and is not an idle timer. The separate opt-in `agentIdleTimeoutMs` fires after that long without real backend activity; ACP `session/update` re-arms it and synthetic progress heartbeats do not. Per-call values can tighten but cannot escape finite host ceilings. Every retry gets fresh clocks.\n- **Old journals stay usable.** Input formats below 2 replay positionally with `fallbackReason: "inputs-format-legacy"`. A current-format crash snapshot uses identity matching even without terminal-environment capture. Ancestor-scoped rows carried from \u22640.23 resume chains replay only while that ancestor run is still persisted. Journals resume across filesystem, environment, engine, Node, and V8 changes; `replayEligibility` reports those differences as diagnostics, never as gates.\n- **A background start returns immediately.** It sends no progress after it returns; collect progress with later bounded awaits. Its `interaction` block explains that ACP permissions may block an agent and names await/inspect plus `permissions-response` as the control path. Background runs have no live checkpoint channel, so authored `headless` checkpoint modes apply. When a run\'s owner process dies, a pending whole-stop intent is applied under the reclaimed lease; otherwise cold preflights reconcile stale `pending`/`running` state to `paused` with `pauseReason:"interrupted"`. A live owner lease is never stolen because of a timeout.\n- A run paused with `reason: "auth_required"` resumes as a new run after that backend\'s credentials are configured.\n\n### Execution logs \u2014 the events resource\n\nEvery journaling run publishes an MCP resource at `workflow://runs/{runId}/events`. Subscribe to the canonical URI for advisory `resources/updated` hints, then read and paginate with `after`, `limit`, and `streamId`. This bounded/redacted stream is observability, not an exact result-reconstruction API; use `/result` or `action:"result"` for authored output. Progress is coarse and redacted: `agentTranscript` rows are assistant/tool upserts partitioned by `(scope, callIndex, executionStartSeq)` and reduced by greatest revision per entry index. The durable cursor is authoritative when hints coalesce or a subscriber falls behind.\n\nEmbedding hosts can drive the same contract with `runDynamicWorkflow` / `WorkflowManager` from `@automatalabs/workflows`; the script contract is identical either way.\n'
|
|
32571
32663
|
},
|
|
32572
32664
|
{
|
|
32573
32665
|
"id": "workflow/models-and-config",
|
|
@@ -33755,14 +33847,16 @@ import {
|
|
|
33755
33847
|
WorkflowManager as WorkflowManager2
|
|
33756
33848
|
} from "@automatalabs/workflows";
|
|
33757
33849
|
var SCRIPT_RESOURCE_MIME_TYPE = "text/javascript";
|
|
33850
|
+
var RESULT_RESOURCE_MIME_TYPE = "application/json";
|
|
33758
33851
|
var SCRIPT_RESOURCE_LIST_LIMIT = 50;
|
|
33759
33852
|
var EVENTS_RESOURCE_MIME_TYPE = "application/json";
|
|
33760
33853
|
var WORKFLOW_RUN_EVENTS_SCHEMA_VERSION = 1;
|
|
33761
33854
|
var SCRIPT_URI_PATTERN = /^workflow:\/\/runs\/([a-z0-9]+-[a-z0-9]+)\/script$/;
|
|
33855
|
+
var RESULT_URI_PATTERN = /^workflow:\/\/runs\/([a-z0-9]+-[a-z0-9]+)\/result$/;
|
|
33762
33856
|
var EVENTS_URI_PATTERN = /^workflow:\/\/runs\/([a-z0-9]+-[a-z0-9]+)\/events(?:\?([^#]*))?$/;
|
|
33763
33857
|
var STREAM_ID_PATTERN = /^[0-9a-f]{32}$/;
|
|
33764
33858
|
function resourceNotFound(uri) {
|
|
33765
|
-
throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Workflow
|
|
33859
|
+
throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Workflow resource not found: ${uri}`);
|
|
33766
33860
|
}
|
|
33767
33861
|
function workflowScriptUri(runId) {
|
|
33768
33862
|
return `workflow://runs/${runId}/script`;
|
|
@@ -33770,9 +33864,18 @@ function workflowScriptUri(runId) {
|
|
|
33770
33864
|
function workflowRunIdFromScriptUri(uri) {
|
|
33771
33865
|
return SCRIPT_URI_PATTERN.exec(uri)?.[1];
|
|
33772
33866
|
}
|
|
33867
|
+
function workflowResultUri(runId) {
|
|
33868
|
+
return `workflow://runs/${runId}/result`;
|
|
33869
|
+
}
|
|
33870
|
+
function workflowRunIdFromResultUri(uri) {
|
|
33871
|
+
return RESULT_URI_PATTERN.exec(uri)?.[1];
|
|
33872
|
+
}
|
|
33773
33873
|
function workflowRunEventsUri(runId) {
|
|
33774
33874
|
return `workflow://runs/${runId}/events`;
|
|
33775
33875
|
}
|
|
33876
|
+
function hasExactResult(state) {
|
|
33877
|
+
return state.status === "completed" && state.result !== void 0;
|
|
33878
|
+
}
|
|
33776
33879
|
function parseDecimal(value, max = Number.MAX_SAFE_INTEGER) {
|
|
33777
33880
|
if (!/^(?:0|[1-9][0-9]*)$/.test(value)) return void 0;
|
|
33778
33881
|
const parsed = Number(value);
|
|
@@ -33839,6 +33942,15 @@ var WorkflowScriptResources = class {
|
|
|
33839
33942
|
this.modernNotifier = modernNotifier;
|
|
33840
33943
|
this.router = source instanceof WorkflowManager2 ? singleStoreRouter(source) : source.router;
|
|
33841
33944
|
this.detachRunDeleted = this.router.onRunDeleted(this.onRunDeleted);
|
|
33945
|
+
this.detachRunEventPersisted = this.modernNotifier ? () => void 0 : this.router.onRunEventPersisted((record2) => {
|
|
33946
|
+
if (record2.event.type !== "complete") return;
|
|
33947
|
+
queueMicrotask(() => {
|
|
33948
|
+
try {
|
|
33949
|
+
if (this.availableResultUri(record2.runId)) void this.mcp.sendResourceListChanged();
|
|
33950
|
+
} catch {
|
|
33951
|
+
}
|
|
33952
|
+
});
|
|
33953
|
+
});
|
|
33842
33954
|
this.detachRunStopped = this.router.onRunStopped(({ runId }) => this.cancelPendingElicitation(runId));
|
|
33843
33955
|
const previousOnClose = this.mcp.server.onclose;
|
|
33844
33956
|
this.mcp.server.onclose = () => {
|
|
@@ -33846,6 +33958,7 @@ var WorkflowScriptResources = class {
|
|
|
33846
33958
|
this.elicitationControllers.clear();
|
|
33847
33959
|
for (const uri of [...this.eventSubscriptions.keys()]) this.closeEventSubscription(uri);
|
|
33848
33960
|
this.detachRunStopped();
|
|
33961
|
+
this.detachRunEventPersisted();
|
|
33849
33962
|
this.detachRunDeleted();
|
|
33850
33963
|
previousOnClose?.();
|
|
33851
33964
|
};
|
|
@@ -33855,6 +33968,7 @@ var WorkflowScriptResources = class {
|
|
|
33855
33968
|
modernNotifier;
|
|
33856
33969
|
router;
|
|
33857
33970
|
detachRunDeleted;
|
|
33971
|
+
detachRunEventPersisted;
|
|
33858
33972
|
detachRunStopped;
|
|
33859
33973
|
subscriptions = /* @__PURE__ */ new Set();
|
|
33860
33974
|
externalReaders = /* @__PURE__ */ new Map();
|
|
@@ -33863,16 +33977,13 @@ var WorkflowScriptResources = class {
|
|
|
33863
33977
|
silentDeletionRunIds = /* @__PURE__ */ new Set();
|
|
33864
33978
|
elicitationControllers = /* @__PURE__ */ new Map();
|
|
33865
33979
|
onRunDeleted = ({ runId }) => {
|
|
33866
|
-
|
|
33867
|
-
this.subscriptions.delete(
|
|
33980
|
+
this.subscriptions.delete(workflowScriptUri(runId));
|
|
33981
|
+
this.subscriptions.delete(workflowResultUri(runId));
|
|
33868
33982
|
this.closeEventSubscription(workflowRunEventsUri(runId));
|
|
33869
33983
|
this.cancelPendingElicitation(runId);
|
|
33870
33984
|
this.deletedRunIds.add(runId);
|
|
33871
33985
|
const notify = !this.silentDeletionRunIds.delete(runId);
|
|
33872
|
-
if (notify)
|
|
33873
|
-
if (this.modernNotifier) this.modernNotifier.resourcesChanged();
|
|
33874
|
-
else void this.mcp.sendResourceListChanged();
|
|
33875
|
-
}
|
|
33986
|
+
if (notify && !this.modernNotifier) void this.mcp.sendResourceListChanged();
|
|
33876
33987
|
};
|
|
33877
33988
|
/** The persistence store containing runId, if any known project store holds it. */
|
|
33878
33989
|
persistenceFor(runId) {
|
|
@@ -33959,6 +34070,57 @@ var WorkflowScriptResources = class {
|
|
|
33959
34070
|
}
|
|
33960
34071
|
return newestToOldest.reverse();
|
|
33961
34072
|
}
|
|
34073
|
+
/** Exact persisted result metadata, available only for completed runs with a JSON value. */
|
|
34074
|
+
serializedResult(runId) {
|
|
34075
|
+
const state = this.loadState(runId);
|
|
34076
|
+
if (!state) {
|
|
34077
|
+
throw new ProtocolError(
|
|
34078
|
+
ProtocolErrorCode.InvalidParams,
|
|
34079
|
+
`No workflow run found for runId "${runId}" in this server's project-scoped run store.`
|
|
34080
|
+
);
|
|
34081
|
+
}
|
|
34082
|
+
if (!hasExactResult(state)) {
|
|
34083
|
+
throw new ProtocolError(
|
|
34084
|
+
ProtocolErrorCode.InvalidParams,
|
|
34085
|
+
state.status === "completed" ? `Workflow run "${runId}" completed without a JSON result.` : `Workflow result for runId "${runId}" is unavailable while the run is ${state.status}.`
|
|
34086
|
+
);
|
|
34087
|
+
}
|
|
34088
|
+
let text;
|
|
34089
|
+
try {
|
|
34090
|
+
text = JSON.stringify(state.result);
|
|
34091
|
+
} catch {
|
|
34092
|
+
throw new ProtocolError(
|
|
34093
|
+
ProtocolErrorCode.InternalError,
|
|
34094
|
+
`Workflow result for runId "${runId}" could not be serialized.`
|
|
34095
|
+
);
|
|
34096
|
+
}
|
|
34097
|
+
if (text === void 0) {
|
|
34098
|
+
throw new ProtocolError(
|
|
34099
|
+
ProtocolErrorCode.InternalError,
|
|
34100
|
+
`Workflow result for runId "${runId}" could not be serialized.`
|
|
34101
|
+
);
|
|
34102
|
+
}
|
|
34103
|
+
return {
|
|
34104
|
+
uri: workflowResultUri(runId),
|
|
34105
|
+
text,
|
|
34106
|
+
bytes: Buffer.byteLength(text, "utf8")
|
|
34107
|
+
};
|
|
34108
|
+
}
|
|
34109
|
+
availableResultUri(runId) {
|
|
34110
|
+
const state = this.loadState(runId);
|
|
34111
|
+
return state && hasExactResult(state) ? workflowResultUri(runId) : void 0;
|
|
34112
|
+
}
|
|
34113
|
+
resultLink(runId) {
|
|
34114
|
+
const state = this.loadState(runId);
|
|
34115
|
+
if (!state || !hasExactResult(state)) return void 0;
|
|
34116
|
+
return {
|
|
34117
|
+
type: "resource_link",
|
|
34118
|
+
uri: workflowResultUri(runId),
|
|
34119
|
+
name: `${state.workflowName} result (${state.runId})`,
|
|
34120
|
+
description: `exact workflow result \xB7 completed ${state.completedAt ?? state.updatedAt}`,
|
|
34121
|
+
mimeType: RESULT_RESOURCE_MIME_TYPE
|
|
34122
|
+
};
|
|
34123
|
+
}
|
|
33962
34124
|
links(lineage) {
|
|
33963
34125
|
const links = [];
|
|
33964
34126
|
for (const entry of lineage) {
|
|
@@ -33968,8 +34130,8 @@ var WorkflowScriptResources = class {
|
|
|
33968
34130
|
links.push({
|
|
33969
34131
|
type: "resource_link",
|
|
33970
34132
|
uri: entry.uri,
|
|
33971
|
-
name: `${state.workflowName} (${state.runId})`,
|
|
33972
|
-
description:
|
|
34133
|
+
name: `${state.workflowName} script (${state.runId})`,
|
|
34134
|
+
description: `workflow script \xB7 ${state.status} \xB7 started ${state.startedAt}`,
|
|
33973
34135
|
mimeType: SCRIPT_RESOURCE_MIME_TYPE
|
|
33974
34136
|
});
|
|
33975
34137
|
}
|
|
@@ -33985,8 +34147,8 @@ var WorkflowScriptResources = class {
|
|
|
33985
34147
|
list: () => ({
|
|
33986
34148
|
resources: this.recentRuns().map((state) => ({
|
|
33987
34149
|
uri: workflowScriptUri(state.runId),
|
|
33988
|
-
name: `${state.workflowName} (${state.runId})`,
|
|
33989
|
-
description:
|
|
34150
|
+
name: `${state.workflowName} script (${state.runId})`,
|
|
34151
|
+
description: `workflow script \xB7 ${state.status} \xB7 started ${state.startedAt}`,
|
|
33990
34152
|
mimeType: SCRIPT_RESOURCE_MIME_TYPE
|
|
33991
34153
|
}))
|
|
33992
34154
|
}),
|
|
@@ -34001,6 +34163,28 @@ var WorkflowScriptResources = class {
|
|
|
34001
34163
|
},
|
|
34002
34164
|
(uri) => this.readResource(uri.toString())
|
|
34003
34165
|
);
|
|
34166
|
+
this.mcp.registerResource(
|
|
34167
|
+
"workflow-run-result",
|
|
34168
|
+
new ResourceTemplate("workflow://runs/{runId}/result", {
|
|
34169
|
+
list: () => ({
|
|
34170
|
+
resources: this.recentRuns().filter(hasExactResult).map((state) => ({
|
|
34171
|
+
uri: workflowResultUri(state.runId),
|
|
34172
|
+
name: `${state.workflowName} result (${state.runId})`,
|
|
34173
|
+
description: `exact workflow result \xB7 completed ${state.completedAt ?? state.updatedAt}`,
|
|
34174
|
+
mimeType: RESULT_RESOURCE_MIME_TYPE
|
|
34175
|
+
}))
|
|
34176
|
+
}),
|
|
34177
|
+
complete: {
|
|
34178
|
+
runId: (partial2) => this.recentRuns().filter(hasExactResult).map((state) => state.runId).filter((runId) => runId.startsWith(partial2))
|
|
34179
|
+
}
|
|
34180
|
+
}),
|
|
34181
|
+
{
|
|
34182
|
+
title: "Workflow run results",
|
|
34183
|
+
description: "Exact JSON results for completed workflow runs. Listing is discovery-only and contains at most the 50 newest runs; direct workflow://runs/{runId}/result reads remain available until run deletion.",
|
|
34184
|
+
mimeType: RESULT_RESOURCE_MIME_TYPE
|
|
34185
|
+
},
|
|
34186
|
+
(uri) => this.readResultResource(uri.toString())
|
|
34187
|
+
);
|
|
34004
34188
|
this.mcp.registerResource(
|
|
34005
34189
|
"workflow-run-events",
|
|
34006
34190
|
new ResourceTemplate("workflow://runs/{runId}/events", {
|
|
@@ -34030,7 +34214,9 @@ var WorkflowScriptResources = class {
|
|
|
34030
34214
|
if (external.available !== void 0 && !external.available(ctx)) resourceNotFound(uri);
|
|
34031
34215
|
return external.read();
|
|
34032
34216
|
}
|
|
34033
|
-
|
|
34217
|
+
if (uri.includes("/events")) return this.readEventsResource(uri);
|
|
34218
|
+
if (workflowRunIdFromResultUri(uri)) return this.readResultResource(uri);
|
|
34219
|
+
return this.readResource(uri);
|
|
34034
34220
|
});
|
|
34035
34221
|
this.mcp.server.setRequestHandler("resources/subscribe", (request, ctx) => {
|
|
34036
34222
|
const uri = request.params.uri;
|
|
@@ -34045,6 +34231,12 @@ var WorkflowScriptResources = class {
|
|
|
34045
34231
|
this.subscriptions.add(uri);
|
|
34046
34232
|
return {};
|
|
34047
34233
|
}
|
|
34234
|
+
const resultRunId = workflowRunIdFromResultUri(uri);
|
|
34235
|
+
if (resultRunId) {
|
|
34236
|
+
if (!this.availableResultUri(resultRunId)) resourceNotFound(uri);
|
|
34237
|
+
this.subscriptions.add(uri);
|
|
34238
|
+
return {};
|
|
34239
|
+
}
|
|
34048
34240
|
if (!uri.includes("/events")) resourceNotFound(uri);
|
|
34049
34241
|
const parsed = parseWorkflowRunEventsUri(uri);
|
|
34050
34242
|
if (!parsed) malformedEventsUri();
|
|
@@ -34058,7 +34250,7 @@ var WorkflowScriptResources = class {
|
|
|
34058
34250
|
if (external.available !== void 0 && !external.available(ctx)) resourceNotFound(uri);
|
|
34059
34251
|
return {};
|
|
34060
34252
|
}
|
|
34061
|
-
const runId = workflowRunIdFromScriptUri(uri);
|
|
34253
|
+
const runId = workflowRunIdFromScriptUri(uri) ?? workflowRunIdFromResultUri(uri);
|
|
34062
34254
|
if (runId) {
|
|
34063
34255
|
if (!this.loadState(runId) && !this.loadTombstone(runId) && !this.deletedRunIds.has(runId) && !this.subscriptions.has(uri)) resourceNotFound(uri);
|
|
34064
34256
|
this.subscriptions.delete(uri);
|
|
@@ -34227,6 +34419,20 @@ var WorkflowScriptResources = class {
|
|
|
34227
34419
|
mapEventError(error51, parsed);
|
|
34228
34420
|
}
|
|
34229
34421
|
}
|
|
34422
|
+
readResultResource(uri) {
|
|
34423
|
+
const runId = workflowRunIdFromResultUri(uri);
|
|
34424
|
+
if (!runId) resourceNotFound(uri);
|
|
34425
|
+
const result = this.serializedResult(runId);
|
|
34426
|
+
return {
|
|
34427
|
+
contents: [
|
|
34428
|
+
{
|
|
34429
|
+
uri: result.uri,
|
|
34430
|
+
mimeType: RESULT_RESOURCE_MIME_TYPE,
|
|
34431
|
+
text: result.text
|
|
34432
|
+
}
|
|
34433
|
+
]
|
|
34434
|
+
};
|
|
34435
|
+
}
|
|
34230
34436
|
readResource(uri) {
|
|
34231
34437
|
const runId = workflowRunIdFromScriptUri(uri);
|
|
34232
34438
|
if (!runId) resourceNotFound(uri);
|
|
@@ -34557,7 +34763,7 @@ var DEFAULT_REQUEST_STATE_CODEC = createRequestStateCodec({
|
|
|
34557
34763
|
bind: (ctx) => ctx.mcpReq.method
|
|
34558
34764
|
});
|
|
34559
34765
|
var require2 = createRequire(import.meta.url);
|
|
34560
|
-
var SERVER_VERSION = true ? "0.38.
|
|
34766
|
+
var SERVER_VERSION = true ? "0.38.2" : require2("../package.json").version;
|
|
34561
34767
|
var SERVER_INSTRUCTIONS = [
|
|
34562
34768
|
"This server exposes three model-facing tools for authoring and orchestrating multi-agent work. workflow and repl spawn subagents over the same ACP backends \u2014 the registry built-ins Claude, Codex, OpenCode, and pi, plus any registered custom agents \u2014 and key their durable state by an absolute projectDir (required on the shared daemon; defaults to the server's own project in single-project mode). Backend credentials come from each agent's own login (claude, codex, opencode, pi), so there is nothing auth-shaped to configure here.",
|
|
34563
34769
|
'\u2022 docs \u2014 SELECTIVE VERSION-MATCHED REFERENCE. Omit topic or use topic:"index" for the bounded catalog, then read exactly one workflow/* or repl/* topic. It embeds the selected text/markdown resource, runs no code, opens no backend, and needs no projectDir. Use it when the compact tool descriptions do not contain enough syntax or lifecycle detail.',
|
|
@@ -35338,17 +35544,98 @@ function persistedOutcome(persisted, status) {
|
|
|
35338
35544
|
...persisted.checkpointsTaken === void 0 ? {} : { checkpointsTaken: persisted.checkpointsTaken },
|
|
35339
35545
|
...persisted.resumeReport === void 0 ? {} : { resumeReport: persisted.resumeReport },
|
|
35340
35546
|
...persisted.replayEligibility === void 0 ? {} : { replayEligibility: persisted.replayEligibility },
|
|
35341
|
-
scriptUri: workflowScriptUri(persisted.runId)
|
|
35547
|
+
scriptUri: workflowScriptUri(persisted.runId),
|
|
35548
|
+
...status.status === "completed" && persisted.result !== void 0 ? { resultUri: workflowResultUri(persisted.runId) } : {}
|
|
35342
35549
|
};
|
|
35343
35550
|
}
|
|
35344
35551
|
function terminalOutcome(manager, runId, status) {
|
|
35552
|
+
const persisted = manager.getPersistence().load(runId);
|
|
35553
|
+
const resultUri = persisted?.status === "completed" && persisted.result !== void 0 ? workflowResultUri(runId) : void 0;
|
|
35345
35554
|
const live = manager.getRun(runId)?.result;
|
|
35346
35555
|
if (live) {
|
|
35347
|
-
return toWorkflowExecutionOutcome(live, {
|
|
35556
|
+
return toWorkflowExecutionOutcome(live, {
|
|
35557
|
+
scriptUri: workflowScriptUri(runId),
|
|
35558
|
+
...resultUri === void 0 ? {} : { resultUri }
|
|
35559
|
+
});
|
|
35348
35560
|
}
|
|
35349
|
-
const persisted = manager.getPersistence().load(runId);
|
|
35350
35561
|
return persisted ? persistedOutcome(persisted, status) : void 0;
|
|
35351
35562
|
}
|
|
35563
|
+
var INLINE_WORKFLOW_RESULT_MAX_BYTES = 4096;
|
|
35564
|
+
function resultResourceFields(resources, runId) {
|
|
35565
|
+
const resultUri = resources.availableResultUri(runId);
|
|
35566
|
+
return resultUri === void 0 ? {} : { resultUri };
|
|
35567
|
+
}
|
|
35568
|
+
function resultContentBlocks(resources, runId, inline) {
|
|
35569
|
+
const link = resources.resultLink(runId);
|
|
35570
|
+
if (!link) return [];
|
|
35571
|
+
const resultUri = link.uri;
|
|
35572
|
+
if (inline) {
|
|
35573
|
+
const result = resources.serializedResult(runId);
|
|
35574
|
+
if (result.bytes <= INLINE_WORKFLOW_RESULT_MAX_BYTES) {
|
|
35575
|
+
return [
|
|
35576
|
+
{
|
|
35577
|
+
type: "text",
|
|
35578
|
+
text: `Workflow result (exact JSON):
|
|
35579
|
+
${result.text}`,
|
|
35580
|
+
annotations: { audience: ["assistant"] }
|
|
35581
|
+
},
|
|
35582
|
+
link
|
|
35583
|
+
];
|
|
35584
|
+
}
|
|
35585
|
+
return [
|
|
35586
|
+
{
|
|
35587
|
+
type: "text",
|
|
35588
|
+
text: `Exact workflow result: ${result.bytes} UTF-8 bytes at ${resultUri}. Read that resource directly, or call workflow with action="result", runId="${runId}", offset=0 and follow endOffset while hasMore is true for bounded exact chunks.`,
|
|
35589
|
+
annotations: { audience: ["assistant"] }
|
|
35590
|
+
},
|
|
35591
|
+
link
|
|
35592
|
+
];
|
|
35593
|
+
}
|
|
35594
|
+
return [
|
|
35595
|
+
{
|
|
35596
|
+
type: "text",
|
|
35597
|
+
text: `Exact workflow result: ${resultUri}. Read that resource directly, or call workflow with action="result", runId="${runId}", offset=0 and follow endOffset while hasMore is true for bounded exact chunks.`,
|
|
35598
|
+
annotations: { audience: ["assistant"] }
|
|
35599
|
+
},
|
|
35600
|
+
link
|
|
35601
|
+
];
|
|
35602
|
+
}
|
|
35603
|
+
function isUtf8ContinuationByte(byte) {
|
|
35604
|
+
return byte !== void 0 && (byte & 192) === 128;
|
|
35605
|
+
}
|
|
35606
|
+
function resultRetrievalPage(resources, runId, offset, maxBytes) {
|
|
35607
|
+
const result = resources.serializedResult(runId);
|
|
35608
|
+
const buffer = Buffer.from(result.text, "utf8");
|
|
35609
|
+
if (offset > buffer.length) {
|
|
35610
|
+
throw new ProtocolError(
|
|
35611
|
+
ProtocolErrorCode.InvalidParams,
|
|
35612
|
+
`Workflow result offset ${offset} exceeds totalBytes ${buffer.length} for runId "${runId}".`
|
|
35613
|
+
);
|
|
35614
|
+
}
|
|
35615
|
+
if (offset < buffer.length && isUtf8ContinuationByte(buffer[offset])) {
|
|
35616
|
+
throw new ProtocolError(
|
|
35617
|
+
ProtocolErrorCode.InvalidParams,
|
|
35618
|
+
`Workflow result offset ${offset} is not a UTF-8 boundary for runId "${runId}"; use the previous endOffset.`
|
|
35619
|
+
);
|
|
35620
|
+
}
|
|
35621
|
+
let endOffset = Math.min(buffer.length, offset + maxBytes);
|
|
35622
|
+
while (endOffset > offset && endOffset < buffer.length && isUtf8ContinuationByte(buffer[endOffset])) {
|
|
35623
|
+
endOffset--;
|
|
35624
|
+
}
|
|
35625
|
+
return {
|
|
35626
|
+
action: "result",
|
|
35627
|
+
runId,
|
|
35628
|
+
status: "completed",
|
|
35629
|
+
resultUri: result.uri,
|
|
35630
|
+
mimeType: RESULT_RESOURCE_MIME_TYPE,
|
|
35631
|
+
encoding: "utf-8",
|
|
35632
|
+
totalBytes: buffer.length,
|
|
35633
|
+
offset,
|
|
35634
|
+
endOffset,
|
|
35635
|
+
hasMore: endOffset < buffer.length,
|
|
35636
|
+
chunk: buffer.subarray(offset, endOffset).toString("utf8")
|
|
35637
|
+
};
|
|
35638
|
+
}
|
|
35352
35639
|
var AWAIT_CANCELLED = /* @__PURE__ */ Symbol("await-cancelled");
|
|
35353
35640
|
var AWAIT_UNKNOWN_RUN = /* @__PURE__ */ Symbol("await-unknown-run");
|
|
35354
35641
|
var EVENT_LOG_POLL_FALLBACK_CODES = /* @__PURE__ */ new Set([
|
|
@@ -35605,7 +35892,7 @@ function createWorkflowServer(runner, options = {}) {
|
|
|
35605
35892
|
const workflowToolOutputSchema = workflowToolOutputShape;
|
|
35606
35893
|
const workflowToolConfig = {
|
|
35607
35894
|
title: "Discover, validate, run, inspect, await, answer permissions, stop, or narrow-cancel a workflow",
|
|
35608
|
-
description: 'Author and operate JavaScript agent workflows through one project-scoped tool. A script\'s first statement must be `export const meta = { name, description, phases? }`. When present, phases must be an array of objects shaped `{ title: string, detail?: string, model?: string }`, never an array of strings. Inside the deterministic script realm use agent(prompt, options?) for one subagent; parallel([thunks]) for a barrier; pipeline(items, ...stages) for streaming stages; checkpoint(prompt, options?) for a human gate; phase(title) and log(message) for progress; and return the final JSON-serializable value. Top-level await is supported. Imports, require, network APIs, Date.now(), and Math.random() are unavailable. Always label agent calls; schema is a plain JSON Schema object for structured results. The only agent option keys are label, phase, model, tier, mode, configOptions, schema, cwd, timeoutMs, idleTimeoutMs, retries, isolation:"worktree", resume, agentType, mcpServers, images, meta, promptMeta, and keepSession; unknown keys reject before admission. Every parallel entry must be a thunk: parallel([() => agent(...), () => agent(...)]). For deeper syntax, read docs topic workflow/quickstart and then one related workflow/* topic. Minimal script: `export const meta = { name: "review", description: "Review a target", phases: [{ title: "Review" }] }; phase("Review"); const report = await agent("Review " + args.target, { label: "review" }); return { report };`. Omit model for the server default (explicit AGENTPRISM_DEFAULT_BACKEND, else a zero-token auto-selected project pin), or use a backend name alone to preserve that backend\'s configured default. Before choosing a pinned model, mode, or configOptions, call action:"config" with projectDir and optional harnesses/modelFilter; after choosing a model, pass modelSpecs to read its model-specific options. Config returns every harness-advertised mode name, description, and metadata plus AgentPrism\'s omitted-mode default: Claude auto, Codex agent, OpenCode build, and no Pi mode. Pin only exact advertised ids. Config opens no-prompt sessions, spends zero tokens, and starts no workflow. action:"run" automatically performs static validation, a mocked dry run, and routed config checks before admission. Invalid scripts return bounded diagnostics with status:"rejected" and create no run ID, reserve no background slot, and spend no tokens. Run, resume, inspect, await, answer a live ACP permission, or stop an admitted workflow through the same tool. The script orchestrates agent() subagents (and optional checkpoint() gates) over registry built-ins\u2014currently Claude, Codex, OpenCode, and pi\u2014ACP backends, plus registered custom agents. Supply exactly one of inline script or absolute scriptPath; path content is read once and snapshotted at admission. ' + (requireProjectDir ? "config and run REQUIRE projectDir (absolute): it is the discovery cwd and selects the project-scoped run store/default execution cwd. " : "run optionally takes projectDir (absolute) to select the project-scoped run store; default is this server's own project. ") + `inspect/await/stop/permissions-response locate the project store from runId and never accept projectDir. Foreground is the default and streams progress; background:true returns a durable runId for bounded action:"await" calls. run and await honor _meta.progressToken with notifications/progress while they block. Pass resumeFromRunId to execute a new run from a prior journal prefix. In hosts that render MCP Apps, every call of this tool shows a live self-updating run-monitor panel and the panel reports phase starts, pauses, and terminal outcomes on its own \u2014 do NOT poll action:"inspect" to check on a run there; prefer a single bounded action:"await". Use action:"inspect" with a runId when you need machine-readable status data: a safe bounded status, log tail, attributed call previews, and pending ACP permissions. Await returns early with action-required when one appears. Elicitation-capable hosts can present the exact backend options; otherwise use action:"permissions-response" with the returned permissionId and an exact advertised optionId or cancelled outcome. Use action:"stop" to durably abort through the run's execution owner; cross-generation control may return a durable pending operationId before final settlement. Add callIndex to cancel only that live agent and keep the run live. forceOwner explicitly authorizes terminating a superseded owner and is forbidden with callIndex. labelGlob remains an output filter. A final whole-run stop makes resume safe immediately; pending control must be retried or observed with inspect/await. Every admitted script is readable at workflow://runs/{runId}/script
|
|
35895
|
+
description: 'Author and operate JavaScript agent workflows through one project-scoped tool. A script\'s first statement must be `export const meta = { name, description, phases? }`. When present, phases must be an array of objects shaped `{ title: string, detail?: string, model?: string }`, never an array of strings. Inside the deterministic script realm use agent(prompt, options?) for one subagent; parallel([thunks]) for a barrier; pipeline(items, ...stages) for streaming stages; checkpoint(prompt, options?) for a human gate; phase(title) and log(message) for progress; and return the final JSON-serializable value. Top-level await is supported. Imports, require, network APIs, Date.now(), and Math.random() are unavailable. Always label agent calls; schema is a plain JSON Schema object for structured results. The only agent option keys are label, phase, model, tier, mode, configOptions, schema, cwd, timeoutMs, idleTimeoutMs, retries, isolation:"worktree", resume, agentType, mcpServers, images, meta, promptMeta, and keepSession; unknown keys reject before admission. Every parallel entry must be a thunk: parallel([() => agent(...), () => agent(...)]). For deeper syntax, read docs topic workflow/quickstart and then one related workflow/* topic. Minimal script: `export const meta = { name: "review", description: "Review a target", phases: [{ title: "Review" }] }; phase("Review"); const report = await agent("Review " + args.target, { label: "review" }); return { report };`. Omit model for the server default (explicit AGENTPRISM_DEFAULT_BACKEND, else a zero-token auto-selected project pin), or use a backend name alone to preserve that backend\'s configured default. Before choosing a pinned model, mode, or configOptions, call action:"config" with projectDir and optional harnesses/modelFilter; after choosing a model, pass modelSpecs to read its model-specific options. Config returns every harness-advertised mode name, description, and metadata plus AgentPrism\'s omitted-mode default: Claude auto, Codex agent, OpenCode build, and no Pi mode. Pin only exact advertised ids. Config opens no-prompt sessions, spends zero tokens, and starts no workflow. action:"run" automatically performs static validation, a mocked dry run, and routed config checks before admission. Invalid scripts return bounded diagnostics with status:"rejected" and create no run ID, reserve no background slot, and spend no tokens. Run, resume, inspect, await, retrieve an exact completed result, answer a live ACP permission, or stop an admitted workflow through the same tool. The script orchestrates agent() subagents (and optional checkpoint() gates) over registry built-ins\u2014currently Claude, Codex, OpenCode, and pi\u2014ACP backends, plus registered custom agents. Supply exactly one of inline script or absolute scriptPath; path content is read once and snapshotted at admission. ' + (requireProjectDir ? "config and run REQUIRE projectDir (absolute): it is the discovery cwd and selects the project-scoped run store/default execution cwd. " : "run optionally takes projectDir (absolute) to select the project-scoped run store; default is this server's own project. ") + `inspect/await/result/stop/permissions-response locate the project store from runId and never accept projectDir. Foreground is the default and streams progress; background:true returns a durable runId for bounded action:"await" calls. run and await honor _meta.progressToken with notifications/progress while they block. Pass resumeFromRunId to execute a new run from a prior journal prefix. In hosts that render MCP Apps, every call of this tool shows a live self-updating run-monitor panel and the panel reports phase starts, pauses, and terminal outcomes on its own \u2014 do NOT poll action:"inspect" to check on a run there; prefer a single bounded action:"await". Use action:"inspect" with a runId when you need machine-readable status data: a safe bounded status, log tail, attributed call previews, and pending ACP permissions. Await returns early with action-required when one appears. Elicitation-capable hosts can present the exact backend options; otherwise use action:"permissions-response" with the returned permissionId and an exact advertised optionId or cancelled outcome. Use action:"stop" to durably abort through the run's execution owner; cross-generation control may return a durable pending operationId before final settlement. Add callIndex to cancel only that live agent and keep the run live. forceOwner explicitly authorizes terminating a superseded owner and is forbidden with callIndex. labelGlob remains an output filter. A final whole-run stop makes resume safe immediately; pending control must be retried or observed with inspect/await. Every admitted script is readable at workflow://runs/{runId}/script. Completed JSON results are readable at workflow://runs/{runId}/result; small results are also copied into text for content-first hosts, while large results can be paged exactly with action:"result", offset, and maxBytes. Result and script resource links are labelled separately. Background runs are tracked per project, capped at four active/starting runs, and use headless checkpoint semantics; checkpointReplies continue a checkpoint pause in a new run.`,
|
|
35609
35896
|
inputSchema: workflowToolInputSchema,
|
|
35610
35897
|
outputSchema: workflowToolOutputSchema,
|
|
35611
35898
|
annotations: void 0
|
|
@@ -35749,7 +36036,12 @@ function createWorkflowServer(runner, options = {}) {
|
|
|
35749
36036
|
);
|
|
35750
36037
|
const projected = addInspectionResourceFields(
|
|
35751
36038
|
status,
|
|
35752
|
-
{
|
|
36039
|
+
{
|
|
36040
|
+
scriptUri: workflowScriptUri(requestState.runId),
|
|
36041
|
+
...resultResourceFields(scriptResources, requestState.runId),
|
|
36042
|
+
lineage,
|
|
36043
|
+
pendingPermissions: remaining
|
|
36044
|
+
},
|
|
35753
36045
|
inspectionRetentionMetadata(manager, requestState.runId, status)
|
|
35754
36046
|
);
|
|
35755
36047
|
return {
|
|
@@ -35764,6 +36056,7 @@ function createWorkflowServer(runner, options = {}) {
|
|
|
35764
36056
|
${formatInspectionSummary(projected)}`,
|
|
35765
36057
|
annotations: { audience: ["assistant"] }
|
|
35766
36058
|
},
|
|
36059
|
+
...resultContentBlocks(scriptResources, requestState.runId, false),
|
|
35767
36060
|
...scriptResources.links(lineage)
|
|
35768
36061
|
],
|
|
35769
36062
|
isError: false
|
|
@@ -35839,6 +36132,35 @@ ${formatInspectionSummary(projected)}`,
|
|
|
35839
36132
|
}
|
|
35840
36133
|
}
|
|
35841
36134
|
}
|
|
36135
|
+
if (parsedInput.action === "result") {
|
|
36136
|
+
try {
|
|
36137
|
+
const page = resultRetrievalPage(
|
|
36138
|
+
scriptResources,
|
|
36139
|
+
parsedInput.runId,
|
|
36140
|
+
parsedInput.offset ?? 0,
|
|
36141
|
+
parsedInput.maxBytes ?? WORKFLOW_RESULT_CHUNK_BYTES_DEFAULT
|
|
36142
|
+
);
|
|
36143
|
+
const resultLink = scriptResources.resultLink(parsedInput.runId);
|
|
36144
|
+
return {
|
|
36145
|
+
structuredContent: { ...page },
|
|
36146
|
+
content: [
|
|
36147
|
+
{
|
|
36148
|
+
type: "text",
|
|
36149
|
+
text: JSON.stringify(page),
|
|
36150
|
+
annotations: { audience: ["assistant"] }
|
|
36151
|
+
},
|
|
36152
|
+
...resultLink === void 0 ? [] : [resultLink]
|
|
36153
|
+
],
|
|
36154
|
+
isError: false
|
|
36155
|
+
};
|
|
36156
|
+
} catch (error51) {
|
|
36157
|
+
if (!(error51 instanceof ProtocolError)) throw error51;
|
|
36158
|
+
return {
|
|
36159
|
+
content: [{ type: "text", text: error51.message }],
|
|
36160
|
+
isError: true
|
|
36161
|
+
};
|
|
36162
|
+
}
|
|
36163
|
+
}
|
|
35842
36164
|
if (parsedInput.action === "permissions-response") {
|
|
35843
36165
|
const acknowledgement = await respondToPermission(
|
|
35844
36166
|
manager,
|
|
@@ -35866,7 +36188,12 @@ ${formatInspectionSummary(projected)}`,
|
|
|
35866
36188
|
);
|
|
35867
36189
|
const projected = addInspectionResourceFields(
|
|
35868
36190
|
status,
|
|
35869
|
-
{
|
|
36191
|
+
{
|
|
36192
|
+
scriptUri: workflowScriptUri(parsedInput.runId),
|
|
36193
|
+
...resultResourceFields(scriptResources, parsedInput.runId),
|
|
36194
|
+
lineage,
|
|
36195
|
+
pendingPermissions
|
|
36196
|
+
},
|
|
35870
36197
|
inspectionRetentionMetadata(manager, parsedInput.runId, status)
|
|
35871
36198
|
);
|
|
35872
36199
|
return {
|
|
@@ -35881,6 +36208,7 @@ ${formatInspectionSummary(projected)}`,
|
|
|
35881
36208
|
` + formatInspectionSummary(projected) + formatPendingPermissions(pendingPermissions),
|
|
35882
36209
|
annotations: { audience: ["assistant"] }
|
|
35883
36210
|
},
|
|
36211
|
+
...resultContentBlocks(scriptResources, parsedInput.runId, false),
|
|
35884
36212
|
...scriptResources.links(lineage)
|
|
35885
36213
|
],
|
|
35886
36214
|
isError: false
|
|
@@ -35956,6 +36284,7 @@ ${formatInspectionSummary(projected)}`,
|
|
|
35956
36284
|
status,
|
|
35957
36285
|
{
|
|
35958
36286
|
scriptUri: workflowScriptUri(parsedInput.runId),
|
|
36287
|
+
...resultResourceFields(scriptResources, parsedInput.runId),
|
|
35959
36288
|
lineage,
|
|
35960
36289
|
pendingPermissions,
|
|
35961
36290
|
interaction: permissionInteraction(canElicitPermission)
|
|
@@ -35976,6 +36305,7 @@ ${formatInspectionSummary(projected)}`,
|
|
|
35976
36305
|
Permission ${acknowledgement.permissionId} resolved.` : "") + formatPendingPermissions(pendingPermissions),
|
|
35977
36306
|
annotations: { audience: ["assistant"] }
|
|
35978
36307
|
},
|
|
36308
|
+
...resultContentBlocks(scriptResources, parsedInput.runId, false),
|
|
35979
36309
|
...scriptResources.links(lineage)
|
|
35980
36310
|
],
|
|
35981
36311
|
isError: false
|
|
@@ -36177,6 +36507,7 @@ Permission ${acknowledgement.permissionId} resolved.` : "") + formatPendingPermi
|
|
|
36177
36507
|
status,
|
|
36178
36508
|
{
|
|
36179
36509
|
scriptUri: workflowScriptUri(parsedInput.runId),
|
|
36510
|
+
...resultResourceFields(scriptResources, parsedInput.runId),
|
|
36180
36511
|
lineage,
|
|
36181
36512
|
stopped,
|
|
36182
36513
|
alreadyTerminal
|
|
@@ -36187,7 +36518,11 @@ Permission ${acknowledgement.permissionId} resolved.` : "") + formatPendingPermi
|
|
|
36187
36518
|
const currentLink = scriptResources.links(lineage).filter((link) => link.uri === workflowScriptUri(parsedInput.runId));
|
|
36188
36519
|
return {
|
|
36189
36520
|
structuredContent: { ...result },
|
|
36190
|
-
content: [
|
|
36521
|
+
content: [
|
|
36522
|
+
{ type: "text", text: formatStopSummary(result) },
|
|
36523
|
+
...resultContentBlocks(scriptResources, parsedInput.runId, false),
|
|
36524
|
+
...currentLink
|
|
36525
|
+
],
|
|
36191
36526
|
isError: false
|
|
36192
36527
|
};
|
|
36193
36528
|
}
|
|
@@ -36350,6 +36685,7 @@ Permission ${acknowledgement.permissionId} resolved.` : "") + formatPendingPermi
|
|
|
36350
36685
|
pendingPermissions,
|
|
36351
36686
|
interaction: permissionInteraction(canElicitPermission),
|
|
36352
36687
|
scriptUri: workflowScriptUri(parsedInput.runId),
|
|
36688
|
+
...resultResourceFields(scriptResources, parsedInput.runId),
|
|
36353
36689
|
lineage
|
|
36354
36690
|
},
|
|
36355
36691
|
inspectionRetentionMetadata(manager, parsedInput.runId, status)
|
|
@@ -36367,6 +36703,7 @@ Permission ${acknowledgement.permissionId} resolved.` : "") + formatPendingPermi
|
|
|
36367
36703
|
text: formatAwaitSummary(result) + formatPendingPermissions(pendingPermissions),
|
|
36368
36704
|
annotations: { audience: ["assistant"] }
|
|
36369
36705
|
},
|
|
36706
|
+
...resultContentBlocks(scriptResources, parsedInput.runId, true),
|
|
36370
36707
|
...scriptResources.links(lineage)
|
|
36371
36708
|
],
|
|
36372
36709
|
isError: false
|
|
@@ -36686,14 +37023,16 @@ Call workflow with action="await" or action="inspect"; elicitation-capable clien
|
|
|
36686
37023
|
});
|
|
36687
37024
|
}
|
|
36688
37025
|
const scriptUri = workflowScriptUri(run.runId);
|
|
37026
|
+
const resultFields = resultResourceFields(scriptResources, run.runId);
|
|
36689
37027
|
const structuredContent = {
|
|
36690
|
-
...toWorkflowToolResult(run, { scriptSource, scriptUri })
|
|
37028
|
+
...toWorkflowToolResult(run, { scriptSource, scriptUri, ...resultFields })
|
|
36691
37029
|
};
|
|
36692
37030
|
const isError = run.status === "failed" || run.status === "aborted";
|
|
36693
37031
|
return {
|
|
36694
37032
|
structuredContent: { ...structuredContent },
|
|
36695
37033
|
content: [
|
|
36696
37034
|
{ type: "text", text: `${formatRunSummary(run)}${preflightWarningText}` },
|
|
37035
|
+
...resultContentBlocks(scriptResources, run.runId, true),
|
|
36697
37036
|
...scriptResources.links([{ runId: run.runId, uri: scriptUri, available: true }])
|
|
36698
37037
|
],
|
|
36699
37038
|
isError
|
|
@@ -38881,6 +39220,16 @@ async function createDaemon(options) {
|
|
|
38881
39220
|
const detachModernRunDeleted = projects.onRunDeleted(() => modernNotifier.resourcesChanged());
|
|
38882
39221
|
const detachModernRunEvent = projects.onRunEventPersisted((record2) => {
|
|
38883
39222
|
modernNotifier.resourceUpdated(workflowRunEventsUri(record2.runId));
|
|
39223
|
+
if (record2.event.type !== "complete") return;
|
|
39224
|
+
queueMicrotask(() => {
|
|
39225
|
+
try {
|
|
39226
|
+
const state = projects.storeFor(record2.runId)?.manager.getPersistence().load(record2.runId);
|
|
39227
|
+
if (state?.status === "completed" && state.result !== void 0) {
|
|
39228
|
+
modernNotifier.resourcesChanged();
|
|
39229
|
+
}
|
|
39230
|
+
} catch {
|
|
39231
|
+
}
|
|
39232
|
+
});
|
|
38884
39233
|
});
|
|
38885
39234
|
const handleMcpRequest = async (req, res) => {
|
|
38886
39235
|
const sessionHeader = req.headers["mcp-session-id"];
|
|
@@ -53262,12 +53611,16 @@ export {
|
|
|
53262
53611
|
MCP_ENDPOINT_PATH,
|
|
53263
53612
|
RESOURCE_MIME_TYPE,
|
|
53264
53613
|
RESOURCE_URI_META_KEY,
|
|
53614
|
+
RESULT_RESOURCE_MIME_TYPE,
|
|
53265
53615
|
RUN_MONITOR_RESOURCE_URI,
|
|
53266
53616
|
ReplPresenceLedger,
|
|
53267
53617
|
SCRIPT_RESOURCE_LIST_LIMIT,
|
|
53268
53618
|
SCRIPT_RESOURCE_MIME_TYPE,
|
|
53269
53619
|
SHUTDOWN_DEADLINE_MS,
|
|
53270
53620
|
WORKFLOW_EVENTS_TOOL_NAME,
|
|
53621
|
+
WORKFLOW_RESULT_CHUNK_BYTES_DEFAULT,
|
|
53622
|
+
WORKFLOW_RESULT_CHUNK_BYTES_MAX,
|
|
53623
|
+
WORKFLOW_RESULT_CHUNK_BYTES_MIN,
|
|
53271
53624
|
WORKFLOW_RUN_EVENTS_SCHEMA_VERSION,
|
|
53272
53625
|
WorkflowPermissionBroker,
|
|
53273
53626
|
WorkflowProjectRegistry,
|
|
@@ -53310,7 +53663,9 @@ export {
|
|
|
53310
53663
|
toWorkflowExecutionOutcome,
|
|
53311
53664
|
toWorkflowToolResult,
|
|
53312
53665
|
validateRequest,
|
|
53666
|
+
workflowResultUri,
|
|
53313
53667
|
workflowRunEventsUri,
|
|
53668
|
+
workflowRunIdFromResultUri,
|
|
53314
53669
|
workflowRunIdFromScriptUri,
|
|
53315
53670
|
workflowScriptUri,
|
|
53316
53671
|
workflowToolInputShape,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automatalabs/workflows",
|
|
3
|
-
"version": "0.58.
|
|
3
|
+
"version": "0.58.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22"
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"typebox": "1.3.2",
|
|
34
|
-
"@automatalabs/repl-engine": "0.4.
|
|
34
|
+
"@automatalabs/repl-engine": "0.4.13",
|
|
35
35
|
"@automatalabs/shared-types": "0.34.0",
|
|
36
36
|
"@automatalabs/workflow-engine": "0.42.0",
|
|
37
|
-
"@automatalabs/acp-agents": "0.43.
|
|
37
|
+
"@automatalabs/acp-agents": "0.43.1"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"esbuild": "^0.28.1"
|