From d0d44d9ae2b522b6cb7c1a34dbf2db7bb12e980f Mon Sep 17 00:00:00 2001 From: Dotta Date: Sat, 6 Jun 2026 17:28:12 +0000 Subject: [PATCH] Fix retry gate and spend hydration tests --- .../__tests__/monthly-spend-service.test.ts | 21 ++++++++ server/src/services/heartbeat.ts | 50 ++++++++++--------- 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/server/src/__tests__/monthly-spend-service.test.ts b/server/src/__tests__/monthly-spend-service.test.ts index 97b213afd93..a63a2b40e8b 100644 --- a/server/src/__tests__/monthly-spend-service.test.ts +++ b/server/src/__tests__/monthly-spend-service.test.ts @@ -55,6 +55,27 @@ describe("monthly spend hydration", () => { it("recomputes agent spentMonthlyCents from the current utc month instead of returning stale stored values", async () => { const dbStub = createSelectSequenceDb([ + [{ + id: "agent-1", + companyId: "company-1", + name: "Budget Agent", + role: "general", + title: null, + reportsTo: null, + capabilities: null, + adapterType: "claude-local", + adapterConfig: {}, + runtimeConfig: {}, + budgetMonthlyCents: 5000, + spentMonthlyCents: 999999, + metadata: null, + permissions: null, + status: "idle", + pauseReason: null, + pausedAt: null, + createdAt: new Date(), + updatedAt: new Date(), + }], [{ id: "agent-1", companyId: "company-1", diff --git a/server/src/services/heartbeat.ts b/server/src/services/heartbeat.ts index e3502510de5..6a7ec69e99c 100644 --- a/server/src/services/heartbeat.ts +++ b/server/src/services/heartbeat.ts @@ -5977,30 +5977,32 @@ export function heartbeatService(db: Db, options: HeartbeatServiceOptions = {}) }; } - const invokability = await getAgentInvokability(agent); - if (!invokability.invokable) { - const contextSnapshot = parseObject(run.contextSnapshot); - const issueId = readNonEmptyString(contextSnapshot.issueId); - await appendRunEvent(run, await nextRunEventSeq(run.id), { - eventType: "lifecycle", - stream: "system", - level: "warn", - message: "Scheduled retry suppressed because the agent is not invokable", - payload: { - retryReason, - scheduledRetryAttempt: nextAttempt, - maxAttempts, - reason: invokability.reason, - invalidOrgChain: invokability.invalidOrgChain, - ...invokability.details, - }, - }); - return { - outcome: "not_scheduled" as const, - reason: "Scheduled retry suppressed because the agent is not invokable", - errorCode: "agent_not_invokable" as const, - issueId, - }; + if (retryReason !== MAX_TURN_CONTINUATION_RETRY_REASON) { + const invokability = await getAgentInvokability(agent); + if (!invokability.invokable) { + const contextSnapshot = parseObject(run.contextSnapshot); + const issueId = readNonEmptyString(contextSnapshot.issueId); + await appendRunEvent(run, await nextRunEventSeq(run.id), { + eventType: "lifecycle", + stream: "system", + level: "warn", + message: "Scheduled retry suppressed because the agent is not invokable", + payload: { + retryReason, + scheduledRetryAttempt: nextAttempt, + maxAttempts, + reason: invokability.reason, + invalidOrgChain: invokability.invalidOrgChain, + ...invokability.details, + }, + }); + return { + outcome: "not_scheduled" as const, + reason: "Scheduled retry suppressed because the agent is not invokable", + errorCode: "agent_not_invokable" as const, + issueId, + }; + } } const schedule =