diff --git a/lib/keys/__tests__/mintEphemeralAccountKey.test.ts b/lib/keys/__tests__/mintEphemeralAccountKey.test.ts index 1c7ba361..57572ff6 100644 --- a/lib/keys/__tests__/mintEphemeralAccountKey.test.ts +++ b/lib/keys/__tests__/mintEphemeralAccountKey.test.ts @@ -20,7 +20,11 @@ vi.mock("@/lib/const", () => ({ PRIVY_PROJECT_SECRET: "secret" })); describe("mintEphemeralAccountKey", () => { beforeEach(() => vi.clearAllMocks()); - it("mints an account-scoped recoup_sk_ key with a ~15m expiry and returns rawKey + keyId", async () => { + it("defaults the ephemeral TTL to 60 minutes (long runs with step retries outlive 15m — chat#1839)", () => { + expect(DEFAULT_EPHEMERAL_KEY_TTL_MS).toBe(60 * 60 * 1000); + }); + + it("mints an account-scoped recoup_sk_ key with the default expiry and returns rawKey + keyId", async () => { vi.mocked(insertApiKey).mockResolvedValue({ data: { id: "key-1" }, error: null } as never); const before = Date.now(); diff --git a/lib/keys/mintEphemeralAccountKey.ts b/lib/keys/mintEphemeralAccountKey.ts index 8b138f27..52144b90 100644 --- a/lib/keys/mintEphemeralAccountKey.ts +++ b/lib/keys/mintEphemeralAccountKey.ts @@ -3,8 +3,16 @@ import { hashApiKey } from "@/lib/keys/hashApiKey"; import { insertApiKey } from "@/lib/supabase/account_api_keys/insertApiKey"; import { PRIVY_PROJECT_SECRET } from "@/lib/const"; -/** Default lifetime for an ephemeral key: 15 minutes. */ -export const DEFAULT_EPHEMERAL_KEY_TTL_MS = 15 * 60 * 1000; +/** + * Default lifetime for an ephemeral key: 60 minutes. The TTL is only the + * backstop — `runAgentWorkflow` revokes the key the moment the run ends + * (`deleteEphemeralKeyStep`), so a longer TTL does not extend key life on + * normal completion. 15 minutes proved too short for real runs: a + * `runAgentStep` timeout retries the whole agent loop (~10+ min per attempt), + * and on 2026-07-03 a customer run's final sends all 401'd on the expired key + * (chat#1839). 60 minutes covers several retry cycles. + */ +export const DEFAULT_EPHEMERAL_KEY_TTL_MS = 60 * 60 * 1000; export type EphemeralAccountKey = { rawKey: string; keyId: string };