mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-23 09:07:46 +02:00
Address Greptile runtime review concerns
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
386b1d8e1a
commit
595d4d988b
4 files changed
+36
-11
No files matched your search
@@ -816,7 +816,7 @@ describeEmbeddedPostgres("issueThreadInteractionService", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("expires request confirmations by default when a user comments after creation", async () => {
|
||||
it("expires request confirmations opted into user-comment supersede after creation", async () => {
|
||||
const { companyId, issueId } = await seedConfirmationIssue();
|
||||
const commentId = randomUUID();
|
||||
|
||||
@@ -828,6 +828,7 @@ describeEmbeddedPostgres("issueThreadInteractionService", () => {
|
||||
payload: {
|
||||
version: 1,
|
||||
prompt: "Proceed with the current draft?",
|
||||
supersedeOnUserComment: true,
|
||||
},
|
||||
}, {
|
||||
userId: "local-board",
|
||||
@@ -857,7 +858,7 @@ describeEmbeddedPostgres("issueThreadInteractionService", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps request confirmations pending when user-comment supersede is explicitly disabled", async () => {
|
||||
it("keeps request confirmations pending unless user-comment supersede is explicitly enabled", async () => {
|
||||
const { companyId, issueId } = await seedConfirmationIssue("Comment supersede opt-out");
|
||||
|
||||
await interactionsSvc.create({
|
||||
@@ -868,7 +869,6 @@ describeEmbeddedPostgres("issueThreadInteractionService", () => {
|
||||
payload: {
|
||||
version: 1,
|
||||
prompt: "Proceed with the current draft?",
|
||||
supersedeOnUserComment: false,
|
||||
},
|
||||
}, {
|
||||
userId: "local-board",
|
||||
@@ -902,6 +902,7 @@ describeEmbeddedPostgres("issueThreadInteractionService", () => {
|
||||
payload: {
|
||||
version: 1,
|
||||
prompt: "Proceed with the current draft?",
|
||||
supersedeOnUserComment: true,
|
||||
},
|
||||
}, {
|
||||
userId: "local-board",
|
||||
@@ -957,6 +958,7 @@ describeEmbeddedPostgres("issueThreadInteractionService", () => {
|
||||
payload: {
|
||||
version: 1,
|
||||
prompt: "Proceed with the current draft?",
|
||||
supersedeOnUserComment: true,
|
||||
},
|
||||
}, {
|
||||
userId: "local-board",
|
||||
@@ -966,6 +968,16 @@ describeEmbeddedPostgres("issueThreadInteractionService", () => {
|
||||
.set({ createdAt, updatedAt: createdAt })
|
||||
.where(eq(issueThreadInteractions.id, created.id));
|
||||
|
||||
await db.insert(issueComments).values({
|
||||
id: randomUUID(),
|
||||
companyId,
|
||||
issueId,
|
||||
authorAgentId: randomUUID(),
|
||||
authorType: "agent",
|
||||
body: "Agent-side progress note.",
|
||||
createdAt: new Date("2026-05-18T12:00:30.000Z"),
|
||||
updatedAt: new Date("2026-05-18T12:00:30.000Z"),
|
||||
});
|
||||
await db.insert(issueComments).values({
|
||||
id: commentId,
|
||||
companyId,
|
||||
|
||||
@@ -79,6 +79,10 @@ describe("pluginLifecycleManager.restartWorker", () => {
|
||||
{} as never,
|
||||
{ loader: loader as PluginLoader, workerManager },
|
||||
);
|
||||
const stopped = vi.fn();
|
||||
const started = vi.fn();
|
||||
lifecycle.on("plugin.worker_stopped", stopped);
|
||||
lifecycle.on("plugin.worker_started", started);
|
||||
|
||||
await lifecycle.restartWorker("plugin-1");
|
||||
|
||||
@@ -87,6 +91,8 @@ describe("pluginLifecycleManager.restartWorker", () => {
|
||||
// The bare worker handle should NOT be bounced — the loader handles
|
||||
// worker (re)start as part of activate.
|
||||
expect(handle.restart).not.toHaveBeenCalled();
|
||||
expect(stopped).not.toHaveBeenCalled();
|
||||
expect(started).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("falls back to bouncing the worker handle when the loader has no runtime services", async () => {
|
||||
@@ -105,11 +111,19 @@ describe("pluginLifecycleManager.restartWorker", () => {
|
||||
{} as never,
|
||||
{ loader: loader as PluginLoader, workerManager },
|
||||
);
|
||||
const stopped = vi.fn();
|
||||
const started = vi.fn();
|
||||
lifecycle.on("plugin.worker_stopped", stopped);
|
||||
lifecycle.on("plugin.worker_started", started);
|
||||
|
||||
await lifecycle.restartWorker("plugin-1");
|
||||
|
||||
expect(loader.unloadSingle).not.toHaveBeenCalled();
|
||||
expect(loader.loadSingle).not.toHaveBeenCalled();
|
||||
expect(handle.restart).toHaveBeenCalledTimes(1);
|
||||
expect(stopped).toHaveBeenCalledTimes(1);
|
||||
expect(stopped).toHaveBeenCalledWith({ pluginId: "plugin-1", pluginKey: "example.plugin" });
|
||||
expect(started).toHaveBeenCalledTimes(1);
|
||||
expect(started).toHaveBeenCalledWith({ pluginId: "plugin-1", pluginKey: "example.plugin" });
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,5 @@
|
||||
import { isDeepStrictEqual } from "node:util";
|
||||
import { and, asc, eq, inArray } from "drizzle-orm";
|
||||
import { and, asc, eq, inArray, isNotNull } from "drizzle-orm";
|
||||
import type { Db } from "@paperclipai/db";
|
||||
import {
|
||||
documents,
|
||||
@@ -159,7 +159,7 @@ function shouldReturnAcceptedConfirmationToCreatorAgent(args: {
|
||||
}
|
||||
|
||||
function shouldSupersedeRequestConfirmationOnUserComment(interaction: RequestConfirmationInteraction) {
|
||||
return interaction.payload.supersedeOnUserComment !== false;
|
||||
return interaction.payload.supersedeOnUserComment === true;
|
||||
}
|
||||
|
||||
function isCommentAtOrAfterInteraction(args: {
|
||||
@@ -1059,12 +1059,12 @@ export function issueThreadInteractionService(db: Db) {
|
||||
.where(and(
|
||||
eq(issueComments.companyId, issue.companyId),
|
||||
eq(issueComments.issueId, issue.id),
|
||||
isNotNull(issueComments.authorUserId),
|
||||
))
|
||||
.orderBy(asc(issueComments.createdAt)),
|
||||
]);
|
||||
|
||||
const userComments = comments.filter((comment) => comment.authorUserId);
|
||||
if (rows.length === 0 || userComments.length === 0) return [];
|
||||
if (rows.length === 0 || comments.length === 0) return [];
|
||||
|
||||
const now = new Date();
|
||||
const expired: IssueThreadInteraction[] = [];
|
||||
@@ -1072,7 +1072,7 @@ export function issueThreadInteractionService(db: Db) {
|
||||
const interaction = hydrateInteraction(row) as RequestConfirmationInteraction;
|
||||
if (!shouldSupersedeRequestConfirmationOnUserComment(interaction)) continue;
|
||||
|
||||
const supersedingComment = userComments.find((comment) => isCommentAtOrAfterInteraction({
|
||||
const supersedingComment = comments.find((comment) => isCommentAtOrAfterInteraction({
|
||||
commentCreatedAt: comment.createdAt,
|
||||
interactionCreatedAt: row.createdAt,
|
||||
}));
|
||||
|
||||
@@ -810,11 +810,10 @@ export function pluginLifecycleManager(
|
||||
"plugin lifecycle: restarting worker (runtime services unavailable; skipping migration re-apply)",
|
||||
);
|
||||
await handle.restart();
|
||||
emitDomain("plugin.worker_stopped", { pluginId, pluginKey: plugin.pluginKey });
|
||||
emitDomain("plugin.worker_started", { pluginId, pluginKey: plugin.pluginKey });
|
||||
}
|
||||
|
||||
emitDomain("plugin.worker_stopped", { pluginId, pluginKey: plugin.pluginKey });
|
||||
emitDomain("plugin.worker_started", { pluginId, pluginKey: plugin.pluginKey });
|
||||
|
||||
log.info(
|
||||
{ pluginId, pluginKey: plugin.pluginKey },
|
||||
"plugin lifecycle: plugin reloaded",
|
||||
|
||||
Reference in new issue
Block a user