优化Agent Connect时的agent状态获取

This commit is contained in:
xintaofei
2026-03-17 23:24:07 +08:00
parent ad062aef96
commit acbdabe9e4
6 changed files with 68 additions and 7 deletions

View File

@@ -244,6 +244,15 @@ pub struct AcpAgentInfo {
pub codex_config_toml: Option<String>, pub codex_config_toml: Option<String>,
} }
/// Lightweight status info for a single agent, used by connect() pre-check.
#[derive(Debug, Clone, Serialize)]
pub struct AcpAgentStatus {
pub agent_type: crate::models::agent::AgentType,
pub available: bool,
pub enabled: bool,
pub installed_version: Option<String>,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum AgentSkillScope { pub enum AgentSkillScope {

View File

@@ -1127,6 +1127,44 @@ pub async fn acp_list_connections(
Ok(manager.list_connections().await) Ok(manager.list_connections().await)
} }
#[tauri::command]
pub async fn acp_get_agent_status(
agent_type: AgentType,
db: tauri::State<'_, AppDatabase>,
) -> Result<crate::acp::types::AcpAgentStatus, AcpError> {
let platform = registry::current_platform();
let meta = registry::get_agent_meta(agent_type);
let setting = agent_setting_service::get_by_agent_type(&db.conn, agent_type)
.await
.map_err(|e| AcpError::protocol(e.to_string()))?;
let (available, installed_version) = match &meta.distribution {
registry::AgentDistribution::Npx { .. } => (
true,
setting.as_ref().and_then(|m| m.installed_version.clone()),
),
registry::AgentDistribution::Binary {
platforms, cmd, ..
} => {
let detected =
binary_cache::detect_installed_version(agent_type, cmd)
.ok()
.flatten();
(
platforms.iter().any(|p| p.platform == platform),
detected,
)
}
};
Ok(crate::acp::types::AcpAgentStatus {
agent_type,
available,
enabled: setting.map(|m| m.enabled).unwrap_or(true),
installed_version,
})
}
#[tauri::command] #[tauri::command]
pub async fn acp_list_agents( pub async fn acp_list_agents(
db: tauri::State<'_, AppDatabase>, db: tauri::State<'_, AppDatabase>,

View File

@@ -275,6 +275,7 @@ pub fn run() {
acp_commands::acp_disconnect, acp_commands::acp_disconnect,
acp_commands::acp_list_connections, acp_commands::acp_list_connections,
acp_commands::acp_list_agents, acp_commands::acp_list_agents,
acp_commands::acp_get_agent_status,
acp_commands::acp_clear_binary_cache, acp_commands::acp_clear_binary_cache,
acp_commands::acp_download_agent_binary, acp_commands::acp_download_agent_binary,
acp_commands::acp_detect_agent_local_version, acp_commands::acp_detect_agent_local_version,

View File

@@ -15,7 +15,7 @@ import { disposeTauriListener } from "@/lib/tauri-listener"
import { inferLiveToolName } from "@/lib/tool-call-normalization" import { inferLiveToolName } from "@/lib/tool-call-normalization"
import { import {
acpConnect, acpConnect,
acpListAgents, acpGetAgentStatus,
acpPrompt, acpPrompt,
acpSetMode, acpSetMode,
acpSetConfigOption, acpSetConfigOption,
@@ -25,7 +25,7 @@ import {
} from "@/lib/tauri" } from "@/lib/tauri"
import type { import type {
AgentType, AgentType,
AcpAgentInfo, AcpAgentStatus,
AcpEvent, AcpEvent,
AvailableCommandInfo, AvailableCommandInfo,
ConnectionStatus, ConnectionStatus,
@@ -1169,7 +1169,7 @@ export function AcpConnectionsProvider({ children }: { children: ReactNode }) {
) )
const resolveAutoLinkBlockState = useCallback( const resolveAutoLinkBlockState = useCallback(
(agent: AcpAgentInfo | null): AutoLinkBlockState => { (agent: AcpAgentStatus | null): AutoLinkBlockState => {
if (!agent) { if (!agent) {
return { kind: "missing_config", reason: t("blocked.missingConfig") } return { kind: "missing_config", reason: t("blocked.missingConfig") }
} }
@@ -1685,11 +1685,9 @@ export function AcpConnectionsProvider({ children }: { children: ReactNode }) {
try { try {
if (isAutoLink) { if (isAutoLink) {
let configuredAgent: AcpAgentInfo | null = null let configuredAgent: AcpAgentStatus | null = null
try { try {
const agents = await acpListAgents() configuredAgent = await acpGetAgentStatus(agentType)
configuredAgent =
agents.find((agent) => agent.agent_type === agentType) ?? null
} catch (error) { } catch (error) {
const reason = t("unableReadAgentConfig", { const reason = t("unableReadAgentConfig", {
message: normalizeErrorMessage(error), message: normalizeErrorMessage(error),

View File

@@ -9,6 +9,7 @@ import type {
SidebarData, SidebarData,
ConnectionInfo, ConnectionInfo,
AcpAgentInfo, AcpAgentInfo,
AcpAgentStatus,
AgentSkillScope, AgentSkillScope,
AgentSkillLayout, AgentSkillLayout,
AgentSkillItem, AgentSkillItem,
@@ -153,6 +154,12 @@ export async function acpListAgents(): Promise<AcpAgentInfo[]> {
return invoke("acp_list_agents") return invoke("acp_list_agents")
} }
export async function acpGetAgentStatus(
agentType: AgentType
): Promise<AcpAgentStatus> {
return invoke("acp_get_agent_status", { agentType })
}
export async function acpClearBinaryCache(agentType: AgentType): Promise<void> { export async function acpClearBinaryCache(agentType: AgentType): Promise<void> {
return invoke("acp_clear_binary_cache", { agentType }) return invoke("acp_clear_binary_cache", { agentType })
} }

View File

@@ -463,6 +463,14 @@ export interface AcpAgentInfo {
codex_config_toml: string | null codex_config_toml: string | null
} }
// Lightweight agent status returned by acp_get_agent_status
export interface AcpAgentStatus {
agent_type: AgentType
available: boolean
enabled: boolean
installed_version: string | null
}
export type AgentSkillScope = "global" | "project" export type AgentSkillScope = "global" | "project"
export type AgentSkillLayout = "markdown_file" | "skill_directory" export type AgentSkillLayout = "markdown_file" | "skill_directory"