Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a981e3e89d |
@@ -250,16 +250,12 @@ _PROVIDER_MODELS: dict[str, list[str]] = {
|
||||
"big-pickle",
|
||||
],
|
||||
"opencode-go": [
|
||||
"kimi-k2.6",
|
||||
"kimi-k2.5",
|
||||
"glm-5.1",
|
||||
"glm-5",
|
||||
"kimi-k2.5",
|
||||
"mimo-v2-pro",
|
||||
"mimo-v2-omni",
|
||||
"minimax-m2.7",
|
||||
"minimax-m2.5",
|
||||
"qwen3.6-plus",
|
||||
"qwen3.5-plus",
|
||||
],
|
||||
"ai-gateway": [
|
||||
"anthropic/claude-opus-4.6",
|
||||
|
||||
@@ -105,7 +105,7 @@ _DEFAULT_PROVIDER_MODELS = {
|
||||
"ai-gateway": ["anthropic/claude-opus-4.6", "anthropic/claude-sonnet-4.6", "openai/gpt-5", "google/gemini-3-flash"],
|
||||
"kilocode": ["anthropic/claude-opus-4.6", "anthropic/claude-sonnet-4.6", "openai/gpt-5.4", "google/gemini-3-pro-preview", "google/gemini-3-flash-preview"],
|
||||
"opencode-zen": ["gpt-5.4", "gpt-5.3-codex", "claude-sonnet-4-6", "gemini-3-flash", "glm-5", "kimi-k2.5", "minimax-m2.7"],
|
||||
"opencode-go": ["kimi-k2.6", "kimi-k2.5", "glm-5.1", "glm-5", "mimo-v2-pro", "mimo-v2-omni", "minimax-m2.5", "minimax-m2.7", "qwen3.6-plus", "qwen3.5-plus"],
|
||||
"opencode-go": ["glm-5", "kimi-k2.5", "mimo-v2-pro", "mimo-v2-omni", "minimax-m2.5", "minimax-m2.7"],
|
||||
"huggingface": [
|
||||
"Qwen/Qwen3.5-397B-A17B", "Qwen/Qwen3-235B-A22B-Thinking-2507",
|
||||
"Qwen/Qwen3-Coder-480B-A35B-Instruct", "deepseek-ai/DeepSeek-R1-0528",
|
||||
|
||||
0
skills/creative/excalidraw/scripts/upload.py
Normal file → Executable file
0
skills/creative/excalidraw/scripts/upload.py
Normal file → Executable file
0
skills/leisure/find-nearby/scripts/find_nearby.py
Normal file → Executable file
0
skills/leisure/find-nearby/scripts/find_nearby.py
Normal file → Executable file
0
skills/media/youtube-content/scripts/fetch_transcript.py
Normal file → Executable file
0
skills/media/youtube-content/scripts/fetch_transcript.py
Normal file → Executable file
0
skills/productivity/google-workspace/scripts/google_api.py
Normal file → Executable file
0
skills/productivity/google-workspace/scripts/google_api.py
Normal file → Executable file
0
skills/productivity/google-workspace/scripts/setup.py
Normal file → Executable file
0
skills/productivity/google-workspace/scripts/setup.py
Normal file → Executable file
0
skills/productivity/ocr-and-documents/scripts/extract_marker.py
Normal file → Executable file
0
skills/productivity/ocr-and-documents/scripts/extract_marker.py
Normal file → Executable file
0
skills/productivity/ocr-and-documents/scripts/extract_pymupdf.py
Normal file → Executable file
0
skills/productivity/ocr-and-documents/scripts/extract_pymupdf.py
Normal file → Executable file
0
skills/red-teaming/godmode/scripts/auto_jailbreak.py
Normal file → Executable file
0
skills/red-teaming/godmode/scripts/auto_jailbreak.py
Normal file → Executable file
0
skills/red-teaming/godmode/scripts/godmode_race.py
Normal file → Executable file
0
skills/red-teaming/godmode/scripts/godmode_race.py
Normal file → Executable file
0
skills/red-teaming/godmode/scripts/parseltongue.py
Normal file → Executable file
0
skills/red-teaming/godmode/scripts/parseltongue.py
Normal file → Executable file
0
skills/research/arxiv/scripts/search_arxiv.py
Normal file → Executable file
0
skills/research/arxiv/scripts/search_arxiv.py
Normal file → Executable file
0
skills/research/polymarket/scripts/polymarket.py
Normal file → Executable file
0
skills/research/polymarket/scripts/polymarket.py
Normal file → Executable file
@@ -4,62 +4,32 @@ import os
|
||||
from unittest.mock import patch
|
||||
|
||||
from hermes_cli.model_switch import list_authenticated_providers
|
||||
from hermes_cli.models import curated_models_for_provider
|
||||
|
||||
|
||||
@patch.dict(os.environ, {"OPENCODE_GO_API_KEY": "test-key"}, clear=False)
|
||||
def test_opencode_go_appears_when_api_key_set():
|
||||
"""opencode-go should appear in list_authenticated_providers when OPENCODE_GO_API_KEY is set."""
|
||||
providers = list_authenticated_providers(current_provider="openrouter")
|
||||
|
||||
|
||||
# Find opencode-go in results
|
||||
opencode_go = next((p for p in providers if p["slug"] == "opencode-go"), None)
|
||||
|
||||
|
||||
assert opencode_go is not None, "opencode-go should appear when OPENCODE_GO_API_KEY is set"
|
||||
assert opencode_go["models"] == [
|
||||
"kimi-k2.6",
|
||||
"kimi-k2.5",
|
||||
"glm-5.1",
|
||||
"glm-5",
|
||||
"mimo-v2-pro",
|
||||
"mimo-v2-omni",
|
||||
"minimax-m2.7",
|
||||
"minimax-m2.5",
|
||||
]
|
||||
assert opencode_go["total_models"] == 10
|
||||
assert opencode_go["models"] == ["glm-5", "kimi-k2.5", "mimo-v2-pro", "mimo-v2-omni", "minimax-m2.7", "minimax-m2.5"]
|
||||
# opencode-go can appear as "built-in" (from PROVIDER_TO_MODELS_DEV when
|
||||
# models.dev is reachable) or "hermes" (from HERMES_OVERLAYS fallback when
|
||||
# the API is unavailable, e.g. in CI).
|
||||
assert opencode_go["source"] in ("built-in", "hermes")
|
||||
|
||||
|
||||
@patch("hermes_cli.models.provider_model_ids", return_value=[])
|
||||
def test_opencode_go_curated_fallback_includes_new_models(_mock_provider_model_ids):
|
||||
"""Fallback catalog should include Kimi K2.6 and both Qwen Plus models."""
|
||||
model_ids = [model_id for model_id, _ in curated_models_for_provider("opencode-go")]
|
||||
|
||||
assert model_ids == [
|
||||
"kimi-k2.6",
|
||||
"kimi-k2.5",
|
||||
"glm-5.1",
|
||||
"glm-5",
|
||||
"mimo-v2-pro",
|
||||
"mimo-v2-omni",
|
||||
"minimax-m2.7",
|
||||
"minimax-m2.5",
|
||||
"qwen3.6-plus",
|
||||
"qwen3.5-plus",
|
||||
]
|
||||
|
||||
|
||||
def test_opencode_go_not_appears_when_no_creds():
|
||||
"""opencode-go should NOT appear when no credentials are set."""
|
||||
# Ensure OPENCODE_GO_API_KEY is not set
|
||||
env_without_key = {k: v for k, v in os.environ.items() if k != "OPENCODE_GO_API_KEY"}
|
||||
|
||||
|
||||
with patch.dict(os.environ, env_without_key, clear=True):
|
||||
providers = list_authenticated_providers(current_provider="openrouter")
|
||||
|
||||
|
||||
# opencode-go should not be in results
|
||||
opencode_go = next((p for p in providers if p["slug"] == "opencode-go"), None)
|
||||
assert opencode_go is None, "opencode-go should not appear without credentials"
|
||||
|
||||
63
tests/tools/test_local_shell_init.py
Normal file
63
tests/tools/test_local_shell_init.py
Normal file
@@ -0,0 +1,63 @@
|
||||
"""Regression tests for bundled skill scripts and local shell execution.
|
||||
|
||||
Issue #953 verifies that bundled skill scripts run out of the box from the
|
||||
installed ~/.hermes/skills tree without manual chmod or PATH surgery.
|
||||
"""
|
||||
|
||||
import shlex
|
||||
import shutil
|
||||
import stat
|
||||
from pathlib import Path
|
||||
|
||||
from tools.environments.local import LocalEnvironment
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
SKILLS_ROOT = REPO_ROOT / "skills"
|
||||
|
||||
|
||||
def _bundled_shebang_scripts() -> list[Path]:
|
||||
scripts: list[Path] = []
|
||||
for path in SKILLS_ROOT.rglob("*"):
|
||||
if not path.is_file() or path.is_symlink() or "scripts" not in path.parts:
|
||||
continue
|
||||
first_line = path.read_bytes().splitlines()[:1]
|
||||
if first_line and first_line[0].startswith(b"#!"):
|
||||
scripts.append(path)
|
||||
return sorted(scripts)
|
||||
|
||||
|
||||
def test_bundled_skill_shebang_scripts_are_executable():
|
||||
missing = []
|
||||
for path in _bundled_shebang_scripts():
|
||||
mode = stat.S_IMODE(path.stat().st_mode)
|
||||
if mode & 0o111 == 0:
|
||||
missing.append(f"{path.relative_to(REPO_ROOT)} ({oct(mode)})")
|
||||
|
||||
assert not missing, (
|
||||
"Bundled shebang scripts must ship executable so synced skill copies run "
|
||||
"without manual chmod:\n" + "\n".join(missing)
|
||||
)
|
||||
|
||||
|
||||
def test_local_environment_executes_installed_skill_script_without_manual_prep(tmp_path):
|
||||
hermes_home = tmp_path / ".hermes"
|
||||
installed_skill = hermes_home / "skills" / "research" / "arxiv"
|
||||
installed_skill.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copytree(SKILLS_ROOT / "research" / "arxiv", installed_skill)
|
||||
|
||||
script_path = installed_skill / "scripts" / "search_arxiv.py"
|
||||
env = LocalEnvironment(
|
||||
cwd=str(tmp_path),
|
||||
timeout=15,
|
||||
env={
|
||||
"HERMES_HOME": str(hermes_home),
|
||||
"PATH": "/custom/bin",
|
||||
},
|
||||
)
|
||||
|
||||
result = env.execute(f"{shlex.quote(str(script_path))} --help")
|
||||
|
||||
assert result["returncode"] == 0, result["output"]
|
||||
assert "Search arXiv and display results in a clean format." in result["output"]
|
||||
assert "python search_arxiv.py" in result["output"]
|
||||
Reference in New Issue
Block a user