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
18 changes: 11 additions & 7 deletions bettercode/gui/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,23 @@ def __init__(self, master, callbacks=None):

def save_anthropic(self):
set_api_key("anthropic", self.ant_key.get())
if self.callbacks: self.callbacks()
if self.callbacks:
self.callbacks()
self.destroy()

def save_openai(self):
set_api_key("openai", self.oai_key.get())
if self.callbacks: self.callbacks()
if self.callbacks:
self.callbacks()
self.destroy()

def save_sub(self):
try:
login(self.sub_user.get(), self.sub_pass.get())
if self.callbacks: self.callbacks()
if self.callbacks:
self.callbacks()
self.destroy()
except:
except Exception:
pass

class BetterCodeApp(ctk.CTk):
Expand Down Expand Up @@ -189,7 +192,8 @@ def open_auth(self):

def handle_send(self, event=None):
text = self.chat_input.get().strip()
if not text: return
if not text:
return

if not self.current_workspace_id:
self.append_chat("system", "Please select a workspace first.")
Expand Down
4 changes: 2 additions & 2 deletions bettercode/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
import threading
from pathlib import Path

_logger = logging.getLogger(__name__)

from bettercode.app_meta import bettercode_home_dir
from bettercode.i18n import detect_system_human_language, normalize_human_language
from bettercode.updater import normalize_version_tag

_logger = logging.getLogger(__name__)


COST_TIER_ORDER = ("low", "medium", "high")
AUTO_MODEL_PREFERENCE_ORDER = ("balanced", "cheaper", "faster", "smarter")
Expand Down
10 changes: 4 additions & 6 deletions bettercode/web/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
from bettercode.context import (
CodeReview,
Message,
MemoryEntry,
RouterTelemetry,
SessionLocal,
Workspace,
Expand All @@ -62,11 +61,11 @@
open_generated_file_payload as _open_generated_file_payload_base,
open_telemetry_log_payload as _open_telemetry_log_payload_base,
)
from bettercode.web.bootstrap import _require_selector_for_app_startup, _start_selector_warmup
from bettercode.web.bootstrap import _require_selector_for_app_startup, _start_selector_warmup # noqa: F401
from bettercode.web.chat_processes import (
ACTIVE_CHAT_PROCESS_META, # noqa: F401
ACTIVE_CHAT_PROCESS_META_LOCK, # noqa: F401
ACTIVE_CHAT_PROCESSES,
ACTIVE_CHAT_PROCESS_META,
ACTIVE_CHAT_PROCESS_META_LOCK,
ACTIVE_CHAT_PROCESSES_LOCK,
PENDING_CHAT_INPUT,
PENDING_CHAT_INPUT_LOCK,
Expand All @@ -86,7 +85,6 @@
_manual_task_analysis as _manual_task_analysis_base,
)
from bettercode.web.generated_paths import (
GENERATED_FILES_DIRNAME,
_bettercode_home_dir,
_resolve_generated_file_path,
_workspace_generated_dir,
Expand Down Expand Up @@ -142,7 +140,7 @@
stop_managed_ollama,
suggest_follow_up_recommendations,
)
from bettercode.updater import check_for_updates, normalize_sha256, normalize_update_platform
from bettercode.updater import normalize_sha256, normalize_update_platform

STATIC_DIR = Path(__file__).with_name("static")

Expand Down
3 changes: 1 addition & 2 deletions bettercode/web/desktop.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@
APP_BUNDLE_ID,
APP_ICON_PATH,
APP_ICON_PNG_PATH,
APP_ICNS_PATH,
APP_NAME,
APP_SLUG,
APP_TRAY_ICON_PATH,
)
from .api import create_app
from .bootstrap import _start_selector_runtime_warmup, _warm_selector_runtime_best_effort
from .bootstrap import _start_selector_runtime_warmup, _warm_selector_runtime_best_effort # noqa: F401


class EmbeddedServer(uvicorn.Server):
Expand Down
1 change: 0 additions & 1 deletion tests/test_main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from unittest.mock import Mock
import plistlib
from pathlib import Path

import bettercode.main as main_module

Expand Down
13 changes: 13 additions & 0 deletions tests/test_selector.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import json

import pytest

from bettercode.router import selector


@pytest.fixture(autouse=True)
def _local_preprocess_enabled(monkeypatch):
monkeypatch.setattr("bettercode.router.selector.get_local_preprocess_mode", lambda: "tiny")


def test_selector_status_reports_missing_ollama(monkeypatch):
monkeypatch.setattr("bettercode.router.selector._ollama_command", lambda: None)

Expand Down Expand Up @@ -322,6 +329,7 @@ def test_top_candidates_preserve_cross_provider_mix():


