diff --git a/server/src/__tests__/agent-live-run-routes.test.ts b/server/src/__tests__/agent-live-run-routes.test.ts index 0f02c2ff..35434b86 100644 --- a/server/src/__tests__/agent-live-run-routes.test.ts +++ b/server/src/__tests__/agent-live-run-routes.test.ts @@ -187,6 +187,8 @@ describe("agent live run routes", () => { status: "running", invocationSource: "on_demand", triggerDetail: "manual", + contextCommentId: "comment-1", + contextWakeCommentId: "comment-1", startedAt: new Date("2026-04-10T09:30:00.000Z"), finishedAt: null, createdAt: new Date("2026-04-10T09:29:59.000Z"), @@ -224,6 +226,8 @@ describe("agent live run routes", () => { status: "running", invocationSource: "on_demand", triggerDetail: "manual", + contextCommentId: "comment-1", + contextWakeCommentId: "comment-1", startedAt: "2026-04-10T09:30:00.000Z", finishedAt: null, createdAt: "2026-04-10T09:29:59.000Z", diff --git a/server/src/routes/agents.ts b/server/src/routes/agents.ts index 1f1ee3e8..c9b755d2 100644 --- a/server/src/routes/agents.ts +++ b/server/src/routes/agents.ts @@ -2858,6 +2858,8 @@ export function agentRoutes( status: heartbeatRuns.status, invocationSource: heartbeatRuns.invocationSource, triggerDetail: heartbeatRuns.triggerDetail, + contextCommentId: sql`${heartbeatRuns.contextSnapshot} ->> 'commentId'`.as("contextCommentId"), + contextWakeCommentId: sql`${heartbeatRuns.contextSnapshot} ->> 'wakeCommentId'`.as("contextWakeCommentId"), startedAt: heartbeatRuns.startedAt, finishedAt: heartbeatRuns.finishedAt, createdAt: heartbeatRuns.createdAt, @@ -3094,6 +3096,8 @@ export function agentRoutes( status: heartbeatRuns.status, invocationSource: heartbeatRuns.invocationSource, triggerDetail: heartbeatRuns.triggerDetail, + contextCommentId: sql`${heartbeatRuns.contextSnapshot} ->> 'commentId'`.as("contextCommentId"), + contextWakeCommentId: sql`${heartbeatRuns.contextSnapshot} ->> 'wakeCommentId'`.as("contextWakeCommentId"), startedAt: heartbeatRuns.startedAt, finishedAt: heartbeatRuns.finishedAt, createdAt: heartbeatRuns.createdAt, diff --git a/server/src/services/heartbeat.ts b/server/src/services/heartbeat.ts index 41383f6f..330a8b70 100644 --- a/server/src/services/heartbeat.ts +++ b/server/src/services/heartbeat.ts @@ -744,6 +744,8 @@ const heartbeatRunIssueSummaryColumns = { status: heartbeatRuns.status, invocationSource: heartbeatRuns.invocationSource, triggerDetail: heartbeatRuns.triggerDetail, + contextCommentId: sql`${heartbeatRuns.contextSnapshot} ->> 'commentId'`.as("contextCommentId"), + contextWakeCommentId: sql`${heartbeatRuns.contextSnapshot} ->> 'wakeCommentId'`.as("contextWakeCommentId"), startedAt: heartbeatRuns.startedAt, finishedAt: heartbeatRuns.finishedAt, createdAt: heartbeatRuns.createdAt, diff --git a/ui/src/api/heartbeats.ts b/ui/src/api/heartbeats.ts index b4bf89c8..fbaad815 100644 --- a/ui/src/api/heartbeats.ts +++ b/ui/src/api/heartbeats.ts @@ -19,6 +19,8 @@ export interface ActiveRunForIssue { status: string; invocationSource: string; triggerDetail: string | null; + contextCommentId?: string | null; + contextWakeCommentId?: string | null; startedAt: string | Date | null; finishedAt: string | Date | null; createdAt: string | Date; @@ -41,6 +43,8 @@ export interface LiveRunForIssue { status: string; invocationSource: string; triggerDetail: string | null; + contextCommentId?: string | null; + contextWakeCommentId?: string | null; startedAt: string | null; finishedAt: string | null; createdAt: string; diff --git a/ui/src/lib/optimistic-issue-comments.test.ts b/ui/src/lib/optimistic-issue-comments.test.ts index f92c3419..038d4c46 100644 --- a/ui/src/lib/optimistic-issue-comments.test.ts +++ b/ui/src/lib/optimistic-issue-comments.test.ts @@ -726,14 +726,61 @@ describe("optimistic issue comments", () => { expect( isQueuedIssueComment({ comment: { + id: "comment-2", createdAt: new Date("2026-03-28T16:20:05.000Z"), }, activeRunStartedAt: new Date("2026-03-28T16:20:00.000Z"), + activeRunWakeCommentId: "comment-1", runId: null, }), ).toBe(true); }); + it("does not mark the comment that triggered the active run as queued", () => { + expect( + isQueuedIssueComment({ + comment: { + id: "comment-1", + createdAt: new Date("2026-03-28T16:20:05.000Z"), + }, + activeRunStartedAt: new Date("2026-03-28T16:20:00.000Z"), + activeRunCommentId: "comment-1", + activeRunWakeCommentId: "comment-1", + runId: null, + }), + ).toBe(false); + }); + + it("does not mark the active run context comment as queued", () => { + expect( + isQueuedIssueComment({ + comment: { + id: "context-comment", + createdAt: new Date("2026-03-28T16:20:05.000Z"), + }, + activeRunStartedAt: new Date("2026-03-28T16:20:00.000Z"), + activeRunCommentId: "context-comment", + activeRunWakeCommentId: "wake-comment", + runId: null, + }), + ).toBe(false); + }); + + it("does not mark the active run wake comment as queued", () => { + expect( + isQueuedIssueComment({ + comment: { + id: "wake-comment", + createdAt: new Date("2026-03-28T16:20:05.000Z"), + }, + activeRunStartedAt: new Date("2026-03-28T16:20:00.000Z"), + activeRunCommentId: "context-comment", + activeRunWakeCommentId: "wake-comment", + runId: null, + }), + ).toBe(false); + }); + it("does not mark comments with an associated run as queued", () => { expect( isQueuedIssueComment({ diff --git a/ui/src/lib/optimistic-issue-comments.ts b/ui/src/lib/optimistic-issue-comments.ts index c1ec5549..eb5fe908 100644 --- a/ui/src/lib/optimistic-issue-comments.ts +++ b/ui/src/lib/optimistic-issue-comments.ts @@ -70,15 +70,24 @@ export function createOptimisticIssueComment(params: { export function isQueuedIssueComment(params: { comment: Pick & Partial> & { + id?: string; authorAgentId?: string | null; }; activeRunStartedAt?: Date | string | null; activeRunAgentId?: string | null; + activeRunCommentId?: string | null; + activeRunWakeCommentId?: string | null; runId?: string | null; interruptedRunId?: string | null; }) { if (params.runId) return false; if (params.interruptedRunId) return false; + if ( + params.comment.id && + (params.comment.id === params.activeRunWakeCommentId || params.comment.id === params.activeRunCommentId) + ) { + return false; + } if (params.comment.authorAgentId && params.activeRunAgentId && params.comment.authorAgentId === params.activeRunAgentId) { return false; } diff --git a/ui/src/pages/IssueDetail.tsx b/ui/src/pages/IssueDetail.tsx index 78a2055f..9f71cf65 100644 --- a/ui/src/pages/IssueDetail.tsx +++ b/ui/src/pages/IssueDetail.tsx @@ -778,6 +778,8 @@ const IssueDetailChatTab = memo(function IssueDetailChatTab({ comment: nextComment, activeRunStartedAt, activeRunAgentId: runningIssueRun?.agentId ?? null, + activeRunCommentId: runningIssueRun?.contextCommentId ?? null, + activeRunWakeCommentId: runningIssueRun?.contextWakeCommentId ?? null, runId: meta?.runId ?? nextComment.runId ?? null, interruptedRunId: meta?.interruptedRunId ?? nextComment.interruptedRunId ?? null, })