Skip to content
Open
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
12 changes: 10 additions & 2 deletions src/cli_agent_orchestrator/providers/codex.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,16 @@
# ASSISTANT_PREFIX_PATTERN and the TUI footer › matches idle prompt).
TUI_PROGRESS_PATTERN = r"•.*\(\d+s\s*•\s*esc to interrupt\)"

# Workspace trust/approval prompt shown when Codex opens a new directory
TRUST_PROMPT_PATTERN = r"allow Codex to work in this folder"
# Workspace trust/approval prompt shown when Codex opens a new directory.
# codex-cli has reworded this dialog across versions, so match either phrasing:
# older: "… allow Codex to work in this folder without asking for approval"
# 0.144.1: "Do you trust the contents of this directory? … › 1. Yes, continue"
# A stale single-phrase pattern silently stops matching on a CLI update, which
# lets the worker hang on the unanswered prompt (it never auto-accepts).
TRUST_PROMPT_PATTERN = (
r"allow Codex to work in this folder"
r"|Do you trust the contents of this (?:directory|folder)"
)
# Codex welcome banner indicating normal startup (no trust prompt)
CODEX_WELCOME_PATTERN = r"OpenAI Codex"

Expand Down
40 changes: 40 additions & 0 deletions test/providers/test_codex_provider_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1482,6 +1482,32 @@ async def test_handle_trust_prompt_detected_and_accepted(self, mock_tmux):
"test-session", "window-0", "Enter"
)

@pytest.mark.asyncio
@patch("cli_agent_orchestrator.providers.codex.get_backend")
async def test_handle_trust_prompt_detected_and_accepted_new_wording(self, mock_tmux):
"""codex-cli reworded the trust dialog (observed on 0.144.1): "Do you
trust the contents of this directory? … › 1. Yes, continue / 2. No,
quit". The handler must still detect it and auto-accept, otherwise the
worker hangs on the unanswered prompt until it times out.
"""
mock_tmux.return_value.get_history.return_value = (
"> You are in /Users/test/project\n"
"\n"
" Do you trust the contents of this directory? Working with "
"untrusted contents comes with higher risk of prompt injection. "
"Trusting the directory allows project-local config, hooks, and "
"exec policies to load.\n"
"› 1. Yes, continue\n"
" 2. No, quit\n"
)

provider = CodexProvider("test1234", "test-session", "window-0")
await provider._handle_trust_prompt(timeout=2.0)

mock_tmux.return_value.send_special_key.assert_called_once_with(
"test-session", "window-0", "Enter"
)

@pytest.mark.asyncio
@patch("cli_agent_orchestrator.providers.codex.get_backend")
async def test_handle_trust_prompt_not_needed(self, mock_tmux):
Expand All @@ -1507,6 +1533,20 @@ def test_get_status_trust_prompt_is_waiting_user_answer(self):
# Should be WAITING_USER_ANSWER (not PROCESSING despite "running" in text)
assert status == TerminalStatus.WAITING_USER_ANSWER

def test_get_status_trust_prompt_new_wording_is_waiting_user_answer(self):
"""The reworded trust dialog (codex-cli 0.144.1) must also report
WAITING_USER_ANSWER so the terminal isn't mistaken for PROCESSING."""
output = (
"> You are in /Users/test/project\n"
"Do you trust the contents of this directory?\n"
"› 1. Yes, continue\n"
)

provider = CodexProvider("test1234", "test-session", "window-0")
status = provider.get_status(output)

assert status == TerminalStatus.WAITING_USER_ANSWER

@pytest.mark.asyncio
@patch("cli_agent_orchestrator.providers.codex.wait_until_status")
@patch("cli_agent_orchestrator.providers.codex.wait_for_shell")
Expand Down
Loading