def test_select_best_model_local_router_prompt_uses_task_fit_metadata(monkeypatch):
monkeypatch.setattr("bettercode.router.selector.get_local_preprocess_mode", lambda: "small")
monkeypatch.setattr("bettercode.router.selector.ensure_selector_runtime", lambda **kwargs: {
"installed": True,
"running": True,
Expand Down Expand Up @@ -577,6 +585,7 @@ def test_select_best_model_uses_intent_gate_for_simple_requests(monkeypatch):


def test_plan_subtasks_skips_local_breakdown_for_simple_requests(monkeypatch):
monkeypatch.setattr("bettercode.router.selector.get_local_preprocess_mode", lambda: "small")
monkeypatch.setattr(
"bettercode.router.selector.ensure_selector_runtime",
lambda **kwargs: (_ for _ in ()).throw(AssertionError("planner should be skipped")),
Expand Down Expand Up @@ -691,6 +700,7 @@ def fake_api_request(method, path, payload=None, timeout=5.0):


def test_suggest_follow_up_recommendations_uses_full_reply_and_allows_custom_prompt(monkeypatch):
monkeypatch.setattr("bettercode.router.selector.get_local_preprocess_mode", lambda: "small")
monkeypatch.setattr("bettercode.router.selector.ensure_selector_runtime", lambda **kwargs: {
"installed": True,
"running": True,
Expand Down Expand Up @@ -721,6 +731,7 @@ def fake_api_request(method, path, payload=None, timeout=5.0):


def test_plan_subtasks_fallback_includes_stage_metadata(monkeypatch):
monkeypatch.setattr("bettercode.router.selector.get_local_preprocess_mode", lambda: "small")
monkeypatch.setattr("bettercode.router.selector.ensure_selector_runtime", lambda **kwargs: {
"installed": False,
"running": False,
Expand All @@ -741,6 +752,7 @@ def test_plan_subtasks_fallback_includes_stage_metadata(monkeypatch):


def test_plan_subtasks_normalizes_local_router_stage_and_model(monkeypatch):
monkeypatch.setattr("bettercode.router.selector.get_local_preprocess_mode", lambda: "small")
monkeypatch.setattr("bettercode.router.selector.ensure_selector_runtime", lambda **kwargs: {
"installed": True,
"running": True,
Expand Down Expand Up @@ -797,6 +809,7 @@ def fake_api_request(method, path, payload=None, timeout=5.0):


def test_plan_subtasks_distributes_tracks_across_multiple_models(monkeypatch):
monkeypatch.setattr("bettercode.router.selector.get_local_preprocess_mode", lambda: "small")
monkeypatch.setattr("bettercode.router.selector.ensure_selector_runtime", lambda **kwargs: {
"installed": True,
"running": True,
Expand Down
14 changes: 9 additions & 5 deletions tests/test_web_api.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import asyncio
import hashlib
import subprocess
import json
from datetime import UTC, datetime, timedelta
Expand Down Expand Up @@ -70,6 +69,7 @@ def _selector_runtime_ready(monkeypatch):
web_api.GIT_STATUS_CACHE.clear()
with web_api.RECENT_FILE_ENTRIES_CACHE_LOCK:
web_api.RECENT_FILE_ENTRIES_CACHE.clear()
web_api._clear_model_discovery_cache()
monkeypatch.setattr(
web_api,
"require_selector_runtime",
Expand Down Expand Up @@ -902,8 +902,13 @@ def fake_run_git(workspace_path, args, check=True):
def test_chat_endpoint_persists_messages(monkeypatch, tmp_path):
monkeypatch.chdir(tmp_path)
monkeypatch.setenv("BETTERCODE_HOME", str(tmp_path / ".bettercode"))
monkeypatch.setitem(web_api.MODEL_DISCOVERY_CACHE, "options", None)
monkeypatch.setitem(web_api.MODEL_DISCOVERY_CACHE, "registry", None)
monkeypatch.setitem(web_api.MODEL_DISCOVERY_CACHE, "options", [
{"id": "smart", "label": "Auto Model Select"},
{"id": "codex/gpt-5", "label": "GPT-5"},
])
monkeypatch.setitem(web_api.MODEL_DISCOVERY_CACHE, "registry", [
{"id": "codex/gpt-5", "label": "GPT-5", "provider": "openai", "runtime": "codex"},
])
monkeypatch.setattr("bettercode.web.api.manage_workspace_context", lambda db, workspace: False)
monkeypatch.setattr("bettercode.web.api._cli_runtimes", lambda: {
"codex": {"available": True, "path": "/usr/bin/codex", "configured": True},
Expand Down Expand Up @@ -1607,8 +1612,6 @@ def test_app_update_endpoint_reports_updates_disabled(monkeypatch, tmp_path):


def test_app_update_payload_does_not_fetch_updates_when_disabled(monkeypatch):
monkeypatch.setattr(web_api, "check_for_updates", lambda *args, **kwargs: (_ for _ in ()).throw(AssertionError("should not fetch real updates")))

payload = web_api.app_update_payload(force_refresh=True)

assert payload == {
Expand Down Expand Up @@ -1662,6 +1665,7 @@ def test_app_info_includes_configured_models_when_cache_is_empty(monkeypatch, tm
monkeypatch.setenv("BETTERCODE_HOME", str(tmp_path / ".bettercode"))
init_db()
web_api._clear_model_discovery_cache()
monkeypatch.setattr("bettercode.web.api._start_model_discovery_warmup", lambda verified=False: None)
monkeypatch.setattr(
"bettercode.web.api._cli_runtimes",
lambda quick=False, force_refresh=False: {
Expand Down
Loading