From 7812230572f2d7e042d8d14ada2381fc71377560 Mon Sep 17 00:00:00 2001 From: Simone Date: Mon, 5 Oct 2026 12:14:33 +0200 Subject: [PATCH] fix(server): subagents no longer inherit parent pull-request links (#14918) Co-authored-by: Simone <185146821+Lucenx9@users.noreply.github.com> --- .../Orchestrator.control-reads.test.ts | 90 +++++++++++++++++++ .../orchestration-v2/SubagentProjection.ts | 2 + 2 files changed, 92 insertions(+) diff --git a/apps/server/src/orchestration-v2/Orchestrator.control-reads.test.ts b/apps/server/src/orchestration-v2/Orchestrator.control-reads.test.ts index ad41ae6ffde66103f3c2ac2a3cefe607a6035fd9..1a02b71982fe0094b6e50b1c7548b6b8570fee30 100644 --- a/apps/server/src/orchestration-v2/Orchestrator.control-reads.test.ts +++ b/apps/server/src/orchestration-v2/Orchestrator.control-reads.test.ts @@ -534,3 +534,93 @@ it.effect("settles only the stopped run's background work, once", () => ]); }).pipe(Effect.provide(testLayer)), ); + +it.effect("keeps delegated child pull-request links independent of the parent", () => + Effect.gen(function* () { + const orchestrator = yield* Orchestrator.OrchestratorV2; + const projections = yield* ProjectionStore.ProjectionStoreV2; + const parentThreadId = ThreadId.make("thread:parent-pr"); + const projectId = ProjectId.make("project:parent-pr"); + const parentPullRequest = { + projectId, + repository: "pingdotgg/t3code", + number: 123, + url: "https://github.com/pingdotgg/t3code/pull/123", + }; + yield* orchestrator.dispatch({ + type: "thread.create", + commandId: CommandId.make("create-parent-pr"), + threadId: parentThreadId, + projectId, + title: "Parent with a linked PR", + modelSelection, + runtimeMode: "full-access", + interactionMode: "default", + branch: "feature/parent-pr", + worktreePath: "/repo-worktree", + createdBy: "user", + creationSource: "web", + }); + yield* orchestrator.dispatch({ + type: "thread.metadata.update", + commandId: CommandId.make("link-parent-pr"), + threadId: parentThreadId, + linkedPullRequest: parentPullRequest, + }); + yield* orchestrator.dispatch({ + type: "message.dispatch", + commandId: CommandId.make("start-parent-pr"), + threadId: parentThreadId, + messageId: MessageId.make("message:parent-pr"), + text: "Delegate a review", + attachments: [], + dispatchMode: { type: "start_immediately" }, + createdBy: "user", + creationSource: "web", + }); + const parent = yield* projections.getThreadProjection(parentThreadId); + const parentRun = parent.runs[0]!; + yield* orchestrator.dispatch({ + type: "delegated_task.request", + commandId: CommandId.make("delegate-parent-pr"), + parentThreadId, + parentRunId: parentRun.id, + parentNodeId: parentRun.rootNodeId!, + task: "Review the changes", + modelSelection, + runtimeMode: "full-access", + interactionMode: "default", + createdBy: "agent", + creationSource: "mcp", + }); + const updatedParent = yield* projections.getThreadProjection(parentThreadId); + const childThreadId = updatedParent.subagents[0]!.childThreadId!; + const child = yield* projections.getThreadProjection(childThreadId); + assert.isNull(child.thread.linkedPullRequest); + assert.deepEqual(child.thread.pullRequests, []); + assert.equal(child.thread.branch, parent.thread.branch); + assert.equal(child.thread.worktreePath, parent.thread.worktreePath); + assert.equal(child.thread.lineage.parentThreadId, parentThreadId); + + const childPullRequest = { + ...parentPullRequest, + number: 456, + url: "https://github.com/pingdotgg/t3code/pull/456", + }; + yield* orchestrator.dispatch({ + type: "thread.metadata.update", + commandId: CommandId.make("link-child-pr"), + threadId: childThreadId, + linkedPullRequest: childPullRequest, + }); + const linkedChild = yield* projections.getThreadProjection(childThreadId); + assert.deepEqual(linkedChild.thread.linkedPullRequest, childPullRequest); + assert.deepEqual( + linkedChild.thread.pullRequests?.map((link) => link.number), + [456], + ); + const parentAfterChildLink = yield* projections.getThreadProjection(parentThreadId); + assert.deepEqual(parentAfterChildLink.thread.linkedPullRequest, parentPullRequest); + assert.deepEqual(parentAfterChildLink.thread.pullRequests, parent.thread.pullRequests); + }).pipe(Effect.provide(testLayer)), +); diff --git a/apps/server/src/orchestration-v2/SubagentProjection.ts b/apps/server/src/orchestration-v2/SubagentProjection.ts index fa912dfda0baa08aab025dfad81c9d103d48efee..f28dc1aa4be5ff8d1a2f157a79428020e6714b0b 100644 --- a/apps/server/src/orchestration-v2/SubagentProjection.ts +++ b/apps/server/src/orchestration-v2/SubagentProjection.ts @@ -57,6 +57,8 @@ export function makeSubagentChildThread(input: { creationSource: input.creationSource, id: input.childThreadId, title: input.title, + linkedPullRequest: null, + pullRequests: [], historyOrigin: undefined, providerInstanceId: input.providerInstanceId, modelSelection: input.modelSelection, -- 2.54.0