mirror of
https://github.com/getpaseo/paseo.git
synced 2026-08-14 12:23:16 +00:00
feat: add provider availability check before creating sessions
This commit is contained in:
@@ -340,6 +340,10 @@ export class AgentManager {
|
|||||||
agentId: resolvedAgentId,
|
agentId: resolvedAgentId,
|
||||||
});
|
});
|
||||||
const client = this.requireClient(normalizedConfig.provider);
|
const client = this.requireClient(normalizedConfig.provider);
|
||||||
|
const available = await client.isAvailable();
|
||||||
|
if (!available) {
|
||||||
|
throw new Error(`Provider '${normalizedConfig.provider}' is not available. Please ensure the CLI is installed.`);
|
||||||
|
}
|
||||||
const session = await client.createSession(normalizedConfig);
|
const session = await client.createSession(normalizedConfig);
|
||||||
return this.registerSession(
|
return this.registerSession(
|
||||||
session,
|
session,
|
||||||
|
|||||||
@@ -287,4 +287,9 @@ export interface AgentClient {
|
|||||||
resumeSession(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>): Promise<AgentSession>;
|
resumeSession(handle: AgentPersistenceHandle, overrides?: Partial<AgentSessionConfig>): Promise<AgentSession>;
|
||||||
listModels(options?: ListModelsOptions): Promise<AgentModelDefinition[]>;
|
listModels(options?: ListModelsOptions): Promise<AgentModelDefinition[]>;
|
||||||
listPersistedAgents?(options?: ListPersistedAgentsOptions): Promise<PersistedAgentDescriptor[]>;
|
listPersistedAgents?(options?: ListPersistedAgentsOptions): Promise<PersistedAgentDescriptor[]>;
|
||||||
|
/**
|
||||||
|
* Check if this provider is available (CLI binary is installed).
|
||||||
|
* Returns true if available, false otherwise.
|
||||||
|
*/
|
||||||
|
isAvailable(): Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { execSync } from "node:child_process";
|
||||||
import { randomUUID } from "node:crypto";
|
import { randomUUID } from "node:crypto";
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import { promises } from "node:fs";
|
import { promises } from "node:fs";
|
||||||
@@ -403,6 +404,15 @@ export class ClaudeAgentClient implements AgentClient {
|
|||||||
return descriptors;
|
return descriptors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async isAvailable(): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const claudePath = execSync("which claude", { encoding: "utf8" }).trim();
|
||||||
|
return Boolean(claudePath);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private assertConfig(config: AgentSessionConfig): ClaudeAgentConfig {
|
private assertConfig(config: AgentSessionConfig): ClaudeAgentConfig {
|
||||||
if (config.provider !== "claude") {
|
if (config.provider !== "claude") {
|
||||||
throw new Error(`ClaudeAgentClient received config for provider '${config.provider}'`);
|
throw new Error(`ClaudeAgentClient received config for provider '${config.provider}'`);
|
||||||
|
|||||||
@@ -1729,4 +1729,13 @@ export class CodexAppServerAgentClient implements AgentClient {
|
|||||||
await client.dispose();
|
await client.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async isAvailable(): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const codexPath = execSync("which codex", { encoding: "utf8" }).trim();
|
||||||
|
return Boolean(codexPath);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4800,6 +4800,15 @@ export class CodexMcpAgentClient implements AgentClient {
|
|||||||
await client.dispose();
|
await client.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async isAvailable(): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const codexPath = execSync("which codex", { encoding: "utf8" }).trim();
|
||||||
|
return Boolean(codexPath);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const __test__ = {
|
export const __test__ = {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { spawn, type ChildProcess } from "node:child_process";
|
import { execSync, spawn, type ChildProcess } from "node:child_process";
|
||||||
import { createOpencodeClient, type OpencodeClient } from "@opencode-ai/sdk/v2/client";
|
import { createOpencodeClient, type OpencodeClient } from "@opencode-ai/sdk/v2/client";
|
||||||
import net from "node:net";
|
import net from "node:net";
|
||||||
import type { Logger } from "pino";
|
import type { Logger } from "pino";
|
||||||
@@ -318,6 +318,15 @@ export class OpenCodeAgentClient implements AgentClient {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async isAvailable(): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const opencodePath = execSync("which opencode", { encoding: "utf8" }).trim();
|
||||||
|
return Boolean(opencodePath);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private assertConfig(config: AgentSessionConfig): OpenCodeAgentConfig {
|
private assertConfig(config: AgentSessionConfig): OpenCodeAgentConfig {
|
||||||
if (config.provider !== "opencode") {
|
if (config.provider !== "opencode") {
|
||||||
throw new Error(`OpenCodeAgentClient received config for provider '${config.provider}'`);
|
throw new Error(`OpenCodeAgentClient received config for provider '${config.provider}'`);
|
||||||
|
|||||||
@@ -664,6 +664,10 @@ class FakeAgentClient implements AgentClient {
|
|||||||
{ provider: this.provider, id: "test-model", label: "Test Model", isDefault: true },
|
{ provider: this.provider, id: "test-model", label: "Test Model", isDefault: true },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async isAvailable(): Promise<boolean> {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTestAgentClients(): Record<string, AgentClient> {
|
export function createTestAgentClients(): Record<string, AgentClient> {
|
||||||
|
|||||||
Reference in New Issue
Block a user