{"version":3,"file":"workflow-dry-run.d.ts","sourceRoot":"","sources":["../../src/evolve/workflow-dry-run.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AA8BxD,MAAM,WAAW,qBAAqB;IACrC,qEAAqE;IACrE,MAAM,EAAE,OAAO,CAAC;IAChB,wEAAwE;IACxE,aAAa,EAAE,QAAQ,GAAG,aAAa,GAAG,kBAAkB,CAAC;IAC7D,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAsB,uBAAuB,CAC5C,KAAK,EAAE,QAAQ,EACf,SAAS,EAAE,oBAAoB,EAC/B,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5D,OAAO,CAAC,qBAAqB,CAAC,CA0DhC","sourcesContent":["import { validateEvoComponentSelection } from \"../components/artifact.ts\";\nimport { EvoComponentProcess } from \"../components/process-runtime.ts\";\nimport {\n\tcreateDefaultEvoAbiRegistry,\n\tWORKFLOW_V1_ABI,\n\ttype WorkflowV1Input,\n\ttype WorkflowV1Output,\n} from \"../components/registry.ts\";\nimport type { EvoPaths } from \"../paths.ts\";\nimport type { EvoWorkflowSelection } from \"../types.ts\";\n\nconst STUB_STATE_DIGEST = \"0\".repeat(64);\n\n/**\n * Canned capability responses for a dry run. The stub spawn-agent answers with\n * an empty JSON object so the orchestration exercises its full protocol\n * surface without spending a single model token; capabilities the stub cannot\n * fake fail with a clean capability error the component must survive.\n */\nfunction stubCapabilityResult(capability: string, payload: unknown): unknown {\n\tif (capability === \"spawn-agent\") {\n\t\tconst model = (payload as { model?: string }).model ?? \"dry-run/stub\";\n\t\tconst slash = model.indexOf(\"/\");\n\t\treturn {\n\t\t\tschemaVersion: 1,\n\t\t\tstatus: \"completed\",\n\t\t\tmodel: { provider: model.slice(0, Math.max(slash, 0)) || \"dry-run\", id: model.slice(slash + 1) || \"stub\" },\n\t\t\tturns: 1,\n\t\t\tstopReason: \"stop\",\n\t\t\tmessages: [{ role: \"assistant\", content: [{ type: \"text\", text: \"{}\" }] }],\n\t\t};\n\t}\n\tif (capability === \"memory-read\") return { stateDigest: STUB_STATE_DIGEST, fragments: [] };\n\tif (capability === \"memory-write\") return { stateDigest: STUB_STATE_DIGEST };\n\tthrow Object.assign(new Error(`Capability is not available in a workflow dry run: ${capability}`), {\n\t\tcode: \"unavailable\",\n\t});\n}\n\nexport interface WorkflowDryRunOutcome {\n\t/** True when the component spoke the protocol cleanly end to end. */\n\tpassed: boolean;\n\t/** Whether the invoke produced a result or a clean structured error. */\n\tinvokeOutcome: \"result\" | \"clean-error\" | \"protocol-failure\";\n\tmarkdown: string;\n}\n\n/**\n * Launch a workflow/v1 selection against a stub capability broker and verify\n * protocol conformance: initialize, health, one invoke with empty args, and a\n * clean shutdown. A workflow whose orchestration fails on stub data may reply\n * with a structured error — that still passes; what fails the dry run is a\n * protocol violation (crash, truncated frame, outstanding capabilities,\n * unparseable reply).\n */\nexport async function dryRunWorkflowSelection(\n\tpaths: EvoPaths,\n\tselection: EvoWorkflowSelection,\n\toptions: { sandbox?: boolean; requestTimeoutMs?: number } = {},\n): Promise<WorkflowDryRunOutcome> {\n\tconst registry = createDefaultEvoAbiRegistry();\n\tconst artifact = await validateEvoComponentSelection(paths, \"workflow\", selection, registry);\n\tconst process = new EvoComponentProcess<WorkflowV1Input, WorkflowV1Output, Record<string, never>>(\n\t\tartifact,\n\t\tWORKFLOW_V1_ABI,\n\t\t{},\n\t\t{\n\t\t\tsandbox: options.sandbox,\n\t\t\t...(options.requestTimeoutMs === undefined ? {} : { requestTimeoutMs: options.requestTimeoutMs }),\n\t\t\tcapabilityBroker: {\n\t\t\t\trequest: async (_identity, frame) => stubCapabilityResult(frame.capability, frame.payload),\n\t\t\t},\n\t\t},\n\t);\n\tlet invokeOutcome: WorkflowDryRunOutcome[\"invokeOutcome\"];\n\tlet detail = \"\";\n\ttry {\n\t\tawait process.start();\n\t\tawait process.health();\n\t\ttry {\n\t\t\tawait process.invoke({\n\t\t\t\ttrigger: selection.trigger,\n\t\t\t\targs: {},\n\t\t\t\thost: { model: \"dry-run/stub\", tools: [], maxOutputTokensPerCall: 1_024 },\n\t\t\t});\n\t\t\tinvokeOutcome = \"result\";\n\t\t} catch (error) {\n\t\t\tdetail = error instanceof Error ? error.message : String(error);\n\t\t\t// A clean structured error leaves the process healthy; a protocol\n\t\t\t// violation kills it and the follow-up health check throws.\n\t\t\ttry {\n\t\t\t\tawait process.health();\n\t\t\t\tinvokeOutcome = \"clean-error\";\n\t\t\t} catch {\n\t\t\t\tinvokeOutcome = \"protocol-failure\";\n\t\t\t}\n\t\t}\n\t\tif (invokeOutcome !== \"protocol-failure\") await process.shutdown();\n\t\telse await process.terminate(new Error(\"workflow dry run failed\"));\n\t} catch (error) {\n\t\tdetail = error instanceof Error ? error.message : String(error);\n\t\tinvokeOutcome = \"protocol-failure\";\n\t\tawait process.terminate(new Error(\"workflow dry run failed\")).catch(() => undefined);\n\t}\n\tconst passed = invokeOutcome !== \"protocol-failure\";\n\tconst markdown = [\n\t\t\"# Workflow dry run\",\n\t\t\"\",\n\t\t`- workflow: ${selection.id} (${selection.trigger})`,\n\t\t`- artifact: ${selection.artifactDigest}`,\n\t\t`- execution boundary: ${process.sandboxKind ?? \"unknown\"}`,\n\t\t\"- initialize: passed\",\n\t\t`- invoke with stub capabilities: ${invokeOutcome}${detail ? ` (${detail.slice(0, 200)})` : \"\"}`,\n\t\t`- verdict: ${passed ? \"passed\" : \"failed\"}`,\n\t\t\"\",\n\t].join(\"\\n\");\n\treturn { passed, invokeOutcome, markdown };\n}\n"]}