diff --git a/src/CodexEventHandler.ts b/src/CodexEventHandler.ts index 7360b6f9..43b4381b 100644 --- a/src/CodexEventHandler.ts +++ b/src/CodexEventHandler.ts @@ -470,7 +470,9 @@ export class CodexEventHandler { return this.createMcpToolProgressEvent(notification.params); case "account/rateLimits/updated": this.handleRateLimitsUpdated(notification.params); - return null; + return this.createCodexSessionInfoUpdate({ + rateLimits: notification.params.rateLimits, + }); case "configWarning": return await this.createConfigWarningEvent(notification.params); case "warning": diff --git a/src/__tests__/CodexACPAgent/data/account-rate-limits-updated.json b/src/__tests__/CodexACPAgent/data/account-rate-limits-updated.json new file mode 100644 index 00000000..905509fb --- /dev/null +++ b/src/__tests__/CodexACPAgent/data/account-rate-limits-updated.json @@ -0,0 +1,34 @@ +{ + "method": "sessionUpdate", + "args": [ + { + "sessionId": "test-session-id", + "update": { + "sessionUpdate": "session_info_update", + "_meta": { + "codex": { + "rateLimits": { + "limitId": "codex", + "limitName": null, + "primary": { + "usedPercent": 42, + "windowDurationMins": 300, + "resetsAt": 1710000000 + }, + "secondary": { + "usedPercent": 7, + "windowDurationMins": 10080, + "resetsAt": 1710600000 + }, + "credits": null, + "individualLimit": null, + "spendControlReached": false, + "planType": "plus", + "rateLimitReachedType": null + } + } + } + } + } + ] +} \ No newline at end of file diff --git a/src/__tests__/CodexACPAgent/rate-limit-events.test.ts b/src/__tests__/CodexACPAgent/rate-limit-events.test.ts new file mode 100644 index 00000000..46909957 --- /dev/null +++ b/src/__tests__/CodexACPAgent/rate-limit-events.test.ts @@ -0,0 +1,55 @@ +import { describe, it, expect, vi, beforeEach } from "vitest"; +import type { SessionState } from "../../CodexAcpServer"; +import type { ServerNotification } from "../../app-server"; +import { AgentMode } from "../../AgentMode"; +import { + createCodexMockTestFixture, + createTestSessionState, + setupPromptAndSendNotifications, + type CodexMockTestFixture, +} from "../acp-test-utils"; + +describe("CodexEventHandler - account rate limit events", () => { + let mockFixture: CodexMockTestFixture; + const sessionId = "test-session-id"; + + beforeEach(() => { + mockFixture = createCodexMockTestFixture(); + vi.clearAllMocks(); + }); + + const rateLimitsUpdatedNotification: ServerNotification = { + method: "account/rateLimits/updated", + params: { + rateLimits: { + limitId: "codex", + limitName: null, + primary: { usedPercent: 42, windowDurationMins: 300, resetsAt: 1710000000 }, + secondary: { usedPercent: 7, windowDurationMins: 10080, resetsAt: 1710600000 }, + credits: null, + individualLimit: null, + spendControlReached: false, + planType: "plus", + rateLimitReachedType: null, + }, + }, + }; + + it("should send account rate limits as session metadata", async () => { + await setupPromptAndSendNotifications(mockFixture, sessionId, createSessionState(), [ + rateLimitsUpdatedNotification, + ]); + + await expect(mockFixture.getAcpConnectionDump([])).toMatchFileSnapshot( + "data/account-rate-limits-updated.json" + ); + }); + + function createSessionState(): SessionState { + return createTestSessionState({ + sessionId, + currentModelId: "model-id[effort]", + agentMode: AgentMode.DEFAULT_AGENT_MODE, + }); + } +});