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
26 changes: 19 additions & 7 deletions agent/telegram_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -1456,9 +1456,20 @@ def label(text: str, active: bool) -> str:
"text": label(model.replace("gpt-", ""), current_model == model),
"callback_data": f"codex_model:model:{model}",
})
effort_labels = {
"low": "Fast",
"medium": "Medium",
"high": "High",
"xhigh": "XHigh",
}
effort_row = [
{
"text": label(effort.title(), current_effort == effort),
"text": label("Default", not current_effort),
"callback_data": "codex_model:effort:default",
}
] + [
{
"text": label(effort_labels[effort], current_effort == effort),
"callback_data": f"codex_model:effort:{effort}",
}
for effort in CODEX_REASONING_EFFORTS
Expand Down Expand Up @@ -5524,6 +5535,8 @@ def handle(self, msg: dict) -> None:
thread_id,
)
cmd, arg = _parse_command(text)
if not cmd and text.strip().lower() == "fast":
cmd = "/fast"

# `/terminal` — owner-only mode switch. Spawns a persistent bash
# in this lane; from this point on plain-text messages route to
Expand Down Expand Up @@ -5708,7 +5721,7 @@ def handle(self, msg: dict) -> None:
# are stdin for it (codex login codes, gh auth login codes, `read`
# answers, `y/n` prompts, …). Slash commands fall through below
# so the user can still `/cancel`, `/queue`, etc.
if not text.startswith("/"):
if not text.startswith("/") and cmd not in {"/fast"}:
goal_entry = _goal_state_for(self.state, slug)
if goal_entry is None and _is_owner(sender, owner) and _wait_for_goal_start(slug):
goal_entry = _goal_state_for(self.state, slug)
Expand Down Expand Up @@ -6035,7 +6048,6 @@ def handle(self, msg: dict) -> None:
reply_to=mid,
thread_id=thread_id,
markdown=True,
reply_markup=_codex_model_picker_markup(settings),
)
return
if cmd == "/model":
Expand Down Expand Up @@ -6475,7 +6487,6 @@ def _cmd_codex_model(
reply_to=reply_to,
thread_id=thread_id,
markdown=True,
reply_markup=_codex_model_picker_markup(settings),
)
return

Expand Down Expand Up @@ -7459,9 +7470,10 @@ def _handle_codex_model_callback(self, cb: dict, data: str) -> None:
model = "" if value == "default" else value
settings = _set_codex_settings(key, self.state, model=model)
toast = "Model updated"
elif action == "effort" and value in CODEX_REASONING_EFFORTS:
settings = _set_codex_settings(key, self.state, reasoning_effort=value)
toast = f"Effort: {value}"
elif action == "effort" and (value == "default" or value in CODEX_REASONING_EFFORTS):
effort = "" if value == "default" else value
settings = _set_codex_settings(key, self.state, reasoning_effort=effort)
toast = "Effort default" if value == "default" else f"Effort: {value}"
else:
self.call(
"answerCallbackQuery",
Expand Down
34 changes: 34 additions & 0 deletions agent/test_telegram_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def test_model_picker_marks_current_choices(self) -> None:
]
self.assertIn("✓ 5.4", labels)
self.assertIn("✓ High", labels)
self.assertIn("Fast", labels)
self.assertIn("Reset Codex defaults", labels)

def test_model_picker_callback_updates_effort_in_place(self) -> None:
Expand Down Expand Up @@ -116,6 +117,39 @@ def fake_call(method: str, **kwargs):
self.assertEqual(bot.state["agents"]["100_123"], "codex")
self.assertTrue(any(method == "editMessageText" for method, _ in calls))

def test_plain_fast_switches_codex_effort(self) -> None:
sent: list[tuple[str, dict]] = []
bot = telegram_bot.Bot.__new__(telegram_bot.Bot)
bot.state = {"offset": 0, "agents": {}, "codex_settings": {}, "owners": {}}
bot.setup_token = None
bot._username = "bux_bot"
bot.react = lambda *_args, **_kwargs: None # type: ignore[method-assign]
bot.typing = lambda *_args, **_kwargs: None # type: ignore[method-assign]
bot.send = lambda _chat, text, **kwargs: sent.append((text, kwargs)) # type: ignore[method-assign]

with (
mock.patch.object(telegram_bot, "load_allow", return_value={100}),
mock.patch.object(telegram_bot, "save_state"),
mock.patch.object(telegram_bot, "_get_shell_session", return_value=None),
mock.patch.object(telegram_bot, "_goal_state_for", return_value=None),
):
bot.handle(
{
"chat": {"id": 100, "type": "private"},
"from": {"id": 55, "username": "Magnus_Mueller"},
"message_id": 123,
"text": "fast",
}
)

self.assertEqual(bot.state["agents"]["100_main"], "codex")
self.assertEqual(
bot.state["codex_settings"]["100_main"],
{"reasoning_effort": "low"},
)
self.assertIn("Fast mode on.", sent[-1][0])
self.assertNotIn("reply_markup", sent[-1][1])

def test_codex_goal_feature_enablement_is_idempotent(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
config = Path(tmp) / "config.toml"
Expand Down
Loading