fix(agents): allow optional securityScheme fields so /public/agent_hub does not 500 (#33897)

Co-authored-by: shivam <shivam@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
devin-ai-integration[bot] 2026-07-20 18:13:09 -07:00 • committed by GitHub
parent 089de50d20
commit 9d6d6c4fe0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 67 additions and 17 deletions

View file

@ -45,26 +45,26 @@ class SecuritySchemeBase(TypedDict, total=False):
description: Optional[str]
class APIKeySecurityScheme(SecuritySchemeBase):
class APIKeySecurityScheme(SecuritySchemeBase, total=False):
"""Defines a security scheme using an API key."""
type: Literal["apiKey"]
in_: Literal["query", "header", "cookie"] # using in_ to avoid Python keyword
name: str
type: Required[Literal["apiKey"]]
in_: Required[Literal["query", "header", "cookie"]] # using in_ to avoid Python keyword
name: Required[str]
class HTTPAuthSecurityScheme(SecuritySchemeBase):
class HTTPAuthSecurityScheme(SecuritySchemeBase, total=False):
"""Defines a security scheme using HTTP authentication."""
type: Literal["http"]
scheme: str
type: Required[Literal["http"]]
scheme: Required[str]
bearerFormat: Optional[str]
class MutualTLSSecurityScheme(SecuritySchemeBase):
class MutualTLSSecurityScheme(SecuritySchemeBase, total=False):
"""Defines a security scheme using mTLS authentication."""
type: Literal["mutualTLS"]
type: Required[Literal["mutualTLS"]]
class OAuthFlows(TypedDict, total=False):
@ -76,19 +76,19 @@ class OAuthFlows(TypedDict, total=False):
password: Optional[Dict[str, Any]]
class OAuth2SecurityScheme(SecuritySchemeBase):
class OAuth2SecurityScheme(SecuritySchemeBase, total=False):
"""Defines a security scheme using OAuth 2.0."""
type: Literal["oauth2"]
flows: OAuthFlows
type: Required[Literal["oauth2"]]
flows: Required[OAuthFlows]
oauth2MetadataUrl: Optional[str]
class OpenIdConnectSecurityScheme(SecuritySchemeBase):
class OpenIdConnectSecurityScheme(SecuritySchemeBase, total=False):
"""Defines a security scheme using OpenID Connect."""
type: Literal["openIdConnect"]
openIdConnectUrl: str
type: Required[Literal["openIdConnect"]]
openIdConnectUrl: Required[str]
# Union of all security schemes

View file

@ -600,6 +600,56 @@ def test_public_agent_hub_rewrites_upstream_url_to_proxy():
assert card["url"].endswith("/a2a/agent-123")
def test_public_agent_hub_serializes_http_security_scheme_without_bearer_format():
"""Regression: agents created through the UI carry an auto-generated
``securitySchemes.LiteLLMKey`` of ``{"type": "http", "scheme": "bearer"}``
with no ``bearerFormat``. The endpoint response_model must accept this
optional-field-omitted scheme; otherwise response validation raises and
/public/agent_hub returns 500, which the frontend swallows into an empty
list and hides the Agent Hub tab."""
from litellm.types.agents import AgentResponse
agent = AgentResponse(
agent_id="agent-123",
agent_name="public-agent",
agent_card_params={
"name": "public-agent",
"url": "https://upstream.internal.example.com/a2a",
"securitySchemes": {
"LiteLLMKey": {
"type": "http",
"scheme": "bearer",
"description": "LiteLLM virtual key",
}
},
},
)
app = FastAPI()
app.include_router(router)
client = TestClient(app)
mock_registry = MagicMock()
mock_registry.get_public_agent_list.return_value = [agent]
with (
patch("litellm.public_agent_groups", ["agent-123"]),
patch(
"litellm.proxy.agent_endpoints.agent_registry.global_agent_registry",
mock_registry,
),
):
response = client.get("/public/agent_hub")
assert response.status_code == 200, response.text
payload = response.json()
assert len(payload) == 1
scheme = payload[0]["securitySchemes"]["LiteLLMKey"]
assert scheme["type"] == "http"
assert scheme["scheme"] == "bearer"
assert "bearerFormat" not in scheme
def test_public_agent_hub_returns_empty_when_no_public_groups():
app = FastAPI()
app.include_router(router)

View file

@ -24341,7 +24341,7 @@ export interface components {
*/
HTTPAuthSecurityScheme: {
/** Bearerformat */
bearerFormat: string | null;
bearerFormat?: string | null;
/** Description */
description?: string | null;
/** Scheme */
@ -28529,7 +28529,7 @@ export interface components {
description?: string | null;
flows: components["schemas"]["OAuthFlows"];
/** Oauth2Metadataurl */
oauth2MetadataUrl: string | null;
oauth2MetadataUrl?: string | null;
/**
* Type
* @constant