mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-01 02:02:20 +00:00
fix(agents): hydrate identities on registry cache misses
This commit is contained in:
parent
38c09a8d7f
commit
cd55488ce6
4 changed files with 65 additions and 4 deletions
|
|
@ -592,7 +592,7 @@ async def get_agent_by_id(
|
|||
if agent is None:
|
||||
agent_row: Final = await agents_table(prisma_client).find_unique(
|
||||
where={"agent_id": agent_id},
|
||||
include={"object_permission": True},
|
||||
include={"object_permission": True, "identity": True},
|
||||
)
|
||||
if agent_row is not None:
|
||||
agent_dict: Final = agent_row.model_dump()
|
||||
|
|
|
|||
|
|
@ -174,7 +174,10 @@ async def _resync_agents(agent_id_or_name: str) -> bool:
|
|||
table: Final = agents_table(prisma_client)
|
||||
id_filter: Final[LiteLLM_AgentsTableWhereUniqueInput] = {"agent_id": agent_id_or_name}
|
||||
name_filter: Final[LiteLLM_AgentsTableWhereUniqueInput] = {"agent_name": agent_id_or_name}
|
||||
include_permission: Final[LiteLLM_AgentsTableInclude] = {"object_permission": True}
|
||||
include_permission: Final[LiteLLM_AgentsTableInclude] = {
|
||||
"object_permission": True,
|
||||
"identity": True,
|
||||
}
|
||||
async with AGENT_RECONCILE_LOCK:
|
||||
if _agent_from_registry(agent_id_or_name) is not None:
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -1389,3 +1389,31 @@ def test_agent_identity_configuration_is_only_returned_to_admins(role, path, mon
|
|||
payload = response.json()[0] if path == "/v1/agents" else response.json()
|
||||
assert payload["identity"] == (binding.model_dump(mode="json") if role == LitellmUserRoles.PROXY_ADMIN else None)
|
||||
assert agent.identity == binding
|
||||
|
||||
|
||||
@pytest.mark.parametrize("role", [LitellmUserRoles.PROXY_ADMIN, LitellmUserRoles.INTERNAL_USER])
|
||||
def test_agent_detail_cache_miss_preserves_admin_identity_visibility(role, monkeypatch):
|
||||
binding = AgentIdentityBinding(
|
||||
agent_id="agent-123", provider="microsoft_entra", tenant_id="tenant", client_id="client",
|
||||
issuer="https://login.microsoftonline.com/tenant/v2.0", revision="revision",
|
||||
)
|
||||
agent = _sample_agent_response()
|
||||
registry = MagicMock()
|
||||
registry.get_agent_by_id.return_value = None
|
||||
registry.ids_for_agent.return_value = frozenset({agent.agent_id})
|
||||
monkeypatch.setattr(agent_endpoints, "AGENT_REGISTRY", registry)
|
||||
monkeypatch.setattr(
|
||||
"litellm.proxy.agent_endpoints.auth.agent_permission_handler.AgentRequestHandler.is_agent_allowed",
|
||||
AsyncMock(return_value=True),
|
||||
)
|
||||
|
||||
async def load_row(*, where, include):
|
||||
assert where == {"agent_id": agent.agent_id}
|
||||
return agent.model_copy(update={"identity": binding if include.get("identity") else None})
|
||||
|
||||
with patch("litellm.proxy.proxy_server.prisma_client") as prisma:
|
||||
prisma.db.litellm_agentstable.find_unique = AsyncMock(side_effect=load_row)
|
||||
prisma.db.litellm_verificationtoken.find_many = AsyncMock(return_value=[])
|
||||
response = _make_app_with_role(role).get("/v1/agents/agent-123")
|
||||
assert response.status_code == 200
|
||||
assert response.json()["identity"] == (binding.model_dump(mode="json") if role == LitellmUserRoles.PROXY_ADMIN else None)
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ async def test_get_agent_with_read_through_recovers_agent_created_on_sibling_rep
|
|||
assert agent.agent_id == agent_id
|
||||
prisma_client.db.litellm_agentstable.find_unique.assert_awaited_once_with(
|
||||
where={"agent_id": agent_id},
|
||||
include={"object_permission": True},
|
||||
include={"object_permission": True, "identity": True},
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -202,7 +202,7 @@ async def test_get_agent_with_read_through_recovers_agent_by_name(clean_agent_re
|
|||
assert agent.agent_name == agent_name
|
||||
prisma_client.db.litellm_agentstable.find_unique.assert_awaited_with(
|
||||
where={"agent_name": agent_name},
|
||||
include={"object_permission": True},
|
||||
include={"object_permission": True, "identity": True},
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -521,3 +521,33 @@ async def test_resync_agents_waits_for_agent_reload_and_skips_duplicate_registra
|
|||
|
||||
assert await resync_task is True
|
||||
assert len(clean_agent_registry.agent_list) == 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("lookup", ["agent-id", "Agent name"])
|
||||
async def test_agent_read_through_hydrates_identity_binding(lookup, clean_agent_registry, fresh_agent_read_through, monkeypatch):
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
from litellm.proxy.common_utils.registry_read_through import get_agent_with_read_through
|
||||
|
||||
binding = {
|
||||
"agent_id": "agent-id", "provider": "microsoft_entra", "tenant_id": "tenant", "client_id": "client",
|
||||
"issuer": "https://login.microsoftonline.com/tenant/v2.0", "revision": "revision",
|
||||
}
|
||||
|
||||
async def load_row(*, where, include):
|
||||
if where == {"agent_id": "Agent name"}:
|
||||
return None
|
||||
row = FakeAgentRow("agent-id", "Agent name").model_dump()
|
||||
return SimpleNamespace(model_dump=lambda: {**row, "identity": binding if include.get("identity") else None})
|
||||
|
||||
prisma = MagicMock()
|
||||
prisma.db.litellm_agentstable.find_unique = AsyncMock(side_effect=load_row)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", prisma)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.store_model_in_db", True)
|
||||
agent = await get_agent_with_read_through(lookup)
|
||||
assert agent is not None
|
||||
assert agent.identity is not None
|
||||
assert agent.identity.model_dump(include=set(binding)) == binding
|
||||
assert clean_agent_registry.get_agent_by_id(agent_id="agent-id").identity == agent.identity
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue