mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-14 23:21:35 +00:00
fix(agents): preserve config agent_list and agent_access_groups when store_model_in_db is enabled
This commit is contained in:
parent
b9008cca35
commit
dccc433703
4 changed files with 50 additions and 6 deletions
|
|
@ -16,6 +16,7 @@ from litellm.types.agents import AgentConfig, AgentResponse, PatchAgentRequest
|
|||
class AgentRegistry:
|
||||
def __init__(self):
|
||||
self.agent_list: List[AgentResponse] = []
|
||||
self.config_agents: Optional[List[AgentConfig]] = None
|
||||
|
||||
def reset_agent_list(self):
|
||||
self.agent_list = []
|
||||
|
|
@ -44,6 +45,7 @@ class AgentRegistry:
|
|||
return hashlib.sha256(json.dumps(agent_config, sort_keys=True).encode()).hexdigest()
|
||||
|
||||
def load_agents_from_config(self, agent_config: Optional[List[AgentConfig]] = None):
|
||||
self.config_agents = agent_config
|
||||
if agent_config is None:
|
||||
return None
|
||||
|
||||
|
|
@ -68,8 +70,10 @@ class AgentRegistry:
|
|||
):
|
||||
self.reset_agent_list()
|
||||
|
||||
if agent_config:
|
||||
for agent_config_item in agent_config:
|
||||
resolved_config = agent_config if agent_config is not None else self.config_agents
|
||||
|
||||
if resolved_config:
|
||||
for agent_config_item in resolved_config:
|
||||
if not isinstance(agent_config_item, dict):
|
||||
raise ValueError("agent_config must be a list of dictionaries")
|
||||
|
||||
|
|
|
|||
|
|
@ -605,8 +605,6 @@ from fastapi.security import OAuth2PasswordBearer
|
|||
from fastapi.security.api_key import APIKeyHeader
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
from litellm.types.agents import AgentConfig
|
||||
|
||||
# import enterprise folder
|
||||
enterprise_router = APIRouter()
|
||||
try:
|
||||
|
|
@ -1885,7 +1883,6 @@ config_passthrough_endpoints: Optional[List[Dict[str, Any]]] = None
|
|||
log_file = "api_log.json"
|
||||
worker_config = None
|
||||
master_key: Optional[str] = None
|
||||
config_agents: Optional[List[AgentConfig]] = None
|
||||
otel_logging = False
|
||||
prisma_client: Optional[PrismaClient] = None
|
||||
shared_aiohttp_session: Optional["ClientSession"] = None # Global shared session for connection reuse
|
||||
|
|
@ -6380,7 +6377,7 @@ class ProxyConfig:
|
|||
|
||||
try:
|
||||
db_agents = await AGENT_REGISTRY.get_all_agents_from_db(prisma_client=prisma_client)
|
||||
AGENT_REGISTRY.load_agents_from_db_and_config(db_agents=db_agents, agent_config=config_agents)
|
||||
AGENT_REGISTRY.load_agents_from_db_and_config(db_agents=db_agents)
|
||||
except Exception as e:
|
||||
verbose_proxy_logger.exception(
|
||||
"litellm.proxy.proxy_server.py::ProxyConfig:_init_agents_in_db - {}".format(str(e))
|
||||
|
|
|
|||
|
|
@ -181,6 +181,7 @@ class AgentConfig(TypedDict, total=False):
|
|||
agent_card_params: Required[AgentCard]
|
||||
litellm_params: Dict[str, Any] # allow for any future litellm params
|
||||
object_permission: AgentObjectPermission
|
||||
agent_access_groups: Optional[List[str]]
|
||||
tpm_limit: Optional[int]
|
||||
rpm_limit: Optional[int]
|
||||
session_tpm_limit: Optional[int]
|
||||
|
|
@ -217,6 +218,7 @@ class AgentResponse(BaseModel):
|
|||
litellm_params: Optional[Dict[str, Any]] = None
|
||||
agent_card_params: Dict[str, Any]
|
||||
object_permission: Optional[Dict[str, Any]] = None
|
||||
agent_access_groups: Optional[List[str]] = None
|
||||
spend: Optional[float] = None
|
||||
tpm_limit: Optional[int] = None
|
||||
rpm_limit: Optional[int] = None
|
||||
|
|
|
|||
|
|
@ -21,6 +21,47 @@ def _sample_agent_card_params() -> dict:
|
|||
}
|
||||
|
||||
|
||||
def test_load_agents_from_db_and_config_preserves_config_agents_when_db_object_reload():
|
||||
"""
|
||||
Regression for #32799: with store_model_in_db, _init_agents_in_db calls
|
||||
load_agents_from_db_and_config() without passing the config agents. Config
|
||||
agents registered at startup must not be wiped; they should be re-registered
|
||||
from the config stored on the registry.
|
||||
"""
|
||||
registry = AgentRegistry()
|
||||
|
||||
config_agent = {
|
||||
"agent_name": "Config Agent",
|
||||
"agent_card_params": _sample_agent_card_params(),
|
||||
}
|
||||
registry.load_agents_from_config([config_agent])
|
||||
assert [a.agent_name for a in registry.get_agent_list()] == ["Config Agent"]
|
||||
|
||||
# Simulate the DB reload path with no db agents and no explicit config passed.
|
||||
registry.load_agents_from_db_and_config(db_agents=[])
|
||||
|
||||
assert [a.agent_name for a in registry.get_agent_list()] == ["Config Agent"]
|
||||
|
||||
|
||||
def test_load_agents_from_config_preserves_agent_access_groups():
|
||||
"""
|
||||
Regression for #32799: agent_access_groups declared on config agents must be
|
||||
retained on the AgentResponse so config agents can be scoped via access groups.
|
||||
"""
|
||||
registry = AgentRegistry()
|
||||
|
||||
config_agent = {
|
||||
"agent_name": "Scoped Agent",
|
||||
"agent_card_params": _sample_agent_card_params(),
|
||||
"agent_access_groups": ["group-a", "group-b"],
|
||||
}
|
||||
registry.load_agents_from_config([config_agent])
|
||||
|
||||
agents = registry.get_agent_list()
|
||||
assert len(agents) == 1
|
||||
assert agents[0].agent_access_groups == ["group-a", "group-b"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_update_agent_in_db_clears_static_headers_and_extra_headers_when_omitted():
|
||||
"""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue