From 6dbd914fb9416ef8db019b1b234cbb4b647aa536 Mon Sep 17 00:00:00 2001 From: Phelipe Lorran <112786693+httpsphl@users.noreply.github.com> Date: Sat, 10 Oct 2026 18:53:00 -0300 Subject: [PATCH] feat(agents): Codex login and limit states, compaction and connected tools (A3d) - account/read at the handshake and codexErrorInfo unauthorized end in auth_error with a notice; usageLimitExceeded pauses the bot until the window's resetsAt. - bots.compact works for Codex: thread/compact/start through the wrapper; the compaction turn shows a notice and no turn line. - The owner's connected tools go in the thread's mcp_servers, secrets in place; a third-party tool's name is read from the request's message. Checked with the real codex: compaction through the daemon. --- app/src/features/chat/ContextMeter.tsx | 18 ++- app/src/features/chat/agentBot.test.tsx | 23 +++ app/src/i18n/en/chat.ts | 1 + app/src/i18n/es/chat.ts | 1 + app/src/i18n/pt-BR/chat.ts | 1 + crates/botloftd/src/agent/codex.rs | 4 + crates/botloftd/src/agent/codex_decoder.rs | 117 +++++++++++++- crates/botloftd/src/agent/codex_wire.rs | 71 +++++++-- crates/botloftd/src/agent/mod.rs | 9 ++ crates/botloftd/src/context/mod.rs | 32 ++-- crates/botloftd/src/supervisor/spawn.rs | 3 + crates/botloftd/src/workspace/connected.rs | 70 +++++++++ crates/botloftd/src/workspace/mod.rs | 2 +- crates/botloftd/tests/codex_bot.rs | 171 +++++++++++++++++++++ docs/spec.md | 7 +- 15 files changed, 497 insertions(+), 33 deletions(-) diff --git a/app/src/features/chat/ContextMeter.tsx b/app/src/features/chat/ContextMeter.tsx index 7ba43671..c21e6a27 100644 --- a/app/src/features/chat/ContextMeter.tsx +++ b/app/src/features/chat/ContextMeter.tsx @@ -39,6 +39,8 @@ export function ContextMeter({ bot, onLater }: { bot: Bot; onLater(text: string) const near = usedTokens >= limit * NEAR; const left = autoCompactTokens === null ? null : autoCompactTokens - usedTokens; const claude = bot.agent === "claude"; + // Claude Code and Codex answer a request to compact (spec 30). + const compactable = claude || bot.agent === "codex"; const running = bot.state === "idle" || bot.state === "busy" || bot.state === "needs_approval"; const compact = async () => { @@ -77,17 +79,19 @@ export function ContextMeter({ bot, onLater }: { bot: Bot; onLater(text: string) )}

- {!claude + {!compactable ? m.estimate - : left === null - ? m.noAuto - : left > 0 - ? m.autoLeft(tokens(left), tokens(autoCompactTokens ?? 0)) - : m.autoNow} + : bot.agent === "codex" + ? m.byItself + : left === null + ? m.noAuto + : left > 0 + ? m.autoLeft(tokens(left), tokens(autoCompactTokens ?? 0)) + : m.autoNow}

{m.about(bot.name)}

{/* Only Claude Code answers a request to compact (spec 30). */} - {claude && ( + {compactable && (