fix(acp): harden session-page connection and localize backend errors

- Session-page connect never triggers download/install; returns
  SdkNotInstalled immediately and prompts the user to install from
  Agent Settings instead
- Binary agents now accept any cached version via
  find_best_cached_binary_for_agent so stale caches still connect
- Bound Initialize handshake with a 60s timeout and convert it to
  AcpError::InitializeTimeout via a sentinel in run_connection
- Spawn background task owns ConnectionManager map insertion and
  removes the entry on exit through an RAII guard that survives
  panics, preventing leaked stale entries
- AcpError gains SdkNotInstalled and InitializeTimeout variants plus
  a stable code() identifier; AcpEvent::Error carries code so the
  frontend can render localized messages by key
- Frontend preflight now runs for all connect sources; error event
  handler switches on code to show translated text for
  initialize_timeout, sdk_not_installed, platform_not_supported,
  process_exited, spawn_failed and download_failed
- Remove ConnectionStatus::Downloading enum variant, all frontend
  branches, and i18n strings; drop obsolete autoLinkFailedTitle,
  autoLinkPreflightFailed, preflightCheckFailedDefault and
  preflightFailedTitle keys across 10 locales
- Add backendErrors.* translations in 10 languages
- Diagnostic logging: always log agent stderr plus binary
  path/size/args/env keys and Initialize timing; gate stdin/stdout
  JSON-RPC tracing behind CODEG_ACP_DEBUG to avoid persisting user
  content into OS log files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
xintaofei
2026-04-12 03:36:08 +08:00
parent 5bda7d06e9
commit 1c1738298b
25 changed files with 595 additions and 255 deletions

View File

@@ -5,7 +5,6 @@ use axum::{extract::Extension, Json};
use serde::Deserialize;
use crate::acp::preflight::PreflightResult;
use crate::acp::registry;
use crate::acp::types::{
AcpAgentInfo, AcpAgentStatus, AgentSkillContent, AgentSkillLayout, AgentSkillScope,
AgentSkillsListResult, ConnectionInfo, ForkResultInfo,
@@ -57,7 +56,6 @@ pub async fn acp_connect(
) -> Result<Json<String>, AppCommandError> {
let db = &state.db;
let manager = &state.connection_manager;
let meta = registry::get_agent_meta(params.agent_type);
let setting = agent_setting_service::get_by_agent_type(&db.conn, params.agent_type)
.await
@@ -93,14 +91,11 @@ pub async fn acp_connect(
runtime_env.insert("OPENCLAW_RESET_SESSION".into(), "1".into());
}
if let registry::AgentDistribution::Npx { cmd, .. } = meta.distribution {
if !acp_commands::is_cmd_available(cmd) {
return Err(AppCommandError::task_execution_failed(format!(
"{} SDK is not installed. Please install it in Agent Settings.",
meta.name
)));
}
}
// Guard: the session page must never trigger a download or install.
// If the agent isn't ready, return SdkNotInstalled here so the frontend
// can prompt the user to install it from Agent Settings.
acp_commands::verify_agent_installed(params.agent_type)
.map_err(|e| AppCommandError::task_execution_failed(e.to_string()))?;
let emitter = state.emitter.clone();
let connection_id = manager