feat: return completed handoffs to Agent Chat (#14408)

Return completed Agent Chat handoffs through a durable outbox and scope each generated update to its supplied tasks. Add recovery, browser delivery, result access, and calibrated quality coverage.

Validated with two consecutive ten-case Claude/Codex campaigns, all CI checks, and a 5/5 review.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip authored and GitHub committed 2026-09-29 10:25:52 -05:00
1 parent 3b4b270650
commit 83076d7e7c
59 files changed
+2696 -83

No files matched your search

@@ -167,6 +167,9 @@ export interface WakeQueueTransaction {
commentIds: string[];
}): Promise<boolean>;
reopenIssue(input: { companyId: string; issueId: string; runId: string }): Promise<IssueSnapshot | null>;
/** Verifies a Done onboarding parent's completion wake against its own completed children. */
isCompletedOnboardingHandoffWake(input: { companyId: string; issueId: string; agentId: string;
reason: string | null; contextSnapshot: Record<string, unknown> }): Promise<boolean>;
/**
* Atomically claims the wake for promotion, guarded on its current
* `deferred_issue_execution` status. Call this before any other write in
@@ -99,6 +99,7 @@ function createFakeHost(overrides: Partial<WakeQueueHost> = {}): WakeQueueHost {
function createFakeTransaction(overrides: Partial<WakeQueueTransaction> = {}): WakeQueueTransaction {
return {
findInvokableAgent: vi.fn(async () => AGENT),
isCompletedOnboardingHandoffWake: vi.fn(async () => false),
findNextDeferredWake: vi.fn(async () => null),
getQueuedCommentLiveness: vi.fn(async () => ({ liveNonSelfCommentIds: [], containedSelfAuthoredComment: false })),
cancelDeferredWake: vi.fn(async () => true),
@@ -510,6 +511,27 @@ describe("releaseIssueExecution", () => {
expect(result.outcome.kind).toBe("released");
});
it.each(["verified", "unverified", "cancelled", "ordinary-task"])("handles a completed onboarding handoff report: %s", async scenario => {
const queue = [wakeCandidate({ agentId: ISSUE.assigneeAgentId!, requestedByActorType: "system",
reason: "issue_children_completed", wakeReason: "issue_children_completed",
deferredContextSeed: { completedChildIssueId: "child", onboardingCompletion: true } })];
const transaction = createFakeTransaction({
findNextDeferredWake: vi.fn(async () => queue.shift() ?? null),
isCompletedOnboardingHandoffWake: vi.fn(async () => scenario !== "unverified"),
});
const release = createReleaseIssueExecution({
issueLock: createFakeIssueLock(createFakeHost(), transaction, { ...ISSUE,
originKind: scenario === "ordinary-task" ? "manual" : "onboarding_first_task",
status: scenario === "cancelled" ? "cancelled" : "done" }),
recovery: createFakeRecovery(),
});
const result = await release({ companyId: RUN.companyId, runId: RUN.id, now: new Date() });
expect(result.outcome.kind).toBe(scenario === "verified" ? "promoted" : "released");
expect(transaction.reopenIssue).not.toHaveBeenCalled();
expect(transaction.finalizePromotedWake).toHaveBeenCalledTimes(scenario === "verified" ? 1 : 0);
expect(transaction.cancelDeferredWake).toHaveBeenCalledTimes(scenario === "verified" ? 0 : 1);
});
it("reopens a completed task before promoting its assignee's human follow-up", async () => {
const queue = [wakeCandidate({
agentId: ISSUE.assigneeAgentId!,
@@ -356,8 +356,13 @@ async function promoteDeferredWake(
// after completion; it cannot revive a cancelled task. Other stale
// continuations cannot revive assignee execution. Cancel before claiming promotion so
// the compare-and-set still sees the deferred wake.
const onboardingResultReport = currentIssue.status === "done" && currentIssue.originKind === "onboarding_first_task" &&
await ports.transaction.isCompletedOnboardingHandoffWake({ companyId: run.companyId, issueId: currentIssue.id,
agentId: workingCandidate.agentId, reason: workingCandidate.wakeReason ?? workingCandidate.reason,
contextSnapshot: workingCandidate.deferredContextSeed });
if (
!shouldReopen &&
!onboardingResultReport &&
(currentIssue.status === "done" || currentIssue.status === "cancelled") &&
workingCandidate.agentId === currentIssue.assigneeAgentId
) {