stageflow 0.9.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/dist/agent/activity.d.ts +9 -0
- package/dist/agent/agentBackend.d.ts +32 -0
- package/dist/agent/agentBackend.js +38 -0
- package/dist/agent/claudeActivity.d.ts +15 -0
- package/dist/agent/claudeActivity.js +58 -0
- package/dist/agent/claudeAdapter.d.ts +5 -0
- package/dist/agent/claudeAdapter.js +331 -0
- package/dist/agent/claudeSession.d.ts +18 -0
- package/dist/agent/claudeSession.js +54 -0
- package/dist/agent/claudeTools.d.ts +89 -0
- package/dist/agent/claudeTools.js +135 -0
- package/dist/agent/fakeAgent.js +24 -4
- package/dist/agent/piAdapter.d.ts +12 -7
- package/dist/agent/piAdapter.js +194 -44
- package/dist/agent/piIsolatedMcp.d.ts +23 -0
- package/dist/agent/piIsolatedMcp.js +223 -0
- package/dist/agent/piIsolatedMcpProbe.d.ts +15 -0
- package/dist/agent/piIsolatedMcpProbe.js +292 -0
- package/dist/agent/port.d.ts +52 -1
- package/dist/agent/port.js +1 -1
- package/dist/agent/resolveAgentPort.d.ts +26 -0
- package/dist/agent/resolveAgentPort.js +39 -0
- package/dist/cli/runCommand.js +2 -2
- package/dist/cli/runsCommand.d.ts +1 -1
- package/dist/cli/runsCommand.js +184 -2
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +11 -5
- package/dist/config/browseCatalog.js +1 -1
- package/dist/config/createPipeline.d.ts +2 -1
- package/dist/config/createPipeline.js +34 -9
- package/dist/config/createStage.js +14 -9
- package/dist/config/loadPipeline.js +11 -1
- package/dist/config/loadStage.d.ts +1 -0
- package/dist/config/loadStage.js +207 -2
- package/dist/config/loadStageflowManifest.js +14 -1
- package/dist/config/mergePipelineIncludes.d.ts +1 -0
- package/dist/config/mergePipelineIncludes.js +14 -1
- package/dist/config/normalizePipelineStageEntry.d.ts +7 -2
- package/dist/config/normalizePipelineStageEntry.js +56 -7
- package/dist/config/parseCompletionContract.d.ts +8 -0
- package/dist/config/parseCompletionContract.js +218 -0
- package/dist/config/parsePreEmitChecks.d.ts +3 -0
- package/dist/config/parsePreEmitChecks.js +65 -0
- package/dist/config/pipelineNeeds.d.ts +19 -0
- package/dist/config/pipelineNeeds.js +151 -0
- package/dist/config/pipelineStageKeys.js +17 -1
- package/dist/config/resolveForkEmitContext.d.ts +6 -2
- package/dist/config/resolveForkEmitContext.js +9 -2
- package/dist/config/resolvePipelineDag.d.ts +2 -1
- package/dist/config/resolvePipelineDag.js +182 -39
- package/dist/config/resolveStageMcpServers.d.ts +35 -0
- package/dist/config/resolveStageMcpServers.js +207 -0
- package/dist/config/validateCatalog.d.ts +1 -1
- package/dist/config/validateCatalog.js +51 -0
- package/dist/config/validateCompletionContract.d.ts +4 -0
- package/dist/config/validateCompletionContract.js +52 -0
- package/dist/envelope/check.d.ts +1 -1
- package/dist/envelope/check.js +86 -13
- package/dist/envelope/cloneForks.d.ts +1 -1
- package/dist/envelope/cloneForks.js +24 -9
- package/dist/envelope/feedbackLoop.d.ts +4 -0
- package/dist/envelope/feedbackLoop.js +31 -0
- package/dist/envelope/payloadSchema.d.ts +7 -1
- package/dist/envelope/payloadSchema.js +170 -13
- package/dist/envelope/preEmitChecks.d.ts +29 -0
- package/dist/envelope/preEmitChecks.js +57 -0
- package/dist/hitl/qaTrail.d.ts +25 -0
- package/dist/hitl/qaTrail.js +51 -0
- package/dist/mcp/catalogTools.js +4 -2
- package/dist/mcp/controlTools.js +72 -0
- package/dist/mcp/readArtifact.d.ts +2 -0
- package/dist/mcp/readArtifact.js +25 -1
- package/dist/mcp/waitingGates.d.ts +2 -1
- package/dist/mcp/waitingGates.js +17 -1
- package/dist/package-meta.d.ts +1 -1
- package/dist/package-meta.js +1 -1
- package/dist/projection/projectRun.d.ts +4 -1
- package/dist/projection/projectRun.js +7 -0
- package/dist/prompt/feedbackLoopContext.d.ts +2 -0
- package/dist/prompt/feedbackLoopContext.js +17 -0
- package/dist/prompt/priorEnvelope.d.ts +2 -2
- package/dist/prompt/priorEnvelope.js +4 -1
- package/dist/runstore/pipelineDagSnapshot.d.ts +1 -0
- package/dist/runstore/pipelineDagSnapshot.js +51 -11
- package/dist/runstore/port.d.ts +185 -3
- package/dist/runstore/port.js +42 -3
- package/dist/runstore/runProjection.d.ts +7 -3
- package/dist/runstore/runProjection.js +30 -15
- package/dist/runstore/sqlite/SqliteRunStore.d.ts +25 -1
- package/dist/runstore/sqlite/SqliteRunStore.js +626 -8
- package/dist/runstore/sqlite/schema.d.ts +1 -1
- package/dist/runstore/sqlite/schema.js +99 -0
- package/dist/runstore/stageInstanceId.d.ts +1 -1
- package/dist/runstore/stageInstanceId.js +3 -2
- package/dist/runstore/trackProjection.js +59 -27
- package/dist/runstore/verificationHistory.d.ts +19 -0
- package/dist/runstore/verificationHistory.js +30 -0
- package/dist/runtime/cloneSchedule.d.ts +40 -4
- package/dist/runtime/cloneSchedule.js +212 -28
- package/dist/runtime/completionCheckRunner.d.ts +137 -0
- package/dist/runtime/completionCheckRunner.js +365 -0
- package/dist/runtime/completionCheckoutBaseline.d.ts +3 -0
- package/dist/runtime/completionCheckoutBaseline.js +44 -0
- package/dist/runtime/envelopeRouting.d.ts +10 -3
- package/dist/runtime/envelopeRouting.js +146 -5
- package/dist/runtime/feedbackLoopCoordinator.d.ts +74 -0
- package/dist/runtime/feedbackLoopCoordinator.js +446 -0
- package/dist/runtime/feedbackLoopDecision.d.ts +44 -0
- package/dist/runtime/feedbackLoopDecision.js +207 -0
- package/dist/runtime/feedbackLoopRoute.d.ts +5 -0
- package/dist/runtime/feedbackLoopRoute.js +13 -0
- package/dist/runtime/feedbackLoopSchedule.d.ts +38 -0
- package/dist/runtime/feedbackLoopSchedule.js +72 -0
- package/dist/runtime/forkGeneration.d.ts +72 -0
- package/dist/runtime/forkGeneration.js +295 -0
- package/dist/runtime/gitCheckoutCapability.d.ts +7 -0
- package/dist/runtime/gitCheckoutCapability.js +97 -0
- package/dist/runtime/manualRecoveryState.d.ts +40 -0
- package/dist/runtime/manualRecoveryState.js +73 -0
- package/dist/runtime/pipelineScheduler.d.ts +13 -1
- package/dist/runtime/pipelineScheduler.js +328 -45
- package/dist/runtime/replayLifecycle.d.ts +107 -0
- package/dist/runtime/replayLifecycle.js +168 -0
- package/dist/runtime/runManager.d.ts +54 -1
- package/dist/runtime/runManager.js +471 -6
- package/dist/runtime/runRetryCoordinator.d.ts +6 -1
- package/dist/runtime/runRetryCoordinator.js +43 -9
- package/dist/runtime/stageAttemptBootstrap.d.ts +3 -1
- package/dist/runtime/stageAttemptBootstrap.js +117 -3
- package/dist/runtime/stageProcessLauncher.d.ts +1 -1
- package/dist/runtime/stageRecovery.js +1 -1
- package/dist/runtime/stageRunner.d.ts +4 -1
- package/dist/runtime/stageRunner.js +29 -3
- package/dist/runtime/stageWorker.js +69 -2
- package/dist/runtime/stageWorkerProtocol.d.ts +1 -1
- package/dist/runtime/verifiedStageExecution.d.ts +31 -0
- package/dist/runtime/verifiedStageExecution.js +127 -0
- package/dist/server/bootstrap.js +1 -0
- package/dist/server/http.js +137 -4
- package/dist/server/operatorResults.js +2 -0
- package/dist/server/projectMcpRoutes.d.ts +6 -0
- package/dist/server/projectMcpRoutes.js +38 -0
- package/dist/tools/askOperator.d.ts +161 -5
- package/dist/tools/askOperator.js +58 -25
- package/dist/tools/emitStageEnvelope.d.ts +12 -12
- package/dist/tools/emitStageEnvelope.js +112 -24
- package/dist/types/completion.d.ts +43 -0
- package/dist/types/completion.js +1 -0
- package/dist/types/envelope.d.ts +18 -0
- package/dist/types/forkChoice.d.ts +9 -4
- package/dist/types/forkChoice.js +1 -1
- package/dist/types/pipeline.d.ts +41 -2
- package/dist/types/preEmitCheck.d.ts +18 -0
- package/dist/types/preEmitCheck.js +1 -0
- package/dist/types/stage.d.ts +14 -0
- package/dist/types/stageflowManifest.d.ts +2 -0
- package/dist/ui/assets/index-Yzh42vhf.js +118 -0
- package/dist/ui/assets/{index-C3N7MXAC.css → index-uVHiae8s.css} +1 -1
- package/dist/ui/index.html +2 -2
- package/package.json +5 -1
- package/skills/stageflow-author/SKILL.md +20 -2
- package/skills/stageflow-author/references/catalog-mapping.md +88 -3
- package/skills/stageflow-author/references/catalog-write-conventions.md +1 -1
- package/skills/stageflow-author/references/stage-prompt-template.md +63 -4
- package/skills/stageflow-session-capture/references/catalog-authoring.md +4 -1
- package/dist/ui/assets/index-CSoGDA3A.js +0 -118
|
@@ -30,29 +30,53 @@ const multiQuestionItemSchema = Type.Object({
|
|
|
30
30
|
message: Type.String({ minLength: 1 }),
|
|
31
31
|
id: Type.Optional(Type.String()),
|
|
32
32
|
});
|
|
33
|
+
const freeTextParamsSchema = Type.Object({
|
|
34
|
+
kind: Type.Literal("free_text"),
|
|
35
|
+
message: Type.String({ minLength: 1 }),
|
|
36
|
+
id: Type.Optional(Type.String()),
|
|
37
|
+
});
|
|
38
|
+
const confirmParamsSchema = Type.Object({
|
|
39
|
+
kind: Type.Literal("confirm"),
|
|
40
|
+
message: Type.String({ minLength: 1 }),
|
|
41
|
+
id: Type.Optional(Type.String()),
|
|
42
|
+
});
|
|
43
|
+
const multiQuestionParamsSchema = Type.Object({
|
|
44
|
+
kind: Type.Literal("multi_question"),
|
|
45
|
+
questions: Type.Array(multiQuestionItemSchema, { minItems: 1 }),
|
|
46
|
+
id: Type.Optional(Type.String()),
|
|
47
|
+
});
|
|
48
|
+
const artifactBackedParamsSchema = Type.Object({
|
|
49
|
+
kind: Type.Literal("artifact_backed"),
|
|
50
|
+
message: Type.String({ minLength: 1 }),
|
|
51
|
+
artifacts: Type.Array(Type.String({ minLength: 1 }), { minItems: 1 }),
|
|
52
|
+
id: Type.Optional(Type.String()),
|
|
53
|
+
});
|
|
54
|
+
const KIND_PARAM_SCHEMAS = {
|
|
55
|
+
free_text: freeTextParamsSchema,
|
|
56
|
+
confirm: confirmParamsSchema,
|
|
57
|
+
multi_question: multiQuestionParamsSchema,
|
|
58
|
+
artifact_backed: artifactBackedParamsSchema,
|
|
59
|
+
};
|
|
33
60
|
export const askOperatorParamsSchema = Type.Union([
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}),
|
|
39
|
-
Type.Object({
|
|
40
|
-
kind: Type.Literal("confirm"),
|
|
41
|
-
message: Type.String({ minLength: 1 }),
|
|
42
|
-
id: Type.Optional(Type.String()),
|
|
43
|
-
}),
|
|
44
|
-
Type.Object({
|
|
45
|
-
kind: Type.Literal("multi_question"),
|
|
46
|
-
questions: Type.Array(multiQuestionItemSchema, { minItems: 1 }),
|
|
47
|
-
id: Type.Optional(Type.String()),
|
|
48
|
-
}),
|
|
49
|
-
Type.Object({
|
|
50
|
-
kind: Type.Literal("artifact_backed"),
|
|
51
|
-
message: Type.String({ minLength: 1 }),
|
|
52
|
-
artifacts: Type.Array(Type.String({ minLength: 1 }), { minItems: 1 }),
|
|
53
|
-
id: Type.Optional(Type.String()),
|
|
54
|
-
}),
|
|
61
|
+
freeTextParamsSchema,
|
|
62
|
+
confirmParamsSchema,
|
|
63
|
+
multiQuestionParamsSchema,
|
|
64
|
+
artifactBackedParamsSchema,
|
|
55
65
|
]);
|
|
66
|
+
/**
|
|
67
|
+
* Narrows the ask_operator params schema to only the declared gate kinds
|
|
68
|
+
* (stage `gate_kinds` allowlist). Omitted/empty falls back to the full
|
|
69
|
+
* union so back-compat stages keep accepting every kind.
|
|
70
|
+
*/
|
|
71
|
+
export function askOperatorParamsSchemaFor(allowedKinds) {
|
|
72
|
+
if (!allowedKinds || allowedKinds.length === 0) {
|
|
73
|
+
return askOperatorParamsSchema;
|
|
74
|
+
}
|
|
75
|
+
const schemas = allowedKinds.map((kind) => KIND_PARAM_SCHEMAS[kind]);
|
|
76
|
+
if (schemas.length === 1)
|
|
77
|
+
return schemas[0];
|
|
78
|
+
return Type.Union(schemas);
|
|
79
|
+
}
|
|
56
80
|
const decisionSchema = Type.Union([
|
|
57
81
|
Type.Literal("accept"),
|
|
58
82
|
Type.Literal("reject"),
|
|
@@ -352,7 +376,7 @@ function toolResult(text, details, options) {
|
|
|
352
376
|
...(options?.isError ? { isError: true } : {}),
|
|
353
377
|
};
|
|
354
378
|
}
|
|
355
|
-
function summarizeAnswer(answer) {
|
|
379
|
+
export function summarizeAnswer(answer) {
|
|
356
380
|
if (answer.kind === "free_text") {
|
|
357
381
|
return `Operator answered: ${answer.text}`;
|
|
358
382
|
}
|
|
@@ -365,16 +389,25 @@ function summarizeAnswer(answer) {
|
|
|
365
389
|
return `Operator answered ${count} question${count === 1 ? "" : "s"}`;
|
|
366
390
|
}
|
|
367
391
|
export function createAskOperatorTool(options) {
|
|
368
|
-
const { requestWait } = options;
|
|
392
|
+
const { requestWait, allowedKinds } = options;
|
|
393
|
+
const allowed = allowedKinds && allowedKinds.length > 0
|
|
394
|
+
? new Set(allowedKinds)
|
|
395
|
+
: null;
|
|
396
|
+
const kindList = allowed
|
|
397
|
+
? [...allowed].join(", ")
|
|
398
|
+
: ASK_OPERATOR_KINDS.join(", ");
|
|
369
399
|
return {
|
|
370
400
|
name: "ask_operator",
|
|
371
401
|
label: "Ask operator",
|
|
372
|
-
description:
|
|
373
|
-
parameters:
|
|
402
|
+
description: `Ask the operator a question and wait for their answer. Supports ${kindList} prompts. Does not complete the stage — call emit_stage_envelope when finished.`,
|
|
403
|
+
parameters: askOperatorParamsSchemaFor(allowedKinds),
|
|
374
404
|
execute: async (_toolCallId, params) => {
|
|
375
405
|
let prompt;
|
|
376
406
|
try {
|
|
377
407
|
const parsed = parseAskOperatorParams(params);
|
|
408
|
+
if (allowed && !allowed.has(parsed.kind)) {
|
|
409
|
+
throw new AskOperatorError(`unsupported prompt kind "${parsed.kind}" (allowed: ${kindList})`);
|
|
410
|
+
}
|
|
378
411
|
prompt = normalizePromptIds(parsed);
|
|
379
412
|
}
|
|
380
413
|
catch (err) {
|
|
@@ -10,13 +10,16 @@
|
|
|
10
10
|
* deadlocks waitForIdle so later pipeline stages never start.
|
|
11
11
|
*/
|
|
12
12
|
import { Type } from "typebox";
|
|
13
|
+
import type { TSchema } from "typebox/type";
|
|
14
|
+
import { type PreEmitCheckOptions } from "../envelope/preEmitChecks.js";
|
|
13
15
|
import type { StageEnvelope } from "../types/envelope.js";
|
|
14
|
-
import type {
|
|
16
|
+
import type { FeedbackLoopConfig } from "../types/pipeline.js";
|
|
17
|
+
import { type CloneEmitContext, type ForkEmitContext } from "../types/forkChoice.js";
|
|
15
18
|
export type EmitCapture = {
|
|
16
19
|
envelope?: StageEnvelope;
|
|
17
20
|
error?: string;
|
|
18
21
|
};
|
|
19
|
-
export declare function createEmitStageEnvelopeTool(capture: EmitCapture, payloadSchema?: unknown, forkEmitContext?: ForkEmitContext, cloneEmitContext?: CloneEmitContext): {
|
|
22
|
+
export declare function createEmitStageEnvelopeTool(capture: EmitCapture, payloadSchema?: unknown, forkEmitContext?: ForkEmitContext, cloneEmitContext?: CloneEmitContext, preEmitCheckOptions?: PreEmitCheckOptions, feedbackLoopEmitContext?: FeedbackLoopConfig): {
|
|
20
23
|
name: string;
|
|
21
24
|
label: string;
|
|
22
25
|
description: string;
|
|
@@ -24,17 +27,14 @@ export declare function createEmitStageEnvelopeTool(capture: EmitCapture, payloa
|
|
|
24
27
|
status: Type.TUnion<[Type.TLiteral<"success">, Type.TLiteral<"failure">]>;
|
|
25
28
|
summary: Type.TString;
|
|
26
29
|
artifacts: Type.TArray<Type.TString>;
|
|
27
|
-
payload: Type.TSchema
|
|
30
|
+
payload: Type.TOptional<TSchema>;
|
|
28
31
|
fork_choice: Type.TArray<Type.TString>;
|
|
29
|
-
clone_forks?: Type.TArray<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
envelope: Type.TUnknown;
|
|
36
|
-
}>>>;
|
|
37
|
-
}>> | undefined;
|
|
32
|
+
clone_forks?: Type.TArray<TSchema> | undefined;
|
|
33
|
+
feedback_loop?: Type.TOptional<TSchema> | undefined;
|
|
34
|
+
checklist_attestations: Type.TOptional<Type.TArray<Type.TObject<{
|
|
35
|
+
check_id: Type.TString;
|
|
36
|
+
items: Type.TArray<Type.TString>;
|
|
37
|
+
}>>>;
|
|
38
38
|
stage_id: Type.TOptional<Type.TString>;
|
|
39
39
|
notes: Type.TOptional<Type.TString>;
|
|
40
40
|
}>;
|
|
@@ -11,9 +11,87 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { Type } from "typebox";
|
|
13
13
|
import { assertRequiredEnvelope, isAdvancingEnvelope, } from "../envelope/check.js";
|
|
14
|
+
import { assertFeedbackLoopAction } from "../envelope/feedbackLoop.js";
|
|
14
15
|
import { assertCloneForks } from "../envelope/cloneForks.js";
|
|
15
16
|
import { normalizeForkChoice } from "../envelope/forkChoice.js";
|
|
16
17
|
import { assertEnvelopePayload, compilePayloadSchema, } from "../envelope/payloadSchema.js";
|
|
18
|
+
import { assertPreEmitChecks, } from "../envelope/preEmitChecks.js";
|
|
19
|
+
import { CLONE_ACTIONS, } from "../types/forkChoice.js";
|
|
20
|
+
function stringLiteralsSchema(values) {
|
|
21
|
+
if (values.length === 1) {
|
|
22
|
+
return Type.Literal(values[0]);
|
|
23
|
+
}
|
|
24
|
+
return Type.Union(values.map((value) => Type.Literal(value)));
|
|
25
|
+
}
|
|
26
|
+
function stageEnvelopeSchema(payloadSchema) {
|
|
27
|
+
return Type.Object({
|
|
28
|
+
status: Type.Union([Type.Literal("success"), Type.Literal("failure")]),
|
|
29
|
+
summary: Type.String({ minLength: 1 }),
|
|
30
|
+
artifacts: Type.Array(Type.String()),
|
|
31
|
+
payload: Type.Optional(payloadSchema !== undefined
|
|
32
|
+
? payloadSchema
|
|
33
|
+
: Type.Record(Type.String(), Type.Unknown())),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function feedbackLoopActionSchema(context) {
|
|
37
|
+
return Type.Union([
|
|
38
|
+
Type.Object({ action: Type.Literal("continue") }, { additionalProperties: false }),
|
|
39
|
+
Type.Object({
|
|
40
|
+
action: Type.Literal("send_back"),
|
|
41
|
+
target: stringLiteralsSchema([context.target]),
|
|
42
|
+
}, { additionalProperties: false }),
|
|
43
|
+
]);
|
|
44
|
+
}
|
|
45
|
+
function cloneForksItemSchema(cloneEmitContext) {
|
|
46
|
+
const allowedActions = cloneEmitContext.allowedActions ?? [...CLONE_ACTIONS];
|
|
47
|
+
const allowSkip = allowedActions.includes("skip");
|
|
48
|
+
const allowOnce = allowedActions.includes("once");
|
|
49
|
+
const allowFanout = allowedActions.includes("fanout");
|
|
50
|
+
const variants = [];
|
|
51
|
+
for (const successor of cloneEmitContext.clonableSuccessors) {
|
|
52
|
+
const successorId = Type.Literal(successor.successorId);
|
|
53
|
+
const nestedPayload = successor.cloneInputSchema !== undefined
|
|
54
|
+
? compilePayloadSchema(successor.cloneInputSchema)
|
|
55
|
+
: undefined;
|
|
56
|
+
const nestedEnvelope = stageEnvelopeSchema(nestedPayload);
|
|
57
|
+
if (allowSkip) {
|
|
58
|
+
variants.push(Type.Object({
|
|
59
|
+
successor_id: successorId,
|
|
60
|
+
action: Type.Literal("skip"),
|
|
61
|
+
}, { additionalProperties: false }));
|
|
62
|
+
}
|
|
63
|
+
if (allowOnce) {
|
|
64
|
+
variants.push(Type.Object({
|
|
65
|
+
successor_id: successorId,
|
|
66
|
+
action: Type.Literal("once"),
|
|
67
|
+
envelope: nestedEnvelope,
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
if (allowFanout) {
|
|
71
|
+
variants.push(Type.Object({
|
|
72
|
+
successor_id: successorId,
|
|
73
|
+
action: Type.Literal("fanout"),
|
|
74
|
+
mode: Type.Union([
|
|
75
|
+
Type.Literal("parallel"),
|
|
76
|
+
Type.Literal("sequential"),
|
|
77
|
+
]),
|
|
78
|
+
clones: Type.Array(Type.Object({
|
|
79
|
+
envelope: nestedEnvelope,
|
|
80
|
+
}), { minItems: 2, maxItems: successor.cloneCap }),
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (variants.length === 0) {
|
|
85
|
+
return Type.Object({
|
|
86
|
+
successor_id: Type.String(),
|
|
87
|
+
action: stringLiteralsSchema(allowedActions),
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
if (variants.length === 1) {
|
|
91
|
+
return variants[0];
|
|
92
|
+
}
|
|
93
|
+
return Type.Union(variants);
|
|
94
|
+
}
|
|
17
95
|
function toolResult(text, details, options) {
|
|
18
96
|
return {
|
|
19
97
|
content: [{ type: "text", text }],
|
|
@@ -22,23 +100,10 @@ function toolResult(text, details, options) {
|
|
|
22
100
|
...(options?.terminate ? { terminate: true } : {}),
|
|
23
101
|
};
|
|
24
102
|
}
|
|
25
|
-
export function createEmitStageEnvelopeTool(capture, payloadSchema, forkEmitContext, cloneEmitContext) {
|
|
103
|
+
export function createEmitStageEnvelopeTool(capture, payloadSchema, forkEmitContext, cloneEmitContext, preEmitCheckOptions, feedbackLoopEmitContext) {
|
|
26
104
|
const compiledPayload = payloadSchema !== undefined
|
|
27
105
|
? compilePayloadSchema(payloadSchema)
|
|
28
106
|
: undefined;
|
|
29
|
-
const cloneForksSchema = Type.Array(Type.Object({
|
|
30
|
-
successor_id: Type.String(),
|
|
31
|
-
action: Type.Union([
|
|
32
|
-
Type.Literal("skip"),
|
|
33
|
-
Type.Literal("once"),
|
|
34
|
-
Type.Literal("fanout"),
|
|
35
|
-
]),
|
|
36
|
-
envelope: Type.Optional(Type.Unknown()),
|
|
37
|
-
mode: Type.Optional(Type.Union([Type.Literal("parallel"), Type.Literal("sequential")])),
|
|
38
|
-
clones: Type.Optional(Type.Array(Type.Object({
|
|
39
|
-
envelope: Type.Unknown(),
|
|
40
|
-
}))),
|
|
41
|
-
}));
|
|
42
107
|
return {
|
|
43
108
|
name: "emit_stage_envelope",
|
|
44
109
|
label: "Emit stage envelope",
|
|
@@ -47,13 +112,28 @@ export function createEmitStageEnvelopeTool(capture, payloadSchema, forkEmitCont
|
|
|
47
112
|
status: Type.Union([Type.Literal("success"), Type.Literal("failure")]),
|
|
48
113
|
summary: Type.String({ minLength: 1 }),
|
|
49
114
|
artifacts: Type.Array(Type.String()),
|
|
50
|
-
payload: compiledPayload !== undefined
|
|
115
|
+
payload: Type.Optional(compiledPayload !== undefined
|
|
51
116
|
? compiledPayload
|
|
52
|
-
: Type.
|
|
53
|
-
fork_choice: forkEmitContext !== undefined
|
|
117
|
+
: Type.Record(Type.String(), Type.Unknown())),
|
|
118
|
+
fork_choice: forkEmitContext !== undefined && feedbackLoopEmitContext === undefined
|
|
54
119
|
? Type.Array(Type.String())
|
|
55
120
|
: Type.Optional(Type.Array(Type.String())),
|
|
56
|
-
...(cloneEmitContext !== undefined
|
|
121
|
+
...(cloneEmitContext !== undefined
|
|
122
|
+
? {
|
|
123
|
+
clone_forks: feedbackLoopEmitContext === undefined
|
|
124
|
+
? Type.Array(cloneForksItemSchema(cloneEmitContext))
|
|
125
|
+
: Type.Optional(Type.Array(cloneForksItemSchema(cloneEmitContext))),
|
|
126
|
+
}
|
|
127
|
+
: {}),
|
|
128
|
+
...(feedbackLoopEmitContext !== undefined
|
|
129
|
+
? {
|
|
130
|
+
feedback_loop: Type.Optional(feedbackLoopActionSchema(feedbackLoopEmitContext)),
|
|
131
|
+
}
|
|
132
|
+
: {}),
|
|
133
|
+
checklist_attestations: Type.Optional(Type.Array(Type.Object({
|
|
134
|
+
check_id: Type.String({ minLength: 1 }),
|
|
135
|
+
items: Type.Array(Type.String()),
|
|
136
|
+
}))),
|
|
57
137
|
stage_id: Type.Optional(Type.String()),
|
|
58
138
|
notes: Type.Optional(Type.String()),
|
|
59
139
|
}),
|
|
@@ -62,15 +142,23 @@ export function createEmitStageEnvelopeTool(capture, payloadSchema, forkEmitCont
|
|
|
62
142
|
return toolResult("Envelope already accepted; later emits are ignored.", { advancing: isAdvancingEnvelope(capture.envelope), error: "" }, { terminate: true });
|
|
63
143
|
}
|
|
64
144
|
try {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
145
|
+
const envelope = assertRequiredEnvelope(params);
|
|
146
|
+
assertFeedbackLoopAction(envelope, feedbackLoopEmitContext);
|
|
147
|
+
const isSendBack = envelope.feedback_loop?.action === "send_back";
|
|
148
|
+
if (envelope.status !== "failure" &&
|
|
149
|
+
!isSendBack &&
|
|
150
|
+
forkEmitContext !== undefined) {
|
|
151
|
+
normalizeForkChoice(envelope.fork_choice, "emit", forkEmitContext);
|
|
68
152
|
}
|
|
69
|
-
if (
|
|
70
|
-
|
|
153
|
+
if (envelope.status !== "failure" &&
|
|
154
|
+
!isSendBack &&
|
|
155
|
+
cloneEmitContext !== undefined) {
|
|
156
|
+
assertCloneForks(envelope, cloneEmitContext);
|
|
71
157
|
}
|
|
72
|
-
const envelope = assertRequiredEnvelope(params);
|
|
73
158
|
assertEnvelopePayload(envelope, payloadSchema);
|
|
159
|
+
if (envelope.status !== "failure") {
|
|
160
|
+
await assertPreEmitChecks(envelope, preEmitCheckOptions);
|
|
161
|
+
}
|
|
74
162
|
capture.envelope = envelope;
|
|
75
163
|
const advancing = isAdvancingEnvelope(envelope);
|
|
76
164
|
return toolResult(advancing
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { StageGateKind } from "./stage.js";
|
|
2
|
+
export declare const COMPLETION_VERIFICATION_FAILURE_PREFIX = "Completion verification failed:";
|
|
3
|
+
export type CompletionCheck = {
|
|
4
|
+
id: string;
|
|
5
|
+
type: "command";
|
|
6
|
+
run: string;
|
|
7
|
+
cwd?: string;
|
|
8
|
+
timeout_ms?: number;
|
|
9
|
+
} | {
|
|
10
|
+
id: string;
|
|
11
|
+
type: "artifact";
|
|
12
|
+
path: string;
|
|
13
|
+
nonempty?: boolean;
|
|
14
|
+
} | {
|
|
15
|
+
id: string;
|
|
16
|
+
type: "checklist";
|
|
17
|
+
items: string[];
|
|
18
|
+
} | {
|
|
19
|
+
id: string;
|
|
20
|
+
type: "payload_schema";
|
|
21
|
+
} | {
|
|
22
|
+
id: string;
|
|
23
|
+
type: "gate";
|
|
24
|
+
kind: StageGateKind;
|
|
25
|
+
} | {
|
|
26
|
+
id: string;
|
|
27
|
+
type: "checkout_changes";
|
|
28
|
+
path_fields?: string[];
|
|
29
|
+
};
|
|
30
|
+
export type CompletionContract = {
|
|
31
|
+
mode: "all";
|
|
32
|
+
checks: CompletionCheck[];
|
|
33
|
+
};
|
|
34
|
+
export type RecoveryPolicy = {
|
|
35
|
+
mode: "repair";
|
|
36
|
+
max_attempts: number;
|
|
37
|
+
retry_safety: "idempotent";
|
|
38
|
+
include_failed_checks: boolean;
|
|
39
|
+
} | {
|
|
40
|
+
mode: "manual";
|
|
41
|
+
retry_safety: "idempotent" | "side_effecting";
|
|
42
|
+
include_failed_checks?: boolean;
|
|
43
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const COMPLETION_VERIFICATION_FAILURE_PREFIX = "Completion verification failed:";
|
package/dist/types/envelope.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { CloneForkItem } from "./forkChoice.js";
|
|
2
2
|
export type EnvelopeStatus = "success" | "failure";
|
|
3
|
+
export type FeedbackLoopAction = {
|
|
4
|
+
action: "continue";
|
|
5
|
+
} | {
|
|
6
|
+
action: "send_back";
|
|
7
|
+
target: string;
|
|
8
|
+
};
|
|
3
9
|
export type StageEnvelope = {
|
|
4
10
|
status: EnvelopeStatus;
|
|
5
11
|
summary: string;
|
|
@@ -7,9 +13,21 @@ export type StageEnvelope = {
|
|
|
7
13
|
payload?: Record<string, unknown>;
|
|
8
14
|
fork_choice?: string[];
|
|
9
15
|
clone_forks?: CloneForkItem[];
|
|
16
|
+
feedback_loop?: FeedbackLoopAction;
|
|
17
|
+
/** Agent's explicit acknowledgement of pipeline-owned checklist items. */
|
|
18
|
+
checklist_attestations?: Array<{
|
|
19
|
+
check_id: string;
|
|
20
|
+
items: string[];
|
|
21
|
+
}>;
|
|
10
22
|
stage_id?: string;
|
|
11
23
|
notes?: string;
|
|
12
24
|
};
|
|
25
|
+
export type SyntheticSkippedEnvelope = {
|
|
26
|
+
status: "skipped";
|
|
27
|
+
summary: string;
|
|
28
|
+
artifacts: string[];
|
|
29
|
+
};
|
|
30
|
+
export type TerminalEnvelope = StageEnvelope | SyntheticSkippedEnvelope;
|
|
13
31
|
export declare class EnvelopeError extends Error {
|
|
14
32
|
constructor(message: string);
|
|
15
33
|
}
|
|
@@ -7,6 +7,8 @@ export type ForkEmitContext = {
|
|
|
7
7
|
immediateSuccessorIds: string[];
|
|
8
8
|
forkShape: ForkChoiceShape | null;
|
|
9
9
|
};
|
|
10
|
+
export declare const CLONE_ACTIONS: readonly ["skip", "once", "fanout"];
|
|
11
|
+
export type CloneAction = (typeof CLONE_ACTIONS)[number];
|
|
10
12
|
export type CloneForkItem = {
|
|
11
13
|
successor_id: string;
|
|
12
14
|
action: "skip";
|
|
@@ -22,9 +24,12 @@ export type CloneForkItem = {
|
|
|
22
24
|
envelope: StageEnvelope;
|
|
23
25
|
}>;
|
|
24
26
|
};
|
|
27
|
+
export type CloneSuccessorEmit = {
|
|
28
|
+
successorId: string;
|
|
29
|
+
cloneCap: number;
|
|
30
|
+
cloneInputSchema?: unknown;
|
|
31
|
+
};
|
|
25
32
|
export type CloneEmitContext = {
|
|
26
|
-
clonableSuccessors:
|
|
27
|
-
|
|
28
|
-
cloneCap: number;
|
|
29
|
-
}>;
|
|
33
|
+
clonableSuccessors: CloneSuccessorEmit[];
|
|
34
|
+
allowedActions?: CloneAction[];
|
|
30
35
|
};
|
package/dist/types/forkChoice.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export const CLONE_ACTIONS = ["skip", "once", "fanout"];
|
package/dist/types/pipeline.d.ts
CHANGED
|
@@ -1,21 +1,47 @@
|
|
|
1
|
+
import type { CloneAction } from "./forkChoice.js";
|
|
1
2
|
import type { StageConfig, StageGateKind } from "./stage.js";
|
|
3
|
+
import type { CompletionContract, RecoveryPolicy } from "./completion.js";
|
|
2
4
|
export type PipelineConfig = {
|
|
3
5
|
id: string;
|
|
4
6
|
stages: string[];
|
|
7
|
+
/** Selects the AgentPort backend for every stage in this pipeline; overrides the global default. */
|
|
8
|
+
agent?: string;
|
|
5
9
|
};
|
|
6
10
|
export type PipelineForkConfig = {
|
|
7
11
|
select: "one" | "subset";
|
|
8
12
|
allow_none: boolean;
|
|
9
13
|
};
|
|
14
|
+
export type NeedTerminalState = "succeeded" | "failed" | "skipped";
|
|
15
|
+
export type PipelineNeedEdge = {
|
|
16
|
+
id: string;
|
|
17
|
+
on: NeedTerminalState[];
|
|
18
|
+
};
|
|
19
|
+
export type PipelineNeedItem = string | {
|
|
20
|
+
id: string;
|
|
21
|
+
on?: NeedTerminalState[];
|
|
22
|
+
};
|
|
23
|
+
export type PipelineNeeds = string | PipelineNeedEdge[];
|
|
24
|
+
/** Runtime feedback-loop policy declared by the stage that can send work back. */
|
|
25
|
+
export type FeedbackLoopConfig = {
|
|
26
|
+
target: string;
|
|
27
|
+
max_replays: number;
|
|
28
|
+
on_max_replays: "require_continue" | "wait_for_human";
|
|
29
|
+
replay_session: "resume" | "new_session";
|
|
30
|
+
};
|
|
10
31
|
export type PipelineStageRef = {
|
|
11
32
|
id: string;
|
|
12
|
-
needs?: string;
|
|
33
|
+
needs?: string | PipelineNeedItem[];
|
|
13
34
|
fork?: {
|
|
14
35
|
select: "one" | "subset";
|
|
15
36
|
allow_none?: boolean;
|
|
16
37
|
};
|
|
17
38
|
clonable?: boolean;
|
|
18
39
|
clone_cap?: number;
|
|
40
|
+
completion?: CompletionContract;
|
|
41
|
+
recovery?: RecoveryPolicy;
|
|
42
|
+
feedback_loop?: FeedbackLoopConfig;
|
|
43
|
+
/** Omitted means this stage is safe to include in a feedback replay. */
|
|
44
|
+
replay_safe?: boolean;
|
|
19
45
|
};
|
|
20
46
|
export type PipelineStageYamlEntry = PipelineStageRef & {
|
|
21
47
|
uses?: string;
|
|
@@ -23,7 +49,10 @@ export type PipelineStageYamlEntry = PipelineStageRef & {
|
|
|
23
49
|
model?: string;
|
|
24
50
|
payload_schema?: unknown;
|
|
25
51
|
gate_kinds?: StageGateKind[];
|
|
52
|
+
clone_input_schema?: unknown;
|
|
53
|
+
clone_actions?: CloneAction[];
|
|
26
54
|
skill?: string;
|
|
55
|
+
mcp?: string[];
|
|
27
56
|
};
|
|
28
57
|
export type PipelineIncludeEntry = {
|
|
29
58
|
local: string;
|
|
@@ -34,14 +63,19 @@ export type PipelineFragmentConfig = {
|
|
|
34
63
|
};
|
|
35
64
|
export type NormalizedPipelineStageEntry = {
|
|
36
65
|
id: string;
|
|
37
|
-
needs?:
|
|
66
|
+
needs?: PipelineNeeds;
|
|
38
67
|
fork?: {
|
|
39
68
|
select: "one" | "subset";
|
|
40
69
|
allow_none?: boolean;
|
|
41
70
|
};
|
|
42
71
|
clonable?: boolean;
|
|
43
72
|
clone_cap?: number;
|
|
73
|
+
completion?: CompletionContract;
|
|
74
|
+
recovery?: RecoveryPolicy;
|
|
75
|
+
feedback_loop?: FeedbackLoopConfig;
|
|
76
|
+
replay_safe?: boolean;
|
|
44
77
|
skill?: string;
|
|
78
|
+
mcp?: string[];
|
|
45
79
|
body: {
|
|
46
80
|
kind: "inline";
|
|
47
81
|
raw: Record<string, unknown>;
|
|
@@ -61,12 +95,17 @@ export type PipelineStageSource = {
|
|
|
61
95
|
export type ResolvedPipelineStageNode = {
|
|
62
96
|
id: string;
|
|
63
97
|
needs: string | null;
|
|
98
|
+
needsEdges: PipelineNeedEdge[];
|
|
64
99
|
ancestors: string[];
|
|
65
100
|
stageIndex: number;
|
|
66
101
|
fork?: PipelineForkConfig;
|
|
67
102
|
clonable?: boolean;
|
|
68
103
|
clone_cap?: number;
|
|
69
104
|
definition_id?: string;
|
|
105
|
+
completion?: CompletionContract;
|
|
106
|
+
recovery?: RecoveryPolicy;
|
|
107
|
+
feedback_loop?: FeedbackLoopConfig;
|
|
108
|
+
replay_safe?: boolean;
|
|
70
109
|
};
|
|
71
110
|
export type ResolvedPipelineDag = {
|
|
72
111
|
nodes: ResolvedPipelineStageNode[];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { StageGateKind } from "./stage.js";
|
|
2
|
+
/**
|
|
3
|
+
* In-session checks `emit_stage_envelope` must satisfy this attempt before a
|
|
4
|
+
* success emit is accepted. Distinct from `CompletionCheck`/`CompletionContract`
|
|
5
|
+
* (`src/types/completion.ts`): those run post-hoc, after a candidate envelope
|
|
6
|
+
* has already been captured, driven by the pipeline-wiring `completion` field.
|
|
7
|
+
* `PreEmitCheck` runs synchronously inside the agent's own `emit_stage_envelope`
|
|
8
|
+
* tool call, driven by the stage-body `pre_emit_checks` field.
|
|
9
|
+
*/
|
|
10
|
+
export type PreEmitCheck = {
|
|
11
|
+
id: string;
|
|
12
|
+
type: "gate";
|
|
13
|
+
kind: StageGateKind;
|
|
14
|
+
} | {
|
|
15
|
+
id: string;
|
|
16
|
+
type: "artifact_declared";
|
|
17
|
+
basename: string;
|
|
18
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/types/stage.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { PreEmitCheck } from "./preEmitCheck.js";
|
|
2
|
+
import type { CloneAction } from "./forkChoice.js";
|
|
1
3
|
export declare const STAGE_GATE_KINDS: readonly ["free_text", "confirm", "multi_question", "artifact_backed"];
|
|
2
4
|
export type StageGateKind = (typeof STAGE_GATE_KINDS)[number];
|
|
3
5
|
export type StageConfig = {
|
|
@@ -8,5 +10,17 @@ export type StageConfig = {
|
|
|
8
10
|
payload_schema?: unknown;
|
|
9
11
|
/** Declared ask_operator kinds this stage is expected to stop on. */
|
|
10
12
|
gate_kinds?: StageGateKind[];
|
|
13
|
+
/** In-session checks emit must satisfy this attempt before success is accepted. */
|
|
14
|
+
pre_emit_checks?: PreEmitCheck[];
|
|
15
|
+
clone_input_schema?: unknown;
|
|
16
|
+
clone_actions?: CloneAction[];
|
|
17
|
+
/** Optional stage wall-clock timeout in milliseconds (default 60 minutes). */
|
|
18
|
+
timeout_ms?: number;
|
|
11
19
|
skill?: string;
|
|
20
|
+
mcp?: string[];
|
|
21
|
+
/**
|
|
22
|
+
* Selects the AgentPort backend for this stage, overriding pipeline/global.
|
|
23
|
+
* Parsed but not yet consulted — see STAGE_LEVEL_AGENT_OVERRIDE_ENABLED.
|
|
24
|
+
*/
|
|
25
|
+
agent?: string;
|
|
12
26
|
};
|
|
@@ -11,6 +11,8 @@ export type StageflowManifestCatalog = {
|
|
|
11
11
|
export type StageflowManifest = {
|
|
12
12
|
version: StageflowManifestVersion;
|
|
13
13
|
catalog: StageflowManifestCatalog;
|
|
14
|
+
/** Default AgentPort backend for every pipeline/stage that doesn't override it. */
|
|
15
|
+
agent?: string;
|
|
14
16
|
};
|
|
15
17
|
export type LoadedManifest = {
|
|
16
18
|
path: string;
|