import { Annotation, END, START, StateGraph, } from '@langchain/langgraph'; import { buildRunEvent, normalizeRunSpec, } from './contracts.mjs'; export const CODE_RUN_SHADOW_WORKFLOW = 'code-run-v1'; const ShadowState = Annotation.Root({ spec: Annotation(), status: Annotation({ reducer: (_current, update) => update, default: () => 'queued', }), phase: Annotation({ reducer: (_current, update) => update, default: () => 'accepted', }), plan: Annotation({ reducer: (_current, update) => update, default: () => null, }), result: Annotation({ reducer: (_current, update) => update, default: () => null, }), events: Annotation({ reducer: (current, update) => [...current, ...update], default: () => [], }), }); function eventFor(state, type, data = null) { return buildRunEvent({ runId: state.spec.runId, sequence: state.events.length + 1, type, data, }); } function validateNode(state) { const spec = normalizeRunSpec(state.spec); if (spec.workflow.name !== CODE_RUN_SHADOW_WORKFLOW) { const error = new Error(`Unsupported workflow: ${spec.workflow.name}`); error.code = 'WORKFLOW_NOT_SUPPORTED'; throw error; } if (spec.policy.executionMode !== 'observe-only' || spec.policy.sideEffectsAllowed !== false) { const error = new Error('Phase 2 LangGraph service accepts observe-only runs'); error.code = 'WORKFLOW_OBSERVE_ONLY_REQUIRED'; throw error; } return { spec, status: 'running', phase: 'validated', events: [eventFor(state, 'workflow_validated', { workflow: spec.workflow, executionMode: 'observe-only', })], }; } function planNode(state) { const taskType = String(state.spec.input?.taskType ?? '').trim() || 'code-change'; const instruction = String(state.spec.input?.instruction ?? ''); const plan = { taskType, executorAdapter: 'native-agent-run', instructionCharacters: instruction.length, steps: [ 'accept_control_plane_run', 'project_executor_boundary', 'record_shadow_result', ], }; return { phase: 'planned', plan, events: [eventFor(state, 'workflow_planned', { taskType, executorAdapter: plan.executorAdapter, stepCount: plan.steps.length, })], }; } function finalizeNode(state) { const result = { observed: true, executed: false, executorAdapter: state.plan.executorAdapter, taskType: state.plan.taskType, }; return { status: 'succeeded', phase: 'completed', result, events: [eventFor(state, 'workflow_completed', result)], }; } export function createCodeRunShadowGraph({ checkpointer } = {}) { if (!checkpointer) throw new Error('Code run shadow graph requires a checkpointer'); return new StateGraph(ShadowState) .addNode('validate_run', validateNode) .addNode('build_plan', planNode) .addNode('finalize_run', finalizeNode) .addEdge(START, 'validate_run') .addEdge('validate_run', 'build_plan') .addEdge('build_plan', 'finalize_run') .addEdge('finalize_run', END) .compile({ checkpointer }); } export const codeRunShadowGraphInternals = { ShadowState, eventFor, validateNode, planNode, finalizeNode, };