mirror of
https://github.com/Alishahryar1/free-claude-code.git
synced 2026-04-28 03:20:01 +00:00
refactor: remove OpenRouter rollback, shims, and redundant layers
- OpenRouter: native Anthropic only; remove chat_request and OPENROUTER_TRANSPORT - Drop OpenAICompatibleProvider alias, api.request_utils, voice_pipeline facade - Simplify OpenRouter SSE, generic reasoning in conversion, messaging dispatch - Shared markdown table helpers; API optimization response helper; contract guards - Restore PLAN.md; update docs and tests
This commit is contained in:
parent
22837720ca
commit
0e3b2c24b4
43 changed files with 356 additions and 615 deletions
|
|
@ -1,28 +1,35 @@
|
|||
import importlib
|
||||
from types import SimpleNamespace
|
||||
from typing import cast
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from config.settings import Settings
|
||||
|
||||
|
||||
def test_warn_if_process_auth_token_logs_warning():
|
||||
api_app_mod = importlib.import_module("api.app")
|
||||
settings = SimpleNamespace(uses_process_anthropic_auth_token=lambda: True)
|
||||
api_runtime_mod = importlib.import_module("api.runtime")
|
||||
settings = cast(
|
||||
Settings, SimpleNamespace(uses_process_anthropic_auth_token=lambda: True)
|
||||
)
|
||||
|
||||
with patch.object(api_app_mod.logger, "warning") as warning:
|
||||
api_app_mod._warn_if_process_auth_token(settings)
|
||||
with patch.object(api_runtime_mod.logger, "warning") as warning:
|
||||
api_runtime_mod.warn_if_process_auth_token(settings)
|
||||
|
||||
warning.assert_called_once()
|
||||
assert "ANTHROPIC_AUTH_TOKEN" in warning.call_args.args[0]
|
||||
|
||||
|
||||
def test_warn_if_process_auth_token_skips_explicit_dotenv_config():
|
||||
api_app_mod = importlib.import_module("api.app")
|
||||
settings = SimpleNamespace(uses_process_anthropic_auth_token=lambda: False)
|
||||
api_runtime_mod = importlib.import_module("api.runtime")
|
||||
settings = cast(
|
||||
Settings, SimpleNamespace(uses_process_anthropic_auth_token=lambda: False)
|
||||
)
|
||||
|
||||
with patch.object(api_app_mod.logger, "warning") as warning:
|
||||
api_app_mod._warn_if_process_auth_token(settings)
|
||||
with patch.object(api_runtime_mod.logger, "warning") as warning:
|
||||
api_runtime_mod.warn_if_process_auth_token(settings)
|
||||
|
||||
warning.assert_not_called()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
"""Tests for api/request_utils.py module."""
|
||||
"""Tests for API request detection and token counting helpers."""
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ from api.detection import (
|
|||
is_title_generation_request,
|
||||
)
|
||||
from api.models.anthropic import Message, MessagesRequest
|
||||
from api.request_utils import get_token_count
|
||||
from core.anthropic import get_token_count
|
||||
|
||||
|
||||
class TestQuotaCheckRequest:
|
||||
|
|
|
|||
|
|
@ -25,6 +25,14 @@ def test_provider_adapters_do_not_import_runtime_layers() -> None:
|
|||
assert offenders == []
|
||||
|
||||
|
||||
def test_removed_openrouter_rollback_transport_stays_removed() -> None:
|
||||
repo_root = Path(__file__).resolve().parents[2]
|
||||
|
||||
assert not (repo_root / "providers" / "open_router" / "chat_request.py").exists()
|
||||
assert _text_occurrences(repo_root, "OpenRouter" + "ChatProvider") == []
|
||||
assert _text_occurrences(repo_root, "OPENROUTER" + "_TRANSPORT") == []
|
||||
|
||||
|
||||
def test_architecture_doc_names_enforced_boundaries() -> None:
|
||||
repo_root = Path(__file__).resolve().parents[2]
|
||||
text = (repo_root / "PLAN.md").read_text(encoding="utf-8")
|
||||
|
|
@ -59,3 +67,34 @@ def _imports_from(path: Path) -> list[str]:
|
|||
elif isinstance(node, ast.ImportFrom) and node.module:
|
||||
imports.append(node.module)
|
||||
return imports
|
||||
|
||||
|
||||
def _text_occurrences(repo_root: Path, needle: str) -> list[str]:
|
||||
searchable_paths = [
|
||||
repo_root / "api",
|
||||
repo_root / "cli",
|
||||
repo_root / "config",
|
||||
repo_root / "core",
|
||||
repo_root / "messaging",
|
||||
repo_root / "providers",
|
||||
repo_root / "smoke",
|
||||
repo_root / "tests",
|
||||
repo_root / ".env.example",
|
||||
repo_root / "AGENTS.md",
|
||||
repo_root / "PLAN.md",
|
||||
repo_root / "README.md",
|
||||
repo_root / "pyproject.toml",
|
||||
]
|
||||
occurrences: list[str] = []
|
||||
for root in searchable_paths:
|
||||
paths = root.rglob("*") if root.is_dir() else (root,)
|
||||
for path in paths:
|
||||
if not path.is_file():
|
||||
continue
|
||||
try:
|
||||
text = path.read_text(encoding="utf-8")
|
||||
except UnicodeDecodeError:
|
||||
continue
|
||||
if needle in text:
|
||||
occurrences.append(str(path.relative_to(repo_root)))
|
||||
return sorted(occurrences)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
"""Tests for messaging/rendering/discord_markdown.py."""
|
||||
|
||||
from messaging.rendering.discord_markdown import (
|
||||
_is_gfm_table_header_line,
|
||||
_normalize_gfm_tables,
|
||||
discord_bold,
|
||||
discord_code_inline,
|
||||
escape_discord,
|
||||
|
|
@ -11,6 +9,10 @@ from messaging.rendering.discord_markdown import (
|
|||
format_status_discord,
|
||||
render_markdown_to_discord,
|
||||
)
|
||||
from messaging.rendering.markdown_tables import (
|
||||
_is_gfm_table_header_line,
|
||||
normalize_gfm_tables,
|
||||
)
|
||||
|
||||
|
||||
class TestEscapeDiscord:
|
||||
|
|
@ -114,20 +116,20 @@ class TestNormalizeGfmTables:
|
|||
"""Tests for _normalize_gfm_tables."""
|
||||
|
||||
def test_single_line_unchanged(self):
|
||||
assert _normalize_gfm_tables("hello") == "hello"
|
||||
assert normalize_gfm_tables("hello") == "hello"
|
||||
|
||||
def test_two_lines_no_table_unchanged(self):
|
||||
assert _normalize_gfm_tables("a\nb") == "a\nb"
|
||||
assert normalize_gfm_tables("a\nb") == "a\nb"
|
||||
|
||||
def test_table_gets_blank_line_before(self):
|
||||
text = "para\n| A | B |\n|---|\n| 1 | 2 |"
|
||||
result = _normalize_gfm_tables(text)
|
||||
result = normalize_gfm_tables(text)
|
||||
assert "para" in result
|
||||
assert "| A | B |" in result
|
||||
|
||||
def test_table_inside_fence_unchanged(self):
|
||||
text = "```\n| A | B |\n|---|\n```"
|
||||
result = _normalize_gfm_tables(text)
|
||||
result = normalize_gfm_tables(text)
|
||||
assert result == text
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -204,15 +204,15 @@ def test_convert_assistant_message_thinking():
|
|||
assert "reasoning_content" not in result[0]
|
||||
|
||||
|
||||
def test_convert_assistant_message_thinking_include_reasoning_for_openrouter():
|
||||
"""When include_reasoning_for_openrouter=True, reasoning_content is added."""
|
||||
def test_convert_assistant_message_thinking_include_reasoning_content():
|
||||
"""When include_reasoning_content=True, reasoning_content is added."""
|
||||
content = [
|
||||
MockBlock(type="thinking", thinking="I need to calculate this."),
|
||||
MockBlock(type="text", text="The answer is 4."),
|
||||
]
|
||||
messages = [MockMessage("assistant", content)]
|
||||
result = AnthropicToOpenAIConverter.convert_messages(
|
||||
messages, include_reasoning_for_openrouter=True
|
||||
messages, include_reasoning_content=True
|
||||
)
|
||||
|
||||
assert len(result) == 1
|
||||
|
|
@ -229,7 +229,7 @@ def test_convert_assistant_message_thinking_removed_when_disabled():
|
|||
result = AnthropicToOpenAIConverter.convert_messages(
|
||||
messages,
|
||||
include_thinking=False,
|
||||
include_reasoning_for_openrouter=True,
|
||||
include_reasoning_content=True,
|
||||
)
|
||||
|
||||
assert len(result) == 1
|
||||
|
|
|
|||
|
|
@ -55,8 +55,8 @@ def llamacpp_config():
|
|||
@pytest.fixture(autouse=True)
|
||||
def mock_rate_limiter():
|
||||
"""Mock the global rate limiter to prevent waiting."""
|
||||
with patch("providers.llamacpp.client.GlobalRateLimiter") as mock:
|
||||
instance = mock.get_instance.return_value
|
||||
with patch("providers.anthropic_messages.GlobalRateLimiter") as mock:
|
||||
instance = mock.get_scoped_instance.return_value
|
||||
instance.wait_if_blocked = AsyncMock(return_value=False)
|
||||
|
||||
async def _passthrough(fn, *args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -55,8 +55,8 @@ def lmstudio_config():
|
|||
@pytest.fixture(autouse=True)
|
||||
def mock_rate_limiter():
|
||||
"""Mock the global rate limiter to prevent waiting."""
|
||||
with patch("providers.lmstudio.client.GlobalRateLimiter") as mock:
|
||||
instance = mock.get_instance.return_value
|
||||
with patch("providers.anthropic_messages.GlobalRateLimiter") as mock:
|
||||
instance = mock.get_scoped_instance.return_value
|
||||
instance.wait_if_blocked = AsyncMock(return_value=False)
|
||||
|
||||
async def _passthrough(fn, *args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from unittest.mock import AsyncMock, MagicMock, patch
|
|||
import pytest
|
||||
|
||||
from providers.base import ProviderConfig
|
||||
from providers.open_router import OpenRouterChatProvider, OpenRouterProvider
|
||||
from providers.open_router import OpenRouterProvider
|
||||
from providers.open_router.request import OPENROUTER_DEFAULT_MAX_TOKENS
|
||||
|
||||
|
||||
|
|
@ -453,13 +453,3 @@ async def test_stream_response_error_path(open_router_provider):
|
|||
assert "message_start" in event_text
|
||||
assert "API failed" in event_text
|
||||
assert "message_stop" in event_text
|
||||
|
||||
|
||||
def test_openai_chat_rollback_provider_builds_legacy_extra_body(open_router_config):
|
||||
with patch("providers.openai_compat.AsyncOpenAI"):
|
||||
provider = OpenRouterChatProvider(open_router_config)
|
||||
|
||||
body = provider._build_request_body(MockRequest())
|
||||
|
||||
assert "extra_body" in body
|
||||
assert body["extra_body"]["reasoning"] == {"enabled": True}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from providers.deepseek import DeepSeekProvider
|
|||
from providers.llamacpp import LlamaCppProvider
|
||||
from providers.lmstudio import LMStudioProvider
|
||||
from providers.nvidia_nim import NvidiaNimProvider
|
||||
from providers.open_router import OpenRouterChatProvider, OpenRouterProvider
|
||||
from providers.open_router import OpenRouterProvider
|
||||
from providers.registry import (
|
||||
PROVIDER_DESCRIPTORS,
|
||||
ProviderRegistry,
|
||||
|
|
@ -35,7 +35,6 @@ def _make_settings(**overrides):
|
|||
mock.http_write_timeout = 10.0
|
||||
mock.http_connect_timeout = 2.0
|
||||
mock.enable_thinking = True
|
||||
mock.openrouter_transport = "anthropic"
|
||||
mock.nim = NimSettings()
|
||||
for key, value in overrides.items():
|
||||
setattr(mock, key, value)
|
||||
|
|
@ -63,15 +62,6 @@ def test_create_provider_uses_native_openrouter_by_default():
|
|||
assert isinstance(provider, OpenRouterProvider)
|
||||
|
||||
|
||||
def test_create_provider_can_use_openrouter_openai_rollback():
|
||||
with patch("providers.openai_compat.AsyncOpenAI"):
|
||||
provider = create_provider(
|
||||
"open_router", _make_settings(openrouter_transport="openai")
|
||||
)
|
||||
|
||||
assert isinstance(provider, OpenRouterChatProvider)
|
||||
|
||||
|
||||
def test_create_provider_instantiates_each_builtin():
|
||||
settings = _make_settings()
|
||||
cases = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue