mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-11 13:24:55 +01:00
fix: make connection checks and task handoffs reliable (#13404)
Preserve connection-probe outcomes through cleanup, reduce unrelated startup work, and report selected Claude authentication accurately. Make artifact download actions match their labels. Route delegated feedback through its active child, retain accepted messages across completion, and avoid redundant worker runs for proven closing notes. Preserve explicit follow-ups, human input, company boundaries, source provenance, and mixed issue references. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
2d47a8058d
commit
f1d57863d2
20 files changed
+740
-65
No files matched your search
@@ -4,6 +4,7 @@ import { currentConversationCommentCondition } from "../../../services/agent-con
|
||||
import { getExecutionBlocker } from "../../../services/execution-blocker.js";
|
||||
import { and, asc, eq, inArray, isNull, notInArray, or, sql } from "drizzle-orm";
|
||||
import type { Db } from "@paperclipai/db";
|
||||
import { extractIssueReferenceIdentifiers } from "@paperclipai/shared";
|
||||
import {
|
||||
agentWakeupRequests,
|
||||
agents,
|
||||
@@ -373,6 +374,44 @@ function buildTransaction(tx: Db, deps: WakeQueuePostgresAdapterDeps, db: Db, ru
|
||||
return { allSelfAuthored: rows.length > 0 && rows.every((row) => row.createdByRunId === finishingRunId) };
|
||||
},
|
||||
|
||||
async isCompletedDelegationMention({ companyId, issueId, finishingRunId, wakeAgentId, commentIds }) {
|
||||
if (
|
||||
run.companyId !== companyId || run.id !== finishingRunId ||
|
||||
readNonEmptyString(parseObject(run.contextSnapshot).issueId) !== issueId
|
||||
) return false;
|
||||
const uniqueCommentIds = [...new Set(commentIds)];
|
||||
if (uniqueCommentIds.length === 0) return false;
|
||||
const parent = await tx.select({ status: issues.status, assigneeAgentId: issues.assigneeAgentId, identifier: issues.identifier })
|
||||
.from(issues).where(and(eq(issues.companyId, companyId), eq(issues.id, issueId)))
|
||||
.then((rows) => rows[0]);
|
||||
if (parent?.status !== "done" || parent.assigneeAgentId !== run.agentId) return false;
|
||||
|
||||
const comments = await tx.select({ body: issueComments.body, createdByRunId: issueComments.createdByRunId,
|
||||
authorAgentId: issueComments.authorAgentId })
|
||||
.from(issueComments).where(and(
|
||||
eq(issueComments.companyId, companyId), eq(issueComments.issueId, issueId),
|
||||
inArray(issueComments.id, uniqueCommentIds), isNull(issueComments.deletedAt), currentConversationCommentCondition(),
|
||||
));
|
||||
if (comments.length !== uniqueCommentIds.length || comments.some((comment) =>
|
||||
comment.createdByRunId !== run.id || (comment.authorAgentId !== null && comment.authorAgentId !== run.agentId)
|
||||
)) return false;
|
||||
const referencesByComment = comments.map((comment) => extractIssueReferenceIdentifiers(comment.body)
|
||||
.filter((identifier) => identifier !== parent.identifier));
|
||||
// A parent link is context; every other reference must identify the
|
||||
// single completed child. Never discard unrelated follow-up work.
|
||||
if (referencesByComment.some((references) => references.length !== 1)) return false;
|
||||
const identifiers = [...new Set(referencesByComment.flat())];
|
||||
const children = await tx.select({ identifier: issues.identifier, status: issues.status })
|
||||
.from(issues).where(and(
|
||||
eq(issues.companyId, companyId), eq(issues.parentId, issueId),
|
||||
eq(issues.assigneeAgentId, wakeAgentId), inArray(issues.identifier, identifiers),
|
||||
));
|
||||
return referencesByComment.every((references) => {
|
||||
const referencedChildren = children.filter((child) => child.identifier !== null && references.includes(child.identifier));
|
||||
return referencedChildren.length === 1 && referencedChildren[0].status === "done";
|
||||
});
|
||||
},
|
||||
|
||||
async reopenIssue({ companyId, issueId }) {
|
||||
const updated = await issuesSvc.updateForCompany(issueId, companyId, { status: "todo", executionState: null }, tx);
|
||||
return updated ? toIssueSnapshot(updated as unknown as IssueRow) : null;
|
||||
|
||||
Reference in new issue
Block a user