mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 09:41:04 +01:00
fix(adapters): preserve issue reports through delivery
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
b996985902
commit
27dd2d5cc7
3 files changed
+83
-2
No files matched your search
@@ -821,6 +821,36 @@ describe("renderPaperclipWakePrompt", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("preserves cross-issue reports in adapter payloads and prompts", () => {
|
||||
const payload = {
|
||||
reports: [
|
||||
{
|
||||
id: "report-1",
|
||||
targetIssueId: "issue-target",
|
||||
originIssueId: "issue-origin",
|
||||
originRunId: "run-origin",
|
||||
originAgentId: "agent-origin",
|
||||
fingerprint: "audit-result",
|
||||
payload: {
|
||||
type: "audit.result",
|
||||
summary: "Audit passed",
|
||||
data: { checks: 9 },
|
||||
},
|
||||
wakeRequested: true,
|
||||
createdAt: "2026-07-12T16:00:00.000Z",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const serialized = stringifyPaperclipWakePayload(payload);
|
||||
expect(JSON.parse(serialized ?? "{}")).toMatchObject(payload);
|
||||
|
||||
const prompt = renderPaperclipWakePrompt(payload);
|
||||
expect(prompt).toContain("Cross-issue reports in delivery order:");
|
||||
expect(prompt).toContain("report report-1 from issue issue-origin run run-origin");
|
||||
expect(prompt).toContain('"summary":"Audit passed"');
|
||||
});
|
||||
|
||||
it("escapes backticks and strips control characters in the branch guard", () => {
|
||||
const prompt = renderPaperclipWakePrompt({
|
||||
reason: "issue_assigned",
|
||||
|
||||
@@ -615,6 +615,18 @@ type PaperclipWakeExecutionWorkspace = {
|
||||
branchName: string | null;
|
||||
};
|
||||
|
||||
type PaperclipWakeReport = {
|
||||
id: string;
|
||||
targetIssueId: string;
|
||||
originIssueId: string;
|
||||
originRunId: string;
|
||||
originAgentId: string;
|
||||
fingerprint: string;
|
||||
payload: Record<string, unknown>;
|
||||
wakeRequested: boolean;
|
||||
createdAt: string | null;
|
||||
};
|
||||
|
||||
type PaperclipWakePayload = {
|
||||
reason: string | null;
|
||||
issue: PaperclipWakeIssue | null;
|
||||
@@ -639,6 +651,7 @@ type PaperclipWakePayload = {
|
||||
commentIds: string[];
|
||||
latestCommentId: string | null;
|
||||
comments: PaperclipWakeComment[];
|
||||
reports: PaperclipWakeReport[];
|
||||
requestedCount: number;
|
||||
includedCount: number;
|
||||
missingCount: number;
|
||||
@@ -681,6 +694,28 @@ function normalizePaperclipWakeComment(value: unknown): PaperclipWakeComment | n
|
||||
};
|
||||
}
|
||||
|
||||
function normalizePaperclipWakeReport(value: unknown): PaperclipWakeReport | null {
|
||||
const report = parseObject(value);
|
||||
const id = asString(report.id, "").trim();
|
||||
const targetIssueId = asString(report.targetIssueId, "").trim();
|
||||
const originIssueId = asString(report.originIssueId, "").trim();
|
||||
const originRunId = asString(report.originRunId, "").trim();
|
||||
const originAgentId = asString(report.originAgentId, "").trim();
|
||||
const fingerprint = asString(report.fingerprint, "").trim();
|
||||
if (!id || !targetIssueId || !originIssueId || !originRunId || !originAgentId || !fingerprint) return null;
|
||||
return {
|
||||
id,
|
||||
targetIssueId,
|
||||
originIssueId,
|
||||
originRunId,
|
||||
originAgentId,
|
||||
fingerprint,
|
||||
payload: parseObject(report.payload),
|
||||
wakeRequested: asBoolean(report.wakeRequested, false),
|
||||
createdAt: asString(report.createdAt, "").trim() || null,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizePaperclipWakePlanReviewAuthor(value: unknown): PaperclipWakePlanReviewAuthor | null {
|
||||
const author = parseObject(value);
|
||||
const type = asString(author.type, "").trim() || null;
|
||||
@@ -1175,6 +1210,11 @@ export function normalizePaperclipWakePayload(value: unknown): PaperclipWakePayl
|
||||
.map((entry) => normalizePaperclipWakeComment(entry))
|
||||
.filter((entry): entry is PaperclipWakeComment => Boolean(entry))
|
||||
: [];
|
||||
const reports = Array.isArray(payload.reports)
|
||||
? payload.reports
|
||||
.map((entry) => normalizePaperclipWakeReport(entry))
|
||||
.filter((entry): entry is PaperclipWakeReport => Boolean(entry))
|
||||
: [];
|
||||
const commentWindow = parseObject(payload.commentWindow);
|
||||
const commentIds = Array.isArray(payload.commentIds)
|
||||
? payload.commentIds
|
||||
@@ -1210,7 +1250,7 @@ export function normalizePaperclipWakePayload(value: unknown): PaperclipWakePayl
|
||||
const activeTreeHold = normalizePaperclipWakeTreeHoldSummary(payload.activeTreeHold);
|
||||
const checkboxSelection = normalizePaperclipWakeCheckboxSelection(payload.checkboxSelection);
|
||||
const executionWorkspace = normalizePaperclipWakeExecutionWorkspace(payload.executionWorkspace);
|
||||
if (comments.length === 0 && commentIds.length === 0 && annotationDeltas.length === 0 && childIssueSummaries.length === 0 && unresolvedBlockerIssueIds.length === 0 && unresolvedBlockerSummaries.length === 0 && !activeTreeHold && !executionStage && !continuationSummary && !planReviewContext && !livenessContinuation && !taskWatchdog && !checkboxSelection && !executionWorkspace && !normalizePaperclipWakeIssue(payload.issue)) {
|
||||
if (comments.length === 0 && reports.length === 0 && commentIds.length === 0 && annotationDeltas.length === 0 && childIssueSummaries.length === 0 && unresolvedBlockerIssueIds.length === 0 && unresolvedBlockerSummaries.length === 0 && !activeTreeHold && !executionStage && !continuationSummary && !planReviewContext && !livenessContinuation && !taskWatchdog && !checkboxSelection && !executionWorkspace && !normalizePaperclipWakeIssue(payload.issue)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1238,6 +1278,7 @@ export function normalizePaperclipWakePayload(value: unknown): PaperclipWakePayl
|
||||
commentIds,
|
||||
latestCommentId: asString(payload.latestCommentId, "").trim() || null,
|
||||
comments,
|
||||
reports,
|
||||
requestedCount: asNumber(commentWindow.requestedCount, comments.length || commentIds.length),
|
||||
includedCount: asNumber(commentWindow.includedCount, comments.length),
|
||||
missingCount: asNumber(commentWindow.missingCount, 0),
|
||||
@@ -1667,6 +1708,17 @@ export function renderPaperclipWakePrompt(
|
||||
lines.push("");
|
||||
}
|
||||
|
||||
if (normalized.reports.length > 0) {
|
||||
lines.push("Cross-issue reports in delivery order:");
|
||||
for (const [index, report] of normalized.reports.entries()) {
|
||||
lines.push(
|
||||
`${index + 1}. report ${report.id} from issue ${report.originIssueId} run ${report.originRunId}`,
|
||||
JSON.stringify(report.payload),
|
||||
"",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return lines.join("\n").trim();
|
||||
}
|
||||
|
||||
|
||||
@@ -12830,7 +12830,6 @@ export function heartbeatService(db: Db, options: HeartbeatServiceOptions = {})
|
||||
: null,
|
||||
startedAt: meta.startedAt,
|
||||
});
|
||||
await acknowledgePendingReports();
|
||||
},
|
||||
authToken: authToken ?? undefined,
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user