mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-07 02:59:05 +00:00
fix(agents): PUT update_agent_in_db clears static_headers and extra_headers when omitted
For full-replace PUT semantics, always include static_headers and extra_headers
in update_data, defaulting to {} and [] when not supplied. Previously,
omitting these fields left stale DB values intact (e.g. auth headers).
Made-with: Cursor
This commit is contained in:
parent
04c904f4d6
commit
501671aa43
2 changed files with 119 additions and 7 deletions
|
|
@ -305,24 +305,22 @@ class AgentRegistry:
|
|||
|
||||
# Serialize static_headers for update
|
||||
static_headers_obj_u = agent.get("static_headers")
|
||||
static_headers_val_u: Optional[str] = (
|
||||
static_headers_val_u: str = (
|
||||
safe_dumps(dict(static_headers_obj_u))
|
||||
if static_headers_obj_u is not None
|
||||
else None
|
||||
else safe_dumps({})
|
||||
)
|
||||
extra_headers_val_u: Optional[List[str]] = agent.get("extra_headers")
|
||||
extra_headers_val_u: List[str] = agent.get("extra_headers") or []
|
||||
|
||||
update_data: Dict[str, Any] = {
|
||||
"agent_name": agent_name,
|
||||
"litellm_params": litellm_params,
|
||||
"agent_card_params": agent_card_params,
|
||||
"static_headers": static_headers_val_u,
|
||||
"extra_headers": extra_headers_val_u,
|
||||
"updated_by": updated_by,
|
||||
"updated_at": datetime.now(timezone.utc),
|
||||
}
|
||||
if static_headers_val_u is not None:
|
||||
update_data["static_headers"] = static_headers_val_u
|
||||
if extra_headers_val_u is not None:
|
||||
update_data["extra_headers"] = extra_headers_val_u
|
||||
if agent.get("object_permission") is not None:
|
||||
existing_agent = await prisma_client.db.litellm_agentstable.find_unique(
|
||||
where={"agent_id": agent_id}
|
||||
|
|
|
|||
114
tests/test_litellm/proxy/agent_endpoints/test_agent_registry.py
Normal file
114
tests/test_litellm/proxy/agent_endpoints/test_agent_registry.py
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
"""Unit tests for AgentRegistry DB operations."""
|
||||
|
||||
from unittest.mock import AsyncMock, MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from litellm.proxy.agent_endpoints.agent_registry import AgentRegistry
|
||||
|
||||
|
||||
def _sample_agent_card_params() -> dict:
|
||||
return {
|
||||
"protocolVersion": "1.0",
|
||||
"name": "Test Agent",
|
||||
"description": "desc",
|
||||
"url": "http://localhost",
|
||||
"version": "1.0.0",
|
||||
"capabilities": {"streaming": True},
|
||||
"defaultInputModes": ["text"],
|
||||
"defaultOutputModes": ["text"],
|
||||
"skills": [],
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_update_agent_in_db_clears_static_headers_and_extra_headers_when_omitted():
|
||||
"""
|
||||
PUT (full-replace) should clear static_headers and extra_headers when omitted.
|
||||
Previously, omitting these fields left stale DB values intact.
|
||||
"""
|
||||
registry = AgentRegistry()
|
||||
mock_prisma = MagicMock()
|
||||
|
||||
# Simulate existing agent that had headers set
|
||||
updated_agent = MagicMock()
|
||||
updated_agent.model_dump.return_value = {
|
||||
"agent_id": "agent-123",
|
||||
"agent_name": "Updated Agent",
|
||||
"agent_card_params": _sample_agent_card_params(),
|
||||
"litellm_params": {},
|
||||
"static_headers": {},
|
||||
"extra_headers": [],
|
||||
"object_permission": None,
|
||||
}
|
||||
updated_agent.object_permission = None
|
||||
|
||||
mock_update = AsyncMock(return_value=updated_agent)
|
||||
mock_prisma.db.litellm_agentstable.update = mock_update
|
||||
|
||||
# Agent config WITHOUT static_headers or extra_headers (omitted)
|
||||
agent_config = {
|
||||
"agent_name": "Updated Agent",
|
||||
"agent_card_params": _sample_agent_card_params(),
|
||||
"litellm_params": {},
|
||||
}
|
||||
|
||||
await registry.update_agent_in_db(
|
||||
agent_id="agent-123",
|
||||
agent=agent_config,
|
||||
prisma_client=mock_prisma,
|
||||
updated_by="test-user",
|
||||
)
|
||||
|
||||
mock_update.assert_awaited_once()
|
||||
call_kwargs = mock_update.call_args.kwargs
|
||||
update_data = call_kwargs["data"]
|
||||
|
||||
# Should include static_headers and extra_headers with empty defaults
|
||||
assert "static_headers" in update_data
|
||||
assert update_data["static_headers"] == "{}"
|
||||
assert "extra_headers" in update_data
|
||||
assert update_data["extra_headers"] == []
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_update_agent_in_db_preserves_explicit_static_headers_and_extra_headers():
|
||||
"""PUT with explicit values should still work correctly."""
|
||||
registry = AgentRegistry()
|
||||
mock_prisma = MagicMock()
|
||||
|
||||
updated_agent = MagicMock()
|
||||
updated_agent.model_dump.return_value = {
|
||||
"agent_id": "agent-123",
|
||||
"agent_name": "Updated Agent",
|
||||
"agent_card_params": _sample_agent_card_params(),
|
||||
"litellm_params": {},
|
||||
"static_headers": {"Authorization": "Bearer xyz"},
|
||||
"extra_headers": ["X-Custom-Header"],
|
||||
"object_permission": None,
|
||||
}
|
||||
updated_agent.object_permission = None
|
||||
|
||||
mock_update = AsyncMock(return_value=updated_agent)
|
||||
mock_prisma.db.litellm_agentstable.update = mock_update
|
||||
|
||||
agent_config = {
|
||||
"agent_name": "Updated Agent",
|
||||
"agent_card_params": _sample_agent_card_params(),
|
||||
"litellm_params": {},
|
||||
"static_headers": {"Authorization": "Bearer xyz"},
|
||||
"extra_headers": ["X-Custom-Header"],
|
||||
}
|
||||
|
||||
await registry.update_agent_in_db(
|
||||
agent_id="agent-123",
|
||||
agent=agent_config,
|
||||
prisma_client=mock_prisma,
|
||||
updated_by="test-user",
|
||||
)
|
||||
|
||||
call_kwargs = mock_update.call_args.kwargs
|
||||
update_data = call_kwargs["data"]
|
||||
|
||||
assert update_data["static_headers"] == '{"Authorization": "Bearer xyz"}'
|
||||
assert update_data["extra_headers"] == ["X-Custom-Header"]
|
||||
Loading…
Add table
Reference in a new issue