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
14 changes: 7 additions & 7 deletions tests/test_agent_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def test_agent_help_lists_command():
def test_list_voices_prints_and_exits_without_connecting(monkeypatch):
called = {"ran": False}

def fake_run_session(*a, **k):
def fake_run_session(api_key, *, renderer, player, mic, config):
called["ran"] = True

monkeypatch.setattr("aai_cli.commands.agent.run_session", fake_run_session)
Expand Down Expand Up @@ -61,7 +61,7 @@ def test_agent_unauthenticated_runs_login(monkeypatch):
monkeypatch.setattr("aai_cli.context.run_login_flow", _login_result)
monkeypatch.setattr("aai_cli.commands.agent.FileSource", lambda src: f"filesrc:{src}")

def fake_run_session(api_key, **_kwargs):
def fake_run_session(api_key, *, renderer, player, mic, config):
raise AssertionError(f"agent session should not run after auto-login: {api_key}")

monkeypatch.setattr("aai_cli.commands.agent.run_session", fake_run_session)
Expand Down Expand Up @@ -157,8 +157,8 @@ def _capture_run_session(monkeypatch):
"""Patch run_session to record its kwargs and return the dict it fills in."""
seen = {}

def fake_run_session(api_key, **kwargs):
seen.update(kwargs)
def fake_run_session(api_key, *, renderer, player, mic, config):
seen.update(renderer=renderer, player=player, mic=mic, config=config)

monkeypatch.setattr("aai_cli.commands.agent.run_session", fake_run_session)
return seen
Expand Down Expand Up @@ -227,7 +227,7 @@ def test_agent_file_source_no_start_talking_notice(monkeypatch, tmp_path):
monkeypatch.setattr("aai_cli.output.resolve_json", lambda *, explicit: False)
monkeypatch.setattr("aai_cli.commands.agent.FileSource", lambda src: "filesrc")

def fake_run_session(api_key, *, renderer, **kwargs):
def fake_run_session(api_key, *, renderer, player, mic, config):
renderer.connected() # session.ready arrives even for a file-driven run

monkeypatch.setattr("aai_cli.commands.agent.run_session", fake_run_session)
Expand Down Expand Up @@ -257,7 +257,7 @@ def close(self):

monkeypatch.setattr("aai_cli.commands.agent.DuplexAudio", FakeDuplex)

def fake_run_session(api_key, *, renderer, **kwargs):
def fake_run_session(api_key, *, renderer, player, mic, config):
renderer.connected()

monkeypatch.setattr("aai_cli.commands.agent.run_session", fake_run_session)
Expand Down Expand Up @@ -344,7 +344,7 @@ def test_agent_output_text_emits_plain_transcript(monkeypatch):
config.set_api_key("default", "sk_live")
monkeypatch.setattr("aai_cli.commands.agent.FileSource", lambda src: "filesrc")

def fake_run_session(api_key, *, renderer, **kwargs):
def fake_run_session(api_key, *, renderer, player, mic, config):
renderer.user_final("hello there")
renderer.agent_transcript("hi, how can I help?", interrupted=False)

Expand Down
6 changes: 4 additions & 2 deletions tests/test_coding_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def test_skill_presence_requires_skill_md(tmp_path):
def test_mcp_present_when_claude_mcp_get_succeeds(monkeypatch):
calls = []

def fake_run(cmd, **kwargs):
def fake_run(cmd, *, timeout=120):
calls.append(list(cmd))
return subprocess.CompletedProcess(args=cmd, returncode=0, stdout="", stderr="")

Expand All @@ -92,7 +92,9 @@ def test_mcp_absent_when_claude_mcp_get_fails(monkeypatch):
monkeypatch.setattr(
coding_agent,
"run",
lambda cmd, **kw: subprocess.CompletedProcess(args=cmd, returncode=1, stdout="", stderr=""),
lambda cmd, *, timeout=120: subprocess.CompletedProcess(
args=cmd, returncode=1, stdout="", stderr=""
),
)
assert coding_agent.mcp_present() is False

