308 lines
14 KiB
Rust
308 lines
14 KiB
Rust
use crate::ai::blocklist::task_status_sync_model::classify_renderable_error;
|
|
use crate::server::server_api::ai::TaskStatusUpdate;
|
|
use galaxy_graphql::ai::{AgentTaskState, PlatformErrorCode};
|
|
|
|
use super::terminal::ShareSessionError;
|
|
use super::AgentDriverError;
|
|
|
|
/// Classify an `AgentDriverError` into a task state and a `TaskStatusUpdate`
|
|
/// suitable for reporting via `update_agent_task`.
|
|
pub fn classify_driver_error(error: &AgentDriverError) -> (AgentTaskState, TaskStatusUpdate) {
|
|
match error {
|
|
// --- Warp-side errors (task → ERROR) ---
|
|
AgentDriverError::TerminalUnavailable | AgentDriverError::InvalidRuntimeState => (
|
|
AgentTaskState::Error,
|
|
TaskStatusUpdate::with_error_code(
|
|
"An internal error occurred. Please try running your task again. If the issue persists, contact support.",
|
|
PlatformErrorCode::InternalError,
|
|
),
|
|
),
|
|
AgentDriverError::BootstrapFailed => (
|
|
AgentTaskState::Error,
|
|
TaskStatusUpdate::with_error_code(
|
|
"Terminal session failed to start. Please try running your task again.",
|
|
PlatformErrorCode::InternalError,
|
|
),
|
|
),
|
|
AgentDriverError::ShareSessionFailed { error: share_err } => {
|
|
let message = match share_err {
|
|
ShareSessionError::Internal(_) => {
|
|
"Failed to share agent session due to an internal error. Please try running your task again.".to_string()
|
|
}
|
|
ShareSessionError::Failed(reason) => {
|
|
// The reason string comes from the session-sharing layer and is aimed at
|
|
// interactive users (e.g. "try sharing again"). Provide a cloud-agent-
|
|
// appropriate message instead of wrapping it, which would produce
|
|
// repetitive "try again" text.
|
|
format!("Failed to share agent session: {reason}")
|
|
}
|
|
ShareSessionError::Disabled => {
|
|
"Session sharing is not enabled for your account. This is likely because \
|
|
an administrator has disabled session sharing for your team. Please \
|
|
verify that session sharing is enabled in your team settings, or try \
|
|
running without the --share flag."
|
|
.to_string()
|
|
}
|
|
ShareSessionError::Timeout => {
|
|
"Failed to share agent session: timed out waiting for the session sharing \
|
|
server to respond. Please check your network connection and try again."
|
|
.to_string()
|
|
}
|
|
ShareSessionError::Interrupted => {
|
|
"Session sharing was interrupted before it could complete. Please try running your task again.".to_string()
|
|
}
|
|
};
|
|
(
|
|
AgentTaskState::Error,
|
|
TaskStatusUpdate::with_error_code(
|
|
message,
|
|
match share_err {
|
|
ShareSessionError::Disabled => PlatformErrorCode::FeatureNotAvailable,
|
|
_ => PlatformErrorCode::InternalError,
|
|
},
|
|
),
|
|
)
|
|
}
|
|
AgentDriverError::WarpDriveSyncFailed => (
|
|
AgentTaskState::Error,
|
|
TaskStatusUpdate::with_error_code(
|
|
"Warp Drive failed to sync. Please check your network connection and try again.",
|
|
PlatformErrorCode::InternalError,
|
|
),
|
|
),
|
|
AgentDriverError::NotLoggedIn => {
|
|
let bin = galaxy_cli::binary_name().unwrap_or_else(|| "warp".to_string());
|
|
(
|
|
AgentTaskState::Error,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!(
|
|
"Authentication required. Log in via '{bin} login', provide an API key via '--api-key', or set the WARP_API_KEY environment variable."
|
|
),
|
|
PlatformErrorCode::AuthenticationRequired,
|
|
),
|
|
)
|
|
}
|
|
AgentDriverError::CloudProviderSetupFailed(err) => (
|
|
AgentTaskState::Error,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!("Error configuring cloud access: {err:#}"),
|
|
PlatformErrorCode::InternalError,
|
|
),
|
|
),
|
|
|
|
// --- User-side errors (task → FAILED) ---
|
|
AgentDriverError::MCPServerNotFound(uuid) => (
|
|
AgentTaskState::Failed,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!(
|
|
"MCP server {uuid} was not found. Verify the server exists in your Warp Drive and the UUID is correct."
|
|
),
|
|
PlatformErrorCode::EnvironmentSetupFailed,
|
|
),
|
|
),
|
|
AgentDriverError::MCPStartupFailed => (
|
|
AgentTaskState::Failed,
|
|
TaskStatusUpdate::with_error_code(
|
|
"One or more MCP servers failed to start. Check that your MCP server configuration is valid and the server process is runnable.",
|
|
PlatformErrorCode::EnvironmentSetupFailed,
|
|
),
|
|
),
|
|
AgentDriverError::MCPJsonParseError(msg) => (
|
|
AgentTaskState::Failed,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!("Failed to parse MCP server JSON configuration: {msg}"),
|
|
PlatformErrorCode::EnvironmentSetupFailed,
|
|
),
|
|
),
|
|
AgentDriverError::MCPMissingVariables => (
|
|
AgentTaskState::Failed,
|
|
TaskStatusUpdate::with_error_code(
|
|
"MCP server configuration is missing required variables. Provide all required environment variables or template values.",
|
|
PlatformErrorCode::EnvironmentSetupFailed,
|
|
),
|
|
),
|
|
AgentDriverError::ProfileError(name) => (
|
|
AgentTaskState::Failed,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!(
|
|
"Agent profile \"{name}\" not found. Check the profile ID and ensure it exists in your team's Warp Drive."
|
|
),
|
|
PlatformErrorCode::ResourceNotFound,
|
|
),
|
|
),
|
|
AgentDriverError::AIWorkflowNotFound(id) => (
|
|
AgentTaskState::Failed,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!(
|
|
"Saved prompt not found for ID {id}. Verify the prompt exists in your Warp Drive."
|
|
),
|
|
PlatformErrorCode::ResourceNotFound,
|
|
),
|
|
),
|
|
AgentDriverError::EnvironmentNotFound(id) => (
|
|
AgentTaskState::Failed,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!(
|
|
"Environment '{id}' not found. Verify the environment ID and ensure it exists in your team settings."
|
|
),
|
|
PlatformErrorCode::ResourceNotFound,
|
|
),
|
|
),
|
|
AgentDriverError::EnvironmentSetupFailed(msg) => (
|
|
AgentTaskState::Failed,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!(
|
|
"Environment setup failed: {msg}. Check your repository URLs and setup commands."
|
|
),
|
|
PlatformErrorCode::EnvironmentSetupFailed,
|
|
),
|
|
),
|
|
AgentDriverError::InvalidWorkingDirectory { path, .. } => (
|
|
AgentTaskState::Failed,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!(
|
|
"Working directory '{}' does not exist or is not a directory. Verify the path in your environment configuration.",
|
|
path.display()
|
|
),
|
|
PlatformErrorCode::EnvironmentSetupFailed,
|
|
),
|
|
),
|
|
|
|
// --- Conversation errors ---
|
|
// Delegate to classify_renderable_error for proper ERROR vs FAILED
|
|
// distinction and PlatformErrorCode. This is a belt-and-suspenders
|
|
// fallback — TaskStatusSyncModel handles most conversation errors,
|
|
// but the driver catches them too if the conversation ends with an error.
|
|
AgentDriverError::ConversationError { error } => {
|
|
let (state, update) = classify_renderable_error(error);
|
|
(
|
|
state,
|
|
update.unwrap_or_else(|| {
|
|
TaskStatusUpdate::with_error_code(
|
|
error.to_string(),
|
|
PlatformErrorCode::InternalError,
|
|
)
|
|
}),
|
|
)
|
|
}
|
|
|
|
// --- Cancellation / Blocked (no error code) ---
|
|
AgentDriverError::ConversationCancelled { .. } => (
|
|
AgentTaskState::Cancelled,
|
|
TaskStatusUpdate::message("Task cancelled."),
|
|
),
|
|
AgentDriverError::ConversationBlocked { blocked_action } => (
|
|
AgentTaskState::Blocked,
|
|
TaskStatusUpdate::message(format!(
|
|
"The agent got stuck waiting for user confirmation on the action: {blocked_action}"
|
|
)),
|
|
),
|
|
|
|
// --- Setup errors ---
|
|
AgentDriverError::TeamMetadataRefreshTimeout => (
|
|
AgentTaskState::Error,
|
|
TaskStatusUpdate::with_error_code(
|
|
"Timed out refreshing team metadata. Please check your network connection and try again.",
|
|
PlatformErrorCode::InternalError,
|
|
),
|
|
),
|
|
AgentDriverError::SkillResolutionFailed(msg) => (
|
|
AgentTaskState::Failed,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!("Skill resolution failed: {msg}"),
|
|
PlatformErrorCode::ResourceNotFound,
|
|
),
|
|
),
|
|
AgentDriverError::ConfigBuildFailed(err) => (
|
|
AgentTaskState::Failed,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!("Failed to build agent configuration: {err}"),
|
|
PlatformErrorCode::EnvironmentSetupFailed,
|
|
),
|
|
),
|
|
AgentDriverError::PromptResolutionFailed(err) => (
|
|
AgentTaskState::Error,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!("Failed to resolve prompt for the run: {err}"),
|
|
PlatformErrorCode::InternalError,
|
|
),
|
|
),
|
|
AgentDriverError::SecretsFetchFailed(err) => (
|
|
AgentTaskState::Error,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!("Failed to fetch task secrets: {err}"),
|
|
PlatformErrorCode::InternalError,
|
|
),
|
|
),
|
|
AgentDriverError::AwsBedrockCredentialsFailed(msg) => (
|
|
AgentTaskState::Failed,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!("Failed to initialize AWS Bedrock credentials: {msg}"),
|
|
PlatformErrorCode::EnvironmentSetupFailed,
|
|
),
|
|
),
|
|
AgentDriverError::ConversationLoadFailed(msg) => (
|
|
AgentTaskState::Error,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!("Failed to load conversation: {msg}"),
|
|
PlatformErrorCode::InternalError,
|
|
),
|
|
),
|
|
AgentDriverError::ConversationHarnessMismatch { conversation_id, expected, got } => (
|
|
AgentTaskState::Failed,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!(
|
|
"Conversation {conversation_id} was produced by the {expected} harness, but --harness {got} was requested. \
|
|
Re-run with --harness {expected} (or omit --harness) to continue this conversation."
|
|
),
|
|
PlatformErrorCode::EnvironmentSetupFailed,
|
|
),
|
|
),
|
|
AgentDriverError::TaskHarnessMismatch { task_id, expected, got } => (
|
|
AgentTaskState::Failed,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!(
|
|
"Task {task_id} was created with the {expected} harness, but --harness {got} was requested. \
|
|
Re-run with --harness {expected} (or omit --harness) to continue this task."
|
|
),
|
|
PlatformErrorCode::EnvironmentSetupFailed,
|
|
),
|
|
),
|
|
AgentDriverError::ConversationResumeStateMissing { harness, conversation_id } => (
|
|
AgentTaskState::Failed,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!(
|
|
"Conversation {conversation_id} has no stored transcript for the {harness} harness. \
|
|
The prior run may have crashed before saving any state."
|
|
),
|
|
PlatformErrorCode::ResourceNotFound,
|
|
),
|
|
),
|
|
AgentDriverError::HarnessCommandFailed { exit_code } => (
|
|
AgentTaskState::Failed,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!("Harness command exited with code {exit_code}"),
|
|
PlatformErrorCode::InternalError,
|
|
),
|
|
),
|
|
AgentDriverError::HarnessSetupFailed { harness, reason } => (
|
|
AgentTaskState::Failed,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!("Harness '{harness}' validation failed: {reason}"),
|
|
PlatformErrorCode::EnvironmentSetupFailed,
|
|
),
|
|
),
|
|
AgentDriverError::HarnessConfigSetupFailed { harness, error } => (
|
|
AgentTaskState::Failed,
|
|
TaskStatusUpdate::with_error_code(
|
|
format!("Harness '{harness}' config setup failed: {error}"),
|
|
PlatformErrorCode::EnvironmentSetupFailed,
|
|
),
|
|
),
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "error_classification_tests.rs"]
|
|
mod tests;
|