mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-17 18:25:42 +02:00
[eric] agents: fetch live connections for the sub-agent model pin (run/ split starved it with [], every sub-agent 401d on router routes)
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
"""Configure the SDK environment for the run's provider route: set ANTHROPIC/OPENAI/GOOGLE
|
||||
auth env vars (direct key, OpenSwarm Pro proxy, OpenRouter, or 9Router) and pin subagent models,
|
||||
ensuring 9Router is up where the route needs it. sub_conns is the active-connection list for
|
||||
subagent-model fallback (empty today)."""
|
||||
ensuring 9Router is up where the route needs it."""
|
||||
|
||||
import os
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Dict, Optional
|
||||
|
||||
from typeguard import typechecked
|
||||
|
||||
@@ -50,7 +49,6 @@ async def configure_provider_env(
|
||||
resolved_model: object,
|
||||
api_type: Optional[str],
|
||||
global_settings: AppSettings,
|
||||
sub_conns: List,
|
||||
) -> None:
|
||||
from backend.apps.nine_router import is_running as nine_router_running
|
||||
from backend.apps.agents.providers.registry import NINEROUTER_MODEL_PREFIXES as NINEROUTER_MODEL_PREFIXES
|
||||
@@ -198,7 +196,9 @@ async def configure_provider_env(
|
||||
"ANTHROPIC_API_KEY": "9router",
|
||||
"ANTHROPIC_BASE_URL": "http://localhost:20128",
|
||||
}
|
||||
# Pin subagents to whichever lane the user has, else CLI's default Haiku 4.5 hits 9Router with no Claude route and 401s. NOTE: callers pass sub_conns=[] today so this is inert (latent regression from the run/ split; pyright caught the dangling _conns ref).
|
||||
# Pin subagents to whichever lane the user has, else the CLI's default Haiku 4.5 hits 9Router with no Claude route and every sub-agent 401s while the parent turn works. Fetched live here (fail-open []) so no caller can starve the pin with a stale list again, the run/ split did exactly that and silently killed sub-agents on router routes.
|
||||
from backend.apps.nine_router import get_providers as p_get_providers
|
||||
sub_conns = await p_get_providers()
|
||||
active = {c.get("provider") for c in sub_conns
|
||||
if isinstance(c, dict) and c.get("isActive")}
|
||||
sub_model = None
|
||||
|
||||
@@ -188,7 +188,7 @@ class RunOptions(AgentManagerProtocol):
|
||||
}
|
||||
# cc/cx/gc/ag/gemini/openrouter prefixes force 9Router; route="api" bypasses to the provider's host directly; otherwise Pro proxy or key.
|
||||
await configure_provider_env(
|
||||
options_kwargs, session, resolved_model, api_type, global_settings, []
|
||||
options_kwargs, session, resolved_model, api_type, global_settings
|
||||
)
|
||||
if mcp_servers:
|
||||
options_kwargs["mcp_servers"] = mcp_servers
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
"""The sub-agent model pin on the 9Router-direct route must come from LIVE router
|
||||
connections. The run/ split passed a hardcoded empty list, the pin never fired, and every
|
||||
sub-agent 401'd ("No credentials for provider: anthropic") while the parent turn worked."""
|
||||
import asyncio
|
||||
from typing import Dict
|
||||
|
||||
from pytest import MonkeyPatch
|
||||
|
||||
import backend.apps.agents.manager.configure_provider_env as cpe
|
||||
from backend.apps.agents.core.models import AgentSession
|
||||
from backend.apps.settings.models import AppSettings
|
||||
|
||||
|
||||
def run_env_for(connections: list, monkeypatch: MonkeyPatch) -> Dict:
|
||||
import backend.apps.nine_router as nr_pkg
|
||||
|
||||
async def fake_get_providers() -> list:
|
||||
return connections
|
||||
|
||||
monkeypatch.setattr(nr_pkg, "is_running", lambda: True)
|
||||
monkeypatch.setattr(nr_pkg, "get_providers", fake_get_providers)
|
||||
session = AgentSession(name="t", model="opus-4-8-cc")
|
||||
options_kwargs: Dict = {}
|
||||
asyncio.run(
|
||||
cpe.configure_provider_env(
|
||||
options_kwargs, session, "cc/claude-opus-4-8", "anthropic", AppSettings()
|
||||
)
|
||||
)
|
||||
return options_kwargs.get("env", {})
|
||||
|
||||
|
||||
def test_subagent_pin_set_from_live_claude_connection(monkeypatch: MonkeyPatch) -> None:
|
||||
env = run_env_for([{"provider": "claude", "isActive": True}], monkeypatch)
|
||||
assert env.get("CLAUDE_CODE_SUBAGENT_MODEL") == "cc/claude-sonnet-4-6"
|
||||
assert env.get("ANTHROPIC_SMALL_FAST_MODEL") == "cc/claude-haiku-4-5-20251001"
|
||||
|
||||
|
||||
def test_subagent_pin_absent_only_when_no_active_lane(monkeypatch: MonkeyPatch) -> None:
|
||||
env = run_env_for([], monkeypatch)
|
||||
assert "CLAUDE_CODE_SUBAGENT_MODEL" not in env
|
||||
|
||||
|
||||
def test_subagent_pin_codex_lane(monkeypatch: MonkeyPatch) -> None:
|
||||
env = run_env_for([{"provider": "codex", "isActive": True}], monkeypatch)
|
||||
assert env.get("CLAUDE_CODE_SUBAGENT_MODEL") == "cx/gpt-5.4-mini"
|
||||
Reference in New Issue
Block a user