Expand Down
2 changes: 1 addition & 1 deletion tests/test_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ def test_run_command_auto_logs_in_when_env_key_set_but_error_is_not_a_rejection(
monkeypatch.setenv(config.ENV_API_KEY, "sk_env")
ran = {"login": 0}

def fake_login(**_kwargs):
def fake_login(*, json_mode=False):
ran["login"] += 1
return LoginResult(api_key="sk_auto", session_jwt="j", session_token="t", account_id=7)

Expand Down
6 changes: 3 additions & 3 deletions tests/test_deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,16 @@ def _stub(
monkeypatch.setattr("aai_cli.output.is_agentic", lambda: agentic)
calls: dict[str, object] = {}

def fake_confirm(prompt: str, *a: object, **k: object) -> bool:
def fake_confirm(prompt: str) -> bool:
calls["prompt"] = prompt
return confirm

monkeypatch.setattr("typer.confirm", fake_confirm)

def fake_run(cmd: list[str], **kwargs: object) -> types.SimpleNamespace:
def fake_run(cmd: list[str], *, cwd: Path, check: bool) -> types.SimpleNamespace:
runs = calls.setdefault("runs", [])
assert isinstance(runs, list)
runs.append({"cmd": cmd, "cwd": kwargs.get("cwd"), "check": kwargs.get("check")})
runs.append({"cmd": cmd, "cwd": cwd, "check": check})
return types.SimpleNamespace(returncode=returncode)

monkeypatch.setattr("aai_cli.commands.deploy.subprocess.run", fake_run)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_init_template_serve.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ def test_ask_failure_is_graceful(monkeypatch: pytest.MonkeyPatch) -> None:

@pytest.mark.parametrize("template", TOKEN_TEMPLATES)
def test_token_mints_token_and_ws_url(template: str, monkeypatch: pytest.MonkeyPatch) -> None:
def fake_get(*_args: object, **_kwargs: object) -> object:
def fake_get(url: str, *, params: object, headers: object) -> object:
return SimpleNamespace(raise_for_status=lambda: None, json=lambda: {"token": "tok-1"})

with serve(template) as (module, client):
Expand Down
10 changes: 8 additions & 2 deletions tests/test_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@
runner = CliRunner()


def _fake_login_result(key="sk_from_oauth", **_kwargs):
def _login_result(key="sk_from_oauth"):
return LoginResult(api_key=key, session_jwt="jwt_x", session_token="tok_x", account_id=7)


def _fake_login_result(*, json_mode=False):
return _login_result()


def test_login_with_api_key_flag_stores_key(mocker):
mocker.patch("aai_cli.commands.login.client.validate_key", autospec=True, return_value=True)
result = runner.invoke(app, ["login", "--api-key", "sk_flag", "--json"])
Expand Down Expand Up @@ -227,7 +231,9 @@ def test_login_binds_env_to_profile(monkeypatch):


def test_sandbox_flag_is_shortcut_for_env(monkeypatch):
monkeypatch.setattr("aai_cli.context.run_login_flow", lambda **_: _fake_login_result("sk_x"))
monkeypatch.setattr(
"aai_cli.context.run_login_flow", lambda *, json_mode=False: _login_result("sk_x")
)
result = runner.invoke(app, ["--sandbox", "login"])
assert result.exit_code == 0
assert config.get_profile_env("default") == "sandbox000"
Expand Down
2 changes: 1 addition & 1 deletion tests/test_login_guards.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
runner = CliRunner()


def _fake_login_result(key="sk_from_oauth", **_kwargs):
def _fake_login_result(key="sk_from_oauth"):
return LoginResult(api_key=key, session_jwt="jwt_x", session_token="tok_x", account_id=7)


Expand Down
4 changes: 2 additions & 2 deletions tests/test_macos_audio_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ def test_build_helper_compiles_to_cache(monkeypatch, tmp_path):
monkeypatch.setattr(macos, "user_cache_path", lambda _app: tmp_path)
seen = {}

def fake_run(cmd, **kwargs):
def fake_run(cmd, *, capture_output, text, check):
seen["cmd"] = cmd
seen["kwargs"] = kwargs
seen["kwargs"] = {"capture_output": capture_output, "text": text, "check": check}
Path(cmd[-1]).write_bytes(b"binary")
return types.SimpleNamespace(returncode=0, stderr="", stdout="")

Expand Down
32 changes: 28 additions & 4 deletions tests/test_onboard_sections.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,10 +254,32 @@ def test_build_path_scaffolds(ctx: WizardContext, monkeypatch: pytest.MonkeyPatc
calls = 0
seen: dict[str, object] = {}

def _fake_run_init(*a: object, **k: object) -> Path:
def _fake_run_init(
state: object,
*,
template: str | None,
directory: str | None,
no_install: bool,
no_open: bool,
force: bool,
here: bool,
port: int,
json_mode: bool,
launch: bool = True,
) -> Path:
nonlocal calls
calls += 1
seen.update(k)
seen.update(
template=template,
directory=directory,
no_install=no_install,
no_open=no_open,
force=force,
here=here,
port=port,
json_mode=json_mode,
launch=launch,
)
return Path("/scaffolded/app")

monkeypatch.setattr(init_cmd, "run_init", _fake_run_init)
Expand Down Expand Up @@ -354,9 +376,11 @@ def _spy_launch(monkeypatch: pytest.MonkeyPatch) -> dict[str, object]:
"""Replace init's launch_app with a recorder; returns the captured target + kwargs."""
captured: dict[str, object] = {}

def _fake_launch(target: Path, **k: object) -> None:
def _fake_launch(
target: Path, *, port: int, use_uv: bool, no_open: bool, json_mode: bool
) -> None:
captured["target"] = target
captured.update(k)
captured.update(port=port, use_uv=use_uv, no_open=no_open, json_mode=json_mode)

monkeypatch.setattr(init_cmd, "launch_app", _fake_launch)
return captured
Expand Down
2 changes: 1 addition & 1 deletion tests/test_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ def test_status_enters_spinner_when_not_json_and_not_quiet(monkeypatch):
entered = {"status": False}

@contextlib.contextmanager
def fake_status(*a, **k):
def fake_status(message):
entered["status"] = True
yield

Expand Down
46 changes: 26 additions & 20 deletions tests/test_stream_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@
runner = CliRunner()


def _drive_turns(
api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None, **_kwargs
):
def _drive_turns(api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None):
# Simulate the streaming client driving the renderer callbacks.
if on_begin:
on_begin(types.SimpleNamespace(id="sess"))
Expand Down Expand Up @@ -57,7 +55,7 @@ def test_stream_file_uses_filesource(monkeypatch, tmp_path):
seen = {}

def fake_stream_audio(
api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None, **_kwargs
api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None
):
seen["source_type"] = type(source).__name__
seen["rate"] = params.sample_rate
Expand Down Expand Up @@ -96,7 +94,9 @@ def __iter__(self):

order = []

def fake_stream_audio(api_key, source, *, params, on_begin=None, **_kwargs):
def fake_stream_audio(
api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None
):
if on_begin:
on_begin(types.SimpleNamespace(id="x")) # Begin must NOT print "Listening…"
order.append("begin")
Expand All @@ -114,7 +114,7 @@ def test_stream_file_shows_no_listening_notice(monkeypatch, tmp_path):
config.set_api_key("default", "sk_live")
monkeypatch.setattr("aai_cli.output.resolve_json", lambda *, explicit: False)

def fake(api_key, source, *, params, on_begin=None, **_kwargs):
def fake(api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None):
if on_begin:
on_begin(types.SimpleNamespace(id="x"))

Expand All @@ -136,7 +136,9 @@ def test_stream_unauthenticated_runs_login(monkeypatch):
monkeypatch.setattr("aai_cli.context._interactive_session", lambda: True)
monkeypatch.setattr("aai_cli.context.run_login_flow", _login_result)

def fake_stream_audio(api_key, source, *, params, **_kwargs):
def fake_stream_audio(
api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None
):
raise AssertionError(f"streaming should not start after auto-login: {api_key}")

monkeypatch.setattr("aai_cli.commands.stream.client.stream_audio", fake_stream_audio)
Expand All @@ -147,9 +149,7 @@ def fake_stream_audio(api_key, source, *, params, **_kwargs):


def _capture_source(seen):
def fake(
api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None, **_kwargs
):
def fake(api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None):
seen["source"] = source
seen["rate"] = params.sample_rate

Expand Down Expand Up @@ -222,9 +222,7 @@ def test_stream_file_json_output(monkeypatch, tmp_path):

config.set_api_key("default", "sk_live")

def fake(
api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None, **_kwargs
):
def fake(api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None):
# In non-follow mode begin/turn/termination must all be wired through to the
# renderer (pins the `follow is not None` None-vs-handler choices).
if on_begin:
Expand Down Expand Up @@ -253,7 +251,7 @@ def test_stream_prompt_biases_speech_model(monkeypatch):
config.set_api_key("default", "sk_live")
seen = {}

def fake(api_key, source, *, params, **kwargs):
def fake(api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None):
seen["prompt"] = params.prompt

monkeypatch.setattr("aai_cli.commands.stream.client.stream_audio", fake)
Expand All @@ -276,7 +274,7 @@ def test_stream_youtube_url_downloads_then_streams(monkeypatch, tmp_path):
monkeypatch.setattr("aai_cli.commands.stream.youtube.download_audio", lambda url, d: fake)
seen = {}

def fake_stream(api_key, source, *, params, **kwargs):
def fake_stream(api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None):
seen["source_type"] = type(source).__name__
seen["src"] = getattr(source, "source", None)

Expand All @@ -300,7 +298,7 @@ def test_stream_podcast_page_url_downloads_then_streams(monkeypatch, tmp_path):
monkeypatch.setattr("aai_cli.commands.stream.youtube.download_audio", lambda url, d: fake)
seen = {}

def fake_stream(api_key, source, *, params, **kwargs):
def fake_stream(api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None):
seen["source_type"] = type(source).__name__
seen["src"] = getattr(source, "source", None)

Expand Down Expand Up @@ -347,7 +345,9 @@ def test_stream_sample_rate_floor_accepts_one_for_stdin(monkeypatch):
config.set_api_key("default", "sk_live")
seen = {}

def fake_stream_audio(api_key, source, *, params, **_kwargs):
def fake_stream_audio(
api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None
):
seen["rate"] = params.sample_rate
b"".join(source) # drain the StdinSource

Expand All @@ -361,7 +361,9 @@ def test_stream_reads_raw_pcm_from_stdin(monkeypatch):
config.set_api_key("default", "sk_live")
seen = {}

def fake_stream_audio(api_key, source, *, params, on_begin=None, **_kwargs):
def fake_stream_audio(
api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None
):
seen["rate"] = params.sample_rate
seen["audio"] = b"".join(source) # consume the StdinSource

Expand Down Expand Up @@ -389,7 +391,9 @@ def __init__(self, *, target_rate=None, device=None, capture_rate=None, on_open=
def __iter__(self):
return iter([b"mic"])

def fake_stream_audio(api_key, source, *, params, **_kwargs):
def fake_stream_audio(
api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None
):
if type(source).__name__ == "FakeMic":
raise APIError("mic failed")
time.sleep(0.2)
Expand All @@ -406,7 +410,9 @@ def test_stream_output_text_emits_plain_finalized_turns(monkeypatch):
# `-o text` -> only finalized transcripts as plain stdout lines (pipe into assembly llm).
config.set_api_key("default", "sk_live")

def fake_stream_audio(api_key, source, *, params, on_begin=None, on_turn=None, **_kwargs):
def fake_stream_audio(
api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None
):
if on_turn:
on_turn(types.SimpleNamespace(transcript="partial", end_of_turn=False))
on_turn(types.SimpleNamespace(transcript="hello world", end_of_turn=True))
Expand Down
4 changes: 3 additions & 1 deletion tests/test_stream_command_flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ def test_stream_maps_turn_detection_flags(monkeypatch):
config.set_api_key("default", "sk_live")
captured = {}

def fake_stream_audio(api_key, source, *, params, **kw):
def fake_stream_audio(
api_key, source, *, params, on_begin=None, on_turn=None, on_termination=None
):
captured["params"] = params

monkeypatch.setattr("aai_cli.commands.stream.client.stream_audio", fake_stream_audio)
Expand Down
Loading
Loading