fix(run_agent): forward api_key/base_url/api_mode to background review agent (#15543)#15645
Conversation
…w agent (NousResearch#15543) Custom providers resolve their credentials (api_key + base_url) from config.yaml at AIAgent init time. The background review agent was spawned without those fields, so the child re-ran credential resolution, found nothing in PROVIDER_REGISTRY, and crashed with "No LLM provider configured." Pass the already-resolved `self.api_key`, `self.base_url`, and `self.api_mode` directly to the review agent's constructor so it inherits the parent's connection settings unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes background review agent initialization so it inherits already-resolved provider credentials/config from the parent AIAgent, preventing failures for custom providers that can’t be re-resolved from config/env in the child thread (issue #15543).
Changes:
- Forward
api_key,base_url, andapi_modefrom the parent agent to the background review agent constructor. - Add regression tests that verify credential propagation into the background review agent across multiple provider/api_mode scenarios.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
run_agent.py |
Passes resolved api_key/base_url/api_mode into the background review AIAgent to avoid re-resolving credentials. |
tests/run_agent/test_background_review_credentials.py |
Adds regression coverage validating that the background review agent receives the parent’s resolved credentials/config. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| _MEMORY_REVIEW_PROMPT="review-memory", | ||
| _SKILL_REVIEW_PROMPT="review-skills", | ||
| _COMBINED_REVIEW_PROMPT="review-both", | ||
| _summarize_background_review_actions=staticmethod(lambda msgs, snap: []), |
| review_memory=review_memory, | ||
| review_skills=review_skills, | ||
| ) | ||
| done.wait(timeout=5) |
Two Copilot-caught issues in the credential-propagation test: 1. `staticmethod(lambda ...)` on a `SimpleNamespace` does not go through the descriptor protocol, so accessing `self._summarize_background_review_actions` returns the wrapper object (not the lambda), which is non-callable and would raise `TypeError` in the real code path. Drop the `staticmethod()` wrapper and expose the plain lambda directly. 2. `done.wait(timeout=5)` ignored its return value. If the background thread stalled, the test exited the `patch()` context, unpatched `run_agent.AIAgent`, and let assertions run against an empty dict — producing a misleading PASS. Assert the wait result to make time-outs a hard failure. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briandevans
left a comment
There was a problem hiding this comment.
Thanks @copilot — both findings are real. Addressed in 58054e6a.
1. staticmethod on SimpleNamespace (line 47) ✅ — You're right: staticmethod only acts as a descriptor when defined on a class, not when assigned to a SimpleNamespace attribute. The runtime path calls self._summarize_background_review_actions(...) which would return the wrapper object (not the lambda), causing a silent TypeError swallowed by the surrounding except Exception. Dropped the staticmethod() wrapper — it's a plain callable now.
2. Ignored done.wait() return value (line 74) ✅ — If the background thread stalled, the with patch(...) context exited, run_agent.AIAgent was unpatched, and assertions ran against an empty captured dict producing a false PASS. Now asserts the result: assert done.wait(timeout=5), "background thread did not call AIAgent within 5 s".
|
Both Copilot findings addressed in
|
|
Closing — superseded by @teknium1's #16099, which is the better fix here. @teknium1's PR introduced a
Thanks @teknium1 for the more thorough fix. |
Spawned review AIAgent was missing resolved credentials, causing failures with custom providers (OpenRouter, Cerebras, etc.) that can't be re-resolved from config/env in the child thread. Fixes NousResearch#15543 (same fix as upstream PR NousResearch#15645)
Summary
_spawn_background_review()now passesapi_key,base_url, andapi_modefrom the parent agent to the review agent constructorThe bug
Custom providers (self-hosted endpoints, proxies) resolve their credentials from
config.yamlatAIAgentinit time — the resolvedapi_keyandbase_urllive on the parent instance. When_spawn_background_review()spawned the child agent with onlyprovider=self.provider, the child re-ran credential resolution from scratch. For custom providers not inPROVIDER_REGISTRY, this found nothing and raised:The fix
Three additional kwargs in the
AIAgent(...)constructor call inside_run_review():The parent's credentials are already fully resolved at this point — no re-resolution needed, and no environment variables or config files need to be consulted again.
Test plan
AssertionError: assert None == 'sk-custom-key-abcdefgh'; restored → 0 failurestests/run_agent/— 1058 passed, 1 pre-existing baseline (test_inf_stays_string_for_integer_onlyfails on cleanorigin/main)tests/run_agent/test_background_review_summary.py— 8 passedRelated
🤖 Generated with Claude Code