Files
EvoScientist/tests/test_command_completions.py
m4 57176b359a feat(runtime)!: switch middleware and agent factories to snapshot-driven models
Replace config.yaml-driven model selection with registry snapshot resolution
across the runtime chain:

- ConfigurableModelMiddleware reads configurable["runtime_snapshot_id"] only;
  model/model_provider overrides are rejected with MODEL_CONFIG_OUTSIDE_SNAPSHOT
- MessageBudgetMiddleware derives budgets from snapshot reserves
  (system/tools/attachments) and re-resolves the summarizer per snapshot
- Agent factory and subagent factory resolve models via SnapshotRuntime
  (auxiliary/tool_selector/scheduler -> defaults.auxiliary ?? defaults.primary)
- Remove ModelFallbackMiddleware, /model-fallback command, and fallback chain
- Add model_registry/runtime.py SnapshotRuntime glue layer

Legacy config.yaml LLM fields, /model command, and llm/models.py remain for
Task 7. Report: .superpowers/sdd/briefs/task-6-report.md
2026-07-21 12:54:35 +08:00

131 lines
4.4 KiB
Python

"""Tests for multi-stage command completions, categories, and dynamic completions."""
from unittest.mock import patch
from EvoScientist.commands._completion_engine import compute_completions
class TestTopLevelCompletions:
def test_slash_returns_all_commands(self):
r = compute_completions("/", 1)
names = [c.text for c in r.candidates]
assert "/mcp" in names
assert "/help" in names
assert "/new" in names
def test_prefix_filters(self):
r = compute_completions("/mc", 3)
names = [c.text for c in r.candidates]
assert "/mcp" in names
assert "/help" not in names
def test_exact_leaf_hides(self):
r = compute_completions("/new", 4)
assert r.kind == "empty"
def test_exact_with_subcommands_hides_without_space(self):
r = compute_completions("/mcp", 4)
assert r.kind == "empty"
def test_results_have_categories(self):
r = compute_completions("/", 1)
cats = {c.category for c in r.candidates}
assert "Session" in cats
assert "MCP" in cats
assert "General" in cats
def test_category_ordering(self):
r = compute_completions("/", 1)
cats = []
for c in r.candidates:
if not cats or cats[-1] != c.category:
cats.append(c.category)
assert cats.index("Session") < cats.index("General")
class TestAliasVisibility:
def test_alias_prefix_matches(self):
r = compute_completions("/skills-re", 10)
names = [c.text for c in r.candidates]
assert "/autoskills" in names
def test_alias_exact_hides_leaf(self):
r = compute_completions("/quit", 5)
assert r.kind == "empty"
def test_alias_exact_hides_without_space(self):
r = compute_completions("/q", 2)
assert r.kind == "empty"
def test_alias_space_shows_subcommands(self):
r = compute_completions("/skills-review ", 15)
names = [c.text for c in r.candidates]
assert "approve" in names
assert "list" in names
class TestSubcommandCompletions:
def test_space_shows_subcommands(self):
r = compute_completions("/mcp ", 5)
names = [c.text for c in r.candidates]
assert "list" in names
assert "config" in names
assert "install" in names
def test_prefix_filters_subcommands(self):
r = compute_completions("/mcp c", 6)
names = [c.text for c in r.candidates]
assert "config" in names
assert "list" not in names
def test_leaf_subcommand_stops(self):
r = compute_completions("/autoskills help ", 17)
assert r.kind == "empty"
def test_channel_all_types(self):
r = compute_completions("/channel ", 9)
names = [c.text for c in r.candidates]
assert "status" in names
assert "telegram" in names
assert "discord" in names
def test_autoskills_subcommands(self):
r = compute_completions("/autoskills ", 12)
names = [c.text for c in r.candidates]
assert "approve" in names
assert "reject" in names
class TestDynamicCompletions:
def _invalidate_mcp_cache(self):
from EvoScientist.commands.implementation.mcp import MCPCommand
from EvoScientist.commands.manager import manager
cmd = manager.get_command("/mcp")
if isinstance(cmd, MCPCommand):
cmd._invalidate_server_cache()
def test_mcp_config_server_names(self):
self._invalidate_mcp_cache()
fake_config = {"myserver": {}, "other": {}}
with patch("EvoScientist.mcp.load_mcp_config", return_value=fake_config):
r = compute_completions("/mcp config ", 12)
names = [c.text for c in r.candidates]
assert "myserver" in names
assert "other" in names
def test_mcp_config_prefix_filters(self):
self._invalidate_mcp_cache()
fake_config = {"myserver": {}, "other": {}}
with patch("EvoScientist.mcp.load_mcp_config", return_value=fake_config):
r = compute_completions("/mcp config my", 14)
names = [c.text for c in r.candidates]
assert names == ["myserver"]
def test_mcp_remove_shows_servers(self):
self._invalidate_mcp_cache()
fake_config = {"srv1": {}}
with patch("EvoScientist.mcp.load_mcp_config", return_value=fake_config):
r = compute_completions("/mcp remove ", 12)
assert [c.text for c in r.candidates] == ["srv1"]