Skip to content

Commit 884fe01

Browse files
committed
Release 0.7.16
1 parent de42d24 commit 884fe01

19 files changed

Lines changed: 58 additions & 59 deletions

openclaw-plugin/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@anjieyang/uncommon-route",
3-
"version": "0.7.15",
3+
"version": "0.7.16",
44
"description": "OpenClaw plugin for UncommonRoute, the local LLM router that cuts premium-model spend",
55
"type": "module",
66
"main": "src/index.js",

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "uncommon-route"
3-
version = "0.7.15"
3+
version = "0.7.16"
44
description = "Local LLM router that cuts premium-model spend with adaptive 3-tier routing, OpenAI + Anthropic compatible"
55
requires-python = ">=3.11"
66
license = "MIT"

tests/test_calibration.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import json
2-
from pathlib import Path
31

42
from uncommon_route.decision.calibration import (
53
PlattCalibrator,

tests/test_ensemble.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from uncommon_route.signals.base import TierVote
2-
from uncommon_route.decision.ensemble import Ensemble, EnsembleResult
2+
from uncommon_route.decision.ensemble import Ensemble
33

44

55
def test_unanimous_vote():

tests/test_index_growth.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import json
22
import numpy as np
3-
from pathlib import Path
43
from uncommon_route.learning.index_growth import EmbeddingIndexManager
54

65

tests/test_keyword_free.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
from __future__ import annotations
88

99
import json
10-
import math
11-
from collections import defaultdict
1210
from pathlib import Path
1311

1412
from uncommon_route.router.structural import (
@@ -130,7 +128,7 @@ def test_keyword_free_training_accuracy():
130128
print(f" Disagreements: {len(disagreements)}/{total}")
131129

132130
if disagreements:
133-
print(f"\n Sample disagreements (first 10):")
131+
print("\n Sample disagreements (first 10):")
134132
for prompt, expected, pred_kw, pred_no_kw in disagreements[:10]:
135133
print(f" '{prompt}...'")
136134
print(f" expected={expected} with_kw={pred_kw} no_kw={pred_no_kw}")
@@ -143,7 +141,7 @@ def test_keyword_free_held_out():
143141
test_path = data_dir / "test.jsonl"
144142

145143
if not train_path.exists() or not test_path.exists():
146-
print(f"\n train.jsonl or test.jsonl not found, skipping held-out test")
144+
print("\n train.jsonl or test.jsonl not found, skipping held-out test")
147145
return
148146

149147
def load_jsonl(path):
@@ -232,7 +230,7 @@ def test_keyword_free_specific_cases():
232230
("证明哥德尔不完备定理", "COMPLEX"),
233231
]
234232

235-
print(f"\n Keyword-free classifier on specific cases:")
233+
print("\n Keyword-free classifier on specific cases:")
236234
correct = 0
237235
total = len(test_prompts)
238236
for prompt, expected in test_prompts:

tests/test_learning_weights.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import json
2-
from pathlib import Path
31
from uncommon_route.learning.weights import SignalWeightTracker
42

53

@@ -17,7 +15,6 @@ def test_correct_signal_weight_increases():
1715

1816
def test_abstaining_signal_not_updated():
1917
tracker = SignalWeightTracker(initial_weights=[0.5, 0.5])
20-
old_w1 = tracker.weights[1]
2118
tracker.update(predictions=[1, None], abstained=[False, True], actual_tier=1)
2219
# Abstaining signal weight changes only due to normalization
2320
# but should not be directly penalized/rewarded

tests/test_persistence.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import json
2-
from pathlib import Path
32
from uncommon_route.persistence import LearnedState, save_state, load_state, reset_state
43

54

tests/test_reported_issues.py

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,18 @@
1111

1212
from __future__ import annotations
1313

14-
import json
15-
import copy
16-
from dataclasses import replace
1714

1815
from uncommon_route.router.api import route
19-
from uncommon_route.router.classifier import classify, extract_features, _ensure_model_loaded, update_model, save_online_model, rollback_online_model
20-
from uncommon_route.router.config import DEFAULT_CONFIG, DEFAULT_MODEL_PRICING, DEFAULT_MODEL_CAPABILITIES
16+
from uncommon_route.router.classifier import classify, extract_features, _ensure_model_loaded, update_model, rollback_online_model
2117
from uncommon_route.router.types import (
2218
ModelCapabilities,
2319
ModelPricing,
24-
RequestRequirements,
25-
RoutingConstraints,
2620
RoutingFeatures,
2721
RoutingMode,
28-
ScoringConfig,
2922
Tier,
3023
WorkloadHints,
3124
)
3225
from uncommon_route.model_experience import (
33-
CandidateExperience,
3426
InMemoryModelExperienceStorage,
3527
ModelExperienceStore,
3628
)
@@ -189,7 +181,6 @@ def test_issue3_minimax_never_wins_for_complex():
189181
def test_issue3_minimax_ranking_across_tiers():
190182
"""Check MiniMax's position in ranking for each complexity level."""
191183
for complexity, label in [(0.15, "SIMPLE"), (0.45, "MEDIUM"), (0.85, "COMPLEX")]:
192-
tier = Tier.SIMPLE if complexity < 0.33 else (Tier.MEDIUM if complexity < 0.67 else Tier.COMPLEX)
193184
# Use a neutral prompt and force complexity via routing features
194185
decision = route(
195186
"do something",
@@ -211,7 +202,7 @@ def test_issue3_quality_prior_is_benchmark_based():
211202
opus_quality = cache.get_quality("anthropic/claude-opus-4.6")
212203
oss_quality = cache.get_quality("nvidia/gpt-oss-120b")
213204

214-
print(f"\n Benchmark quality (not price-based):")
205+
print("\n Benchmark quality (not price-based):")
215206
print(f" MiniMax: {minimax_quality:.3f}")
216207
print(f" Opus: {opus_quality:.3f}")
217208
print(f" gpt-oss: {oss_quality:.3f}")
@@ -248,7 +239,7 @@ def test_issue4_any_tools_means_agentic():
248239
prompt="hello",
249240
)
250241

251-
print(f"\n Prompt: 'hello'")
242+
print("\n Prompt: 'hello'")
252243
print(f" step_type: {step_type}")
253244
print(f" is_agentic: {features.is_agentic}")
254245
print(f" needs_tool_calling: {features.needs_tool_calling}")
@@ -404,7 +395,7 @@ def test_issue6_anthropic_model_resolution():
404395
opus_resolved = mapper.resolve("anthropic/claude-opus-4.6")
405396
sonnet_resolved = mapper.resolve("anthropic/claude-sonnet-4.6")
406397

407-
print(f"\n Pre-discovery:")
398+
print("\n Pre-discovery:")
408399
print(f" Opus → {opus_resolved}")
409400
print(f" Sonnet → {sonnet_resolved}")
410401
print(f" Is gateway: {mapper.is_gateway}")
@@ -424,10 +415,31 @@ def test_issue6_openrouter_detected_as_gateway():
424415
assert mapper.resolve("xai/grok-4-1-fast-reasoning") == "xai/grok-4-1-fast-reasoning"
425416

426417

418+
def test_issue6_learned_fallbacks_do_not_override_gateway_seed_aliases():
419+
"""Runtime fallback aliases from one gateway should not hide known model renames."""
420+
from uncommon_route.model_map import DiscoveredModel, ModelMapper
421+
422+
mapper = ModelMapper("https://openrouter.ai/api/v1")
423+
mapper._learned_aliases["xai/grok-4-1-fast-reasoning"] = "google/gemini-2.5-flash"
424+
for model_id in ["x-ai/grok-4.1-fast", "google/gemini-2.5-flash"]:
425+
provider = model_id.split("/", 1)[0]
426+
mapper._pool[model_id] = DiscoveredModel(
427+
id=model_id,
428+
provider=provider,
429+
owned_by=provider,
430+
pricing=ModelPricing(0.2, 0.8),
431+
capabilities=ModelCapabilities(tool_calling=True, vision=False, reasoning=False),
432+
)
433+
mapper._upstream_models.add(model_id)
434+
mapper._build_map()
435+
mapper._discovered = True
436+
437+
assert mapper.resolve("xai/grok-4-1-fast-reasoning") == "x-ai/grok-4.1-fast"
438+
439+
427440
def test_issue6_legacy_model_ids_resolve_to_live_successors():
428441
"""Legacy internal ids should map onto current upstream successors."""
429442
from uncommon_route.model_map import DiscoveredModel, ModelMapper
430-
from uncommon_route.router.types import ModelCapabilities, ModelPricing
431443

432444
live_models = [
433445
"x-ai/grok-4",
@@ -488,7 +500,6 @@ def test_issue6_legacy_model_ids_resolve_to_live_successors():
488500
def test_issue6_image_generation_models_do_not_enter_chat_routing_pool():
489501
"""Image-generation catalog entries should not become chat candidates."""
490502
from uncommon_route.model_map import DiscoveredModel, ModelMapper, is_routable_chat_model
491-
from uncommon_route.router.types import ModelCapabilities, ModelPricing
492503

493504
mapper = ModelMapper("https://api.commonstack.ai/v1")
494505
for model_id in [

tests/test_telemetry.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
"""E2E tests for telemetry: opt-in logic, record lifecycle, buffer, privacy."""
22

3-
import json
43
import os
5-
from pathlib import Path
64
from unittest import mock
75

86
import numpy as np

0 commit comments

Comments
 (0)