fix(agents): unwrap wrapped engines to derive opencode provider URL (+ clear guard)

The real `jarvis ask --agent opencode` path passes an InstrumentedEngine
(telemetry wrapper) whose underlying engine — and its `_host` — lives at
`_inner`. The base-URL derivation only checked the top object, so it returned
"", no provider was registered, and opencode 500'd on `openjarvis/<model>`.
Direct construction with a raw engine masked this; only the CLI path exposed
it.

- _derive_openai_base_url now unwraps up to 6 wrapper layers
  (`_inner`/`_engine`/`_wrapped`) to find `_host`/`base_url`.
- run() resolves the provider/model spec up front and, when it genuinely
  can't (no base URL + bare model name), returns a clear actionable error
  instead of letting opencode 500.

Tests: wrapper-unwrap derivation + unresolvable-provider guard. 20 passed,
ruff clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
krypticmouse
2026-05-29 01:10:25 +00:00
co-authored by Claude Opus 4.7
parent 6a011b4abb
commit 00b85b71dd
2 changed files with 60 additions and 19 deletions
+13
View File
@@ -71,6 +71,11 @@ class TestDeriveBaseUrl:
eng = SimpleNamespace(base_url="http://y/v1")
assert _derive_openai_base_url(eng) == "http://y/v1"
def test_unwraps_wrapper_engine(self):
# InstrumentedEngine wraps the real engine at `_inner`; must unwrap.
wrapped = SimpleNamespace(_inner=SimpleNamespace(_host="http://localhost:11434"))
assert _derive_openai_base_url(wrapped) == "http://localhost:11434/v1"
def test_none_when_unknown(self):
assert _derive_openai_base_url(SimpleNamespace()) == ""
@@ -136,6 +141,14 @@ class TestRunGracefulDegradation:
assert res.metadata.get("error") is True
assert "opencode" in res.content.lower()
def test_unresolvable_provider_fails_clearly(self, tmp_path):
# No derivable base URL + bare model name -> clear error, not a 500
# (and we fail before spawning a server).
agent = OpenCodeAgent(SimpleNamespace(), "qwen3:8b", workspace=str(tmp_path))
res = agent.run("do something")
assert res.metadata.get("error") is True
assert "could not determine" in res.content.lower()
class _FakeResp:
def __init__(self, data):