import { logger } from "../middleware/logger.js"; import type { DurableChatWakeupRequest } from "./durable-chat-wakeup.js"; type WakeupTriggerDetail = "manual" | "ping" | "callback" | "system"; type WakeupSource = "timer" | "assignment" | "on_demand" | "automation"; export interface IssueAssignmentWakeupDeps { wakeup: ( agentId: string, opts: { source?: WakeupSource; triggerDetail?: WakeupTriggerDetail; reason?: string | null; payload?: Record | null; idempotencyKey?: string | null; allowRunCoalescing?: boolean; requestedByActorType?: "user" | "agent" | "system"; requestedByActorId?: string | null; contextSnapshot?: Record; durableChatRequest?: DurableChatWakeupRequest; }, ) => Promise; } export function queueIssueAssignmentWakeup(input: { heartbeat: IssueAssignmentWakeupDeps; issue: { id: string; assigneeAgentId: string | null; status: string }; reason: string; mutation: string; contextSource: string; requestedByActorType?: "user" | "agent" | "system"; requestedByActorId?: string | null; taskKey?: string | null; /** Latest issue comment that caused this wakeup. Included in both payload * and context so the heartbeat can build the exact turn that was requested. */ wakeCommentId?: string | null; /** Closed, server-derived omission counts for provider attachments on the * exact wake comment. These are prompt diagnostics, never authorization. */ attachmentOmissionReasons?: Record | null; rethrowOnError?: boolean; durableChatRequest?: DurableChatWakeupRequest; }) { if (!input.issue.assigneeAgentId || input.issue.status === "backlog") return; return input.heartbeat .wakeup(input.issue.assigneeAgentId, { source: "assignment", triggerDetail: "system", reason: input.reason, payload: { issueId: input.issue.id, mutation: input.mutation, ...(input.taskKey ? { taskKey: input.taskKey } : {}), ...(input.wakeCommentId ? { wakeCommentId: input.wakeCommentId } : {}), }, requestedByActorType: input.requestedByActorType, requestedByActorId: input.requestedByActorId ?? null, ...(input.durableChatRequest ? { durableChatRequest: input.durableChatRequest } : {}), contextSnapshot: { issueId: input.issue.id, source: input.contextSource, ...(input.taskKey ? { taskKey: input.taskKey } : {}), ...(input.wakeCommentId ? { wakeCommentId: input.wakeCommentId } : {}), ...(input.wakeCommentId && input.attachmentOmissionReasons ? { externalAttachmentOmissions: [ { commentId: input.wakeCommentId, reasons: input.attachmentOmissionReasons, }, ], } : {}), }, }) .catch((err) => { logger.warn( { err, issueId: input.issue.id }, "failed to wake assignee on issue assignment", ); if (input.rethrowOnError) throw err; return null; }); }