fix(acp): forward the resolved credential pool into ACP agents

resolve_runtime_provider() selects a provider-scoped credential pool and returns
it as runtime["credential_pool"]; oneshot and the gateway hand it to AIAgent, but
acp_adapter/session.py::_make_agent dropped it, so a long-lived ACP process had
_credential_pool=None and could not refresh/rotate on HTTP 401 after OAuth
token expiry — the only recovery was restarting the ACP process (#70292).

Forward the pool by identity like the other surfaces. The pool is already
provider-scoped and its selected entry matches the agent's initial api_key, so
the existing account-isolation guards are preserved rather than bypassed.

Salvaged from PR #70293 (the cherry-pick claimed in #77029 never reached
acp_adapter/session.py); regression test asserts the pool object is retained.

Fixes #70292
This commit is contained in:
Stefan van Biljon
2026-09-18 23:32:19 -07:00
committed by Teknium
parent c6d0b632d5
commit 4a8c7ce6e7
2 changed files with 23 additions and 0 deletions

View File

@@ -423,6 +423,7 @@ class SessionManager:
kwargs.update({
"provider": runtime.get("provider"), "api_mode": api_mode or runtime.get("api_mode"),
"base_url": base_url or runtime.get("base_url"), "api_key": runtime.get("api_key"),
"credential_pool": runtime.get("credential_pool"),
"command": runtime.get("command"), "args": list(runtime.get("args") or []),
})
except Exception:

View File

@@ -142,6 +142,28 @@ class TestCreateSession:
assert (seen[0]["enabled_toolsets"], seen[0]["disabled_toolsets"]) == (["hermes-acp", "mcp-cfg-server"], None)
assert (seen[1]["enabled_toolsets"], seen[1]["disabled_toolsets"]) == (["hermes-acp", "mcp-acp-server"], ["browser"])
def test_make_agent_forwards_resolved_credential_pool(self, monkeypatch):
"""#70292: the provider-scoped credential pool selected by resolve_runtime_provider reaches the
ACP agent by identity, so a long-lived session can refresh/rotate on 401 instead of needing a restart."""
seen: list[dict] = []
sentinel_pool = object()
class FakeAgent:
def __init__(self, **kwargs):
seen.append(kwargs)
monkeypatch.setattr("run_agent.AIAgent", FakeAgent)
monkeypatch.setattr("hermes_cli.config.load_config", lambda: {"model": {"default": "m", "provider": "openai-codex"}})
monkeypatch.setattr("hermes_cli.runtime_provider.resolve_runtime_provider", lambda **_kw: {
"provider": "openai-codex", "api_mode": "codex_app_server", "api_key": "test-key", "credential_pool": sentinel_pool,
})
monkeypatch.setattr("hermes_cli.mcp_startup.ensure_mcp_discovery_before_agent_build", lambda **_kw: None)
monkeypatch.setattr("acp_adapter.session._register_task_cwd", lambda task_id, cwd: None)
SessionManager(db=None)._make_agent(session_id="s", cwd=".")
assert seen[0]["credential_pool"] is sentinel_pool