feat: persist blocked executor jobs

This commit is contained in:
john
2026-07-24 23:07:46 +08:00
parent d21c4849a9
commit bbb43f97a3
17 changed files with 649 additions and 26 deletions
@@ -67,12 +67,49 @@ function validateNode(state) {
};
}
function planNode(state) {
async function planNode(state, executorGateway) {
const taskType = String(state.spec.input?.taskType ?? '').trim() || 'code-change';
const instruction = String(state.spec.input?.instruction ?? '');
const executorJob = await executorGateway.createJob({
jobId: `${state.spec.runId}:executor-preview`,
idempotencyKey: `${state.spec.runId}:build_plan:v1`,
executor: 'goosed',
task: {
type: taskType,
instruction,
workspaceRef: state.spec.input?.workspaceRef ?? null,
inputRefs: state.spec.input?.inputRefs ?? [],
},
subject: state.spec.subject,
authorization: {
executionAllowed: false,
actorId: state.spec.subject?.userId ?? null,
},
policy: {
sideEffectsAllowed: false,
networkAllowed: false,
},
controls: {
timeoutMs: state.spec.limits?.timeoutMs,
cancellationAllowed: true,
fallbackExecutor: 'aider',
},
metadata: {
source: 'langgraph-shadow-plan',
workflow: state.spec.workflow,
},
});
const plan = {
taskType,
executorAdapter: 'native-agent-run',
executorJob: {
kind: 'executor-job',
id: executorJob.job.jobId,
executor: executorJob.job.executor,
status: executorJob.job.status,
reason: executorJob.job.reason,
durable: executorGateway.status().store.durable,
},
instructionCharacters: instruction.length,
steps: [
'accept_control_plane_run',
@@ -86,6 +123,7 @@ function planNode(state) {
events: [eventFor(state, 'workflow_planned', {
taskType,
executorAdapter: plan.executorAdapter,
executorJob: plan.executorJob,
stepCount: plan.steps.length,
})],
};
@@ -106,11 +144,14 @@ function finalizeNode(state) {
};
}
export function createCodeRunShadowGraph({ checkpointer } = {}) {
export function createCodeRunShadowGraph({ checkpointer, executorGateway } = {}) {
if (!checkpointer) throw new Error('Code run shadow graph requires a checkpointer');
if (!executorGateway?.createJob) {
throw new Error('Code run shadow graph requires an Executor Gateway');
}
return new StateGraph(ShadowState)
.addNode('validate_run', validateNode)
.addNode('build_plan', planNode)
.addNode('build_plan', (state) => planNode(state, executorGateway))
.addNode('finalize_run', finalizeNode)
.addEdge(START, 'validate_run')
.addEdge('validate_run', 'build_plan')