Files
2026-07-13 13:39:12 +08:00

206 lines
7.2 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* OmniRoute MCP Session Pool Tools — Manage and monitor anonymous web session pools.
*
* Tools:
* 1. omniroute_pool_status — Get pool stats for one or all providers
* 2. omniroute_pool_sessions — List per-session details for a provider's pool
* 3. omniroute_pool_reset — Shut down and recreate a pool
* 4. omniroute_pool_warm — Warm up a pool to a target session count
* 5. omniroute_pool_health — Aggregated pool health with breaker state and issues
*/
import { z } from "zod";
import { PoolRegistry } from "../../services/sessionPool/poolRegistry.ts";
import { getWebSessionPoolHealth } from "../../services/webSessionPoolHealth.ts";
import { getBrowserPoolMetrics } from "../../services/browserPool.ts";
// ─── Input Schemas ─────────────────────────────────────────────────────────
export const poolStatusInput = z.object({
provider: z
.string()
.optional()
.describe("Provider name (e.g. 'pollinations'). Omit to list all pools"),
});
export const poolSessionsInput = z.object({
provider: z.string().describe("Provider name (e.g. 'pollinations')"),
});
export const poolResetInput = z.object({
provider: z.string().describe("Provider name (e.g. 'pollinations')"),
});
export const poolWarmInput = z.object({
provider: z.string().describe("Provider name (e.g. 'pollinations')"),
count: z
.number()
.int()
.min(1)
.max(50)
.default(6)
.describe("Target session count (150)"),
});
export const poolHealthInput = z.object({
provider: z
.string()
.optional()
.describe("Provider name (e.g. 'pollinations'). Omit to list all pools"),
});
// ─── Handlers ──────────────────────────────────────────────────────────────
/**
* Handle pool_status tool: return stats for one or all pools
*/
export async function handlePoolStatus(
args: z.infer<typeof poolStatusInput>,
): Promise<Record<string, unknown>> {
if (args.provider) {
const stats = PoolRegistry.getStats(args.provider);
if (!stats) {
return { error: `No pool found for provider '${args.provider}'` };
}
return { provider: args.provider, stats };
}
const all = PoolRegistry.getAllStats();
return {
totalPools: all.length,
providers: PoolRegistry.listProviders(),
pools: all,
};
}
/**
* Handle pool_sessions tool: list per-session details for a provider's pool
*/
export async function handlePoolSessions(
args: z.infer<typeof poolSessionsInput>,
): Promise<Record<string, unknown>> {
const details = PoolRegistry.getSessionDetails(args.provider);
if (!details) {
return { error: `No pool found for provider '${args.provider}'` };
}
const stats = PoolRegistry.getStats(args.provider);
return {
provider: args.provider,
sessionCount: details.length,
stats,
sessions: details,
};
}
/**
* Handle pool_reset tool: shut down and recreate a pool
*/
export async function handlePoolReset(
args: z.infer<typeof poolResetInput>,
): Promise<Record<string, unknown>> {
const existed = PoolRegistry.resetPool(args.provider);
return {
provider: args.provider,
reset: existed,
message: existed
? `Pool '${args.provider}' shut down and removed. It will be recreated on next request.`
: `No pool found for provider '${args.provider}'`,
};
}
/**
* Handle pool_warm tool: warm up a pool to a target session count
*/
export async function handlePoolWarm(
args: z.infer<typeof poolWarmInput>,
): Promise<Record<string, unknown>> {
// If pool doesn't exist yet, we can't warm it
const pool = PoolRegistry.getPool(args.provider);
if (!pool) {
return { error: `No pool found for provider '${args.provider}'` };
}
const before = pool.totalCount;
await pool.warmUp(args.count);
const after = pool.totalCount;
return {
provider: args.provider,
targetCount: args.count,
sessionsBefore: before,
sessionsAfter: after,
created: after - before,
};
}
export async function handlePoolHealth(
args: z.infer<typeof poolHealthInput>,
): Promise<Record<string, unknown>> {
const report = getWebSessionPoolHealth(args.provider);
return report as unknown as Record<string, unknown>;
}
export const browserPoolStatusInput = z.object({});
/**
* Handle browser_pool_status tool (#3368 PR7): return the stealth browser
* pool's live status plus cumulative lifecycle telemetry.
*/
export async function handleBrowserPoolStatus(): Promise<Record<string, unknown>> {
return getBrowserPoolMetrics();
}
// ─── Tool Registry ─────────────────────────────────────────────────────────
export const poolTools = {
omniroute_pool_status: {
name: "omniroute_pool_status",
description:
"Returns session pool status for a specific provider or all providers. Includes session counts by state (active/cooldown/dead), request totals, success rate, and throughput.",
scopes: ["read:health"],
inputSchema: poolStatusInput,
handler: (args: z.infer<typeof poolStatusInput>) => handlePoolStatus(args),
},
omniroute_pool_sessions: {
name: "omniroute_pool_sessions",
description:
"Lists all sessions in a provider's pool with per-session details: fingerprint, status, request counts, inflight, cooldown remaining, and age.",
scopes: ["read:health"],
inputSchema: poolSessionsInput,
handler: (args: z.infer<typeof poolSessionsInput>) => handlePoolSessions(args),
},
omniroute_pool_reset: {
name: "omniroute_pool_reset",
description:
"Shuts down and removes all sessions for a provider's pool. A new pool will be created automatically on the next request.",
scopes: ["write:resilience"],
inputSchema: poolResetInput,
handler: (args: z.infer<typeof poolResetInput>) => handlePoolReset(args),
},
omniroute_pool_warm: {
name: "omniroute_pool_warm",
description:
"Warms a session pool to the specified session count (150). Sessions beyond the current count are created with fresh browser fingerprints.",
scopes: ["write:resilience"],
inputSchema: poolWarmInput,
handler: (args: z.infer<typeof poolWarmInput>) => handlePoolWarm(args),
},
omniroute_pool_health: {
name: "omniroute_pool_health",
description:
"Returns aggregated web-session pool health: pool stats + circuit breaker state + per-session details + health status (healthy/degraded/down) + issues list.",
scopes: ["read:health"],
inputSchema: poolHealthInput,
handler: (args: z.infer<typeof poolHealthInput>) => handlePoolHealth(args),
},
omniroute_browser_pool_status: {
name: "omniroute_browser_pool_status",
description:
"Returns the stealth browser pool's live status (enabled, active contexts, browser running, stealth available, idle age) plus cumulative lifecycle telemetry: browser launches/failures, context create/reuse/evict/release counts, context-create failures, and shutdowns with the last reason.",
scopes: ["read:health"],
inputSchema: browserPoolStatusInput,
handler: () => handleBrowserPoolStatus(),
},
};