mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-05 08:07:05 +00:00
fix(agents): keep the published agent in public_agent_groups
`POST /v1/agents/{id}/make_public` appended the agent id to
`litellm.public_agent_groups` and only then called `get_config()`, which
re-applies the DB's `litellm_settings` over the module globals and threw the
append away. The config it saved was therefore a no-op: the endpoint answered
200 with an empty `public_agent_groups`, the agent never reached
`GET /public/agent_hub`, and re-publishing never hit the "already public" 400.
Read the config first, derive the new list from the refreshed globals, save it,
then update the global
Also fixes the e2e model hub spec, which is flaky for a second reason: the
"Make Models Public" modal preselects the groups that are already public, so a
blind click on "Select All" cleared them and left "Next" disabled for the full
15s action timeout. Check the box instead of toggling it, and wait for "Next"
to be enabled before clicking
This commit is contained in:
parent
658f50663d
commit
ccbd3e495c
3 changed files with 87 additions and 16 deletions
|
|
@ -939,35 +939,34 @@ async def make_agent_public(
|
|||
if agent is None:
|
||||
raise HTTPException(status_code=404, detail=f"Agent with ID {agent_id} not found")
|
||||
|
||||
if litellm.public_agent_groups is None:
|
||||
litellm.public_agent_groups = []
|
||||
# handle duplicates
|
||||
if not AGENT_REGISTRY.ids_for_agent(agent.agent_id).isdisjoint(litellm.public_agent_groups):
|
||||
# get_config() re-applies the DB's litellm_settings over the in-memory
|
||||
# globals, so read it before deriving the new list and assign the global after
|
||||
config: Final = await proxy_config.get_config()
|
||||
|
||||
current_public_agent_groups: Final = list(litellm.public_agent_groups or [])
|
||||
if not AGENT_REGISTRY.ids_for_agent(agent.agent_id).isdisjoint(current_public_agent_groups):
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"Agent with name {agent.agent_name} already in public agent groups",
|
||||
)
|
||||
litellm.public_agent_groups.append(agent.agent_id)
|
||||
updated_public_agent_groups: Final = [*current_public_agent_groups, agent.agent_id]
|
||||
|
||||
# Load existing config
|
||||
config: Final = await proxy_config.get_config()
|
||||
|
||||
# Update config with new settings
|
||||
if "litellm_settings" not in config or config["litellm_settings"] is None:
|
||||
config["litellm_settings"] = {}
|
||||
|
||||
config["litellm_settings"]["public_agent_groups"] = litellm.public_agent_groups
|
||||
config["litellm_settings"]["public_agent_groups"] = updated_public_agent_groups
|
||||
|
||||
# Save the updated config
|
||||
await proxy_config.save_config(new_config=config)
|
||||
|
||||
litellm.public_agent_groups = updated_public_agent_groups
|
||||
|
||||
verbose_proxy_logger.debug(
|
||||
"Updated public agent groups to: %s by user: %s", litellm.public_agent_groups, user_api_key_dict.user_id
|
||||
"Updated public agent groups to: %s by user: %s", updated_public_agent_groups, user_api_key_dict.user_id
|
||||
)
|
||||
|
||||
return {
|
||||
"message": "Successfully updated public agent groups",
|
||||
"public_agent_groups": litellm.public_agent_groups,
|
||||
"public_agent_groups": updated_public_agent_groups,
|
||||
"updated_by": user_api_key_dict.user_id,
|
||||
}
|
||||
except HTTPException:
|
||||
|
|
|
|||
|
|
@ -22,11 +22,14 @@ test.describe("AI Hub (internal admin view)", () => {
|
|||
// on the disabled-Next button or the success toast.
|
||||
await expect(modal.getByText(/Select All \(\d+\)/)).toBeVisible({ timeout: 5_000 });
|
||||
|
||||
// Step 1: pick the seeded models via "Select All"
|
||||
await modal.getByText(/Select All/i).click();
|
||||
// Step 1: pick the seeded models via "Select All". check() rather than click() because
|
||||
// the modal preselects groups that are already public, and a click would clear them.
|
||||
await modal.getByRole("checkbox", { name: /Select All/ }).check();
|
||||
|
||||
// Move to confirm step
|
||||
await modal.getByRole("button", { name: "Next" }).click();
|
||||
const next = modal.getByRole("button", { name: "Next" });
|
||||
await expect(next).toBeEnabled();
|
||||
await next.click();
|
||||
await expect(modal.getByText("Confirm Making Models Public")).toBeVisible({ timeout: 5_000 });
|
||||
|
||||
// Submit
|
||||
|
|
|
|||
|
|
@ -1062,3 +1062,72 @@ def test_merged_agent_card_url_has_no_double_slash_without_proxy_base_url(
|
|||
interface_url = merged["supportedInterfaces"][0]["url"]
|
||||
assert interface_url == f"{base_url.rstrip('/')}/a2a/agent-xyz"
|
||||
assert "//a2a" not in interface_url
|
||||
|
||||
|
||||
class _DbBackedProxyConfig:
|
||||
"""Round-trips `litellm_settings` through the DB overlay the proxy applies on every
|
||||
`get_config()`, which is what re-assigns the `litellm.public_*` globals in production."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.stored_litellm_settings: dict = {}
|
||||
|
||||
async def get_config(self) -> dict:
|
||||
from litellm.proxy.proxy_server import ProxyConfig
|
||||
|
||||
config: dict = {"litellm_settings": {}}
|
||||
if not self.stored_litellm_settings:
|
||||
return config
|
||||
return ProxyConfig()._update_config_fields(
|
||||
current_config=config,
|
||||
param_name="litellm_settings",
|
||||
db_param_value=dict(self.stored_litellm_settings),
|
||||
)
|
||||
|
||||
async def save_config(self, new_config: dict) -> None:
|
||||
self.stored_litellm_settings = dict(new_config.get("litellm_settings") or {})
|
||||
|
||||
|
||||
def test_make_agent_public_twice_keeps_both_agents_public(monkeypatch):
|
||||
"""A second /make_public call must not drop the agent published by the first one."""
|
||||
import litellm
|
||||
from litellm.proxy.agent_endpoints import agent_registry as agent_registry_module
|
||||
from litellm.proxy.agent_endpoints.agent_registry import AgentRegistry
|
||||
|
||||
registry = AgentRegistry()
|
||||
registry.register_agent(_sample_agent_response(agent_id="agent-1", agent_name="Agent One"))
|
||||
registry.register_agent(_sample_agent_response(agent_id="agent-2", agent_name="Agent Two"))
|
||||
|
||||
monkeypatch.setattr(agent_registry_module, "global_agent_registry", registry)
|
||||
monkeypatch.setattr(litellm, "public_agent_groups", None)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", MagicMock())
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.proxy_config", _DbBackedProxyConfig())
|
||||
|
||||
first = client.post("/v1/agents/agent-1/make_public", headers={"Authorization": "Bearer test-key"})
|
||||
second = client.post("/v1/agents/agent-2/make_public", headers={"Authorization": "Bearer test-key"})
|
||||
|
||||
assert first.status_code == 200
|
||||
assert second.status_code == 200
|
||||
assert second.json()["public_agent_groups"] == ["agent-1", "agent-2"]
|
||||
assert [agent.agent_id for agent in registry.get_public_agent_list()] == ["agent-1", "agent-2"]
|
||||
|
||||
|
||||
def test_make_agent_public_rejects_an_already_public_agent(monkeypatch):
|
||||
"""The duplicate guard must still fire when the published list comes back from the DB."""
|
||||
import litellm
|
||||
from litellm.proxy.agent_endpoints import agent_registry as agent_registry_module
|
||||
from litellm.proxy.agent_endpoints.agent_registry import AgentRegistry
|
||||
|
||||
registry = AgentRegistry()
|
||||
registry.register_agent(_sample_agent_response(agent_id="agent-1", agent_name="Agent One"))
|
||||
|
||||
monkeypatch.setattr(agent_registry_module, "global_agent_registry", registry)
|
||||
monkeypatch.setattr(litellm, "public_agent_groups", None)
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.prisma_client", MagicMock())
|
||||
monkeypatch.setattr("litellm.proxy.proxy_server.proxy_config", _DbBackedProxyConfig())
|
||||
|
||||
first = client.post("/v1/agents/agent-1/make_public", headers={"Authorization": "Bearer test-key"})
|
||||
duplicate = client.post("/v1/agents/agent-1/make_public", headers={"Authorization": "Bearer test-key"})
|
||||
|
||||
assert first.status_code == 200
|
||||
assert duplicate.status_code == 400
|
||||
assert "already in public agent groups" in duplicate.json()["detail"]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue