@@ -538,6 +538,7 @@ function commandThreadId(command: OrchestrationV2ServerCommand): ThreadId {
538538 case "queued-run.reorder":
539539 case "queued-run.cancel":
540540 case "queued-run.edit":
541+ case "queued-run.editing":
541542 case "runtime-request.respond":
542543 case "runtime-request.delivery.fail":
543544 case "thread.user-input.dismiss":
@@ -1620,6 +1621,8 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio
16201621 );
16211622 return;
16221623 }
1624+ // After the pause checks, so a failure during the edit still pauses the queue.
1625+ if (options?.queuedRunId === undefined && storedQueuedRun.editing === true) return;
16231626 // Move queued ordinals after runs that started while they waited to preserve transcript and checkpoint order.
16241627 // Started runs have prompts; cancelled queued messages do not.
16251628 const newerRunIds = projection.runs
@@ -9740,6 +9743,36 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio
97409743 }
97419744 });
97429745
9746+ const dispatchQueuedRunEditing = Effect.fn("Orchestrator.dispatchQueuedRunEditing")(function* (
9747+ command: Extract<OrchestrationV2Command, { readonly type: "queued-run.editing" }>,
9748+ events: Ref.Ref<Array<OrchestrationV2DomainEvent>>,
9749+ ) {
9750+ const projection = yield* projectionStore
9751+ .getThreadRecords(command.threadId, ["runs"])
9752+ .pipe(Effect.mapError(() => new OrchestratorProjectionError({ threadId: command.threadId })));
9753+ const queuedRun = projection.runs.find((candidate) => candidate.id === command.runId);
9754+ if (queuedRun === undefined || queuedRun.status !== "queued") {
9755+ return yield* new OrchestratorDispatchError({
9756+ commandId: command.commandId,
9757+ commandType: command.type,
9758+ cause: `Run ${command.runId} is not queued.`,
9759+ });
9760+ }
9761+ if ((queuedRun.editing === true) === command.editing) return;
9762+ yield* emit(
9763+ events,
9764+ command,
9765+ )({
9766+ type: "run.updated",
9767+ threadId: command.threadId,
9768+ runId: queuedRun.id,
9769+ ...(queuedRun.rootNodeId === null ? {} : { nodeId: queuedRun.rootNodeId }),
9770+ providerInstanceId: queuedRun.providerInstanceId,
9771+ occurredAt: yield* DateTime.now,
9772+ payload: { ...queuedRun, editing: command.editing },
9773+ });
9774+ });
9775+
97439776 const subagentCount = (threadId: ThreadId) =>
97449777 projectionStore
97459778 .getSubagentCount(threadId)
@@ -13151,7 +13184,8 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio
1315113184 runId: run.id,
1315213185 providerInstanceId: run.providerInstanceId,
1315313186 occurredAt: now,
13154- payload: { ...run, queueHeld: false },
13187+ // Also the way out of an edit hold left by a client that went away.
13188+ payload: { ...run, queueHeld: false, editing: false },
1315513189 });
1315613190 }
1315713191 if (queued.length === 0) {
@@ -13176,6 +13210,9 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio
1317613210 case "queued-run.edit":
1317713211 yield* dispatchQueuedRunEdit(command, events);
1317813212 break;
13213+ case "queued-run.editing":
13214+ yield* dispatchQueuedRunEditing(command, events);
13215+ break;
1317913216 case "checkpoint.rollback":
1318013217 yield* dispatchCheckpointRollback(command, events, effects);
1318113218 break;
@@ -13292,7 +13329,11 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio
1329213329 }),
1329313330 ),
1329413331 );
13295- if (command.type === "queue.resume" || command.type === "queued-run.start") {
13332+ if (
13333+ command.type === "queue.resume" ||
13334+ command.type === "queued-run.start" ||
13335+ (command.type === "queued-run.editing" && !command.editing)
13336+ ) {
1329613337 yield* mapDispatchError(command)(
1329713338 startNextQueuedRun(
1329813339 command.threadId,
@@ -13439,7 +13480,11 @@ const makeOrchestrator = Effect.fn("orchestrationV2.Orchestrator.layer")(functio
1343913480 detail: committed.receipt.error ?? "Previously rejected.",
1344013481 });
1344113482 }
13442- if (command.type === "queue.resume" || command.type === "queued-run.start") {
13483+ if (
13484+ command.type === "queue.resume" ||
13485+ command.type === "queued-run.start" ||
13486+ (command.type === "queued-run.editing" && !command.editing)
13487+ ) {
1344313488 yield* mapDispatchError(command)(
1344413489 startNextQueuedRun(
1344513490 command.threadId,
0 commit comments