mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-10 22:41:41 +00:00
Agents health checks (#23044)
* feat: add health check toggle to agents page Backend: - Add health_check query parameter to GET /v1/agents endpoint - When health_check=true, performs concurrent GET requests to each agent's URL and filters out agents with unreachable URLs (5s timeout) - Agents returning HTTP <500 are considered healthy; 5xx and connection errors mark agents as unhealthy UI: - Add Health Check toggle (Switch) to agents panel header - Toggle triggers re-fetch with health_check=true, filtering the agent list - Icon color changes (green/gray) to indicate toggle state - Tooltip explains behavior: 'only agents with reachable URLs are shown' Networking: - Update getAgentsList to accept optional healthCheck boolean parameter Tests: - Backend: 9 new tests covering health check filtering, _check_agent_url_health helper (no URL, 200, 404, 500, connection error cases) - UI: 3 new tests verifying toggle renders, initial fetch without health check, and fetch with health check after toggle click Co-authored-by: Krish Dholakia <krrishdholakia@gmail.com> * fix: fix greptile comment re: security issue * fix: fix based on greptile feedback * fix: align health check tests with implementation - Rename test_should_return_unhealthy_when_no_url to test_should_return_healthy_when_no_url (implementation returns healthy=True for agents without a URL) - Patch get_async_httpx_client instead of httpx.AsyncClient so mocks actually intercept the HTTP calls made by _check_agent_url_health - Remove unnecessary __aenter__/__aexit__ context-manager mocks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: undo _experimental/out renames from cherry-pick Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update litellm/proxy/agent_endpoints/endpoints.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This commit is contained in:
parent
e7714f0ce6
commit
03ca98123f
8 changed files with 374 additions and 13 deletions
|
|
@ -8,12 +8,15 @@ Follows the A2A Spec.
|
|||
3. Get specific agent via GET `/v1/agents/{agent_id}`
|
||||
"""
|
||||
|
||||
from typing import Any, List, Optional
|
||||
import asyncio
|
||||
import os
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Request
|
||||
|
||||
import litellm
|
||||
from litellm._logging import verbose_proxy_logger
|
||||
from litellm.llms.custom_httpx.http_handler import get_async_httpx_client
|
||||
from litellm.proxy._types import CommonProxyErrors, LitellmUserRoles, UserAPIKeyAuth
|
||||
from litellm.proxy.auth.user_api_key_auth import user_api_key_auth
|
||||
from litellm.proxy.common_utils.rbac_utils import check_feature_access_for_user
|
||||
|
|
@ -25,6 +28,7 @@ from litellm.types.agents import (
|
|||
MakeAgentsPublicRequest,
|
||||
PatchAgentRequest,
|
||||
)
|
||||
from litellm.types.llms.custom_http import httpxSpecialProvider
|
||||
from litellm.types.proxy.management_endpoints.common_daily_activity import (
|
||||
SpendAnalyticsPaginatedResponse,
|
||||
)
|
||||
|
|
@ -49,6 +53,48 @@ def _check_agent_management_permission(user_api_key_dict: UserAPIKeyAuth) -> Non
|
|||
)
|
||||
|
||||
|
||||
AGENT_HEALTH_CHECK_TIMEOUT_SECONDS = float(
|
||||
os.environ.get("LITELLM_AGENT_HEALTH_CHECK_TIMEOUT", "5.0")
|
||||
)
|
||||
AGENT_HEALTH_CHECK_GATHER_TIMEOUT_SECONDS = float(
|
||||
os.environ.get("LITELLM_AGENT_HEALTH_CHECK_GATHER_TIMEOUT", "30.0")
|
||||
)
|
||||
|
||||
|
||||
async def _check_agent_url_health(
|
||||
agent: AgentResponse,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Perform a GET request against the agent's URL and return the health result.
|
||||
|
||||
Returns a dict with ``agent_id``, ``healthy`` (bool), and an optional
|
||||
``error`` message.
|
||||
"""
|
||||
url = (agent.agent_card_params or {}).get("url")
|
||||
if not url:
|
||||
return {"agent_id": agent.agent_id, "healthy": True}
|
||||
|
||||
try:
|
||||
client = get_async_httpx_client(
|
||||
llm_provider=httpxSpecialProvider.AgentHealthCheck,
|
||||
params={"timeout": AGENT_HEALTH_CHECK_TIMEOUT_SECONDS},
|
||||
)
|
||||
response = await client.get(url)
|
||||
if response.status_code >= 500:
|
||||
return {
|
||||
"agent_id": agent.agent_id,
|
||||
"healthy": False,
|
||||
"error": f"HTTP {response.status_code}",
|
||||
}
|
||||
return {"agent_id": agent.agent_id, "healthy": True}
|
||||
except Exception as exc:
|
||||
return {
|
||||
"agent_id": agent.agent_id,
|
||||
"healthy": False,
|
||||
"error": str(exc),
|
||||
}
|
||||
|
||||
|
||||
@router.get(
|
||||
"/v1/agents",
|
||||
tags=["[beta] A2A Agents"],
|
||||
|
|
@ -57,6 +103,9 @@ def _check_agent_management_permission(user_api_key_dict: UserAPIKeyAuth) -> Non
|
|||
)
|
||||
async def get_agents(
|
||||
request: Request,
|
||||
health_check: bool = Query(
|
||||
False,
|
||||
description="When true, performs a GET request to each agent's URL. Agents with reachable URLs (HTTP status < 500) and agents without a URL are returned; unreachable agents are filtered out.",
|
||||
user_api_key_dict: UserAPIKeyAuth = Depends(user_api_key_auth), # Used for auth
|
||||
):
|
||||
"""
|
||||
|
|
@ -67,6 +116,13 @@ async def get_agents(
|
|||
-H "Authorization: Bearer your-key" \
|
||||
```
|
||||
|
||||
Pass `?health_check=true` to filter out agents whose URL is unreachable:
|
||||
```
|
||||
curl -X GET "http://localhost:4000/v1/agents?health_check=true" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer your-key" \
|
||||
```
|
||||
|
||||
Returns: List[AgentResponse]
|
||||
|
||||
"""
|
||||
|
|
@ -112,6 +168,44 @@ async def get_agents(
|
|||
and (agent.agent_id in litellm.public_agent_groups)
|
||||
)
|
||||
|
||||
if health_check:
|
||||
agents_with_url = [
|
||||
agent
|
||||
for agent in returned_agents
|
||||
if (agent.agent_card_params or {}).get("url")
|
||||
]
|
||||
agents_without_url = [
|
||||
agent
|
||||
for agent in returned_agents
|
||||
if not (agent.agent_card_params or {}).get("url")
|
||||
]
|
||||
try:
|
||||
health_results = await asyncio.wait_for(
|
||||
asyncio.gather(
|
||||
*[_check_agent_url_health(agent) for agent in agents_with_url]
|
||||
),
|
||||
timeout=AGENT_HEALTH_CHECK_GATHER_TIMEOUT_SECONDS,
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
verbose_proxy_logger.warning(
|
||||
"Agent health check gather timed out after %s seconds",
|
||||
AGENT_HEALTH_CHECK_GATHER_TIMEOUT_SECONDS,
|
||||
)
|
||||
health_results = [
|
||||
{"agent_id": agent.agent_id, "healthy": False, "error": "Health check timed out"}
|
||||
for agent in agents_with_url
|
||||
]
|
||||
healthy_ids = {
|
||||
result["agent_id"]
|
||||
for result in health_results
|
||||
if result["healthy"]
|
||||
}
|
||||
returned_agents = [
|
||||
agent
|
||||
for agent in agents_with_url
|
||||
if agent.agent_id in healthy_ids
|
||||
] + agents_without_url
|
||||
|
||||
return returned_agents
|
||||
except HTTPException:
|
||||
raise
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ class httpxSpecialProvider(str, Enum):
|
|||
MCP = "mcp"
|
||||
RAG = "rag"
|
||||
A2AProvider = "a2a_provider"
|
||||
AgentHealthCheck = "agent_health_check"
|
||||
A2A = "a2a"
|
||||
PromptManagement = "prompt_management"
|
||||
UI = "ui"
|
||||
|
|
|
|||
|
|
@ -439,3 +439,200 @@ class TestAgentRoutesIncludesAgentIdPattern:
|
|||
from litellm.proxy._types import LiteLLMRoutes
|
||||
|
||||
assert "/v1/agents/{agent_id}" in LiteLLMRoutes.agent_routes.value
|
||||
|
||||
|
||||
class TestAgentHealthCheck:
|
||||
"""Tests for the health_check query parameter on GET /v1/agents."""
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _setup(self, monkeypatch):
|
||||
from litellm.proxy.agent_endpoints import agent_registry as ar_mod
|
||||
|
||||
self.admin_client = _make_app_with_role(LitellmUserRoles.PROXY_ADMIN)
|
||||
self.mock_registry = MagicMock()
|
||||
monkeypatch.setattr(ar_mod, "global_agent_registry", self.mock_registry)
|
||||
|
||||
def _make_agent(self, agent_id: str, url: str | None = None) -> AgentResponse:
|
||||
card = _sample_agent_card_params()
|
||||
if url is not None:
|
||||
card["url"] = url
|
||||
else:
|
||||
card.pop("url", None)
|
||||
return AgentResponse(
|
||||
agent_id=agent_id,
|
||||
agent_name=f"Agent {agent_id}",
|
||||
agent_card_params=card,
|
||||
litellm_params={},
|
||||
)
|
||||
|
||||
def test_should_return_all_agents_when_health_check_disabled(self):
|
||||
agents = [self._make_agent("a1", "http://reachable"), self._make_agent("a2", "http://unreachable")]
|
||||
self.mock_registry.get_agent_list = MagicMock(return_value=agents)
|
||||
|
||||
resp = self.admin_client.get(
|
||||
"/v1/agents", headers={"Authorization": "Bearer k"}
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
assert len(resp.json()) == 2
|
||||
|
||||
def test_should_filter_unhealthy_agents_when_health_check_enabled(self, monkeypatch):
|
||||
agents = [
|
||||
self._make_agent("a1", "http://reachable"),
|
||||
self._make_agent("a2", "http://unreachable"),
|
||||
]
|
||||
self.mock_registry.get_agent_list = MagicMock(return_value=agents)
|
||||
|
||||
results = iter([
|
||||
{"agent_id": "a1", "healthy": True},
|
||||
{"agent_id": "a2", "healthy": False, "error": "Connection refused"},
|
||||
])
|
||||
monkeypatch.setattr(
|
||||
agent_endpoints,
|
||||
"_check_agent_url_health",
|
||||
AsyncMock(side_effect=lambda agent: next(results)),
|
||||
)
|
||||
|
||||
resp = self.admin_client.get(
|
||||
"/v1/agents?health_check=true",
|
||||
headers={"Authorization": "Bearer k"},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert len(data) == 1
|
||||
assert data[0]["agent_id"] == "a1"
|
||||
|
||||
def test_should_return_empty_list_when_all_agents_unhealthy(self, monkeypatch):
|
||||
agents = [self._make_agent("a1", "http://down")]
|
||||
self.mock_registry.get_agent_list = MagicMock(return_value=agents)
|
||||
monkeypatch.setattr(
|
||||
agent_endpoints,
|
||||
"_check_agent_url_health",
|
||||
AsyncMock(return_value={"agent_id": "a1", "healthy": False, "error": "timeout"}),
|
||||
)
|
||||
|
||||
resp = self.admin_client.get(
|
||||
"/v1/agents?health_check=true",
|
||||
headers={"Authorization": "Bearer k"},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
assert len(resp.json()) == 0
|
||||
|
||||
def test_should_return_all_agents_when_all_healthy(self, monkeypatch):
|
||||
agents = [self._make_agent("a1", "http://ok1"), self._make_agent("a2", "http://ok2")]
|
||||
self.mock_registry.get_agent_list = MagicMock(return_value=agents)
|
||||
|
||||
results = iter([
|
||||
{"agent_id": "a1", "healthy": True},
|
||||
{"agent_id": "a2", "healthy": True},
|
||||
])
|
||||
monkeypatch.setattr(
|
||||
agent_endpoints,
|
||||
"_check_agent_url_health",
|
||||
AsyncMock(side_effect=lambda agent: next(results)),
|
||||
)
|
||||
|
||||
resp = self.admin_client.get(
|
||||
"/v1/agents?health_check=true",
|
||||
headers={"Authorization": "Bearer k"},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
assert len(resp.json()) == 2
|
||||
|
||||
|
||||
class TestCheckAgentUrlHealth:
|
||||
"""Unit tests for the _check_agent_url_health helper."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_should_return_healthy_when_no_url(self):
|
||||
from litellm.proxy.agent_endpoints.endpoints import _check_agent_url_health
|
||||
|
||||
agent = AgentResponse(
|
||||
agent_id="no-url",
|
||||
agent_name="No URL Agent",
|
||||
agent_card_params={"name": "test"},
|
||||
litellm_params={},
|
||||
)
|
||||
result = await _check_agent_url_health(agent)
|
||||
assert result["healthy"] is True
|
||||
assert "error" not in result
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("litellm.proxy.agent_endpoints.endpoints.get_async_httpx_client")
|
||||
async def test_should_return_healthy_for_200(self, mock_get_client):
|
||||
from litellm.proxy.agent_endpoints.endpoints import _check_agent_url_health
|
||||
|
||||
mock_response = MagicMock()
|
||||
mock_response.status_code = 200
|
||||
mock_client = AsyncMock()
|
||||
mock_client.get = AsyncMock(return_value=mock_response)
|
||||
mock_get_client.return_value = mock_client
|
||||
|
||||
agent = AgentResponse(
|
||||
agent_id="ok",
|
||||
agent_name="OK Agent",
|
||||
agent_card_params={"url": "http://example.com"},
|
||||
litellm_params={},
|
||||
)
|
||||
result = await _check_agent_url_health(agent)
|
||||
assert result["healthy"] is True
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("litellm.proxy.agent_endpoints.endpoints.get_async_httpx_client")
|
||||
async def test_should_return_unhealthy_for_500(self, mock_get_client):
|
||||
from litellm.proxy.agent_endpoints.endpoints import _check_agent_url_health
|
||||
|
||||
mock_response = MagicMock()
|
||||
mock_response.status_code = 500
|
||||
mock_client = AsyncMock()
|
||||
mock_client.get = AsyncMock(return_value=mock_response)
|
||||
mock_get_client.return_value = mock_client
|
||||
|
||||
agent = AgentResponse(
|
||||
agent_id="err",
|
||||
agent_name="Error Agent",
|
||||
agent_card_params={"url": "http://failing.com"},
|
||||
litellm_params={},
|
||||
)
|
||||
result = await _check_agent_url_health(agent)
|
||||
assert result["healthy"] is False
|
||||
assert "HTTP 500" in result["error"]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("litellm.proxy.agent_endpoints.endpoints.get_async_httpx_client")
|
||||
async def test_should_return_unhealthy_on_connection_error(self, mock_get_client):
|
||||
from litellm.proxy.agent_endpoints.endpoints import _check_agent_url_health
|
||||
|
||||
mock_client = AsyncMock()
|
||||
mock_client.get = AsyncMock(side_effect=Exception("Connection refused"))
|
||||
mock_get_client.return_value = mock_client
|
||||
|
||||
agent = AgentResponse(
|
||||
agent_id="down",
|
||||
agent_name="Down Agent",
|
||||
agent_card_params={"url": "http://down.com"},
|
||||
litellm_params={},
|
||||
)
|
||||
result = await _check_agent_url_health(agent)
|
||||
assert result["healthy"] is False
|
||||
assert "Connection refused" in result["error"]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("litellm.proxy.agent_endpoints.endpoints.get_async_httpx_client")
|
||||
async def test_should_treat_404_as_healthy(self, mock_get_client):
|
||||
"""A 404 means the server is reachable, just not the specific path."""
|
||||
from litellm.proxy.agent_endpoints.endpoints import _check_agent_url_health
|
||||
|
||||
mock_response = MagicMock()
|
||||
mock_response.status_code = 404
|
||||
mock_client = AsyncMock()
|
||||
mock_client.get = AsyncMock(return_value=mock_response)
|
||||
mock_get_client.return_value = mock_client
|
||||
|
||||
agent = AgentResponse(
|
||||
agent_id="notfound",
|
||||
agent_name="NotFound Agent",
|
||||
agent_card_params={"url": "http://example.com/missing"},
|
||||
litellm_params={},
|
||||
)
|
||||
result = await _check_agent_url_health(agent)
|
||||
assert result["healthy"] is True
|
||||
|
|
|
|||
15
ui/litellm-dashboard/package-lock.json
generated
15
ui/litellm-dashboard/package-lock.json
generated
|
|
@ -13279,6 +13279,21 @@
|
|||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-ia32-msvc": {
|
||||
"version": "14.2.33",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.33.tgz",
|
||||
"integrity": "sha512-pc9LpGNKhJ0dXQhZ5QMmYxtARwwmWLpeocFmVG5Z0DzWq5Uf0izcI8tLc+qOpqxO1PWqZ5A7J1blrUIKrIFc7Q==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import React from "react";
|
||||
import { render, screen, waitFor } from "@testing-library/react";
|
||||
import { render, screen, waitFor, act, fireEvent } from "@testing-library/react";
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import AgentsPanel from "./agents";
|
||||
import * as networking from "./networking";
|
||||
|
||||
vi.mock("./networking", () => ({
|
||||
getAgentsList: vi.fn().mockResolvedValue({ agents: [] }),
|
||||
|
|
@ -68,4 +69,37 @@ describe("AgentsPanel", () => {
|
|||
expect(grid).toHaveAttribute("data-is-admin", "false");
|
||||
});
|
||||
});
|
||||
|
||||
it("should render the Health Check toggle", async () => {
|
||||
render(<AgentsPanel accessToken="test-token" userRole="Admin" />);
|
||||
expect(screen.getByText("Health Check")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should render the Health Check toggle for non-admin users too", async () => {
|
||||
render(<AgentsPanel accessToken="test-token" userRole="Internal User" />);
|
||||
expect(screen.getByText("Health Check")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should call getAgentsList with health_check=false on initial load", async () => {
|
||||
render(<AgentsPanel accessToken="test-token" userRole="Admin" />);
|
||||
await waitFor(() => {
|
||||
expect(networking.getAgentsList).toHaveBeenCalledWith("test-token", false);
|
||||
});
|
||||
});
|
||||
|
||||
it("should call getAgentsList with health_check=true when toggle is enabled", async () => {
|
||||
render(<AgentsPanel accessToken="test-token" userRole="Admin" />);
|
||||
await waitFor(() => {
|
||||
expect(networking.getAgentsList).toHaveBeenCalledWith("test-token", false);
|
||||
});
|
||||
|
||||
const toggle = screen.getByRole("switch");
|
||||
await act(async () => {
|
||||
fireEvent.click(toggle);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(networking.getAgentsList).toHaveBeenCalledWith("test-token", true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Button } from "@tremor/react";
|
||||
import { Modal, Alert } from "antd";
|
||||
import { Modal, Alert, Switch, Tooltip } from "antd";
|
||||
import { CheckCircleOutlined } from "@ant-design/icons";
|
||||
import { getAgentsList, deleteAgentCall, keyListCall } from "./networking";
|
||||
import AddAgentForm from "./agents/add_agent_form";
|
||||
import AgentCardGrid from "./agents/agent_card_grid";
|
||||
|
|
@ -26,17 +27,18 @@ const AgentsPanel: React.FC<AgentsPanelProps> = ({ accessToken, userRole }) => {
|
|||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
const [agentToDelete, setAgentToDelete] = useState<{ id: string; name: string } | null>(null);
|
||||
const [selectedAgentId, setSelectedAgentId] = useState<string | null>(null);
|
||||
const [healthCheckEnabled, setHealthCheckEnabled] = useState(false);
|
||||
|
||||
const isAdmin = userRole ? isAdminRole(userRole) : false;
|
||||
|
||||
const fetchAgents = async () => {
|
||||
const fetchAgents = async (healthCheck?: boolean) => {
|
||||
if (!accessToken) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response: AgentsResponse = await getAgentsList(accessToken);
|
||||
const response: AgentsResponse = await getAgentsList(accessToken, healthCheck ?? healthCheckEnabled);
|
||||
setAgentsList(response.agents || []);
|
||||
} catch (error) {
|
||||
console.error("Error fetching agents:", error);
|
||||
|
|
@ -89,6 +91,11 @@ const AgentsPanel: React.FC<AgentsPanelProps> = ({ accessToken, userRole }) => {
|
|||
}
|
||||
}, [accessToken, agentsList.length]);
|
||||
|
||||
const handleHealthCheckToggle = (checked: boolean) => {
|
||||
setHealthCheckEnabled(checked);
|
||||
fetchAgents(checked);
|
||||
};
|
||||
|
||||
const handleAddAgent = () => {
|
||||
if (selectedAgentId) {
|
||||
setSelectedAgentId(null);
|
||||
|
|
@ -141,13 +148,25 @@ const AgentsPanel: React.FC<AgentsPanelProps> = ({ accessToken, userRole }) => {
|
|||
showIcon
|
||||
className="mb-3"
|
||||
/>
|
||||
{isAdmin && (
|
||||
<div className="mt-2">
|
||||
<div className="mt-2 flex items-center gap-4">
|
||||
{isAdmin && (
|
||||
<Button onClick={handleAddAgent} disabled={!accessToken}>
|
||||
+ Add New Agent
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
<Tooltip title="When enabled, only agents with reachable URLs are shown">
|
||||
<div className="flex items-center gap-2">
|
||||
<CheckCircleOutlined className={healthCheckEnabled ? "text-green-500" : "text-gray-400"} />
|
||||
<span className="text-sm text-gray-600">Health Check</span>
|
||||
<Switch
|
||||
size="small"
|
||||
checked={healthCheckEnabled}
|
||||
onChange={handleHealthCheckToggle}
|
||||
loading={isLoading && healthCheckEnabled}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{selectedAgentId ? (
|
||||
|
|
|
|||
|
|
@ -7607,9 +7607,10 @@ export const getMajorAirlines = async (accessToken: string) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const getAgentsList = async (accessToken: string) => {
|
||||
export const getAgentsList = async (accessToken: string, healthCheck: boolean = false) => {
|
||||
try {
|
||||
const url = proxyBaseUrl ? `${proxyBaseUrl}/v1/agents` : `/v1/agents`;
|
||||
const params = healthCheck ? "?health_check=true" : "";
|
||||
const url = proxyBaseUrl ? `${proxyBaseUrl}/v1/agents${params}` : `/v1/agents${params}`;
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react-jsx",
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue