mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-04 11:01:16 +01:00
Fix accepted plan wake comment handoff
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
a5b3db58dc
commit
a379a0264d
2 files changed
+43
-17
No files matched your search
@@ -737,6 +737,17 @@ describeEmbeddedPostgres("accepted plan workspace refresh", () => {
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
});
|
||||
const planCommentId = randomUUID();
|
||||
await db.insert(issueComments).values({
|
||||
id: planCommentId,
|
||||
companyId,
|
||||
issueId,
|
||||
authorUserId: "board-user-1",
|
||||
authorType: "user",
|
||||
body: "Keep the accepted plan rollout split into separate child tasks.",
|
||||
createdAt: new Date("2026-06-07T00:00:00.000Z"),
|
||||
updatedAt: new Date("2026-06-07T00:00:00.000Z"),
|
||||
});
|
||||
await seedAcceptedPlanClaim({
|
||||
companyId,
|
||||
issueId,
|
||||
@@ -803,5 +814,14 @@ describeEmbeddedPostgres("accepted plan workspace refresh", () => {
|
||||
expect(adapterInput.runtime.sessionId).toBe("accepted-plan-retry-session");
|
||||
expect(adapterInput.context.acceptedPlanWakeRouting).toBeUndefined();
|
||||
expect(adapterInput.context.paperclipTaskMarkdown).toContain("Create child issues from the approved plan only");
|
||||
expect(adapterInput.context.paperclipTaskMarkdown).toContain("Comments included with the confirmed plan:");
|
||||
expect(adapterInput.context.paperclipTaskMarkdown).toContain(planCommentId);
|
||||
expect(adapterInput.context.paperclipTaskMarkdown).toContain(
|
||||
"Keep the accepted plan rollout split into separate child tasks.",
|
||||
);
|
||||
expect(adapterInput.context.paperclipWake).toEqual(expect.objectContaining({
|
||||
commentIds: [planCommentId],
|
||||
commentContextSource: "accepted_plan_confirmation",
|
||||
}));
|
||||
}, 20_000);
|
||||
});
|
||||
@@ -2291,6 +2291,20 @@ function normalizeInteractionContinuationWakeContext(
|
||||
clearInteractionContinuationWakeContext(contextSnapshot);
|
||||
}
|
||||
|
||||
function isAcceptedPlanContinuationWakeContext(
|
||||
contextSnapshot: Record<string, unknown>,
|
||||
issueWorkMode?: string | null,
|
||||
) {
|
||||
return (
|
||||
readNonEmptyString(contextSnapshot.workspaceRefreshReason) === "accepted_plan_confirmation" ||
|
||||
(
|
||||
issueWorkMode === "planning" &&
|
||||
readNonEmptyString(contextSnapshot.interactionKind) === "request_confirmation" &&
|
||||
readNonEmptyString(contextSnapshot.interactionStatus) === "accepted"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
type AcceptedPlanWakeRoutingDecision = {
|
||||
otherActiveClaimIssueId: string;
|
||||
otherActiveClaimIdentifier: string | null;
|
||||
@@ -2418,13 +2432,10 @@ export async function buildPaperclipWakePayload(input: {
|
||||
.then((rows) => rows[0] ?? null)
|
||||
: null);
|
||||
let acceptedPlanCommentWindowTruncated = false;
|
||||
const acceptedPlanContinuationWake =
|
||||
readNonEmptyString(input.contextSnapshot.workspaceRefreshReason) === "accepted_plan_confirmation" ||
|
||||
(
|
||||
issueSummary?.workMode === "planning" &&
|
||||
readNonEmptyString(input.contextSnapshot.interactionKind) === "request_confirmation" &&
|
||||
readNonEmptyString(input.contextSnapshot.interactionStatus) === "accepted"
|
||||
);
|
||||
const acceptedPlanContinuationWake = isAcceptedPlanContinuationWakeContext(
|
||||
input.contextSnapshot,
|
||||
issueSummary?.workMode,
|
||||
);
|
||||
if (commentIds.length === 0 && acceptedPlanContinuationWake && issueSummary?.id) {
|
||||
const recentPlanCommentRows = await input.db
|
||||
.select({ id: issueComments.id })
|
||||
@@ -2434,7 +2445,7 @@ export async function buildPaperclipWakePayload(input: {
|
||||
eq(issueComments.issueId, issueSummary.id),
|
||||
isNull(issueComments.deletedAt),
|
||||
))
|
||||
.orderBy(desc(issueComments.createdAt), desc(issueComments.id))
|
||||
.orderBy(desc(issueComments.createdAt))
|
||||
.limit(MAX_INLINE_WAKE_COMMENTS + 1);
|
||||
acceptedPlanCommentWindowTruncated = recentPlanCommentRows.length > MAX_INLINE_WAKE_COMMENTS;
|
||||
commentIds = recentPlanCommentRows
|
||||
@@ -7804,13 +7815,7 @@ export function heartbeatService(db: Db, options: HeartbeatServiceOptions = {})
|
||||
companyId: agent.companyId,
|
||||
agentId: agent.id,
|
||||
issueId,
|
||||
acceptedPlanContinuationWake:
|
||||
readNonEmptyString(context.workspaceRefreshReason) === "accepted_plan_confirmation"
|
||||
|| (
|
||||
issueContext.workMode === "planning"
|
||||
&& readNonEmptyString(context.interactionKind) === "request_confirmation"
|
||||
&& readNonEmptyString(context.interactionStatus) === "accepted"
|
||||
),
|
||||
acceptedPlanContinuationWake: isAcceptedPlanContinuationWakeContext(context, issueContext.workMode),
|
||||
contextSnapshot: context,
|
||||
})
|
||||
: null;
|
||||
@@ -7949,9 +7954,10 @@ export function heartbeatService(db: Db, options: HeartbeatServiceOptions = {})
|
||||
} else {
|
||||
delete context[PAPERCLIP_WAKE_PAYLOAD_KEY];
|
||||
}
|
||||
const acceptedPlanWakeRouting = parseObject(context.acceptedPlanWakeRouting);
|
||||
const acceptedPlanContinuationForTask =
|
||||
readNonEmptyString(context.workspaceRefreshReason) === "accepted_plan_confirmation"
|
||||
&& !parseObject(context.acceptedPlanWakeRouting);
|
||||
isAcceptedPlanContinuationWakeContext(context, issueRef?.workMode) &&
|
||||
Object.keys(acceptedPlanWakeRouting).length === 0;
|
||||
const acceptedPlanCommentsForTask =
|
||||
acceptedPlanContinuationForTask && Array.isArray(paperclipWakePayload?.comments)
|
||||
? paperclipWakePayload.comments.map((comment) => ({
|
||||
|
||||
Reference in new issue
Block a user