mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-07 02:59:05 +00:00
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:
parent
089de50d20
commit
9d6d6c4fe0
3 changed files with 67 additions and 17 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
4
ui/litellm-dashboard/src/lib/http/schema.d.ts
generated
vendored
4
ui/litellm-dashboard/src/lib/http/schema.d.ts
generated
vendored
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue