Skip to content

Commit 49646a1

Browse files
committed
fix: ignore of lib folder inside src
1 parent adfc469 commit 49646a1

File tree

7 files changed

+539
-167
lines changed

7 files changed

+539
-167
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ node_modules/
1313
dist/
1414
build/
1515
lib/
16+
!src/**/lib
1617

1718
# Cloudflare Workers
1819
.wrangler/
@@ -63,4 +64,4 @@ tmp/
6364
.turbo
6465

6566
data/
66-
*.db
67+
*.db

packages/playground/src/components/agent-selector.tsx

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,26 @@ export function AgentSelector({
3030
}: AgentSelectorProps) {
3131
const [agents, setAgents] = useState<Agent[]>(getAllAgents());
3232
const [isAddModalOpen, setIsAddModalOpen] = useState(false);
33-
33+
3434
// Use health monitoring for all agents
35-
const { health: agentHealth, isLoading, error } = useAgentsHealth(agents, 30000);
36-
35+
const {
36+
health: agentHealth,
37+
isLoading,
38+
error,
39+
} = useAgentsHealth(agents, 30000);
40+
3741
// Find health status for selected agent
38-
const selectedAgentHealth = agentHealth.find(a => a.id === selectedAgent.id)?.health;
42+
const selectedAgentHealth = agentHealth.find(
43+
(a) => a.id === selectedAgent.id,
44+
)?.health;
3945
const isConnected = selectedAgentHealth?.isOnline ?? false;
4046

4147
const handleValueChange = (value: string) => {
4248
if (value === "__add_agent__") {
4349
setIsAddModalOpen(true);
4450
return;
4551
}
46-
52+
4753
const agent = agents.find((a) => a.id === value);
4854
if (agent) {
4955
onAgentChange(agent);
@@ -72,10 +78,10 @@ export function AgentSelector({
7278
</div>
7379
</div>
7480

75-
<Select value={selectedAgent.id} onValueChange={handleValueChange}>
76-
<SelectTrigger className="w-[240px] bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 text-gray-900 dark:text-white shadow-sm">
77-
<SelectValue placeholder="Select an agent" />
78-
</SelectTrigger>
81+
<Select value={selectedAgent.id} onValueChange={handleValueChange}>
82+
<SelectTrigger className="w-[240px] bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-600 text-gray-900 dark:text-white shadow-sm">
83+
<SelectValue placeholder="Select an agent" />
84+
</SelectTrigger>
7985
<SelectContent className="bg-white dark:bg-gray-800 border-gray-200 dark:border-gray-700">
8086
{agentHealth.map((agent) => (
8187
<SelectItem
@@ -86,20 +92,28 @@ export function AgentSelector({
8692
>
8793
<div className="flex items-center gap-2">
8894
<div className="flex items-center">
89-
<Circle
95+
<Circle
9096
className={`h-2 w-2 ${
91-
agent.health?.isOnline
92-
? (agent.health.responseTime && agent.health.responseTime > 2000 ? 'text-yellow-400' : 'text-green-400')
93-
: 'text-red-400'
94-
}`}
97+
agent.health?.isOnline
98+
? agent.health.responseTime &&
99+
agent.health.responseTime > 2000
100+
? "text-yellow-400"
101+
: "text-green-400"
102+
: "text-red-400"
103+
}`}
95104
fill="currentColor"
96105
/>
97106
</div>
98107
<div className="flex flex-col">
99108
<div className="flex items-center gap-2">
100-
<span className="font-medium text-gray-900 dark:text-white">{agent.name}</span>
109+
<span className="font-medium text-gray-900 dark:text-white">
110+
{agent.name}
111+
</span>
101112
{!agent.health?.isOnline && (
102-
<Badge variant="destructive" className="text-xs py-0 px-1 h-4">
113+
<Badge
114+
variant="destructive"
115+
className="text-xs py-0 px-1 h-4"
116+
>
103117
Offline
104118
</Badge>
105119
)}
@@ -116,7 +130,7 @@ export function AgentSelector({
116130
</div>
117131
</SelectItem>
118132
))}
119-
133+
120134
{/* Add Agent Option */}
121135
<SelectItem
122136
value="__add_agent__"
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
// Agent health monitoring service
2+
3+
import { Agent, AgentHealthStatus } from "@/lib/config";
4+
import { testAgentConnection } from "@/lib/agent-storage";
5+
6+
// Cache for health check results to prevent excessive requests
7+
const healthCheckCache = new Map<string, { status: AgentHealthStatus; timestamp: number }>();
8+
9+
// Cache timeout in milliseconds (5 minutes)
10+
const CACHE_TIMEOUT = 5 * 60 * 1000;
11+
12+
/**
13+
* Check if a cached health status is still valid
14+
*/
15+
function isCacheValid(timestamp: number): boolean {
16+
return Date.now() - timestamp < CACHE_TIMEOUT;
17+
}
18+
19+
/**
20+
* Get cached health status for an agent
21+
*/
22+
function getCachedHealth(agentUrl: string): AgentHealthStatus | null {
23+
const cached = healthCheckCache.get(agentUrl);
24+
if (cached && isCacheValid(cached.timestamp)) {
25+
return cached.status;
26+
}
27+
return null;
28+
}
29+
30+
/**
31+
* Update cached health status for an agent
32+
*/
33+
function setCachedHealth(agentUrl: string, status: AgentHealthStatus): void {
34+
healthCheckCache.set(agentUrl, {
35+
status,
36+
timestamp: Date.now(),
37+
});
38+
}
39+
40+
/**
41+
* Check the health of a single agent
42+
*
43+
* @param agent - The agent to check
44+
* @param force - Skip cache and force a new check
45+
* @returns Updated agent with health status
46+
*/
47+
export async function checkAgentHealth(agent: Agent, force: boolean = false): Promise<Agent> {
48+
// Return cached status if available and not forced
49+
if (!force) {
50+
const cached = getCachedHealth(agent.url);
51+
if (cached) {
52+
return {
53+
...agent,
54+
health: cached,
55+
lastChecked: cached.lastChecked,
56+
};
57+
}
58+
}
59+
60+
const startTime = Date.now();
61+
62+
try {
63+
const result = await testAgentConnection(agent.url);
64+
const responseTime = Date.now() - startTime;
65+
66+
const healthStatus: AgentHealthStatus = {
67+
isOnline: result.isOnline,
68+
lastChecked: Date.now(),
69+
responseTime,
70+
error: result.error,
71+
};
72+
73+
setCachedHealth(agent.url, healthStatus);
74+
75+
return {
76+
...agent,
77+
health: healthStatus,
78+
lastChecked: healthStatus.lastChecked,
79+
};
80+
} catch (error) {
81+
const healthStatus: AgentHealthStatus = {
82+
isOnline: false,
83+
lastChecked: Date.now(),
84+
error: error instanceof Error ? error.message : "Unknown error",
85+
};
86+
87+
setCachedHealth(agent.url, healthStatus);
88+
89+
return {
90+
...agent,
91+
health: healthStatus,
92+
lastChecked: healthStatus.lastChecked,
93+
};
94+
}
95+
}
96+
97+
/**
98+
* Check the health of multiple agents
99+
*
100+
* @param agents - Array of agents to check
101+
* @param force - Skip cache and force new checks
102+
* @returns Array of agents with updated health status
103+
*/
104+
export async function checkAgentsHealth(agents: Agent[], force: boolean = false): Promise<Agent[]> {
105+
// Run health checks in parallel for better performance
106+
const healthChecks = agents.map(agent => checkAgentHealth(agent, force));
107+
return Promise.all(healthChecks);
108+
}
109+
110+
/**
111+
* Get a human-readable status message for an agent's health
112+
*
113+
* @param agent - The agent to get status for
114+
* @returns Status message string
115+
*/
116+
export function getAgentStatusMessage(agent: Agent): string {
117+
if (!agent.health) {
118+
return "Unknown";
119+
}
120+
121+
if (!agent.health.isOnline) {
122+
return agent.health.error || "Offline";
123+
}
124+
125+
if (agent.health.responseTime) {
126+
return `Online (${agent.health.responseTime}ms)`;
127+
}
128+
129+
return "Online";
130+
}
131+
132+
/**
133+
* Get status color for an agent based on health
134+
*
135+
* @param agent - The agent to get color for
136+
* @returns Color string for UI
137+
*/
138+
export function getAgentStatusColor(agent: Agent): "green" | "red" | "yellow" | "gray" {
139+
if (!agent.health) {
140+
return "gray";
141+
}
142+
143+
if (!agent.health.isOnline) {
144+
return "red";
145+
}
146+
147+
if (agent.health.responseTime && agent.health.responseTime > 2000) {
148+
return "yellow";
149+
}
150+
151+
return "green";
152+
}

0 commit comments

Comments
 (0)