mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-10 12:07:09 +02:00
Merge branch 'codex/hermes-native-runner' into codex/hermes-qualification
* codex/hermes-native-runner: fix(ui): preserve exact retry feedback across agent aliases
This commit is contained in:
commit
85367ea3dc
3 files changed
+42
-7
No files matched your search
@@ -201,12 +201,11 @@ function registerModuleMocks() {
|
||||
}));
|
||||
}
|
||||
|
||||
let errorHandler: typeof import("../middleware/index.js").errorHandler;
|
||||
let issueRoutes: typeof import("../routes/issues.js").issueRoutes;
|
||||
|
||||
async function createApp(transaction: (callback: (tx: Record<string, never>) => Promise<unknown>) => Promise<unknown> =
|
||||
async (callback) => callback({})) {
|
||||
const [{ errorHandler }, { issueRoutes }] = await Promise.all([
|
||||
vi.importActual<typeof import("../middleware/index.js")>("../middleware/index.js"),
|
||||
vi.importActual<typeof import("../routes/issues.js")>("../routes/issues.js"),
|
||||
]);
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
app.use((req, _res, next) => {
|
||||
@@ -249,7 +248,7 @@ function makeIssue(overrides: Record<string, unknown> = {}) {
|
||||
}
|
||||
|
||||
describe("issue update comment wakeups", () => {
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
vi.doUnmock("../routes/issues.js");
|
||||
vi.doUnmock("../routes/authz.js");
|
||||
@@ -267,7 +266,11 @@ describe("issue update comment wakeups", () => {
|
||||
mockIssueService.getWakeableParentAfterChildCompletion.mockResolvedValue(null);
|
||||
mockIssueService.getCurrentScheduledRetry.mockResolvedValue(null);
|
||||
mockIssueService.listReviewAttention.mockResolvedValue(new Map());
|
||||
});
|
||||
[{ errorHandler }, { issueRoutes }] = await Promise.all([
|
||||
vi.importActual<typeof import("../middleware/index.js")>("../middleware/index.js"),
|
||||
vi.importActual<typeof import("../routes/issues.js")>("../routes/issues.js"),
|
||||
]);
|
||||
}, 30_000);
|
||||
|
||||
it.each(["post", "patch"] as const)("rejects %s board messages under an inherited pause before any mutation", async (method) => {
|
||||
const existing = makeIssue();
|
||||
|
||||
@@ -1355,12 +1355,26 @@ test.describe("Exact failed chat run retry", () => {
|
||||
body: Record<string, unknown>;
|
||||
}> = [];
|
||||
const destinations: string[] = [];
|
||||
let releaseCanonicalRead = () => {};
|
||||
const canonicalRead = new Promise<void>((resolve) => {
|
||||
releaseCanonicalRead = resolve;
|
||||
});
|
||||
page.once("close", releaseCanonicalRead);
|
||||
page.on("framenavigated", (frame) => {
|
||||
if (frame === page.mainFrame()) destinations.push(frame.url());
|
||||
});
|
||||
await page.route("**/api/**", async (route) => {
|
||||
const url = new URL(route.request().url());
|
||||
const pathname = url.pathname;
|
||||
if (surface === "agent run" && outcome === "denied"
|
||||
&& pathname === "/api/agents/maya" && route.request().method() === "GET") {
|
||||
// Canonical URL refresh must preserve the selected run and its
|
||||
// retry feedback while the alias lookup is still pending.
|
||||
const response = await route.fetch();
|
||||
await canonicalRead;
|
||||
if (!page.isClosed()) await route.fulfill({ response });
|
||||
return;
|
||||
}
|
||||
if (pathname === "/api/instance/settings/experimental") {
|
||||
await fulfill(route, {
|
||||
enableChatConnectors: true,
|
||||
@@ -1455,6 +1469,10 @@ test.describe("Exact failed chat run retry", () => {
|
||||
});
|
||||
if (outcome === "denied") {
|
||||
await expect(page.getByText(denial, { exact: true })).toBeVisible();
|
||||
if (surface === "agent run") {
|
||||
await page.screenshot({ path: testInfo.outputPath("exact-retry-denied-during-canonical-refresh.png") });
|
||||
}
|
||||
releaseCanonicalRead();
|
||||
if (surface !== "agent run") {
|
||||
await expect(
|
||||
page.getByText("Run retry failed", { exact: true }),
|
||||
|
||||
@@ -964,6 +964,20 @@ export function AgentDetail() {
|
||||
|
||||
useEffect(() => {
|
||||
if (!agent) return;
|
||||
if (routeAgentRef !== canonicalAgentRef) {
|
||||
// Reuse the authorized response across the alias redirect. An empty
|
||||
// alias query would unmount the selected run and discard its mutations.
|
||||
queryClient.setQueryData(
|
||||
[...queryKeys.agents.detail(canonicalAgentRef), lookupCompanyId ?? null],
|
||||
agent,
|
||||
);
|
||||
if (lookupCompanyId !== agent.companyId) {
|
||||
queryClient.setQueryData(
|
||||
[...queryKeys.agents.detail(canonicalAgentRef), agent.companyId],
|
||||
agent,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (urlRunId) {
|
||||
if (routeAgentRef !== canonicalAgentRef) {
|
||||
navigate(`/agents/${canonicalAgentRef}/runs/${urlRunId}`, { replace: true });
|
||||
@@ -976,7 +990,7 @@ export function AgentDetail() {
|
||||
navigate(agentDetailHref(canonicalAgentRef, canonicalTab), { replace: true });
|
||||
return;
|
||||
}
|
||||
}, [agent, routeAgentRef, canonicalAgentRef, urlRunId, urlTab, activeView, legacyAuditSection, navigate]);
|
||||
}, [agent, routeAgentRef, canonicalAgentRef, urlRunId, urlTab, activeView, legacyAuditSection, navigate, lookupCompanyId, queryClient]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!agent?.companyId || agent.companyId === selectedCompanyId) return;
|
||||
|
||||
Reference in new issue
Block a user