Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
- Codex reasoning summaries can echo trailing empty HTML comments from model instructions. Keep
that provider-specific cleanup in `src/ReasoningText.ts` across live deltas and history replay;
do not filter assistant text, raw reasoning, or HTML globally in the client renderer.
- App-server `warning` and `configWarning` notifications are structured ACP session info updates:
put `{ message, source }` under `_meta.codex.warning`. Never emit them as agent message text;
Lody persists that metadata as an `agent_warning` system notice, and text chunks would pollute
assistant history, generated titles, and replayed prompts.
- Account rate-limit windows are dynamic. Read the full `account/rateLimits/read` snapshot when a
session opens, merge sparse `account/rateLimits/updated` values into that snapshot, and preserve
each window's `windowDurationMins` in the ACP extension. Never infer 5-hour/7-day meaning from
Expand Down
14 changes: 12 additions & 2 deletions src/CodexEventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,11 +437,21 @@ export class CodexEventHandler {

private async createConfigWarningEvent(event: ConfigWarningNotification): Promise<UpdateSessionEvent> {
const detailsText = event.details ? `\n\n${event.details}` : "";
return createAgentTextMessageChunk(`Config warning: ${event.summary}${detailsText}\n\n`);
return this.createCodexSessionInfoUpdate({
warning: {
message: `${event.summary}${detailsText}`,
source: "configWarning",
},
});
}

private createWarningEvent(event: WarningNotification): UpdateSessionEvent {
return createAgentTextMessageChunk(`Warning: ${event.message}\n\n`);
return this.createCodexSessionInfoUpdate({
warning: {
message: event.message,
source: "warning",
},
});
}

private createModelReroutedEvent(event: ModelReroutedNotification): UpdateSessionEvent {
Expand Down
38 changes: 38 additions & 0 deletions src/__tests__/CodexACPAgent/data/warning-events.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"method": "sessionUpdate",
"args": [
{
"sessionId": "test-session-id",
"update": {
"sessionUpdate": "session_info_update",
"_meta": {
"codex": {
"warning": {
"message": "Falling back from WebSockets to HTTPS transport. unexpected status 401",
"source": "warning"
}
}
}
}
}
]
}
{
"method": "sessionUpdate",
"args": [
{
"sessionId": "test-session-id",
"update": {
"sessionUpdate": "session_info_update",
"_meta": {
"codex": {
"warning": {
"message": "Project configuration could not be loaded\n\nUsing the default configuration instead.",
"source": "configWarning"
}
}
}
}
}
]
}
48 changes: 48 additions & 0 deletions src/__tests__/CodexACPAgent/warning-events.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { ServerNotification } from "../../app-server";
import {
createCodexMockTestFixture,
createTestSessionState,
setupPromptAndSendNotifications,
type CodexMockTestFixture,
} from "../acp-test-utils";

describe("CodexEventHandler - warning events", () => {
let mockFixture: CodexMockTestFixture;
const sessionId = "test-session-id";

beforeEach(() => {
mockFixture = createCodexMockTestFixture();
vi.clearAllMocks();
});

it("sends runtime and configuration warnings as structured session metadata", async () => {
const notifications: ServerNotification[] = [
{
method: "warning",
params: {
threadId: sessionId,
message: "Falling back from WebSockets to HTTPS transport. unexpected status 401",
},
},
{
method: "configWarning",
params: {
summary: "Project configuration could not be loaded",
details: "Using the default configuration instead.",
},
},
];

await setupPromptAndSendNotifications(
mockFixture,
sessionId,
createTestSessionState({ sessionId }),
notifications,
);

await expect(mockFixture.getAcpConnectionDump([])).toMatchFileSnapshot(
"data/warning-events.json",
);
});
});
Loading