Clean up on Google AI Studio, or on Antigravity

OpenRouter's free tier rate-limits and carries no free Gemini model, and
cleaning up through Claude Code costs a fixed few seconds because it opens
a whole CLI session to drop three "uh"s. Google's own free tier suits a
short, frequent request, and its OpenAI-compatible endpoint answers
/chat/completions, so cleanup there is one request and the same code path
OpenRouter already takes.

The one thing that is not shared is the thinking level. Google reads
OpenAI's flat reasoning_effort rather than OpenRouter's object, and "none"
is how thinking is turned off, so it is sent rather than skipped: a Flash
model left to think spends exactly the second this provider was chosen to
save. Its top two rungs land on "high", which is as far as Google goes.

Speech to text stays where it was. That endpoint has no
/audio/transcriptions behind it, audio only goes in as base64 inside a
chat message, and what comes back has none of the segment times a subtitle
file or a meeting transcript is built out of.

Antigravity joins as well, on cleanup and as an agent. It is a CLI like the
other two and costs the same session, so it is here for people who already
pay for it rather than as an answer to the speed. It takes neither an empty
tool list nor a read-only sandbox, and cleanup.py now says so plainly
instead of implying parity; what it gets is a project of its own, the home
directory, and its slash commands off.

Three things were already wrong and are fixed on the way past, because the
new providers walk the same paths: doctor raised KeyError on the local
model, whose executable is ""; the history recorded Claude's model whoever
answered; and every agent row read "asked Claude".

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
oztturk
2026-08-26 16:23:04 +03:00
co-authored by Claude Opus 5
parent 3663c7fd57
commit 1812461612
16 changed files with 901 additions and 122 deletions
+65
View File
@@ -384,6 +384,37 @@ class Cleanup(DikteTest):
self.assertEqual(sent_json(calls[0])["reasoning"],
{"effort": "high", "exclude": True})
def test_gemini_takes_openai_s_flat_field_rather_than_the_object(self):
_, calls = self.call(chat_reply("Hello."), reasoning="low",
provider="gemini", service="Google AI Studio")
payload = sent_json(calls[0])
self.assertEqual(payload["reasoning_effort"], "low")
self.assertNotIn("reasoning", payload)
def test_gemini_is_told_to_stop_thinking_rather_than_left_alone(self):
""""none" is the one level worth sending: Flash thinks by default."""
_, calls = self.call(chat_reply("Hello."), reasoning="none",
provider="gemini", service="Google AI Studio")
self.assertEqual(sent_json(calls[0])["reasoning_effort"], "none")
def test_a_rung_google_does_not_have_lands_on_the_nearest_one(self):
for asked in ("xhigh", "max"):
with self.subTest(asked=asked):
_, calls = self.call(chat_reply("Hello."), reasoning=asked,
provider="gemini", service="Google AI Studio")
self.assertEqual(sent_json(calls[0])["reasoning_effort"], "high")
def test_gemini_left_on_the_model_s_own_default_is_told_nothing(self):
_, calls = self.call(chat_reply("Hello."), provider="gemini",
service="Google AI Studio")
self.assertNotIn("reasoning_effort", sent_json(calls[0]))
def test_a_missing_gemini_key_says_google_ai_studio(self):
with self.assertRaises(api.ApiError) as caught:
api.cleanup("hello", "", "gemini-3.5-flash-lite", "prompt",
provider="gemini", service="Google AI Studio")
self.assertIn("Google AI Studio", str(caught.exception))
def test_a_local_base_url(self):
_, calls = self.call(chat_reply("Hello."), base_url="http://localhost:1234/v1")
self.assertEqual(calls[0].full_url, "http://localhost:1234/v1/chat/completions")
@@ -513,6 +544,40 @@ class ModelLists(DikteTest):
api.openai_models("", api.GROQ_URL, "Groq")
self.assertIn("Groq", str(caught.exception))
def test_gemini_keeps_only_the_models_that_answer_a_chat_request(self):
with fake_urlopen({"data": [{"id": "gemini-3.5-flash"},
{"id": "text-embedding-004"},
{"id": "imagen-4.0"},
{"id": "gemini-2.5-flash-lite"}]}) as calls:
models = api.gemini_models("AIza-test")
self.assertEqual(calls[0].full_url,
"https://generativelanguage.googleapis.com/v1beta/openai/models")
self.assertEqual(models, ["gemini-2.5-flash-lite", "gemini-3.5-flash"])
def test_the_long_form_of_an_id_is_shortened_to_what_a_request_wants(self):
with fake_urlopen({"data": [{"id": "models/gemini-3.5-flash-lite"}]}):
self.assertEqual(api.gemini_models("AIza-test"),
["gemini-3.5-flash-lite"])
def test_a_gemini_id_that_is_not_a_chat_model_is_left_out(self):
"""Google names its pictures and its voices `gemini` too."""
with fake_urlopen({"data": [{"id": "gemini-3.5-flash"},
{"id": "gemini-embedding-001"},
{"id": "gemini-2.5-flash-image"},
{"id": "gemini-2.5-flash-preview-tts"},
{"id": "gemini-2.5-native-audio"}]}):
self.assertEqual(api.gemini_models("AIza-test"), ["gemini-3.5-flash"])
def test_gemini_sends_the_key_as_a_bearer_token(self):
with fake_urlopen({"data": []}) as calls:
api.gemini_models("AIza-test")
self.assertEqual(calls[0].get_header("Authorization"), "Bearer AIza-test")
def test_a_missing_gemini_key_says_google_ai_studio(self):
with self.assertRaises(api.ApiError) as caught:
api.gemini_models("")
self.assertIn("Google AI Studio", str(caught.exception))
if __name__ == "__main__":
unittest.main()
+160 -24
View File
@@ -58,15 +58,36 @@ class Provider(DikteTest):
def test_what_each_one_runs(self):
self.assertEqual(assistant.executable("claude"), "claude")
self.assertEqual(assistant.executable("codex"), "codex")
self.assertEqual(assistant.executable("agy"), "agy")
self.assertEqual(assistant.executable("openrouter"), "")
def test_the_model_recorded_is_the_one_that_answered(self):
"""The history used to write Claude's setting whoever had answered."""
self.assertEqual(assistant.model(self.config()), "sonnet")
self.assertEqual(
assistant.model(self.config(assistant_provider="codex")), "codex")
self.assertEqual(
assistant.model(self.config(assistant_provider="agy")), "agy")
self.assertEqual(
assistant.model(self.config(assistant_provider="agy",
assistant_agy_model="gemini-3.1-pro-low")),
"gemini-3.1-pro-low")
self.assertEqual(
assistant.model(self.config(assistant_provider="openrouter")),
"google/gemini-3.5-flash")
def test_what_each_one_is_called(self):
self.assertEqual(assistant.display_name(self.config()), "Claude")
self.assertEqual(
assistant.display_name(self.config(assistant_provider="codex")), "Codex")
self.assertEqual(
assistant.display_name(self.config(assistant_provider="openrouter")),
"OpenRouter")
for name, called in (("codex", "Codex"), ("agy", "Antigravity"),
("openrouter", "OpenRouter")):
with self.subTest(name=name):
self.assertEqual(
assistant.display_name(self.config(assistant_provider=name)),
called)
def test_every_provider_has_a_name_to_be_called_by(self):
"""_conclude writes its errors in it, so a gap here is a bare id."""
self.assertEqual(set(assistant.SERVICES), set(assistant.PROVIDERS))
class Effort(unittest.TestCase):
@@ -74,21 +95,26 @@ class Effort(unittest.TestCase):
def test_the_scales_cover_the_same_settings(self):
self.assertEqual(set(assistant.CLAUDE_EFFORT), set(assistant.CODEX_EFFORT))
self.assertEqual(set(assistant.CLAUDE_EFFORT), set(assistant.AGY_EFFORT))
def test_codex_has_no_rung_above_high(self):
self.assertEqual(assistant.CODEX_EFFORT["xhigh"], "high")
self.assertEqual(assistant.CODEX_EFFORT["max"], "high")
def test_neither_codex_nor_agy_has_a_rung_above_high(self):
for scale in (assistant.CODEX_EFFORT, assistant.AGY_EFFORT):
self.assertEqual(scale["xhigh"], "high")
self.assertEqual(scale["max"], "high")
def test_neither_one_asks_for_a_rung_below_low(self):
def test_none_of_them_asks_for_a_rung_below_low(self):
# Claude has none; Codex has one, but calls it "minimal" on the older
# models and "none" on the newer ones, and refuses the wrong word.
for scale in (assistant.CLAUDE_EFFORT, assistant.CODEX_EFFORT):
# models and "none" on the newer ones, and refuses the wrong word; agy
# has three rungs and no word for off at all.
for scale in (assistant.CLAUDE_EFFORT, assistant.CODEX_EFFORT,
assistant.AGY_EFFORT):
self.assertEqual(scale["none"], "low")
self.assertEqual(scale["minimal"], "low")
def test_an_empty_setting_asks_for_nothing(self):
self.assertEqual(assistant.CLAUDE_EFFORT.get("", ""), "")
self.assertEqual(assistant.CODEX_EFFORT.get("", ""), "")
for scale in (assistant.CLAUDE_EFFORT, assistant.CODEX_EFFORT,
assistant.AGY_EFFORT):
self.assertEqual(scale.get("", ""), "")
class Session(DikteTest):
@@ -249,45 +275,52 @@ class Conclude(DikteTest):
def test_an_answer_and_its_session(self):
answer, warning = assistant._conclude(
self.found(answer="done", session="abc"), 0, "", "", "Claude")
self.found(answer="done", session="abc"), 0, "", "", "claude")
self.assertEqual(answer, "done")
self.assertEqual(warning, "")
self.assertEqual(assistant.read_session("claude", 1800), "abc")
def test_codex_stores_under_its_own_name(self):
assistant._conclude(self.found(answer="done", session="t-1"), 0, "",
"", "Codex")
self.assertEqual(assistant.read_session("codex", 1800), "t-1")
def test_each_one_stores_under_its_own_name(self):
for name, session in (("codex", "t-1"), ("agy", "c-9")):
with self.subTest(name=name):
assistant._conclude(self.found(answer="done", session=session),
0, "", "", name)
self.assertEqual(assistant.read_session(name, 1800), session)
def test_the_error_is_written_in_the_provider_s_own_name(self):
with self.assertRaises(assistant.AssistantError) as caught:
assistant._conclude(self.found(), 1, "", "", "agy")
self.assertIn("Antigravity", str(caught.exception))
def test_a_non_zero_exit_with_nothing_to_show_for_it(self):
with self.assertRaises(assistant.AssistantError) as caught:
assistant._conclude(self.found(), 1, "it all went wrong\n", "", "Claude")
assistant._conclude(self.found(), 1, "it all went wrong\n", "", "claude")
self.assertIn("it all went wrong", str(caught.exception))
def test_a_session_that_is_gone_is_raised_apart(self):
with self.assertRaises(assistant._SessionGone):
assistant._conclude(self.found(), 1, "session abc not found",
"abc", "Claude")
"abc", "claude")
def test_a_session_that_is_gone_only_matters_when_one_was_resumed(self):
with self.assertRaises(assistant.AssistantError):
assistant._conclude(self.found(), 1, "session abc not found",
"", "Claude")
"", "claude")
def test_an_answer_survives_a_non_zero_exit(self):
answer, _ = assistant._conclude(self.found(answer="done"), 1, "noise",
"", "Claude")
"", "claude")
self.assertEqual(answer, "done")
def test_a_reported_failure_with_no_answer(self):
with self.assertRaises(assistant.AssistantError) as caught:
assistant._conclude(self.found(failure="the model refused"), 0, "",
"", "Claude")
"", "claude")
self.assertIn("refused", str(caught.exception))
def test_a_run_that_said_nothing_at_all(self):
with self.assertRaises(assistant.AssistantError) as caught:
assistant._conclude(self.found(), 0, "", "", "Codex")
assistant._conclude(self.found(), 0, "", "", "codex")
self.assertIn("Codex", str(caught.exception))
@@ -472,6 +505,109 @@ class AskCodex(DikteTest):
self.assertIn("quota", str(caught.exception))
class AskAgy(DikteTest):
"""agy's stream is shaped nothing like the other two: the key is `event`,
the answer arrives whole in `result.response`, and the conversation to
resume is named in the first line rather than the last."""
def run_ask(self, conf=None, events=None, session=""):
conf = conf or self.config(assistant_provider="agy")
proc = FakeCli(events or [
{"event": "init", "conversation_id": "c-9", "init": {"cwd": "/home"}},
{"event": "result",
"result": {"conversation_id": "c-9", "status": "SUCCESS",
"response": " done "}},
])
stages = []
with only_these_tools("agy"), \
mock.patch.object(subprocess, "Popen", return_value=proc) as popen:
result = assistant._ask_agy("book it", conf, session,
stages.append, None)
return result, popen.call_args.args[0], stages
def test_the_answer_comes_back_stripped(self):
(answer, warning), _, _ = self.run_ask()
self.assertEqual(answer, "done")
self.assertEqual(warning, "")
def test_the_instruction_is_kept_apart_from_the_command(self):
"""agy takes no system prompt, so the two must not read as one."""
conf = self.config(assistant_provider="agy")
_, cmd, _ = self.run_ask(conf)
body = cmd[cmd.index("-p") + 1]
self.assertTrue(body.startswith(conf.assistant_prompt()))
self.assertIn("\n\n---\n\n", body)
self.assertTrue(body.endswith("book it"))
def test_a_first_command_starts_a_project_of_its_own(self):
"""Without it agy works in whichever project it was last in."""
_, cmd, _ = self.run_ask()
self.assertIn("--new-project", cmd)
self.assertNotIn("--conversation", cmd)
def test_a_second_command_carries_the_conversation_rather_than_starting_one(self):
_, cmd, _ = self.run_ask(session="c-9")
self.assertEqual(cmd[cmd.index("--conversation") + 1], "c-9")
self.assertNotIn("--new-project", cmd)
def test_the_conversation_is_kept_under_agy_s_own_name(self):
self.run_ask()
self.assertEqual(assistant.read_session("agy", 1800), "c-9")
def test_it_is_not_left_to_give_up_before_the_caller_does(self):
conf = self.config(assistant_provider="agy", assistant_timeout=90)
_, cmd, _ = self.run_ask(conf)
self.assertEqual(cmd[cmd.index("--print-timeout") + 1], "90s")
def test_no_model_named_means_whatever_agy_is_set_to(self):
_, cmd, _ = self.run_ask()
self.assertNotIn("--model", cmd)
def test_a_model_of_your_own(self):
_, cmd, _ = self.run_ask(
self.config(assistant_provider="agy",
assistant_agy_model="gemini-3.1-pro-low"))
self.assertEqual(cmd[cmd.index("--model") + 1], "gemini-3.1-pro-low")
def test_a_tool_is_named_in_the_corner_as_it_starts(self):
_, _, stages = self.run_ask(events=[
{"event": "step_update",
"step_update": {"step_type": "tool", "state": "ACTIVE",
"tool_name": "run_command"}},
{"event": "step_update",
"step_update": {"step_type": "tool", "state": "DONE",
"tool_name": "run_command"}},
{"event": "result",
"result": {"status": "SUCCESS", "response": "done"}},
])
self.assertEqual(stages, ["Running a command…"])
def test_the_two_dozen_browser_tools_are_one_line_between_them(self):
_, _, stages = self.run_ask(events=[
{"event": "step_update",
"step_update": {"step_type": "tool", "state": "ACTIVE",
"tool_name": "browser_click_element"}},
{"event": "result",
"result": {"status": "SUCCESS", "response": "done"}},
])
self.assertEqual(stages, ["Working in the browser…"])
def test_a_turn_that_did_not_succeed_is_a_failure_rather_than_an_answer(self):
with self.assertRaises(assistant.AssistantError) as caught:
self.run_ask(events=[
{"event": "result",
"result": {"status": "ERROR", "response": "the model refused"}},
])
self.assertIn("refused", str(caught.exception))
def test_a_failure_with_nothing_to_say_is_still_named(self):
with self.assertRaises(assistant.AssistantError) as caught:
self.run_ask(events=[
{"event": "result", "result": {"status": "ERROR"}},
])
self.assertIn("Antigravity", str(caught.exception))
class AskOpenRouter(DikteTest):
def test_a_question_and_an_answer(self):
conf = self.config(assistant_provider="openrouter",
+109
View File
@@ -49,7 +49,9 @@ class Provider(DikteTest):
def test_what_each_one_runs(self):
self.assertEqual(cleanup.executable("claude"), "claude")
self.assertEqual(cleanup.executable("codex"), "codex")
self.assertEqual(cleanup.executable("agy"), "agy")
self.assertEqual(cleanup.executable("openrouter"), "")
self.assertEqual(cleanup.executable("gemini"), "")
def test_the_model_named_in_the_history_is_the_one_that_did_it(self):
self.assertEqual(cleanup.model(self.config(cleanup_model="some/model")),
@@ -65,6 +67,16 @@ class Provider(DikteTest):
self.assertEqual(
cleanup.model(self.config(cleanup_provider="codex",
cleanup_codex_model="gpt-5.4")), "gpt-5.4")
self.assertEqual(
cleanup.model(self.config(cleanup_provider="gemini")),
"gemini-3.5-flash-lite")
# Antigravity is left on its own default the way Codex is.
self.assertEqual(
cleanup.model(self.config(cleanup_provider="agy")), "agy")
self.assertEqual(
cleanup.model(self.config(cleanup_provider="agy",
cleanup_agy_model="gemini-3.7-flash-low")),
"gemini-3.7-flash-low")
class OpenRouter(DikteTest):
@@ -86,6 +98,46 @@ class OpenRouter(DikteTest):
self.assertEqual(calls, [])
class GoogleAiStudio(DikteTest):
"""Cleanup over Google's OpenAI-compatible endpoint: one request, no CLI."""
def setUp(self):
super().setUp()
self.conf = self.config(cleanup_provider="gemini",
gemini_api_key="AIza-test")
def test_it_goes_to_google_with_the_settings_as_they_were(self):
self.conf["cleanup_reasoning"] = "none"
with fake_urlopen(chat_reply("Done.")) as calls:
self.assertEqual(cleanup.run("uh, done", self.conf, "the rules"),
"Done.")
self.assertEqual(
calls[0].full_url,
"https://generativelanguage.googleapis.com/v1beta/openai/chat/completions")
payload = sent_json(calls[0])
self.assertEqual(payload["model"], "gemini-3.5-flash-lite")
self.assertEqual(payload["reasoning_effort"], "none")
self.assertIn("uh, done", payload["messages"][1]["content"])
def test_the_key_travels_as_a_bearer_token(self):
with fake_urlopen(chat_reply("Done.")) as calls:
cleanup.run("uh, done", self.conf, "the rules")
self.assertEqual(calls[0].get_header("Authorization"), "Bearer AIza-test")
def test_a_missing_key_names_google_rather_than_openrouter(self):
self.conf["gemini_api_key"] = ""
with mock.patch.dict(os.environ, {}, clear=True), \
self.assertRaises(api.ApiError) as caught:
cleanup.run("uh, done", self.conf, "the rules")
self.assertIn("Google AI Studio", str(caught.exception))
def test_no_cli_is_started_for_it(self):
patcher, calls = fake_run(stdout="never")
with patcher, fake_urlopen(chat_reply("Done.")):
cleanup.run("uh, done", self.conf, "the rules")
self.assertEqual(calls, [])
class ClaudeCode(DikteTest):
def setUp(self):
super().setUp()
@@ -209,6 +261,63 @@ class Codex(DikteTest):
self.run_cleanup(stdout="tokens used 400", last_message="")
class Antigravity(DikteTest):
def setUp(self):
super().setUp()
self.conf = self.config(cleanup_provider="agy")
self.patch_attr(cleanup.shutil, "which", lambda name: f"/usr/bin/{name}")
def run_cleanup(self, text="uh, book it", **kwargs):
patcher, calls = fake_run(**kwargs)
with patcher:
answer = cleanup.run(text, self.conf, "the rules")
return answer, calls[0]
def test_the_rules_ride_in_front_of_the_transcript(self):
answer, cmd = self.run_cleanup(stdout="Book it.\n")
self.assertEqual(answer, "Book it.")
self.assertEqual(cmd[0], "agy")
self.assertEqual(cmd[cmd.index("-p") + 1],
"the rules\n\n---\n\n<transcript>\nuh, book it\n</transcript>")
def test_it_starts_somewhere_of_its_own_and_takes_no_slash_commands(self):
"""Without --new-project agy works in whichever project it was last in."""
_, cmd = self.run_cleanup(stdout="Book it.")
self.assertIn("--new-project", cmd)
self.assertIn("--disable-slash-commands", cmd)
self.assertEqual(cmd[cmd.index("--output-format") + 1], "text")
def test_it_is_not_left_to_give_up_before_the_caller_does(self):
_, cmd = self.run_cleanup(stdout="Book it.")
self.assertEqual(cmd[cmd.index("--print-timeout") + 1], "180s")
def test_the_model_is_left_alone_until_one_is_typed_in(self):
_, cmd = self.run_cleanup(stdout="Book it.")
self.assertNotIn("--model", cmd)
self.conf["cleanup_agy_model"] = "gemini-3.7-flash-low"
_, cmd = self.run_cleanup(stdout="Book it.")
self.assertEqual(cmd[cmd.index("--model") + 1], "gemini-3.7-flash-low")
def test_the_thinking_setting_lands_on_the_nearest_rung_agy_has(self):
self.conf["cleanup_reasoning"] = "max"
_, cmd = self.run_cleanup(stdout="Book it.")
self.assertEqual(cmd[cmd.index("--effort") + 1], "high")
def test_no_thinking_setting_means_no_flag(self):
_, cmd = self.run_cleanup(stdout="Book it.")
self.assertNotIn("--effort", cmd)
def test_an_answer_of_nothing_is_a_failure_rather_than_an_empty_paste(self):
with self.assertRaises(cleanup.CleanupError):
self.run_cleanup(stdout=" ")
def test_a_program_that_is_not_installed_says_so_before_running_anything(self):
self.patch_attr(cleanup.shutil, "which", lambda name: "")
with self.assertRaises(cleanup.CleanupError) as caught:
self.run_cleanup(stdout="Book it.")
self.assertIn("agy", str(caught.exception))
if __name__ == "__main__":
unittest.main()
+21
View File
@@ -15,6 +15,7 @@ from typing import ClassVar
from unittest import mock
from dikte import audio
from dikte import cleanup
from dikte import cli
from dikte import config as cfg
from dikte import ggml
@@ -503,6 +504,26 @@ class Doctor(DikteTest):
self.assertIn("OpenRouter key, cleaning up on some/model",
self.run_doctor(as_json=False, cleanup_model="some/model"))
def test_it_survives_every_provider_cleanup_can_be_set_to(self):
"""It used to raise KeyError on the local model, whose executable is ""."""
for name in cleanup.PROVIDERS:
with self.subTest(provider=name):
reply = self.run_doctor(cleanup_provider=name)
self.assertEqual(reply["cleanup"]["provider"], name)
self.run_doctor(as_json=False, cleanup_provider=name)
def test_a_provider_with_no_key_to_check_says_so_rather_than_no(self):
"""A CLI needs none, so `false` there would read as one gone missing."""
self.assertIsNone(self.run_doctor(cleanup_provider="claude")["cleanup"]["key"])
self.assertIsNone(self.run_doctor(cleanup_provider="local")["cleanup"]["key"])
self.assertIs(self.run_doctor(cleanup_provider="gemini")["cleanup"]["key"],
False)
def test_cleanup_on_google_is_a_question_about_its_own_key(self):
line = self.run_doctor(as_json=False, cleanup_provider="gemini",
cleanup_gemini_model="gemini-2.5-flash")
self.assertIn("Google AI Studio key, cleaning up on gemini-2.5-flash", line)
def test_it_asks_after_the_programs_this_desktop_actually_uses(self):
"""A missing ydotool on a Mac is a red mark with nothing behind it."""
with mock.patch.object(cli.paste, "desktop", return_value=paste.MACOS):
+8
View File
@@ -134,6 +134,8 @@ class Keys(DikteTest):
def test_every_provider_falls_back_to_the_variable_of_its_own_name(self):
with mock.patch.dict(os.environ, {"GROQ_API_KEY": "gsk-env"}):
self.assertEqual(cfg.Config().groq_key(), "gsk-env")
with mock.patch.dict(os.environ, {"GEMINI_API_KEY": "AIza-env"}):
self.assertEqual(cfg.Config().gemini_key(), "AIza-env")
class TranscribeTarget(DikteTest):
@@ -449,6 +451,12 @@ class Defaults(unittest.TestCase):
def test_the_keys_ship_empty(self):
self.assertEqual(cfg.DEFAULTS["openai_api_key"], "")
self.assertEqual(cfg.DEFAULTS["openrouter_api_key"], "")
self.assertEqual(cfg.DEFAULTS["gemini_api_key"], "")
def test_google_ai_studio_is_a_cleanup_provider_and_not_a_transcriber(self):
"""Its compatible endpoint has no /audio/transcriptions behind it."""
self.assertNotIn("gemini", cfg.TRANSCRIBERS)
self.assertIn("gemini", cleanup.PROVIDERS)
def test_every_language_specific_prompt_has_both_languages(self):
for name in ("CLEANUP_PROMPT", "FILE_CLEANUP_PROMPT", "MEETING_PROMPT",
+30
View File
@@ -50,6 +50,7 @@ CHANGED = {
"openai_api_key": "sk-test-key",
"groq_api_key": "gsk-test-key",
"openrouter_api_key": "sk-or-test-key",
"gemini_api_key": "AIza-test-key",
"transcribe_provider": "openrouter",
"transcribe_model": "whisper-1",
"groq_transcribe_model": "whisper-large-v3",
@@ -59,6 +60,8 @@ CHANGED = {
"cleanup_model": "some/other-model",
"cleanup_claude_model": "opus",
"cleanup_codex_model": "gpt-5",
"cleanup_gemini_model": "gemini-2.5-flash",
"cleanup_agy_model": "gemini-3.1-pro-low",
"cleanup_reasoning": "high",
"local_model": "ggml-small.bin",
"local_gpu": False,
@@ -78,6 +81,7 @@ CHANGED = {
"assistant_codex_model": "gpt-5",
"assistant_codex_sandbox": "read-only",
"assistant_openrouter_model": "some/agent-model",
"assistant_agy_model": "gemini-3.1-pro-low",
"assistant_reasoning": "high",
"assistant_dir": "/tmp",
"assistant_timeout": 600,
@@ -754,3 +758,29 @@ class LocalModels(DikteTest):
self.assertFalse(window.cleanup_form.isRowVisible(window.cleanup_model_row))
# Its own thinking box, because the two default to opposite things.
self.assertFalse(window.cleanup_form.isRowVisible(window.cleanup_reasoning))
def test_each_cleaner_brings_its_own_model_row_and_no_other(self):
window = self.window(cfg.Config())
rows = {"openrouter": window.cleanup_model_row,
"gemini": window.cleanup_gemini_model_row,
"claude": window.cleanup_claude_model,
"codex": window.cleanup_codex_model,
"agy": window.cleanup_agy_model}
for chosen, row in rows.items():
with self.subTest(provider=chosen):
window._select_data(window.cleanup_provider, chosen)
for name, other in rows.items():
self.assertEqual(window.cleanup_form.isRowVisible(other),
name == chosen)
def test_each_agent_brings_its_own_box_and_no_other(self):
window = self.window(cfg.Config())
boxes = {"claude": window.claude_box, "codex": window.codex_box,
"agy": window.agy_box, "openrouter": window.openrouter_box}
for chosen, box in boxes.items():
with self.subTest(provider=chosen):
window._select_data(window.assistant_provider, chosen)
for name, other in boxes.items():
# isHidden rather than isVisible: the window itself is never
# shown in a test, so nothing in it is ever visible.
self.assertEqual(other.isHidden(), name != chosen)