Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
|
||||
from hermes_cli import setup as setup_mod
|
||||
|
||||
|
||||
def test_prompt_choice_escape_keeps_default_without_numbered_fallback(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
setup_mod,
|
||||
"_curses_prompt_choice",
|
||||
lambda question, choices, default=0, description=None: -1,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"builtins.input",
|
||||
lambda *_args, **_kwargs: (_ for _ in ()).throw(
|
||||
AssertionError("Escape must not enter the numbered fallback")
|
||||
),
|
||||
)
|
||||
|
||||
assert setup_mod.prompt_choice("Pick one", ["a", "b"], default=1) == 1
|
||||
|
||||
|
||||
def test_setup_navigation_escape_cancels_and_left_goes_back():
|
||||
state = setup_mod._SetupNavigationState(section_index=1)
|
||||
token = setup_mod._SETUP_NAVIGATION.set(state)
|
||||
try:
|
||||
assert setup_mod._handle_setup_menu_navigation(
|
||||
setup_mod.MenuNavigationEvent.BEGIN
|
||||
).allow_back is True
|
||||
with pytest.raises(setup_mod._SetupCancelled):
|
||||
setup_mod._handle_setup_menu_navigation(
|
||||
setup_mod.MenuNavigationEvent.CANCEL
|
||||
)
|
||||
|
||||
assert setup_mod._handle_setup_menu_navigation(
|
||||
setup_mod.MenuNavigationEvent.BEGIN
|
||||
).allow_back is True
|
||||
with pytest.raises(setup_mod._SetupGoBack) as exc_info:
|
||||
setup_mod._handle_setup_menu_navigation(setup_mod.MenuNavigationEvent.BACK)
|
||||
assert exc_info.value.prompt_index == 1
|
||||
finally:
|
||||
setup_mod._SETUP_NAVIGATION.reset(token)
|
||||
|
||||
|
||||
def test_setup_yes_no_uses_navigable_menu(monkeypatch):
|
||||
calls = []
|
||||
state = setup_mod._SetupNavigationState(section_index=1)
|
||||
token = setup_mod._SETUP_NAVIGATION.set(state)
|
||||
monkeypatch.setattr(
|
||||
setup_mod,
|
||||
"_curses_prompt_choice",
|
||||
lambda question, choices, default=0, description=None: calls.append(
|
||||
(question, choices, default)
|
||||
)
|
||||
or 1,
|
||||
)
|
||||
try:
|
||||
assert setup_mod.prompt_yes_no("Enable it?", default=True) is False
|
||||
finally:
|
||||
setup_mod._SETUP_NAVIGATION.reset(token)
|
||||
|
||||
assert calls == [("Enable it?", ["Yes", "No"], 0)]
|
||||
|
||||
|
||||
def test_setup_steps_move_to_previous_section_or_restart_current_section():
|
||||
calls = []
|
||||
terminal_attempts = 0
|
||||
gateway_attempts = 0
|
||||
|
||||
def model():
|
||||
calls.append("model")
|
||||
|
||||
def terminal():
|
||||
nonlocal terminal_attempts
|
||||
calls.append("terminal")
|
||||
terminal_attempts += 1
|
||||
if terminal_attempts == 1:
|
||||
raise setup_mod._SetupGoBack(prompt_index=0)
|
||||
|
||||
def gateway():
|
||||
nonlocal gateway_attempts
|
||||
calls.append("gateway")
|
||||
gateway_attempts += 1
|
||||
if gateway_attempts == 1:
|
||||
raise setup_mod._SetupGoBack(prompt_index=1)
|
||||
|
||||
state = setup_mod._SetupNavigationState()
|
||||
token = setup_mod._SETUP_NAVIGATION.set(state)
|
||||
try:
|
||||
setup_mod._run_setup_steps(
|
||||
[("Model", model), ("Terminal", terminal), ("Gateway", gateway)]
|
||||
)
|
||||
finally:
|
||||
setup_mod._SETUP_NAVIGATION.reset(token)
|
||||
|
||||
assert calls == [
|
||||
"model",
|
||||
"terminal",
|
||||
"model",
|
||||
"terminal",
|
||||
"gateway",
|
||||
"gateway",
|
||||
]
|
||||
|
||||
|
||||
def test_nested_back_reopens_only_the_immediately_previous_prompt():
|
||||
shown = []
|
||||
attempts = 0
|
||||
|
||||
def model_provider_flow():
|
||||
nonlocal attempts
|
||||
attempts += 1
|
||||
for label in ("provider", "auth method", "existing or reauthenticate"):
|
||||
start = setup_mod._handle_setup_menu_navigation(
|
||||
setup_mod.MenuNavigationEvent.BEGIN
|
||||
)
|
||||
if start.should_replay:
|
||||
setup_mod._handle_setup_menu_navigation(
|
||||
setup_mod.MenuNavigationEvent.RESOLVE, start.replay_value
|
||||
)
|
||||
continue
|
||||
shown.append(label)
|
||||
if label == "existing or reauthenticate" and attempts == 1:
|
||||
setup_mod._handle_setup_menu_navigation(
|
||||
setup_mod.MenuNavigationEvent.BACK
|
||||
)
|
||||
setup_mod._handle_setup_menu_navigation(
|
||||
setup_mod.MenuNavigationEvent.RESOLVE, label
|
||||
)
|
||||
|
||||
state = setup_mod._SetupNavigationState()
|
||||
token = setup_mod._SETUP_NAVIGATION.set(state)
|
||||
try:
|
||||
setup_mod._run_setup_steps([("Model & Provider", model_provider_flow)])
|
||||
finally:
|
||||
setup_mod._SETUP_NAVIGATION.reset(token)
|
||||
|
||||
assert shown[:4] == [
|
||||
"provider",
|
||||
"auth method",
|
||||
"existing or reauthenticate",
|
||||
"auth method",
|
||||
]
|
||||
|
||||
|
||||
def test_section_specific_model_setup_can_go_back_from_model_to_provider(
|
||||
tmp_path, monkeypatch
|
||||
):
|
||||
"""``hermes setup model`` must retain nested setup navigation."""
|
||||
shown = []
|
||||
attempts = 0
|
||||
|
||||
def model_flow(_config):
|
||||
nonlocal attempts
|
||||
attempts += 1
|
||||
for label in ("provider", "model"):
|
||||
start = setup_mod._handle_setup_menu_navigation(
|
||||
setup_mod.MenuNavigationEvent.BEGIN
|
||||
)
|
||||
if start.should_replay:
|
||||
setup_mod._handle_setup_menu_navigation(
|
||||
setup_mod.MenuNavigationEvent.RESOLVE, start.replay_value
|
||||
)
|
||||
continue
|
||||
shown.append(label)
|
||||
if label == "model" and attempts == 1:
|
||||
# This is what the menu does for Left: it only dispatches the
|
||||
# back event when its setup context enables ``← previous``.
|
||||
if start.allow_back:
|
||||
setup_mod._handle_setup_menu_navigation(
|
||||
setup_mod.MenuNavigationEvent.BACK
|
||||
)
|
||||
return
|
||||
setup_mod._handle_setup_menu_navigation(
|
||||
setup_mod.MenuNavigationEvent.RESOLVE, label
|
||||
)
|
||||
|
||||
monkeypatch.setenv("HERMES_HOME", str(tmp_path))
|
||||
monkeypatch.setattr(setup_mod, "is_interactive_stdin", lambda: True)
|
||||
monkeypatch.setattr(
|
||||
setup_mod,
|
||||
"SETUP_SECTIONS",
|
||||
[("model", "Model & Provider", model_flow)],
|
||||
)
|
||||
|
||||
setup_mod.run_setup_wizard(
|
||||
SimpleNamespace(
|
||||
section="model",
|
||||
reset=False,
|
||||
reconfigure=False,
|
||||
quick=False,
|
||||
portal=False,
|
||||
non_interactive=False,
|
||||
)
|
||||
)
|
||||
|
||||
assert shown == ["provider", "model", "provider", "model"]
|
||||
|
||||
|
||||
def test_prompt_strips_bracketed_paste_markers(monkeypatch):
|
||||
monkeypatch.setattr(
|
||||
"builtins.input",
|
||||
lambda _prompt="": "\x1b[200~sk-ant-api-key\x1b[201~",
|
||||
)
|
||||
|
||||
value = setup_mod.prompt("API key")
|
||||
|
||||
assert value == "sk-ant-api-key"
|
||||
|
||||
|
||||
|
||||
|
||||
def test_prompt_choice_uses_curses_helper(monkeypatch):
|
||||
monkeypatch.setattr(setup_mod, "_curses_prompt_choice", lambda question, choices, default=0, description=None: 1)
|
||||
|
||||
idx = setup_mod.prompt_choice("Pick one", ["a", "b", "c"], default=0)
|
||||
|
||||
assert idx == 1
|
||||
Reference in New Issue
Block a user