diff --git a/Cargo.lock b/Cargo.lock index 26bb6926a9..8597c89d1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4886,7 +4886,6 @@ dependencies = [ "which 8.0.3", "winapi", "wiremock", - "zip 8.6.0", ] [[package]] diff --git a/crates/goose-cli/src/cli.rs b/crates/goose-cli/src/cli.rs index 3694127a4e..267c0b3522 100644 --- a/crates/goose-cli/src/cli.rs +++ b/crates/goose-cli/src/cli.rs @@ -580,11 +580,9 @@ enum SessionCommand { }, #[command(name = "diagnostics")] Diagnostics { - /// Session identifier for generating diagnostics #[command(flatten)] identifier: Option, - /// Output path for the diagnostics zip file (optional, defaults to current directory) #[arg(short = 'o', long)] output: Option, }, diff --git a/crates/goose-cli/src/commands/session.rs b/crates/goose-cli/src/commands/session.rs index 1a91a654bd..383867f860 100644 --- a/crates/goose-cli/src/commands/session.rs +++ b/crates/goose-cli/src/commands/session.rs @@ -7,7 +7,9 @@ use etcetera::home_dir; use goose::config::Config; #[cfg(feature = "nostr")] use goose::session::nostr_share; -use goose::session::{generate_diagnostics, Session, SessionManager, SessionType}; +use goose::session::{ + generate_diagnostics, DiagnosticsLevel, Session, SessionManager, SessionType, +}; use goose::utils::safe_truncate; use regex::Regex; use std::fs; @@ -327,19 +329,22 @@ pub async fn handle_diagnostics(session_id: &str, output_path: Option) ); let session_manager = SessionManager::instance(); - let diagnostics_data = generate_diagnostics(&session_manager, session_id) - .await - .with_context(|| { - format!( - "Failed to write to generate diagnostics bundle for session '{}'", - session_id - ) - })?; + let diagnostics_report = + generate_diagnostics(&session_manager, session_id, DiagnosticsLevel::Full) + .await + .with_context(|| { + format!( + "Failed to write to generate diagnostics bundle for session '{}'", + session_id + ) + })?; + let diagnostics_data = serde_json::to_vec_pretty(&diagnostics_report) + .context("Failed to serialize diagnostics report")?; let output_file = if let Some(path) = output_path { path.clone() } else { - PathBuf::from(format!("diagnostics_{}.zip", session_id)) + PathBuf::from(format!("diagnostics_{}.json", session_id)) }; let mut file = fs::File::create(&output_file).context(format!( diff --git a/crates/goose-cli/src/commands/term.rs b/crates/goose-cli/src/commands/term.rs index 26d2a3652d..9c80fc1e0e 100644 --- a/crates/goose-cli/src/commands/term.rs +++ b/crates/goose-cli/src/commands/term.rs @@ -280,9 +280,15 @@ pub async fn handle_term_run(prompt: Vec) -> Result<()> { }; if let Some(oldest_user) = user_messages_after_last_assistant.last() { - session_manager - .truncate_conversation(&session_id, oldest_user.created) - .await?; + if let Some(message_id) = oldest_user.id.as_deref() { + session_manager + .truncate_conversation_from_message(&session_id, message_id) + .await?; + } else { + session_manager + .truncate_conversation(&session_id, oldest_user.created) + .await?; + } } let prompt_with_context = if user_messages_after_last_assistant.is_empty() { diff --git a/crates/goose-sdk-types/src/custom_requests.rs b/crates/goose-sdk-types/src/custom_requests.rs index 48e1bc10b2..89061ba33e 100644 --- a/crates/goose-sdk-types/src/custom_requests.rs +++ b/crates/goose-sdk-types/src/custom_requests.rs @@ -165,6 +165,31 @@ pub struct SteerSessionResponse { pub message_id: String, } +#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcRequest)] +#[request( + method = "_goose/unstable/diagnostics/get", + response = DiagnosticsGetResponse +)] +#[serde(rename_all = "camelCase")] +pub struct DiagnosticsGetRequest { + pub session_id: String, + #[serde(default)] + pub level: DiagnosticsReportLevel, +} + +#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum DiagnosticsReportLevel { + #[default] + Summary, + Full, +} + +#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcResponse)] +pub struct DiagnosticsGetResponse { + pub report: serde_json::Value, +} + /// Delete a session. #[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, JsonRpcRequest)] #[request(method = "session/delete", response = EmptyResponse)] diff --git a/crates/goose-server/src/openapi.rs b/crates/goose-server/src/openapi.rs index 823feb29d5..9e2ef4d864 100644 --- a/crates/goose-server/src/openapi.rs +++ b/crates/goose-server/src/openapi.rs @@ -7,7 +7,11 @@ use goose::conversation::token_usage::Usage; use goose::conversation::Conversation; use goose::download_manager::{DownloadProgress, DownloadStatus}; use goose::providers::base::{ConfigKey, ModelInfo, ProviderMetadata, ProviderType}; -use goose::session::{Session, SessionType, SystemInfo}; +use goose::session::{ + DiagnosticsConfig, DiagnosticsError, DiagnosticsExtensions, DiagnosticsLevel, DiagnosticsLogs, + DiagnosticsPrompt, DiagnosticsReport, DiagnosticsScheduledRecipe, DiagnosticsTextFile, Session, + SessionType, SystemInfo, +}; use goose_providers::model::ModelConfig; use goose_providers::permission::Permission; use goose_providers::permission::PrincipalType; @@ -583,6 +587,15 @@ derive_utoipa!(IconTheme as IconThemeSchema); goose_providers::goose_mode::GooseMode, SessionType, SystemInfo, + DiagnosticsConfig, + DiagnosticsError, + DiagnosticsExtensions, + DiagnosticsLevel, + DiagnosticsLogs, + DiagnosticsPrompt, + DiagnosticsReport, + DiagnosticsScheduledRecipe, + DiagnosticsTextFile, Conversation, IconSchema, IconThemeSchema, diff --git a/crates/goose-server/src/routes/status.rs b/crates/goose-server/src/routes/status.rs index edc6c71c63..ec86e6316b 100644 --- a/crates/goose-server/src/routes/status.rs +++ b/crates/goose-server/src/routes/status.rs @@ -1,9 +1,9 @@ -use axum::body::Body; -use axum::extract::State; -use axum::http::HeaderValue; -use axum::response::IntoResponse; -use axum::{extract::Path, http::StatusCode, routing::get, Json, Router}; -use goose::session::{generate_diagnostics, get_system_info, SystemInfo}; +use axum::extract::{Path, Query, State}; +use axum::{http::StatusCode, routing::get, Json, Router}; +use goose::session::{ + generate_diagnostics, get_system_info, DiagnosticsLevel, DiagnosticsReport, SystemInfo, +}; +use serde::Deserialize; use std::sync::Arc; use crate::state::AppState; @@ -26,34 +26,33 @@ async fn system_info() -> Json { Json(get_system_info()) } +#[derive(Debug, Default, Deserialize, utoipa::IntoParams)] +struct DiagnosticsQuery { + level: Option, +} + #[utoipa::path(get, path = "/diagnostics/{session_id}", + params( + DiagnosticsQuery, + ), responses( - (status = 200, description = "Diagnostics zip file", content_type = "application/zip", body = Vec), + (status = 200, description = "Diagnostics report", body = DiagnosticsReport), (status = 500, description = "Failed to generate diagnostics"), ) )] async fn diagnostics( State(state): State>, Path(session_id): Path, -) -> impl IntoResponse { - match generate_diagnostics(state.session_manager(), &session_id).await { - Ok(zip_data) => { - let filename = format!("attachment; filename=\"diagnostics_{}.zip\"", session_id); - let headers = [ - ( - http::header::CONTENT_TYPE, - HeaderValue::from_static("application/zip"), - ), - ( - http::header::CONTENT_DISPOSITION, - HeaderValue::from_str(&filename).map_err(|_e| StatusCode::BAD_REQUEST)?, - ), - ]; - - Ok((headers, Body::from(zip_data))) - } - Err(_) => Err(StatusCode::INTERNAL_SERVER_ERROR), - } + Query(query): Query, +) -> Result, StatusCode> { + generate_diagnostics( + state.session_manager(), + &session_id, + query.level.unwrap_or(DiagnosticsLevel::Full), + ) + .await + .map(Json) + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR) } pub fn routes(state: Arc) -> Router { Router::new() diff --git a/crates/goose/Cargo.toml b/crates/goose/Cargo.toml index 294bcaee95..9a52ef60f3 100644 --- a/crates/goose/Cargo.toml +++ b/crates/goose/Cargo.toml @@ -168,7 +168,6 @@ byteorder = { version = "1.5", default-features = false, features = ["std"], opt tokenizers = { version = "0.23", default-features = false, features = ["onig"], optional = true } symphonia = { version = "0.5", default-features = false, features = ["aac", "adpcm", "alac", "isomp4", "mkv", "mp3", "pcm", "vorbis", "wav"], optional = true } rubato = { version = "0.16", default-features = false, optional = true } -zip = { workspace = true } sys-info = { version = "0.9", default-features = false } llama-cpp-2 = { workspace = true, optional = true } diff --git a/crates/goose/acp-meta.json b/crates/goose/acp-meta.json index eef554cdf9..f0efcda0fb 100644 --- a/crates/goose/acp-meta.json +++ b/crates/goose/acp-meta.json @@ -40,6 +40,11 @@ "requestType": "SteerSessionRequest_unstable", "responseType": "SteerSessionResponse_unstable" }, + { + "method": "_goose/unstable/diagnostics/get", + "requestType": "DiagnosticsGetRequest_unstable", + "responseType": "DiagnosticsGetResponse_unstable" + }, { "method": "session/delete", "requestType": "DeleteSessionRequest", diff --git a/crates/goose/acp-schema.json b/crates/goose/acp-schema.json index 1cf4fb89f0..b689dba222 100644 --- a/crates/goose/acp-schema.json +++ b/crates/goose/acp-schema.json @@ -973,6 +973,42 @@ "x-side": "agent", "x-method": "_goose/unstable/session/steer" }, + "DiagnosticsGetRequest_unstable": { + "type": "object", + "properties": { + "sessionId": { + "type": "string" + }, + "level": { + "$ref": "#/$defs/DiagnosticsReportLevel", + "default": "summary" + } + }, + "required": [ + "sessionId" + ], + "description": "Generate a diagnostics report for a session.", + "x-side": "agent", + "x-method": "_goose/unstable/diagnostics/get" + }, + "DiagnosticsReportLevel": { + "type": "string", + "enum": [ + "summary", + "full" + ] + }, + "DiagnosticsGetResponse_unstable": { + "type": "object", + "properties": { + "report": {} + }, + "required": [ + "report" + ], + "x-side": "agent", + "x-method": "_goose/unstable/diagnostics/get" + }, "DeleteSessionRequest": { "type": "object", "properties": { @@ -4613,6 +4649,15 @@ "description": "Params for _goose/unstable/session/steer", "title": "SteerSessionRequest_unstable" }, + { + "allOf": [ + { + "$ref": "#/$defs/DiagnosticsGetRequest_unstable" + } + ], + "description": "Params for _goose/unstable/diagnostics/get", + "title": "DiagnosticsGetRequest_unstable" + }, { "allOf": [ { @@ -5250,6 +5295,14 @@ ], "title": "SteerSessionResponse_unstable" }, + { + "allOf": [ + { + "$ref": "#/$defs/DiagnosticsGetResponse_unstable" + } + ], + "title": "DiagnosticsGetResponse_unstable" + }, { "allOf": [ { diff --git a/crates/goose/src/acp/server.rs b/crates/goose/src/acp/server.rs index 4b9b0c6af8..263952592f 100644 --- a/crates/goose/src/acp/server.rs +++ b/crates/goose/src/acp/server.rs @@ -84,6 +84,7 @@ mod agent_requests; pub use agent_requests::agent_request_schemas; mod config; mod custom_dispatch; +mod diagnostics; mod dictation; mod dispatch; mod elicitation; diff --git a/crates/goose/src/acp/server/custom_dispatch.rs b/crates/goose/src/acp/server/custom_dispatch.rs index 1652023637..7b10cc3178 100644 --- a/crates/goose/src/acp/server/custom_dispatch.rs +++ b/crates/goose/src/acp/server/custom_dispatch.rs @@ -82,6 +82,14 @@ impl GooseAcpAgent { self.on_steer_session(req).await } + #[custom_method(DiagnosticsGetRequest)] + async fn dispatch_get_diagnostics( + &self, + req: DiagnosticsGetRequest, + ) -> Result { + self.on_get_diagnostics(req).await + } + #[custom_method(DeleteSessionRequest)] async fn dispatch_delete_session( &self, diff --git a/crates/goose/src/acp/server/diagnostics.rs b/crates/goose/src/acp/server/diagnostics.rs new file mode 100644 index 0000000000..954aeed7aa --- /dev/null +++ b/crates/goose/src/acp/server/diagnostics.rs @@ -0,0 +1,20 @@ +use super::*; +use crate::session::{generate_diagnostics, DiagnosticsLevel}; + +impl GooseAcpAgent { + pub(super) async fn on_get_diagnostics( + &self, + req: DiagnosticsGetRequest, + ) -> Result { + let level = match req.level { + DiagnosticsReportLevel::Summary => DiagnosticsLevel::Summary, + DiagnosticsReportLevel::Full => DiagnosticsLevel::Full, + }; + let report = generate_diagnostics(&self.session_manager, &req.session_id, level) + .await + .internal_err()?; + let report = serde_json::to_value(report).internal_err()?; + + Ok(DiagnosticsGetResponse { report }) + } +} diff --git a/crates/goose/src/session/diagnostics.rs b/crates/goose/src/session/diagnostics.rs index c9e580c7f6..253ff891c7 100644 --- a/crates/goose/src/session/diagnostics.rs +++ b/crates/goose/src/session/diagnostics.rs @@ -2,18 +2,25 @@ use crate::config::base::Config; use crate::config::extensions::get_enabled_extensions; use crate::config::paths::Paths; use crate::prompt_template::list_templates; -use crate::providers::utils::LOGS_TO_KEEP; use crate::session::SessionManager; use serde::{Deserialize, Serialize}; use std::fs; -use std::io::Cursor; -use std::io::Write; use std::path::PathBuf; use utoipa::ToSchema; -use zip::write::SimpleFileOptions; -use zip::ZipWriter; -#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +const SERVER_LOG_TAIL_LINES: usize = 400; +const LLM_LOG_MAX_BYTES: usize = 2 * 1024 * 1024; +const CONFIG_MAX_BYTES: usize = 256 * 1024; + +#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, ToSchema, schemars::JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum DiagnosticsLevel { + #[default] + Summary, + Full, +} + +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, schemars::JsonSchema)] pub struct SystemInfo { pub app_version: String, pub os: String, @@ -24,6 +31,73 @@ pub struct SystemInfo { pub enabled_extensions: Vec, } +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, schemars::JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct DiagnosticsConfig { + pub config_path: String, + pub config_yaml: Option, + pub truncated: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, schemars::JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct DiagnosticsExtensions { + pub enabled: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, schemars::JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct DiagnosticsTextFile { + pub path: String, + pub content: String, + pub truncated: bool, +} + +#[derive(Debug, Clone, Default, Serialize, Deserialize, ToSchema, schemars::JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct DiagnosticsLogs { + pub server: Option, + pub llm: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, schemars::JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct DiagnosticsPrompt { + pub name: String, + pub content: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, schemars::JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct DiagnosticsScheduledRecipe { + pub path: String, + pub content: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, schemars::JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct DiagnosticsError { + pub path: Option, + pub message: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, schemars::JsonSchema)] +#[serde(rename_all = "camelCase")] +pub struct DiagnosticsReport { + pub schema_version: u32, + pub generated_at: String, + pub level: DiagnosticsLevel, + pub system: SystemInfo, + pub config: Option, + pub extensions: DiagnosticsExtensions, + pub session: Option, + pub logs: DiagnosticsLogs, + pub prompts: Vec, + pub schedule: Option, + pub scheduled_recipes: Vec, + pub errors: Vec, +} + impl SystemInfo { pub fn collect() -> Self { let config = Config::global(); @@ -86,6 +160,40 @@ pub fn latest_llm_log_path() -> Option { path.exists().then_some(path) } +fn recent_llm_log_paths() -> Vec { + let logs_dir = Paths::in_state_dir("logs"); + let mut paths: Vec<_> = fs::read_dir(logs_dir) + .ok() + .into_iter() + .flatten() + .filter_map(|entry| entry.ok().map(|entry| entry.path())) + .filter(|path| { + path.file_name() + .and_then(|name| name.to_str()) + .is_some_and(|name| name.starts_with("llm_request.") && name.ends_with(".jsonl")) + }) + .collect(); + + paths.sort_by_key(|path| llm_log_sort_key(path)); + paths +} + +fn llm_log_sort_key(path: &std::path::Path) -> (u8, usize, String) { + let name = path + .file_name() + .and_then(|name| name.to_str()) + .unwrap_or_default(); + let index = name + .strip_prefix("llm_request.") + .and_then(|name| name.strip_suffix(".jsonl")) + .and_then(|name| name.parse::().ok()); + + match index { + Some(index) => (0, index, String::new()), + None => (1, usize::MAX, name.to_string()), + } +} + pub fn read_tail(path: &std::path::Path, max_lines: usize) -> Option { let content = fs::read_to_string(path).ok()?; let lines: Vec<&str> = content.lines().collect(); @@ -128,6 +236,10 @@ pub fn read_capped(path: &std::path::Path, max_bytes: usize) -> Option { )) } +fn was_truncated(content: &str) -> bool { + content.contains("... (") && content.contains(" bytes omitted) ...") +} + fn latest_entry_by_name(dir: &std::path::Path) -> Option { let mut entries: Vec<_> = fs::read_dir(dir).ok()?.filter_map(|e| e.ok()).collect(); entries.sort_by_key(|e| e.file_name()); @@ -137,81 +249,135 @@ fn latest_entry_by_name(dir: &std::path::Path) -> Option { pub async fn generate_diagnostics( session_manager: &SessionManager, session_id: &str, -) -> anyhow::Result> { - let logs_dir = Paths::in_state_dir("logs"); - let config_dir = Paths::config_dir(); - let config_path = config_dir.join("config.yaml"); + level: DiagnosticsLevel, +) -> anyhow::Result { + let config_path = config_path(); let data_dir = Paths::data_dir(); - let system_info = SystemInfo::collect(); + let is_full = matches!(level, DiagnosticsLevel::Full); + let mut errors = Vec::new(); - let mut buffer = Vec::new(); - { - let mut zip = ZipWriter::new(Cursor::new(&mut buffer)); - let options = - SimpleFileOptions::default().compression_method(zip::CompressionMethod::Deflated); - - let mut log_files: Vec<_> = fs::read_dir(&logs_dir)? - .filter_map(|e| e.ok()) - .filter(|e| e.path().extension().is_some_and(|ext| ext == "jsonl")) - .collect(); - - log_files.sort_by_key(|e| e.metadata().ok().and_then(|m| m.modified().ok())); - - for entry in log_files.iter().rev().take(LOGS_TO_KEEP) { - let path = entry.path(); - let name = path.file_name().unwrap().to_str().unwrap(); - zip.start_file(format!("logs/{}", name), options)?; - zip.write_all(&fs::read(&path)?)?; - } - - if let Some(server_log) = latest_server_log_path() { - if let Ok(content) = fs::read(&server_log) { - let name = server_log.file_name().unwrap().to_str().unwrap(); - zip.start_file(format!("logs/server/{}", name), options)?; - zip.write_all(&content)?; - } - } - + let session = if is_full { let session_data = session_manager.export_session(session_id).await?; - zip.start_file("session.json", options)?; - zip.write_all(session_data.as_bytes())?; + Some(serde_json::from_str(&session_data)?) + } else { + None + }; - if config_path.exists() { - zip.start_file("config.yaml", options)?; - zip.write_all(&fs::read(&config_path)?)?; + let config = if is_full { + let config_yaml = if config_path.exists() { + read_capped(&config_path, CONFIG_MAX_BYTES) + } else { + None + }; + let truncated = config_yaml.as_deref().is_some_and(was_truncated); + Some(DiagnosticsConfig { + config_path: config_path.display().to_string(), + config_yaml, + truncated, + }) + } else { + None + }; + + let logs = if is_full { + DiagnosticsLogs { + server: latest_server_log_path().and_then(|path| { + read_tail(&path, SERVER_LOG_TAIL_LINES).map(|content| DiagnosticsTextFile { + path: path.display().to_string(), + content, + truncated: true, + }) + }), + llm: recent_llm_log_paths() + .into_iter() + .filter_map(|path| { + read_capped(&path, LLM_LOG_MAX_BYTES).map(|content| { + let truncated = was_truncated(&content); + DiagnosticsTextFile { + path: path.display().to_string(), + content, + truncated, + } + }) + }) + .collect(), } + } else { + DiagnosticsLogs::default() + }; - zip.start_file("system.txt", options)?; - zip.write_all(system_info.to_text().as_bytes())?; + let prompts = if is_full { + list_templates() + .into_iter() + .map(|template| DiagnosticsPrompt { + name: template.name, + content: template.user_content.unwrap_or(template.default_content), + }) + .collect() + } else { + Vec::new() + }; + let schedule = if is_full { let schedule_json = data_dir.join("schedule.json"); if schedule_json.exists() { - zip.start_file("schedule.json", options)?; - zip.write_all(&fs::read(&schedule_json)?)?; + fs::read_to_string(&schedule_json).ok().and_then(|content| { + match serde_json::from_str(&content) { + Ok(value) => Some(value), + Err(err) => { + errors.push(DiagnosticsError { + path: Some(schedule_json.display().to_string()), + message: err.to_string(), + }); + None + } + } + }) + } else { + None } + } else { + None + }; + let mut scheduled_recipes = Vec::new(); + if is_full { let scheduled_recipes_dir = data_dir.join("scheduled_recipes"); if scheduled_recipes_dir.exists() && scheduled_recipes_dir.is_dir() { for entry in fs::read_dir(&scheduled_recipes_dir)? { let entry = entry?; let path = entry.path(); if path.is_file() { - let name = path.file_name().unwrap().to_str().unwrap(); - zip.start_file(format!("scheduled_recipes/{}", name), options)?; - zip.write_all(&fs::read(&path)?)?; + match fs::read_to_string(&path) { + Ok(content) => scheduled_recipes.push(DiagnosticsScheduledRecipe { + path: path.display().to_string(), + content, + }), + Err(err) => errors.push(DiagnosticsError { + path: Some(path.display().to_string()), + message: err.to_string(), + }), + } } } } - - for template in list_templates() { - let content = template.user_content.unwrap_or(template.default_content); - zip.start_file(format!("prompts/{}.txt", template.name), options)?; - zip.write_all(content.as_bytes())?; - } - - zip.finish()?; } - Ok(buffer) + Ok(DiagnosticsReport { + schema_version: 1, + generated_at: chrono::Utc::now().to_rfc3339(), + level, + system: system_info.clone(), + config, + extensions: DiagnosticsExtensions { + enabled: system_info.enabled_extensions, + }, + session, + logs, + prompts, + schedule, + scheduled_recipes, + errors, + }) } diff --git a/crates/goose/src/session/mod.rs b/crates/goose/src/session/mod.rs index 951c533bcd..c7c5230e80 100644 --- a/crates/goose/src/session/mod.rs +++ b/crates/goose/src/session/mod.rs @@ -11,7 +11,9 @@ mod session_naming; pub use diagnostics::{ config_path, generate_diagnostics, get_system_info, latest_llm_log_path, - latest_server_log_path, read_capped, read_tail, SystemInfo, + latest_server_log_path, read_capped, read_tail, DiagnosticsConfig, DiagnosticsError, + DiagnosticsExtensions, DiagnosticsLevel, DiagnosticsLogs, DiagnosticsPrompt, DiagnosticsReport, + DiagnosticsScheduledRecipe, DiagnosticsTextFile, SystemInfo, }; pub use extension_data::{EnabledExtensionsState, ExtensionData, ExtensionState, TodoState}; pub use session_manager::{ diff --git a/crates/goose/src/session/session_manager.rs b/crates/goose/src/session/session_manager.rs index 1abdf14976..f871feda3f 100644 --- a/crates/goose/src/session/session_manager.rs +++ b/crates/goose/src/session/session_manager.rs @@ -451,6 +451,16 @@ impl SessionManager { .await } + pub async fn truncate_conversation_from_message( + &self, + session_id: &str, + message_id: &str, + ) -> Result<()> { + self.storage + .truncate_conversation_from_message(session_id, message_id) + .await + } + async fn system_generated_name_update( &self, id: &str, @@ -1932,6 +1942,38 @@ impl SessionStorage { Ok(()) } + async fn truncate_conversation_from_message( + &self, + session_id: &str, + message_id: &str, + ) -> Result<()> { + let pool = self.pool().await?; + let mut tx = pool.begin_with("BEGIN IMMEDIATE").await?; + + let boundary = sqlx::query_as::<_, (i64, i64)>( + "SELECT id, created_timestamp FROM messages WHERE session_id = ? AND message_id = ? ORDER BY created_timestamp, id LIMIT 1", + ) + .bind(session_id) + .bind(message_id) + .fetch_optional(&mut *tx) + .await?; + + if let Some((boundary_id, boundary_timestamp)) = boundary { + sqlx::query( + "DELETE FROM messages WHERE session_id = ? AND (created_timestamp > ? OR (created_timestamp = ? AND id >= ?))", + ) + .bind(session_id) + .bind(boundary_timestamp) + .bind(boundary_timestamp) + .bind(boundary_id) + .execute(&mut *tx) + .await?; + } + + tx.commit().await?; + Ok(()) + } + async fn search_chat_history( &self, query: &str, @@ -2218,12 +2260,90 @@ mod tests { .unwrap(); } + async fn set_message_timestamp( + sm: &SessionManager, + session_id: &str, + message_id: &str, + timestamp: &str, + ) { + let pool = sm.storage().pool().await.unwrap(); + let timestamp = chrono::DateTime::parse_from_rfc3339(timestamp).unwrap(); + let timestamp_string = timestamp.format("%Y-%m-%d %H:%M:%S").to_string(); + + sqlx::query( + "UPDATE messages SET timestamp = ?, created_timestamp = ? WHERE session_id = ? AND message_id = ?", + ) + .bind(×tamp_string) + .bind(timestamp.timestamp()) + .bind(session_id) + .bind(message_id) + .execute(pool) + .await + .unwrap(); + } + async fn add_user_message(sm: &SessionManager, session_id: &str) { sm.add_message(session_id, &Message::user().with_text("hello world")) .await .unwrap(); } + #[tokio::test] + async fn test_truncate_conversation_from_message_keeps_same_second_previous_rows() { + let temp_dir = TempDir::new().unwrap(); + let sm = SessionManager::new(temp_dir.path().to_path_buf()); + let session = sm + .create_session( + temp_dir.path().to_path_buf(), + "Same second truncation".to_string(), + SessionType::User, + GooseMode::default(), + ) + .await + .unwrap(); + + let timestamp = "2026-06-23T12:00:00Z"; + sm.add_message( + &session.id, + &Message::assistant() + .with_text("assistant reply") + .with_id("assistant"), + ) + .await + .unwrap(); + set_message_timestamp(&sm, &session.id, "assistant", timestamp).await; + + sm.add_message( + &session.id, + &Message::user() + .with_text("terminal history") + .with_id("terminal-history"), + ) + .await + .unwrap(); + set_message_timestamp(&sm, &session.id, "terminal-history", timestamp).await; + + sm.add_message( + &session.id, + &Message::user() + .with_text("next prompt") + .with_id("next-prompt"), + ) + .await + .unwrap(); + set_message_timestamp(&sm, &session.id, "next-prompt", timestamp).await; + + sm.truncate_conversation_from_message(&session.id, "terminal-history") + .await + .unwrap(); + + let reloaded = sm.get_session(&session.id, true).await.unwrap(); + let messages = reloaded.conversation.unwrap().messages().to_vec(); + assert_eq!(messages.len(), 1); + assert_eq!(messages[0].id.as_deref(), Some("assistant")); + assert_eq!(messages[0].as_concat_text(), "assistant reply"); + } + #[tokio::test] async fn test_maybe_update_name_updates_eligible_session() { let temp_dir = TempDir::new().unwrap(); diff --git a/documentation/docs/guides/goose-cli-commands.md b/documentation/docs/guides/goose-cli-commands.md index 29d5347fb5..09e1d09f2c 100644 --- a/documentation/docs/guides/goose-cli-commands.md +++ b/documentation/docs/guides/goose-cli-commands.md @@ -351,13 +351,13 @@ goose session export --path ./my-session.jsonl -o exported.md --- #### session diagnostics [options] -Generate a comprehensive diagnostics bundle for troubleshooting issues with a specific session. +Generate a comprehensive diagnostics JSON report for troubleshooting issues with a specific session. **Options:** - **`--session-id `**: Generate diagnostics for a specific session by ID - **`-n, --name `**: Generate diagnostics for a specific session by name - **`--path `**: Generate diagnostics for a specific session by file path (legacy) -- **`-o, --output `**: Save diagnostics bundle to a specific file path (default: `diagnostics_{session_id}.zip`) +- **`-o, --output `**: Save diagnostics report to a specific file path (default: `diagnostics_{session_id}.json`) **What's included:** - **System Information**: App version, operating system, architecture, and timestamp @@ -374,18 +374,18 @@ goose session diagnostics --session-id 20251108_5 goose session diagnostics -n my-project-session # Save diagnostics to a custom location -goose session diagnostics --session-id 20251108_5 -o /path/to/my-diagnostics.zip +goose session diagnostics --session-id 20251108_5 -o /path/to/my-diagnostics.json # Interactive selection (prompts you to choose a session) goose session diagnostics ``` :::warning Privacy Notice -Diagnostics bundles contain your session messages and system information. If your session includes sensitive data (API keys, personal information, proprietary code), review the contents before sharing publicly. +Diagnostics reports contain your session messages and system information. If your session includes sensitive data (API keys, personal information, proprietary code), review the contents before sharing publicly. ::: :::tip -Generate diagnostics before reporting bugs to provide technical details that help with faster resolution. The ZIP file can be attached to GitHub issues or shared with support. +Generate diagnostics before reporting bugs to provide technical details that help with faster resolution. The JSON file can be attached to GitHub issues or shared with support. ::: --- diff --git a/documentation/docs/troubleshooting/diagnostics-and-reporting.md b/documentation/docs/troubleshooting/diagnostics-and-reporting.md index 084ee38749..20e69a82cc 100644 --- a/documentation/docs/troubleshooting/diagnostics-and-reporting.md +++ b/documentation/docs/troubleshooting/diagnostics-and-reporting.md @@ -12,13 +12,13 @@ goose provides several built-in features to help you get support, report issues, | Feature | Purpose | Location | Output | |---------|---------|----------|---------| -| **Diagnostics** | Generate troubleshooting data | Chat input toolbar | ZIP file with system info, logs, and session data | +| **Diagnostics** | Generate troubleshooting data | Chat input toolbar | JSON report with system info, logs, and session data | | **Report a Bug** | Submit bug reports | Chat input toolbar OR Settings → App → Help & feedback | Opens GitHub issue template | | **Request a Feature** | Suggest new features | Settings → App → Help & feedback | Opens GitHub issue template | ## Diagnostics System -The diagnostics feature creates a comprehensive troubleshooting bundle that includes system information, session data, configuration files, and recent logs. This is invaluable for debugging issues or getting technical support. +The diagnostics feature creates a comprehensive troubleshooting JSON report that includes system information, session data, configuration files, and recent logs. This is invaluable for debugging issues or getting technical support. ### Generating Diagnostics @@ -27,8 +27,10 @@ The diagnostics feature creates a comprehensive troubleshooting bundle that incl 1. In an active chat session, look for the icon in the bottom toolbar 2. Click the diagnostics button 3. Review the information in the modal about what data will be collected - 4. Click `Download` to generate and save the diagnostics bundle - 5. The ZIP file will be saved as `diagnostics_{session_id}.zip` + 4. Click `Download` to generate and save the diagnostics report + 5. The JSON file will be saved as `diagnostics_{session_id}.json` + + You can use `scripts/diagnostics-viewer.py` to inspect downloaded diagnostics reports; by default it looks in `~/Downloads`. :::tip The diagnostics button is only available when you have an active session, as it needs a session ID to generate the bundle. @@ -45,7 +47,7 @@ The diagnostics feature creates a comprehensive troubleshooting bundle that incl goose session diagnostics # Save to a custom location - goose session diagnostics --session-id --output /path/to/diagnostics.zip + goose session diagnostics --session-id --output /path/to/diagnostics.json ``` To find your session ID, first list available sessions: @@ -65,17 +67,18 @@ The diagnostics feature creates a comprehensive troubleshooting bundle that incl ### Using Diagnostics Data -The diagnostics ZIP file contains several folders: +The diagnostics JSON file contains structured sections: -``` -diagnostics_abc123def.zip -├── logs/ -│ ├── goose-2024-01-15.jsonl -│ ├── goose-2024-01-14.jsonl -│ └── ... -├── session.json # Your session messages -├── config.yaml # Configuration files (if they exist) -└── system.txt # System information +```json +{ + "system": {}, + "session": {}, + "config": {}, + "logs": {}, + "prompts": [], + "schedule": {}, + "errors": [] +} ``` **When to generate diagnostics:** @@ -154,4 +157,3 @@ For issues not resolved by diagnostics: - **[Session and System Logs](/docs/guides/logs)**: View detailed logs for debugging individual sessions - **[Telemetry Export](/docs/guides/environment-variables#observability)**: Configure telemetry for performance analysis and production monitoring - diff --git a/scripts/diagnostics-viewer.py b/scripts/diagnostics-viewer.py index 3129eadf89..8ee4f92f96 100755 --- a/scripts/diagnostics-viewer.py +++ b/scripts/diagnostics-viewer.py @@ -6,9 +6,9 @@ WARNING: entirely vibe coded. use as a throwaway tool -Diagnostics Viewer - Browse and inspect Goose diagnostics bundles. +Diagnostics Viewer - Browse and inspect Goose diagnostics reports. -Scans for diagnostics zip files, displays their sessions, and provides +Scans for diagnostics JSON reports and legacy zip files, displays their sessions, and provides an interactive viewer for examining session data, logs, and other files. """ import json @@ -188,34 +188,114 @@ class SearchOverlay(Container): class DiagnosticsSession: - """Represents a diagnostics bundle.""" + """Represents a diagnostics report or legacy diagnostics bundle.""" - def __init__(self, zip_path: Path): - self.zip_path = zip_path + def __init__(self, path: Path): + self.path = path + self.is_zip = path.suffix == ".zip" self.name = "Unknown Session" - self.session_id = zip_path.stem - self.created_at = zip_path.stat().st_mtime + self.session_id = path.stem + self.created_at = path.stat().st_mtime + self.report = None self._load_session_name() def _load_session_name(self): - """Extract session name from session.json.""" + """Extract session name from the report.""" + if not self.is_zip: + self._load_json_report() + session = (self.report or {}).get("session") or {} + self.name = session.get("name", "Unknown Session") + self.session_id = session.get("id", self.path.stem) + return + try: - with zipfile.ZipFile(self.zip_path, 'r') as zf: + with zipfile.ZipFile(self.path, 'r') as zf: # Find session.json for name in zf.namelist(): if name.endswith('session.json'): with zf.open(name) as f: data = json.load(f) self.name = data.get('name', 'Unknown Session') - self.session_id = data.get('id', self.zip_path.stem) + self.session_id = data.get('id', self.path.stem) break except Exception as e: self.name = f"Error loading: {e}" - def get_file_list(self) -> list[str]: - """Get list of files in the zip, sorted with system.txt first.""" + def _load_json_report(self): + if self.report is not None: + return + try: - with zipfile.ZipFile(self.zip_path, 'r') as zf: + self.report = json.loads(self.path.read_text()) + except Exception as e: + self.report = {"error": f"Error loading: {e}"} + + def _json_virtual_files(self) -> dict[str, str]: + self._load_json_report() + report = self.report or {} + files = { + "diagnostics.json": json.dumps(report, indent=2), + } + + for key, filename in [ + ("system", "system.json"), + ("config", "config.json"), + ("extensions", "extensions.json"), + ("session", "session.json"), + ("schedule", "schedule.json"), + ("errors", "errors.json"), + ]: + value = report.get(key) + if value is not None: + files[filename] = json.dumps(value, indent=2) + + logs = report.get("logs") or {} + server = logs.get("server") + if isinstance(server, dict) and server.get("content") is not None: + files["logs/server.txt"] = server["content"] + + llm_logs = logs.get("llm") or [] + for index, entry in enumerate(llm_logs): + if isinstance(entry, dict) and entry.get("content") is not None: + path = Path(entry.get("path") or f"llm_request.{index}.jsonl") + files[f"logs/{path.name}"] = entry["content"] + + config = report.get("config") or {} + if isinstance(config, dict) and config.get("configYaml"): + files["config.yaml"] = config["configYaml"] + + for prompt in report.get("prompts") or []: + if isinstance(prompt, dict) and prompt.get("name") and prompt.get("content") is not None: + files[f"prompts/{prompt['name']}.txt"] = prompt["content"] + + for recipe in report.get("scheduledRecipes") or []: + if isinstance(recipe, dict) and recipe.get("path") and recipe.get("content") is not None: + path = Path(recipe["path"]) + files[f"scheduled_recipes/{path.name}"] = recipe["content"] + + return files + + def get_file_list(self) -> list[str]: + """Get list of report files, sorted with system first.""" + if not self.is_zip: + files = list(self._json_virtual_files().keys()) + + def sort_key(f): + if f == "system.json": + return (0, f) + elif f == "session.json": + return (1, f) + elif f == "config.yaml" or f == "config.json": + return (2, f) + elif f == "diagnostics.json": + return (3, f) + else: + return (4, f) + + return sorted(files, key=sort_key) + + try: + with zipfile.ZipFile(self.path, 'r') as zf: files = zf.namelist() # Sort: system.txt first, then session.json, then alphabetically @@ -234,13 +314,16 @@ class DiagnosticsSession: return [] def read_file(self, filename: str) -> Optional[str]: - """Read a file from the zip. + """Read a file from the report. Returns: File content as string, or None if file cannot be read. """ + if not self.is_zip: + return self._json_virtual_files().get(filename) + try: - with zipfile.ZipFile(self.zip_path, 'r') as zf: + with zipfile.ZipFile(self.path, 'r') as zf: with zf.open(filename) as f: return f.read().decode('utf-8', errors='replace') except Exception: @@ -591,8 +674,8 @@ class SessionList(Vertical): list_view = self.query_one(ListView) for session in self.sessions: item = ListItem( - Label(f"{session.name}\n[dim]{session.zip_path.name}[/dim]"), - name=session.zip_path.name + Label(f"{session.name}\n[dim]{session.path.name}[/dim]"), + name=session.path.name ) list_view.append(item) @@ -752,13 +835,14 @@ class DiagnosticsApp(App): self.show_session_list() def scan_diagnostics(self): - """Scan for diagnostics zip files.""" + """Scan for diagnostics JSON reports and legacy zip files.""" self.sessions = [] - # Find all diagnostics zip files - for zip_path in self.diagnostics_dir.glob("diagnostics*.zip"): - session = DiagnosticsSession(zip_path) - self.sessions.append(session) + for path in [ + *self.diagnostics_dir.glob("diagnostics*.json"), + *self.diagnostics_dir.glob("diagnostics*.zip"), + ]: + self.sessions.append(DiagnosticsSession(path)) # Sort by creation time (newest first) self.sessions.sort(key=lambda s: s.created_at, reverse=True) @@ -781,9 +865,9 @@ class DiagnosticsApp(App): def on_list_view_selected(self, event: ListView.Selected): """Handle session selection.""" - # Find the session by zip name + # Find the session by diagnostics file name session_name = event.item.name - session = next((s for s in self.sessions if s.zip_path.name == session_name), None) + session = next((s for s in self.sessions if s.path.name == session_name), None) if session: self.show_session_viewer(session) diff --git a/ui/desktop/openapi.json b/ui/desktop/openapi.json index 9c21ebc92b..9ab8f407f6 100644 --- a/ui/desktop/openapi.json +++ b/ui/desktop/openapi.json @@ -1730,6 +1730,19 @@ ], "operationId": "diagnostics", "parameters": [ + { + "name": "level", + "in": "query", + "required": false, + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/DiagnosticsLevel" + } + ], + "nullable": true + } + }, { "name": "session_id", "in": "path", @@ -1741,12 +1754,11 @@ ], "responses": { "200": { - "description": "Diagnostics zip file", + "description": "Diagnostics report", "content": { - "application/zip": { + "application/json": { "schema": { - "type": "string", - "format": "binary" + "$ref": "#/components/schemas/DiagnosticsReport" } } } @@ -4617,6 +4629,200 @@ } } }, + "DiagnosticsConfig": { + "type": "object", + "required": [ + "configPath", + "truncated" + ], + "properties": { + "configPath": { + "type": "string" + }, + "configYaml": { + "type": "string", + "nullable": true + }, + "truncated": { + "type": "boolean" + } + } + }, + "DiagnosticsError": { + "type": "object", + "required": [ + "message" + ], + "properties": { + "message": { + "type": "string" + }, + "path": { + "type": "string", + "nullable": true + } + } + }, + "DiagnosticsExtensions": { + "type": "object", + "required": [ + "enabled" + ], + "properties": { + "enabled": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "DiagnosticsLevel": { + "type": "string", + "enum": [ + "summary", + "full" + ] + }, + "DiagnosticsLogs": { + "type": "object", + "required": [ + "llm" + ], + "properties": { + "llm": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DiagnosticsTextFile" + } + }, + "server": { + "allOf": [ + { + "$ref": "#/components/schemas/DiagnosticsTextFile" + } + ], + "nullable": true + } + } + }, + "DiagnosticsPrompt": { + "type": "object", + "required": [ + "name", + "content" + ], + "properties": { + "content": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "DiagnosticsReport": { + "type": "object", + "required": [ + "schemaVersion", + "generatedAt", + "level", + "system", + "extensions", + "logs", + "prompts", + "scheduledRecipes", + "errors" + ], + "properties": { + "config": { + "allOf": [ + { + "$ref": "#/components/schemas/DiagnosticsConfig" + } + ], + "nullable": true + }, + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DiagnosticsError" + } + }, + "extensions": { + "$ref": "#/components/schemas/DiagnosticsExtensions" + }, + "generatedAt": { + "type": "string" + }, + "level": { + "$ref": "#/components/schemas/DiagnosticsLevel" + }, + "logs": { + "$ref": "#/components/schemas/DiagnosticsLogs" + }, + "prompts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DiagnosticsPrompt" + } + }, + "schedule": { + "nullable": true + }, + "scheduledRecipes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DiagnosticsScheduledRecipe" + } + }, + "schemaVersion": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "session": { + "nullable": true + }, + "system": { + "$ref": "#/components/schemas/SystemInfo" + } + } + }, + "DiagnosticsScheduledRecipe": { + "type": "object", + "required": [ + "path", + "content" + ], + "properties": { + "content": { + "type": "string" + }, + "path": { + "type": "string" + } + } + }, + "DiagnosticsTextFile": { + "type": "object", + "required": [ + "path", + "content", + "truncated" + ], + "properties": { + "content": { + "type": "string" + }, + "path": { + "type": "string" + }, + "truncated": { + "type": "boolean" + } + } + }, "DictationProvider": { "type": "string", "enum": [ diff --git a/ui/desktop/src/acp/diagnostics.ts b/ui/desktop/src/acp/diagnostics.ts new file mode 100644 index 0000000000..553ca8352c --- /dev/null +++ b/ui/desktop/src/acp/diagnostics.ts @@ -0,0 +1,16 @@ +import { getAcpClient } from './acpConnection'; +import type { DiagnosticsReport } from '../api'; + +export type DiagnosticsLevel = 'summary' | 'full'; + +export async function getDiagnosticsReport( + sessionId: string, + level: DiagnosticsLevel +): Promise { + const client = await getAcpClient(); + const response = await client.goose.diagnosticsGet_unstable({ + sessionId, + level, + }); + return response.report as DiagnosticsReport; +} diff --git a/ui/desktop/src/api/index.ts b/ui/desktop/src/api/index.ts index 17ed66891d..33ddd72656 100644 --- a/ui/desktop/src/api/index.ts +++ b/ui/desktop/src/api/index.ts @@ -1,4 +1,4 @@ // This file is auto-generated by @hey-api/openapi-ts export { addExtension, agentAddExtension, agentRemoveExtension, callTool, cancelDownload, cancelLocalModelDownload, checkProvider, cleanupProviderCache, configureProviderOauth, confirmToolAction, createCustomProvider, createSchedule, decodeRecipe, deleteLocalModel, deleteModel, deleteProviderSecret, deleteRecipe, deleteSchedule, diagnostics, downloadHfModel, downloadModel, encodeRecipe, exportApp, forkSession, getCanonicalModelInfo, getCustomProvider, getDictationConfig, getDownloadProgress, getExtensions, getFeatures, getLocalModelDownloadProgress, getModelSettings, getPrompt, getPrompts, getProviderCatalog, getProviderCatalogTemplate, getProviderModelInfo, getProviderModels, getRepoFiles, getSession, getSessionExtensions, getSlashCommands, getTools, getTunnelStatus, importApp, importSessionNostr, inspectRunningJob, killRunningJob, listApps, listBuiltinChatTemplates, listLocalModels, listModels, listProviderSecrets, listRecipes, listSchedules, mcpUiProxy, type Options, parseRecipe, pauseSchedule, providers, readAllConfig, readConfig, readResource, recipeToYaml, removeConfig, removeCustomProvider, removeExtension, reply, resetPrompt, restartAgent, resumeAgent, runNowHandler, savePrompt, saveRecipe, scanRecipe, scheduleRecipe, searchHfModels, sendTelemetryEvent, sessionCancel, sessionEvents, sessionReply, sessionsHandler, setConfigProvider, setRecipeSlashCommand, shareSessionNostr, startAgent, startNanogptSetup, startOpenrouterSetup, startTetrateSetup, startTunnel, status, stopAgent, stopTunnel, syncFeaturedModels, systemInfo, transcribeDictation, unpauseSchedule, updateAgentProvider, updateCustomProvider, updateFromSession, updateModelSettings, updateSchedule, updateSession, updateSessionName, updateSessionUserRecipeValues, updateWorkingDir, upsertConfig, upsertPermissions, validateConfig } from './sdk.gen'; -export type { ActionRequired, ActionRequiredData, AddExtensionData, AddExtensionErrors, AddExtensionRequest, AddExtensionResponse, AddExtensionResponses, AgentAddExtensionData, AgentAddExtensionErrors, AgentAddExtensionResponse, AgentAddExtensionResponses, AgentRemoveExtensionData, AgentRemoveExtensionErrors, AgentRemoveExtensionResponse, AgentRemoveExtensionResponses, Annotations, Author, CallToolData, CallToolError, CallToolErrors, CallToolRequest, CallToolResponse, CallToolResponse2, CallToolResponses, CancelDownloadData, CancelDownloadErrors, CancelDownloadResponses, CancelLocalModelDownloadData, CancelLocalModelDownloadErrors, CancelLocalModelDownloadResponses, CancelRequest, ChatRequest, ChatTemplate, CheckProviderData, CheckProviderRequest, CleanupProviderCacheData, CleanupProviderCacheErrors, CleanupProviderCacheResponse, CleanupProviderCacheResponses, ClientOptions, CommandType, ConfigKey, ConfigKeyQuery, ConfigResponse, ConfigureProviderOauthData, ConfigureProviderOauthErrors, ConfigureProviderOauthResponses, ConfirmToolActionData, ConfirmToolActionErrors, ConfirmToolActionRequest, ConfirmToolActionResponses, Content, ContentBlock, Conversation, CreateCustomProviderData, CreateCustomProviderErrors, CreateCustomProviderResponse, CreateCustomProviderResponse2, CreateCustomProviderResponses, CreateScheduleData, CreateScheduleErrors, CreateScheduleRequest, CreateScheduleResponse, CreateScheduleResponses, CspMetadata, DeclarativeProviderConfig, DecodeRecipeData, DecodeRecipeErrors, DecodeRecipeRequest, DecodeRecipeResponse, DecodeRecipeResponse2, DecodeRecipeResponses, DeleteLocalModelData, DeleteLocalModelErrors, DeleteLocalModelResponses, DeleteModelData, DeleteModelErrors, DeleteModelResponses, DeleteProviderSecretData, DeleteProviderSecretErrors, DeleteProviderSecretResponse, DeleteProviderSecretResponses, DeleteRecipeData, DeleteRecipeErrors, DeleteRecipeRequest, DeleteRecipeResponse, DeleteRecipeResponses, DeleteScheduleData, DeleteScheduleErrors, DeleteScheduleResponse, DeleteScheduleResponses, DiagnosticsData, DiagnosticsErrors, DiagnosticsResponse, DiagnosticsResponses, DictationProvider, DictationProviderStatus, DownloadHfModelData, DownloadHfModelErrors, DownloadHfModelResponse, DownloadHfModelResponses, DownloadModelData, DownloadModelErrors, DownloadModelRequest, DownloadModelResponses, DownloadProgress, DownloadStatus, EmbeddedResource, EncodeRecipeData, EncodeRecipeErrors, EncodeRecipeRequest, EncodeRecipeResponse, EncodeRecipeResponse2, EncodeRecipeResponses, Envs, EnvVarConfig, ErrorResponse, ExportAppData, ExportAppError, ExportAppErrors, ExportAppResponse, ExportAppResponses, ExtensionConfig, ExtensionData, ExtensionEntry, ExtensionLoadResult, ExtensionQuery, ExtensionResponse, FeaturesResponse, ForkRequest, ForkResponse, ForkSessionData, ForkSessionErrors, ForkSessionResponse, ForkSessionResponses, FrontendToolRequest, GetCanonicalModelInfoData, GetCanonicalModelInfoResponse, GetCanonicalModelInfoResponses, GetCustomProviderData, GetCustomProviderErrors, GetCustomProviderResponse, GetCustomProviderResponses, GetDictationConfigData, GetDictationConfigResponse, GetDictationConfigResponses, GetDownloadProgressData, GetDownloadProgressErrors, GetDownloadProgressResponse, GetDownloadProgressResponses, GetExtensionsData, GetExtensionsErrors, GetExtensionsResponse, GetExtensionsResponses, GetFeaturesData, GetFeaturesResponse, GetFeaturesResponses, GetLocalModelDownloadProgressData, GetLocalModelDownloadProgressErrors, GetLocalModelDownloadProgressResponse, GetLocalModelDownloadProgressResponses, GetModelSettingsData, GetModelSettingsErrors, GetModelSettingsResponse, GetModelSettingsResponses, GetPromptData, GetPromptErrors, GetPromptResponse, GetPromptResponses, GetPromptsData, GetPromptsResponse, GetPromptsResponses, GetProviderCatalogData, GetProviderCatalogErrors, GetProviderCatalogResponse, GetProviderCatalogResponses, GetProviderCatalogTemplateData, GetProviderCatalogTemplateErrors, GetProviderCatalogTemplateResponse, GetProviderCatalogTemplateResponses, GetProviderModelInfoData, GetProviderModelInfoErrors, GetProviderModelInfoResponse, GetProviderModelInfoResponses, GetProviderModelsData, GetProviderModelsErrors, GetProviderModelsResponse, GetProviderModelsResponses, GetRepoFilesData, GetRepoFilesResponse, GetRepoFilesResponses, GetSessionData, GetSessionErrors, GetSessionExtensionsData, GetSessionExtensionsErrors, GetSessionExtensionsResponse, GetSessionExtensionsResponses, GetSessionResponse, GetSessionResponses, GetSlashCommandsData, GetSlashCommandsResponse, GetSlashCommandsResponses, GetToolsData, GetToolsErrors, GetToolsQuery, GetToolsResponse, GetToolsResponses, GetTunnelStatusData, GetTunnelStatusResponse, GetTunnelStatusResponses, GooseApp, GooseMode, HfGgufFile, HfModelInfo, HfModelVariant, HfQuantVariant, Icon, IconTheme, ImageContent, ImportAppData, ImportAppError, ImportAppErrors, ImportAppRequest, ImportAppResponse, ImportAppResponse2, ImportAppResponses, ImportSessionNostrData, ImportSessionNostrErrors, ImportSessionNostrRequest, ImportSessionNostrResponse, ImportSessionNostrResponses, InferenceMetadata, InspectJobResponse, InspectRunningJobData, InspectRunningJobErrors, InspectRunningJobResponse, InspectRunningJobResponses, JsonObject, KillJobResponse, KillRunningJobData, KillRunningJobResponses, ListAppsData, ListAppsError, ListAppsErrors, ListAppsRequest, ListAppsResponse, ListAppsResponse2, ListAppsResponses, ListBuiltinChatTemplatesData, ListBuiltinChatTemplatesResponse, ListBuiltinChatTemplatesResponses, ListLocalModelsData, ListLocalModelsResponse, ListLocalModelsResponses, ListModelsData, ListModelsResponse, ListModelsResponses, ListProviderSecretsData, ListProviderSecretsErrors, ListProviderSecretsResponse, ListProviderSecretsResponses, ListRecipeResponse, ListRecipesData, ListRecipesErrors, ListRecipesResponse, ListRecipesResponses, ListSchedulesData, ListSchedulesErrors, ListSchedulesResponse, ListSchedulesResponse2, ListSchedulesResponses, LoadedProvider, LocalModelResponse, McpAppResource, McpUiProxyData, McpUiProxyErrors, McpUiProxyResponses, Message, MessageContent, MessageEvent, MessageMetadata, ModelCapabilities, ModelConfig, ModelDownloadStatus, ModelInfo, ModelInfoData, ModelInfoQuery, ModelInfoResponse, ModelSettings, ModelTemplate, ParseRecipeData, ParseRecipeError, ParseRecipeErrors, ParseRecipeRequest, ParseRecipeResponse, ParseRecipeResponse2, ParseRecipeResponses, PauseScheduleData, PauseScheduleErrors, PauseScheduleResponse, PauseScheduleResponses, Permission, PermissionLevel, PermissionsMetadata, PrincipalType, PromptContentResponse, PromptsListResponse, ProviderCatalogEntry, ProviderDetails, ProviderEngine, ProviderMetadata, ProviderModelInfoQuery, ProvidersData, ProviderSecret, ProviderSecretsResponse, ProviderSecretStatus, ProviderSecretStorage, ProvidersResponse, ProvidersResponse2, ProvidersResponses, ProviderTemplate, ProviderType, RawAudioContent, RawEmbeddedResource, RawImageContent, RawResource, RawTextContent, ReadAllConfigData, ReadAllConfigResponse, ReadAllConfigResponses, ReadConfigData, ReadConfigErrors, ReadConfigResponses, ReadResourceData, ReadResourceErrors, ReadResourceRequest, ReadResourceResponse, ReadResourceResponse2, ReadResourceResponses, Recipe, RecipeManifest, RecipeParameter, RecipeParameterInputType, RecipeParameterRequirement, RecipeToYamlData, RecipeToYamlError, RecipeToYamlErrors, RecipeToYamlRequest, RecipeToYamlResponse, RecipeToYamlResponse2, RecipeToYamlResponses, RedactedThinkingContent, RemoveConfigData, RemoveConfigErrors, RemoveConfigResponse, RemoveConfigResponses, RemoveCustomProviderData, RemoveCustomProviderErrors, RemoveCustomProviderResponse, RemoveCustomProviderResponses, RemoveExtensionData, RemoveExtensionErrors, RemoveExtensionRequest, RemoveExtensionResponse, RemoveExtensionResponses, ReplyData, ReplyErrors, ReplyResponse, ReplyResponses, RepoVariantsResponse, ResetPromptData, ResetPromptErrors, ResetPromptResponse, ResetPromptResponses, ResourceContents, ResourceMetadata, Response, RestartAgentData, RestartAgentErrors, RestartAgentRequest, RestartAgentResponse, RestartAgentResponse2, RestartAgentResponses, ResumeAgentData, ResumeAgentErrors, ResumeAgentRequest, ResumeAgentResponse, ResumeAgentResponse2, ResumeAgentResponses, RetryConfig, Role, RunNowHandlerData, RunNowHandlerErrors, RunNowHandlerResponse, RunNowHandlerResponses, RunNowResponse, SamplingConfig, SavePromptData, SavePromptErrors, SavePromptRequest, SavePromptResponse, SavePromptResponses, SaveRecipeData, SaveRecipeError, SaveRecipeErrors, SaveRecipeRequest, SaveRecipeResponse, SaveRecipeResponse2, SaveRecipeResponses, ScanRecipeData, ScanRecipeRequest, ScanRecipeResponse, ScanRecipeResponse2, ScanRecipeResponses, ScheduledJob, ScheduleRecipeData, ScheduleRecipeErrors, ScheduleRecipeRequest, ScheduleRecipeResponses, SearchHfModelsData, SearchHfModelsErrors, SearchHfModelsResponse, SearchHfModelsResponses, SendTelemetryEventData, SendTelemetryEventResponses, Session, SessionCancelData, SessionCancelResponses, SessionDisplayInfo, SessionEventsData, SessionEventsErrors, SessionEventsResponse, SessionEventsResponses, SessionExtensionsResponse, SessionReplyData, SessionReplyErrors, SessionReplyRequest, SessionReplyResponse, SessionReplyResponse2, SessionReplyResponses, SessionsHandlerData, SessionsHandlerErrors, SessionsHandlerResponse, SessionsHandlerResponses, SessionsQuery, SessionType, SetConfigProviderData, SetProviderRequest, SetRecipeSlashCommandData, SetRecipeSlashCommandErrors, SetRecipeSlashCommandResponses, SetSlashCommandRequest, Settings, SetupResponse, ShareSessionNostrData, ShareSessionNostrErrors, ShareSessionNostrRequest, ShareSessionNostrResponse, ShareSessionNostrResponse2, ShareSessionNostrResponses, SlashCommand, SlashCommandsResponse, StartAgentData, StartAgentError, StartAgentErrors, StartAgentRequest, StartAgentResponse, StartAgentResponses, StartNanogptSetupData, StartNanogptSetupResponse, StartNanogptSetupResponses, StartOpenrouterSetupData, StartOpenrouterSetupResponse, StartOpenrouterSetupResponses, StartTetrateSetupData, StartTetrateSetupResponse, StartTetrateSetupResponses, StartTunnelData, StartTunnelError, StartTunnelErrors, StartTunnelResponse, StartTunnelResponses, StatusData, StatusResponse, StatusResponses, StopAgentData, StopAgentErrors, StopAgentRequest, StopAgentResponse, StopAgentResponses, StopTunnelData, StopTunnelError, StopTunnelErrors, StopTunnelResponses, SubRecipe, SuccessCheck, SyncFeaturedModelsData, SyncFeaturedModelsResponses, SystemInfo, SystemInfoData, SystemInfoResponse, SystemInfoResponses, SystemNotificationContent, SystemNotificationType, TaskSupport, TelemetryEventRequest, Template, TextContent, ThinkingContent, ThinkingEffort, TokenState, Tool, ToolAnnotations, ToolCallingMode, ToolConfirmationRequest, ToolExecution, ToolInfo, ToolPermission, ToolRequest, ToolResponse, TranscribeDictationData, TranscribeDictationErrors, TranscribeDictationResponse, TranscribeDictationResponses, TranscribeRequest, TranscribeResponse, TunnelInfo, TunnelState, UiMetadata, UnpauseScheduleData, UnpauseScheduleErrors, UnpauseScheduleResponse, UnpauseScheduleResponses, UpdateAgentProviderData, UpdateAgentProviderErrors, UpdateAgentProviderResponses, UpdateCustomProviderData, UpdateCustomProviderErrors, UpdateCustomProviderRequest, UpdateCustomProviderResponse, UpdateCustomProviderResponses, UpdateFromSessionData, UpdateFromSessionErrors, UpdateFromSessionRequest, UpdateFromSessionResponses, UpdateModelSettingsData, UpdateModelSettingsErrors, UpdateModelSettingsResponse, UpdateModelSettingsResponses, UpdateProviderRequest, UpdateScheduleData, UpdateScheduleErrors, UpdateScheduleRequest, UpdateScheduleResponse, UpdateScheduleResponses, UpdateSessionData, UpdateSessionErrors, UpdateSessionNameData, UpdateSessionNameErrors, UpdateSessionNameRequest, UpdateSessionNameResponses, UpdateSessionRequest, UpdateSessionResponses, UpdateSessionUserRecipeValuesData, UpdateSessionUserRecipeValuesError, UpdateSessionUserRecipeValuesErrors, UpdateSessionUserRecipeValuesRequest, UpdateSessionUserRecipeValuesResponse, UpdateSessionUserRecipeValuesResponse2, UpdateSessionUserRecipeValuesResponses, UpdateWorkingDirData, UpdateWorkingDirErrors, UpdateWorkingDirRequest, UpdateWorkingDirResponses, UpsertConfigData, UpsertConfigErrors, UpsertConfigQuery, UpsertConfigResponse, UpsertConfigResponses, UpsertPermissionsData, UpsertPermissionsErrors, UpsertPermissionsQuery, UpsertPermissionsResponse, UpsertPermissionsResponses, Usage, ValidateConfigData, ValidateConfigErrors, ValidateConfigResponse, ValidateConfigResponses, WhisperModelResponse, WindowProps } from './types.gen'; +export type { ActionRequired, ActionRequiredData, AddExtensionData, AddExtensionErrors, AddExtensionRequest, AddExtensionResponse, AddExtensionResponses, AgentAddExtensionData, AgentAddExtensionErrors, AgentAddExtensionResponse, AgentAddExtensionResponses, AgentRemoveExtensionData, AgentRemoveExtensionErrors, AgentRemoveExtensionResponse, AgentRemoveExtensionResponses, Annotations, Author, CallToolData, CallToolError, CallToolErrors, CallToolRequest, CallToolResponse, CallToolResponse2, CallToolResponses, CancelDownloadData, CancelDownloadErrors, CancelDownloadResponses, CancelLocalModelDownloadData, CancelLocalModelDownloadErrors, CancelLocalModelDownloadResponses, CancelRequest, ChatRequest, ChatTemplate, CheckProviderData, CheckProviderRequest, CleanupProviderCacheData, CleanupProviderCacheErrors, CleanupProviderCacheResponse, CleanupProviderCacheResponses, ClientOptions, CommandType, ConfigKey, ConfigKeyQuery, ConfigResponse, ConfigureProviderOauthData, ConfigureProviderOauthErrors, ConfigureProviderOauthResponses, ConfirmToolActionData, ConfirmToolActionErrors, ConfirmToolActionRequest, ConfirmToolActionResponses, Content, ContentBlock, Conversation, CreateCustomProviderData, CreateCustomProviderErrors, CreateCustomProviderResponse, CreateCustomProviderResponse2, CreateCustomProviderResponses, CreateScheduleData, CreateScheduleErrors, CreateScheduleRequest, CreateScheduleResponse, CreateScheduleResponses, CspMetadata, DeclarativeProviderConfig, DecodeRecipeData, DecodeRecipeErrors, DecodeRecipeRequest, DecodeRecipeResponse, DecodeRecipeResponse2, DecodeRecipeResponses, DeleteLocalModelData, DeleteLocalModelErrors, DeleteLocalModelResponses, DeleteModelData, DeleteModelErrors, DeleteModelResponses, DeleteProviderSecretData, DeleteProviderSecretErrors, DeleteProviderSecretResponse, DeleteProviderSecretResponses, DeleteRecipeData, DeleteRecipeErrors, DeleteRecipeRequest, DeleteRecipeResponse, DeleteRecipeResponses, DeleteScheduleData, DeleteScheduleErrors, DeleteScheduleResponse, DeleteScheduleResponses, DiagnosticsConfig, DiagnosticsData, DiagnosticsError, DiagnosticsErrors, DiagnosticsExtensions, DiagnosticsLevel, DiagnosticsLogs, DiagnosticsPrompt, DiagnosticsReport, DiagnosticsResponse, DiagnosticsResponses, DiagnosticsScheduledRecipe, DiagnosticsTextFile, DictationProvider, DictationProviderStatus, DownloadHfModelData, DownloadHfModelErrors, DownloadHfModelResponse, DownloadHfModelResponses, DownloadModelData, DownloadModelErrors, DownloadModelRequest, DownloadModelResponses, DownloadProgress, DownloadStatus, EmbeddedResource, EncodeRecipeData, EncodeRecipeErrors, EncodeRecipeRequest, EncodeRecipeResponse, EncodeRecipeResponse2, EncodeRecipeResponses, Envs, EnvVarConfig, ErrorResponse, ExportAppData, ExportAppError, ExportAppErrors, ExportAppResponse, ExportAppResponses, ExtensionConfig, ExtensionData, ExtensionEntry, ExtensionLoadResult, ExtensionQuery, ExtensionResponse, FeaturesResponse, ForkRequest, ForkResponse, ForkSessionData, ForkSessionErrors, ForkSessionResponse, ForkSessionResponses, FrontendToolRequest, GetCanonicalModelInfoData, GetCanonicalModelInfoResponse, GetCanonicalModelInfoResponses, GetCustomProviderData, GetCustomProviderErrors, GetCustomProviderResponse, GetCustomProviderResponses, GetDictationConfigData, GetDictationConfigResponse, GetDictationConfigResponses, GetDownloadProgressData, GetDownloadProgressErrors, GetDownloadProgressResponse, GetDownloadProgressResponses, GetExtensionsData, GetExtensionsErrors, GetExtensionsResponse, GetExtensionsResponses, GetFeaturesData, GetFeaturesResponse, GetFeaturesResponses, GetLocalModelDownloadProgressData, GetLocalModelDownloadProgressErrors, GetLocalModelDownloadProgressResponse, GetLocalModelDownloadProgressResponses, GetModelSettingsData, GetModelSettingsErrors, GetModelSettingsResponse, GetModelSettingsResponses, GetPromptData, GetPromptErrors, GetPromptResponse, GetPromptResponses, GetPromptsData, GetPromptsResponse, GetPromptsResponses, GetProviderCatalogData, GetProviderCatalogErrors, GetProviderCatalogResponse, GetProviderCatalogResponses, GetProviderCatalogTemplateData, GetProviderCatalogTemplateErrors, GetProviderCatalogTemplateResponse, GetProviderCatalogTemplateResponses, GetProviderModelInfoData, GetProviderModelInfoErrors, GetProviderModelInfoResponse, GetProviderModelInfoResponses, GetProviderModelsData, GetProviderModelsErrors, GetProviderModelsResponse, GetProviderModelsResponses, GetRepoFilesData, GetRepoFilesResponse, GetRepoFilesResponses, GetSessionData, GetSessionErrors, GetSessionExtensionsData, GetSessionExtensionsErrors, GetSessionExtensionsResponse, GetSessionExtensionsResponses, GetSessionResponse, GetSessionResponses, GetSlashCommandsData, GetSlashCommandsResponse, GetSlashCommandsResponses, GetToolsData, GetToolsErrors, GetToolsQuery, GetToolsResponse, GetToolsResponses, GetTunnelStatusData, GetTunnelStatusResponse, GetTunnelStatusResponses, GooseApp, GooseMode, HfGgufFile, HfModelInfo, HfModelVariant, HfQuantVariant, Icon, IconTheme, ImageContent, ImportAppData, ImportAppError, ImportAppErrors, ImportAppRequest, ImportAppResponse, ImportAppResponse2, ImportAppResponses, ImportSessionNostrData, ImportSessionNostrErrors, ImportSessionNostrRequest, ImportSessionNostrResponse, ImportSessionNostrResponses, InferenceMetadata, InspectJobResponse, InspectRunningJobData, InspectRunningJobErrors, InspectRunningJobResponse, InspectRunningJobResponses, JsonObject, KillJobResponse, KillRunningJobData, KillRunningJobResponses, ListAppsData, ListAppsError, ListAppsErrors, ListAppsRequest, ListAppsResponse, ListAppsResponse2, ListAppsResponses, ListBuiltinChatTemplatesData, ListBuiltinChatTemplatesResponse, ListBuiltinChatTemplatesResponses, ListLocalModelsData, ListLocalModelsResponse, ListLocalModelsResponses, ListModelsData, ListModelsResponse, ListModelsResponses, ListProviderSecretsData, ListProviderSecretsErrors, ListProviderSecretsResponse, ListProviderSecretsResponses, ListRecipeResponse, ListRecipesData, ListRecipesErrors, ListRecipesResponse, ListRecipesResponses, ListSchedulesData, ListSchedulesErrors, ListSchedulesResponse, ListSchedulesResponse2, ListSchedulesResponses, LoadedProvider, LocalModelResponse, McpAppResource, McpUiProxyData, McpUiProxyErrors, McpUiProxyResponses, Message, MessageContent, MessageEvent, MessageMetadata, ModelCapabilities, ModelConfig, ModelDownloadStatus, ModelInfo, ModelInfoData, ModelInfoQuery, ModelInfoResponse, ModelSettings, ModelTemplate, ParseRecipeData, ParseRecipeError, ParseRecipeErrors, ParseRecipeRequest, ParseRecipeResponse, ParseRecipeResponse2, ParseRecipeResponses, PauseScheduleData, PauseScheduleErrors, PauseScheduleResponse, PauseScheduleResponses, Permission, PermissionLevel, PermissionsMetadata, PrincipalType, PromptContentResponse, PromptsListResponse, ProviderCatalogEntry, ProviderDetails, ProviderEngine, ProviderMetadata, ProviderModelInfoQuery, ProvidersData, ProviderSecret, ProviderSecretsResponse, ProviderSecretStatus, ProviderSecretStorage, ProvidersResponse, ProvidersResponse2, ProvidersResponses, ProviderTemplate, ProviderType, RawAudioContent, RawEmbeddedResource, RawImageContent, RawResource, RawTextContent, ReadAllConfigData, ReadAllConfigResponse, ReadAllConfigResponses, ReadConfigData, ReadConfigErrors, ReadConfigResponses, ReadResourceData, ReadResourceErrors, ReadResourceRequest, ReadResourceResponse, ReadResourceResponse2, ReadResourceResponses, Recipe, RecipeManifest, RecipeParameter, RecipeParameterInputType, RecipeParameterRequirement, RecipeToYamlData, RecipeToYamlError, RecipeToYamlErrors, RecipeToYamlRequest, RecipeToYamlResponse, RecipeToYamlResponse2, RecipeToYamlResponses, RedactedThinkingContent, RemoveConfigData, RemoveConfigErrors, RemoveConfigResponse, RemoveConfigResponses, RemoveCustomProviderData, RemoveCustomProviderErrors, RemoveCustomProviderResponse, RemoveCustomProviderResponses, RemoveExtensionData, RemoveExtensionErrors, RemoveExtensionRequest, RemoveExtensionResponse, RemoveExtensionResponses, ReplyData, ReplyErrors, ReplyResponse, ReplyResponses, RepoVariantsResponse, ResetPromptData, ResetPromptErrors, ResetPromptResponse, ResetPromptResponses, ResourceContents, ResourceMetadata, Response, RestartAgentData, RestartAgentErrors, RestartAgentRequest, RestartAgentResponse, RestartAgentResponse2, RestartAgentResponses, ResumeAgentData, ResumeAgentErrors, ResumeAgentRequest, ResumeAgentResponse, ResumeAgentResponse2, ResumeAgentResponses, RetryConfig, Role, RunNowHandlerData, RunNowHandlerErrors, RunNowHandlerResponse, RunNowHandlerResponses, RunNowResponse, SamplingConfig, SavePromptData, SavePromptErrors, SavePromptRequest, SavePromptResponse, SavePromptResponses, SaveRecipeData, SaveRecipeError, SaveRecipeErrors, SaveRecipeRequest, SaveRecipeResponse, SaveRecipeResponse2, SaveRecipeResponses, ScanRecipeData, ScanRecipeRequest, ScanRecipeResponse, ScanRecipeResponse2, ScanRecipeResponses, ScheduledJob, ScheduleRecipeData, ScheduleRecipeErrors, ScheduleRecipeRequest, ScheduleRecipeResponses, SearchHfModelsData, SearchHfModelsErrors, SearchHfModelsResponse, SearchHfModelsResponses, SendTelemetryEventData, SendTelemetryEventResponses, Session, SessionCancelData, SessionCancelResponses, SessionDisplayInfo, SessionEventsData, SessionEventsErrors, SessionEventsResponse, SessionEventsResponses, SessionExtensionsResponse, SessionReplyData, SessionReplyErrors, SessionReplyRequest, SessionReplyResponse, SessionReplyResponse2, SessionReplyResponses, SessionsHandlerData, SessionsHandlerErrors, SessionsHandlerResponse, SessionsHandlerResponses, SessionsQuery, SessionType, SetConfigProviderData, SetProviderRequest, SetRecipeSlashCommandData, SetRecipeSlashCommandErrors, SetRecipeSlashCommandResponses, SetSlashCommandRequest, Settings, SetupResponse, ShareSessionNostrData, ShareSessionNostrErrors, ShareSessionNostrRequest, ShareSessionNostrResponse, ShareSessionNostrResponse2, ShareSessionNostrResponses, SlashCommand, SlashCommandsResponse, StartAgentData, StartAgentError, StartAgentErrors, StartAgentRequest, StartAgentResponse, StartAgentResponses, StartNanogptSetupData, StartNanogptSetupResponse, StartNanogptSetupResponses, StartOpenrouterSetupData, StartOpenrouterSetupResponse, StartOpenrouterSetupResponses, StartTetrateSetupData, StartTetrateSetupResponse, StartTetrateSetupResponses, StartTunnelData, StartTunnelError, StartTunnelErrors, StartTunnelResponse, StartTunnelResponses, StatusData, StatusResponse, StatusResponses, StopAgentData, StopAgentErrors, StopAgentRequest, StopAgentResponse, StopAgentResponses, StopTunnelData, StopTunnelError, StopTunnelErrors, StopTunnelResponses, SubRecipe, SuccessCheck, SyncFeaturedModelsData, SyncFeaturedModelsResponses, SystemInfo, SystemInfoData, SystemInfoResponse, SystemInfoResponses, SystemNotificationContent, SystemNotificationType, TaskSupport, TelemetryEventRequest, Template, TextContent, ThinkingContent, ThinkingEffort, TokenState, Tool, ToolAnnotations, ToolCallingMode, ToolConfirmationRequest, ToolExecution, ToolInfo, ToolPermission, ToolRequest, ToolResponse, TranscribeDictationData, TranscribeDictationErrors, TranscribeDictationResponse, TranscribeDictationResponses, TranscribeRequest, TranscribeResponse, TunnelInfo, TunnelState, UiMetadata, UnpauseScheduleData, UnpauseScheduleErrors, UnpauseScheduleResponse, UnpauseScheduleResponses, UpdateAgentProviderData, UpdateAgentProviderErrors, UpdateAgentProviderResponses, UpdateCustomProviderData, UpdateCustomProviderErrors, UpdateCustomProviderRequest, UpdateCustomProviderResponse, UpdateCustomProviderResponses, UpdateFromSessionData, UpdateFromSessionErrors, UpdateFromSessionRequest, UpdateFromSessionResponses, UpdateModelSettingsData, UpdateModelSettingsErrors, UpdateModelSettingsResponse, UpdateModelSettingsResponses, UpdateProviderRequest, UpdateScheduleData, UpdateScheduleErrors, UpdateScheduleRequest, UpdateScheduleResponse, UpdateScheduleResponses, UpdateSessionData, UpdateSessionErrors, UpdateSessionNameData, UpdateSessionNameErrors, UpdateSessionNameRequest, UpdateSessionNameResponses, UpdateSessionRequest, UpdateSessionResponses, UpdateSessionUserRecipeValuesData, UpdateSessionUserRecipeValuesError, UpdateSessionUserRecipeValuesErrors, UpdateSessionUserRecipeValuesRequest, UpdateSessionUserRecipeValuesResponse, UpdateSessionUserRecipeValuesResponse2, UpdateSessionUserRecipeValuesResponses, UpdateWorkingDirData, UpdateWorkingDirErrors, UpdateWorkingDirRequest, UpdateWorkingDirResponses, UpsertConfigData, UpsertConfigErrors, UpsertConfigQuery, UpsertConfigResponse, UpsertConfigResponses, UpsertPermissionsData, UpsertPermissionsErrors, UpsertPermissionsQuery, UpsertPermissionsResponse, UpsertPermissionsResponses, Usage, ValidateConfigData, ValidateConfigErrors, ValidateConfigResponse, ValidateConfigResponses, WhisperModelResponse, WindowProps } from './types.gen'; diff --git a/ui/desktop/src/api/types.gen.ts b/ui/desktop/src/api/types.gen.ts index 26cb604a75..e71a21fa67 100644 --- a/ui/desktop/src/api/types.gen.ts +++ b/ui/desktop/src/api/types.gen.ts @@ -247,6 +247,59 @@ export type DeleteRecipeRequest = { id: string; }; +export type DiagnosticsConfig = { + configPath: string; + configYaml?: string | null; + truncated: boolean; +}; + +export type DiagnosticsError = { + message: string; + path?: string | null; +}; + +export type DiagnosticsExtensions = { + enabled: Array; +}; + +export type DiagnosticsLevel = 'summary' | 'full'; + +export type DiagnosticsLogs = { + llm: Array; + server?: DiagnosticsTextFile | null; +}; + +export type DiagnosticsPrompt = { + content: string; + name: string; +}; + +export type DiagnosticsReport = { + config?: DiagnosticsConfig | null; + errors: Array; + extensions: DiagnosticsExtensions; + generatedAt: string; + level: DiagnosticsLevel; + logs: DiagnosticsLogs; + prompts: Array; + schedule?: unknown; + scheduledRecipes: Array; + schemaVersion: number; + session?: unknown; + system: SystemInfo; +}; + +export type DiagnosticsScheduledRecipe = { + content: string; + path: string; +}; + +export type DiagnosticsTextFile = { + content: string; + path: string; + truncated: boolean; +}; + export type DictationProvider = 'openai' | 'elevenlabs' | 'groq' | 'local'; export type DictationProviderStatus = { @@ -3093,7 +3146,9 @@ export type DiagnosticsData = { path: { session_id: string; }; - query?: never; + query?: { + level?: DiagnosticsLevel | null; + }; url: '/diagnostics/{session_id}'; }; @@ -3106,9 +3161,9 @@ export type DiagnosticsErrors = { export type DiagnosticsResponses = { /** - * Diagnostics zip file + * Diagnostics report */ - 200: Blob | File; + 200: DiagnosticsReport; }; export type DiagnosticsResponse = DiagnosticsResponses[keyof DiagnosticsResponses]; diff --git a/ui/desktop/src/components/ui/Diagnostics.tsx b/ui/desktop/src/components/ui/Diagnostics.tsx index 67f8b078f0..c76cc9f763 100644 --- a/ui/desktop/src/components/ui/Diagnostics.tsx +++ b/ui/desktop/src/components/ui/Diagnostics.tsx @@ -2,8 +2,8 @@ import React, { useState } from 'react'; import { AlertTriangle, Download, Github } from 'lucide-react'; import { Button } from './button'; import { toastError } from '../../toasts'; -import { diagnostics, systemInfo } from '../../api'; import { defineMessages, useIntl } from '../../i18n'; +import { getDiagnosticsReport } from '../../acp/diagnostics'; const i18n = defineMessages({ reportProblem: { @@ -13,7 +13,7 @@ const i18n = defineMessages({ description: { id: 'diagnosticsModal.description', defaultMessage: - 'You can download a diagnostics zip file to share with the team, or file a bug directly on GitHub with your system details pre-filled. A diagnostics report contains the following:', + 'You can download a diagnostics JSON report to share with the team, or file a bug directly on GitHub with your system details pre-filled. A diagnostics report contains the following:', }, systemInfo: { id: 'diagnosticsModal.systemInfo', @@ -66,7 +66,7 @@ const i18n = defineMessages({ }, diagnosticsErrorMsg: { id: 'diagnosticsModal.diagnosticsErrorMsg', - defaultMessage: 'Failed to download diagnostics', + defaultMessage: 'Failed to download diagnostics report', }, systemInfoErrorTitle: { id: 'diagnosticsModal.systemInfoErrorTitle', @@ -97,16 +97,14 @@ export const DiagnosticsModal: React.FC = ({ setIsDownloading(true); try { - const response = await diagnostics({ - path: { session_id: sessionId }, - throwOnError: true, + const report = await getDiagnosticsReport(sessionId, 'full'); + const blob = new Blob([`${JSON.stringify(report, null, 2)}\n`], { + type: 'application/json', }); - - const blob = new Blob([response.data], { type: 'application/zip' }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; - a.download = `diagnostics_${sessionId}.zip`; + a.download = `diagnostics_${sessionId}.json`; document.body.appendChild(a); a.click(); document.body.removeChild(a); @@ -127,12 +125,12 @@ export const DiagnosticsModal: React.FC = ({ setIsFilingBug(true); try { - const response = await systemInfo({ throwOnError: true }); - const info = response.data; + const report = await getDiagnosticsReport(sessionId, 'summary'); + const info = report.system; const providerModel = info.provider && info.model - ? `${info.provider} – ${info.model}` + ? `${info.provider} - ${info.model}` : info.provider || info.model || '[e.g. Google – gemini-1.5-pro]'; const extensions = @@ -145,7 +143,7 @@ export const DiagnosticsModal: React.FC = ({ 💡 Before filing, please check common issues: https://goose-docs.ai/docs/troubleshooting -📦 To help us debug faster, attach your **diagnostics zip** if possible. +📦 To help us debug faster, attach your **diagnostics JSON report** if possible. 👉 How to capture it: https://goose-docs.ai/docs/troubleshooting/diagnostics-and-reporting/ A clear and concise description of what the bug is. diff --git a/ui/desktop/src/i18n/messages/en.json b/ui/desktop/src/i18n/messages/en.json index fb45d5fd90..281a6bb932 100644 --- a/ui/desktop/src/i18n/messages/en.json +++ b/ui/desktop/src/i18n/messages/en.json @@ -804,10 +804,10 @@ "defaultMessage": "Configuration settings" }, "diagnosticsModal.description": { - "defaultMessage": "You can download a diagnostics zip file to share with the team, or file a bug directly on GitHub with your system details pre-filled. A diagnostics report contains the following:" + "defaultMessage": "You can download a diagnostics JSON report to share with the team, or file a bug directly on GitHub with your system details pre-filled. A diagnostics report contains the following:" }, "diagnosticsModal.diagnosticsErrorMsg": { - "defaultMessage": "Failed to download diagnostics" + "defaultMessage": "Failed to download diagnostics report" }, "diagnosticsModal.diagnosticsErrorTitle": { "defaultMessage": "Diagnostics Error" diff --git a/ui/sdk/src/generated/client.gen.ts b/ui/sdk/src/generated/client.gen.ts index 7588717d4c..fa13ca5e8a 100644 --- a/ui/sdk/src/generated/client.gen.ts +++ b/ui/sdk/src/generated/client.gen.ts @@ -30,6 +30,8 @@ import type { DeleteRecipeRequest_unstable, DeleteSessionRequest, DeleteSourceRequest_unstable, + DiagnosticsGetRequest_unstable, + DiagnosticsGetResponse_unstable, DictationConfigRequest_unstable, DictationConfigResponse_unstable, DictationModelCancelRequest_unstable, @@ -135,6 +137,7 @@ import { zCustomProviderUpdateResponse_unstable, zDecodeRecipeResponse_unstable, zDefaultsReadResponse_unstable, + zDiagnosticsGetResponse_unstable, zDictationConfigResponse_unstable, zDictationModelDownloadProgressResponse_unstable, zDictationModelsListResponse_unstable, @@ -251,6 +254,18 @@ export class GooseExtClient { ) as SteerSessionResponse_unstable; } + async diagnosticsGet_unstable( + params: DiagnosticsGetRequest_unstable, + ): Promise { + const raw = await this.conn.extMethod( + "_goose/unstable/diagnostics/get", + params, + ); + return zDiagnosticsGetResponse_unstable.parse( + raw, + ) as DiagnosticsGetResponse_unstable; + } + async sessionDelete(params: DeleteSessionRequest): Promise { await this.conn.extMethod("session/delete", params); } diff --git a/ui/sdk/src/generated/index.ts b/ui/sdk/src/generated/index.ts index 543ba4e95d..fc97f03765 100644 --- a/ui/sdk/src/generated/index.ts +++ b/ui/sdk/src/generated/index.ts @@ -1,6 +1,6 @@ // This file is auto-generated by @hey-api/openapi-ts -export type { AddConfigExtensionRequest_unstable, AddSessionExtensionRequest_unstable, Annotations, ArchiveSessionRequest_unstable, AudioContent, BlobResourceContents, ContentBlock, CreateSourceRequest_unstable, CreateSourceResponse_unstable, CustomProviderConfigDto, CustomProviderCreateRequest_unstable, CustomProviderCreateResponse_unstable, CustomProviderDeleteRequest_unstable, CustomProviderDeleteResponse_unstable, CustomProviderReadRequest_unstable, CustomProviderReadResponse_unstable, CustomProviderUpdateRequest_unstable, CustomProviderUpdateResponse_unstable, DecodeRecipeRequest_unstable, DecodeRecipeResponse_unstable, DefaultsReadRequest_unstable, DefaultsReadResponse_unstable, DefaultsSaveRequest_unstable, DeleteRecipeRequest_unstable, DeleteSessionRequest, DeleteSourceRequest_unstable, DictationConfigRequest_unstable, DictationConfigResponse_unstable, DictationDownloadProgress, DictationLocalModelStatus, DictationModelCancelRequest_unstable, DictationModelDeleteRequest_unstable, DictationModelDownloadProgressRequest_unstable, DictationModelDownloadProgressResponse_unstable, DictationModelDownloadRequest_unstable, DictationModelOption, DictationModelSelectRequest_unstable, DictationModelsListRequest_unstable, DictationModelsListResponse_unstable, DictationProviderStatusEntry, DictationSecretDeleteRequest_unstable, DictationSecretSaveRequest_unstable, DictationTranscribeRequest_unstable, DictationTranscribeResponse_unstable, EmbeddedResource, EmbeddedResourceResource, EmptyResponse, EncodeRecipeRequest_unstable, EncodeRecipeResponse_unstable, EnvVariable, ExportSessionRequest_unstable, ExportSessionResponse_unstable, ExportSourceRequest_unstable, ExportSourceResponse_unstable, ExtAgentRequest, ExtAgentResponse, ExtNotification, ExtRequest, ExtResponse, GetAvailableExtensionsRequest_unstable, GetAvailableExtensionsResponse_unstable, GetConfigExtensionsRequest_unstable, GetConfigExtensionsResponse_unstable, GetSessionExtensionsRequest_unstable, GetSessionExtensionsResponse_unstable, GetSessionInfoRequest_unstable, GetSessionInfoResponse_unstable, GetToolsRequest_unstable, GetToolsResponse_unstable, GooseExtension, GooseExtensionEntry, GooseSessionNotification_unstable, GooseSessionUpdate, GooseToolCallRequest_unstable, GooseToolCallResponse_unstable, HttpHeader, ImageContent, ImportSessionRequest_unstable, ImportSessionResponse_unstable, ImportSourcesRequest_unstable, ImportSourcesResponse_unstable, ListProvidersRequest_unstable, ListProvidersResponse_unstable, ListRecipesRequest_unstable, ListRecipesResponse_unstable, ListSourcesRequest_unstable, ListSourcesResponse_unstable, McpServer, McpServerHttp, McpServerSse, McpServerStdio, OnboardingImportApplyRequest_unstable, OnboardingImportApplyResponse_unstable, OnboardingImportCandidate, OnboardingImportCounts, OnboardingImportScanRequest_unstable, OnboardingImportScanResponse_unstable, OnboardingImportSourceKind, ParseRecipeRequest_unstable, ParseRecipeResponse_unstable, PreferenceKey, PreferencesReadRequest_unstable, PreferencesReadResponse_unstable, PreferencesRemoveRequest_unstable, PreferencesSaveRequest_unstable, PreferenceValue, ProviderCatalogListRequest_unstable, ProviderCatalogListResponse_unstable, ProviderCatalogTemplateRequest_unstable, ProviderCatalogTemplateResponse_unstable, ProviderConfigAuthenticateRequest_unstable, ProviderConfigChangeResponse_unstable, ProviderConfigDeleteRequest_unstable, ProviderConfigFieldUpdate, ProviderConfigFieldValueDto, ProviderConfigKey, ProviderConfigReadRequest_unstable, ProviderConfigReadResponse_unstable, ProviderConfigSaveRequest_unstable, ProviderConfigStatusDto, ProviderConfigStatusRequest_unstable, ProviderConfigStatusResponse_unstable, ProviderInventoryEntryDto, ProviderInventoryModelDto, ProviderSetupCatalogEntryDto, ProviderSetupCatalogListRequest_unstable, ProviderSetupCatalogListResponse_unstable, ProviderSetupCategoryDto, ProviderSetupFieldDto, ProviderSetupGroupDto, ProviderSetupMethodDto, ProviderSupportedModelsListRequest_unstable, ProviderSupportedModelsListResponse_unstable, ProviderTemplateCapabilitiesDto, ProviderTemplateCatalogEntryDto, ProviderTemplateDto, ProviderTemplateModelDto, ReadResourceRequest_unstable, ReadResourceResponse_unstable, RecipeAuthorDto, RecipeDto, RecipeExtensionDto, RecipeListEntryDto, RecipeParameterDto, RecipeParameterInputTypeDto, RecipeParameterRequirementDto, RecipeParamsAction, RecipeParamsResponse_unstable, RecipeResponseDto, RecipeRetryConfigDto, RecipeSettingsDto, RecipeSuccessCheckDto, RecipeToYamlRequest_unstable, RecipeToYamlResponse_unstable, RefreshProviderInventoryRequest_unstable, RefreshProviderInventoryResponse_unstable, RefreshProviderInventorySkipDto, RefreshProviderInventorySkipReasonDto, RemoveConfigExtensionRequest_unstable, RemoveSessionExtensionRequest_unstable, RenameSessionRequest_unstable, RequestRecipeParams_unstable, ResourceLink, Role, SaveRecipeRequest_unstable, SaveRecipeResponse_unstable, ScanRecipeRequest_unstable, ScanRecipeResponse_unstable, ScheduleRecipeRequest_unstable, SessionId, SessionInfo, SessionSystemPromptMode, SessionUsageUpdate, SetConfigExtensionEnabledRequest_unstable, SetRecipeSlashCommandRequest_unstable, SetSessionSystemPromptRequest_unstable, SourceEntry, SourceScope, SourceType, StatusMessage, StatusMessageUpdate, SteerSessionRequest_unstable, SteerSessionResponse_unstable, SubRecipeDto, TextContent, TextResourceContents, TruncateSessionConversationRequest_unstable, UnarchiveSessionRequest_unstable, UpdateSessionProjectRequest_unstable, UpdateSourceRequest_unstable, UpdateSourceResponse_unstable, UpdateWorkingDirRequest_unstable } from './types.gen.js'; +export type { AddConfigExtensionRequest_unstable, AddSessionExtensionRequest_unstable, Annotations, ArchiveSessionRequest_unstable, AudioContent, BlobResourceContents, ContentBlock, CreateSourceRequest_unstable, CreateSourceResponse_unstable, CustomProviderConfigDto, CustomProviderCreateRequest_unstable, CustomProviderCreateResponse_unstable, CustomProviderDeleteRequest_unstable, CustomProviderDeleteResponse_unstable, CustomProviderReadRequest_unstable, CustomProviderReadResponse_unstable, CustomProviderUpdateRequest_unstable, CustomProviderUpdateResponse_unstable, DecodeRecipeRequest_unstable, DecodeRecipeResponse_unstable, DefaultsReadRequest_unstable, DefaultsReadResponse_unstable, DefaultsSaveRequest_unstable, DeleteRecipeRequest_unstable, DeleteSessionRequest, DeleteSourceRequest_unstable, DiagnosticsGetRequest_unstable, DiagnosticsGetResponse_unstable, DiagnosticsReportLevel, DictationConfigRequest_unstable, DictationConfigResponse_unstable, DictationDownloadProgress, DictationLocalModelStatus, DictationModelCancelRequest_unstable, DictationModelDeleteRequest_unstable, DictationModelDownloadProgressRequest_unstable, DictationModelDownloadProgressResponse_unstable, DictationModelDownloadRequest_unstable, DictationModelOption, DictationModelSelectRequest_unstable, DictationModelsListRequest_unstable, DictationModelsListResponse_unstable, DictationProviderStatusEntry, DictationSecretDeleteRequest_unstable, DictationSecretSaveRequest_unstable, DictationTranscribeRequest_unstable, DictationTranscribeResponse_unstable, EmbeddedResource, EmbeddedResourceResource, EmptyResponse, EncodeRecipeRequest_unstable, EncodeRecipeResponse_unstable, EnvVariable, ExportSessionRequest_unstable, ExportSessionResponse_unstable, ExportSourceRequest_unstable, ExportSourceResponse_unstable, ExtAgentRequest, ExtAgentResponse, ExtNotification, ExtRequest, ExtResponse, GetAvailableExtensionsRequest_unstable, GetAvailableExtensionsResponse_unstable, GetConfigExtensionsRequest_unstable, GetConfigExtensionsResponse_unstable, GetSessionExtensionsRequest_unstable, GetSessionExtensionsResponse_unstable, GetSessionInfoRequest_unstable, GetSessionInfoResponse_unstable, GetToolsRequest_unstable, GetToolsResponse_unstable, GooseExtension, GooseExtensionEntry, GooseSessionNotification_unstable, GooseSessionUpdate, GooseToolCallRequest_unstable, GooseToolCallResponse_unstable, HttpHeader, ImageContent, ImportSessionRequest_unstable, ImportSessionResponse_unstable, ImportSourcesRequest_unstable, ImportSourcesResponse_unstable, ListProvidersRequest_unstable, ListProvidersResponse_unstable, ListRecipesRequest_unstable, ListRecipesResponse_unstable, ListSourcesRequest_unstable, ListSourcesResponse_unstable, McpServer, McpServerHttp, McpServerSse, McpServerStdio, OnboardingImportApplyRequest_unstable, OnboardingImportApplyResponse_unstable, OnboardingImportCandidate, OnboardingImportCounts, OnboardingImportScanRequest_unstable, OnboardingImportScanResponse_unstable, OnboardingImportSourceKind, ParseRecipeRequest_unstable, ParseRecipeResponse_unstable, PreferenceKey, PreferencesReadRequest_unstable, PreferencesReadResponse_unstable, PreferencesRemoveRequest_unstable, PreferencesSaveRequest_unstable, PreferenceValue, ProviderCatalogListRequest_unstable, ProviderCatalogListResponse_unstable, ProviderCatalogTemplateRequest_unstable, ProviderCatalogTemplateResponse_unstable, ProviderConfigAuthenticateRequest_unstable, ProviderConfigChangeResponse_unstable, ProviderConfigDeleteRequest_unstable, ProviderConfigFieldUpdate, ProviderConfigFieldValueDto, ProviderConfigKey, ProviderConfigReadRequest_unstable, ProviderConfigReadResponse_unstable, ProviderConfigSaveRequest_unstable, ProviderConfigStatusDto, ProviderConfigStatusRequest_unstable, ProviderConfigStatusResponse_unstable, ProviderInventoryEntryDto, ProviderInventoryModelDto, ProviderSetupCatalogEntryDto, ProviderSetupCatalogListRequest_unstable, ProviderSetupCatalogListResponse_unstable, ProviderSetupCategoryDto, ProviderSetupFieldDto, ProviderSetupGroupDto, ProviderSetupMethodDto, ProviderSupportedModelsListRequest_unstable, ProviderSupportedModelsListResponse_unstable, ProviderTemplateCapabilitiesDto, ProviderTemplateCatalogEntryDto, ProviderTemplateDto, ProviderTemplateModelDto, ReadResourceRequest_unstable, ReadResourceResponse_unstable, RecipeAuthorDto, RecipeDto, RecipeExtensionDto, RecipeListEntryDto, RecipeParameterDto, RecipeParameterInputTypeDto, RecipeParameterRequirementDto, RecipeParamsAction, RecipeParamsResponse_unstable, RecipeResponseDto, RecipeRetryConfigDto, RecipeSettingsDto, RecipeSuccessCheckDto, RecipeToYamlRequest_unstable, RecipeToYamlResponse_unstable, RefreshProviderInventoryRequest_unstable, RefreshProviderInventoryResponse_unstable, RefreshProviderInventorySkipDto, RefreshProviderInventorySkipReasonDto, RemoveConfigExtensionRequest_unstable, RemoveSessionExtensionRequest_unstable, RenameSessionRequest_unstable, RequestRecipeParams_unstable, ResourceLink, Role, SaveRecipeRequest_unstable, SaveRecipeResponse_unstable, ScanRecipeRequest_unstable, ScanRecipeResponse_unstable, ScheduleRecipeRequest_unstable, SessionId, SessionInfo, SessionSystemPromptMode, SessionUsageUpdate, SetConfigExtensionEnabledRequest_unstable, SetRecipeSlashCommandRequest_unstable, SetSessionSystemPromptRequest_unstable, SourceEntry, SourceScope, SourceType, StatusMessage, StatusMessageUpdate, SteerSessionRequest_unstable, SteerSessionResponse_unstable, SubRecipeDto, TextContent, TextResourceContents, TruncateSessionConversationRequest_unstable, UnarchiveSessionRequest_unstable, UpdateSessionProjectRequest_unstable, UpdateSourceRequest_unstable, UpdateSourceResponse_unstable, UpdateWorkingDirRequest_unstable } from './types.gen.js'; export const GOOSE_EXT_METHODS = [ { @@ -43,6 +43,11 @@ export const GOOSE_EXT_METHODS = [ requestType: "SteerSessionRequest_unstable", responseType: "SteerSessionResponse_unstable", }, + { + method: "_goose/unstable/diagnostics/get", + requestType: "DiagnosticsGetRequest_unstable", + responseType: "DiagnosticsGetResponse_unstable", + }, { method: "session/delete", requestType: "DeleteSessionRequest", diff --git a/ui/sdk/src/generated/types.gen.ts b/ui/sdk/src/generated/types.gen.ts index 555289163e..8c89ddc376 100644 --- a/ui/sdk/src/generated/types.gen.ts +++ b/ui/sdk/src/generated/types.gen.ts @@ -489,6 +489,20 @@ export type SteerSessionResponse_unstable = { messageId: string; }; +/** + * Generate a diagnostics report for a session. + */ +export type DiagnosticsGetRequest_unstable = { + sessionId: string; + level?: DiagnosticsReportLevel; +}; + +export type DiagnosticsReportLevel = 'summary' | 'full'; + +export type DiagnosticsGetResponse_unstable = { + report: unknown; +}; + /** * Delete a session. */ @@ -1806,14 +1820,14 @@ export type RecipeParamsAction = 'submit' | 'cancel'; export type ExtRequest = { id: string; method: string; - params?: AddSessionExtensionRequest_unstable | RemoveSessionExtensionRequest_unstable | GetToolsRequest_unstable | GooseToolCallRequest_unstable | ReadResourceRequest_unstable | UpdateWorkingDirRequest_unstable | SetSessionSystemPromptRequest_unstable | SteerSessionRequest_unstable | DeleteSessionRequest | GetConfigExtensionsRequest_unstable | GetAvailableExtensionsRequest_unstable | AddConfigExtensionRequest_unstable | RemoveConfigExtensionRequest_unstable | SetConfigExtensionEnabledRequest_unstable | GetSessionExtensionsRequest_unstable | ListProvidersRequest_unstable | ProviderSupportedModelsListRequest_unstable | ProviderCatalogListRequest_unstable | ProviderSetupCatalogListRequest_unstable | ProviderCatalogTemplateRequest_unstable | CustomProviderCreateRequest_unstable | CustomProviderReadRequest_unstable | CustomProviderUpdateRequest_unstable | CustomProviderDeleteRequest_unstable | RefreshProviderInventoryRequest_unstable | ProviderConfigReadRequest_unstable | ProviderConfigStatusRequest_unstable | ProviderConfigSaveRequest_unstable | ProviderConfigDeleteRequest_unstable | ProviderConfigAuthenticateRequest_unstable | PreferencesReadRequest_unstable | PreferencesSaveRequest_unstable | PreferencesRemoveRequest_unstable | DefaultsReadRequest_unstable | DefaultsSaveRequest_unstable | OnboardingImportScanRequest_unstable | OnboardingImportApplyRequest_unstable | ExportSessionRequest_unstable | ImportSessionRequest_unstable | EncodeRecipeRequest_unstable | DecodeRecipeRequest_unstable | ScanRecipeRequest_unstable | ListRecipesRequest_unstable | DeleteRecipeRequest_unstable | ScheduleRecipeRequest_unstable | SetRecipeSlashCommandRequest_unstable | SaveRecipeRequest_unstable | ParseRecipeRequest_unstable | RecipeToYamlRequest_unstable | GetSessionInfoRequest_unstable | TruncateSessionConversationRequest_unstable | UpdateSessionProjectRequest_unstable | RenameSessionRequest_unstable | ArchiveSessionRequest_unstable | UnarchiveSessionRequest_unstable | CreateSourceRequest_unstable | ListSourcesRequest_unstable | UpdateSourceRequest_unstable | DeleteSourceRequest_unstable | ExportSourceRequest_unstable | ImportSourcesRequest_unstable | DictationTranscribeRequest_unstable | DictationConfigRequest_unstable | DictationSecretSaveRequest_unstable | DictationSecretDeleteRequest_unstable | DictationModelsListRequest_unstable | DictationModelDownloadRequest_unstable | DictationModelDownloadProgressRequest_unstable | DictationModelCancelRequest_unstable | DictationModelDeleteRequest_unstable | DictationModelSelectRequest_unstable | { + params?: AddSessionExtensionRequest_unstable | RemoveSessionExtensionRequest_unstable | GetToolsRequest_unstable | GooseToolCallRequest_unstable | ReadResourceRequest_unstable | UpdateWorkingDirRequest_unstable | SetSessionSystemPromptRequest_unstable | SteerSessionRequest_unstable | DiagnosticsGetRequest_unstable | DeleteSessionRequest | GetConfigExtensionsRequest_unstable | GetAvailableExtensionsRequest_unstable | AddConfigExtensionRequest_unstable | RemoveConfigExtensionRequest_unstable | SetConfigExtensionEnabledRequest_unstable | GetSessionExtensionsRequest_unstable | ListProvidersRequest_unstable | ProviderSupportedModelsListRequest_unstable | ProviderCatalogListRequest_unstable | ProviderSetupCatalogListRequest_unstable | ProviderCatalogTemplateRequest_unstable | CustomProviderCreateRequest_unstable | CustomProviderReadRequest_unstable | CustomProviderUpdateRequest_unstable | CustomProviderDeleteRequest_unstable | RefreshProviderInventoryRequest_unstable | ProviderConfigReadRequest_unstable | ProviderConfigStatusRequest_unstable | ProviderConfigSaveRequest_unstable | ProviderConfigDeleteRequest_unstable | ProviderConfigAuthenticateRequest_unstable | PreferencesReadRequest_unstable | PreferencesSaveRequest_unstable | PreferencesRemoveRequest_unstable | DefaultsReadRequest_unstable | DefaultsSaveRequest_unstable | OnboardingImportScanRequest_unstable | OnboardingImportApplyRequest_unstable | ExportSessionRequest_unstable | ImportSessionRequest_unstable | EncodeRecipeRequest_unstable | DecodeRecipeRequest_unstable | ScanRecipeRequest_unstable | ListRecipesRequest_unstable | DeleteRecipeRequest_unstable | ScheduleRecipeRequest_unstable | SetRecipeSlashCommandRequest_unstable | SaveRecipeRequest_unstable | ParseRecipeRequest_unstable | RecipeToYamlRequest_unstable | GetSessionInfoRequest_unstable | TruncateSessionConversationRequest_unstable | UpdateSessionProjectRequest_unstable | RenameSessionRequest_unstable | ArchiveSessionRequest_unstable | UnarchiveSessionRequest_unstable | CreateSourceRequest_unstable | ListSourcesRequest_unstable | UpdateSourceRequest_unstable | DeleteSourceRequest_unstable | ExportSourceRequest_unstable | ImportSourcesRequest_unstable | DictationTranscribeRequest_unstable | DictationConfigRequest_unstable | DictationSecretSaveRequest_unstable | DictationSecretDeleteRequest_unstable | DictationModelsListRequest_unstable | DictationModelDownloadRequest_unstable | DictationModelDownloadProgressRequest_unstable | DictationModelCancelRequest_unstable | DictationModelDeleteRequest_unstable | DictationModelSelectRequest_unstable | { [key: string]: unknown; } | null; }; export type ExtResponse = { id: string; - result?: EmptyResponse | GetToolsResponse_unstable | GooseToolCallResponse_unstable | ReadResourceResponse_unstable | SteerSessionResponse_unstable | GetConfigExtensionsResponse_unstable | GetAvailableExtensionsResponse_unstable | GetSessionExtensionsResponse_unstable | ListProvidersResponse_unstable | ProviderSupportedModelsListResponse_unstable | ProviderCatalogListResponse_unstable | ProviderSetupCatalogListResponse_unstable | ProviderCatalogTemplateResponse_unstable | CustomProviderCreateResponse_unstable | CustomProviderReadResponse_unstable | CustomProviderUpdateResponse_unstable | CustomProviderDeleteResponse_unstable | RefreshProviderInventoryResponse_unstable | ProviderConfigReadResponse_unstable | ProviderConfigStatusResponse_unstable | ProviderConfigChangeResponse_unstable | PreferencesReadResponse_unstable | DefaultsReadResponse_unstable | OnboardingImportScanResponse_unstable | OnboardingImportApplyResponse_unstable | ExportSessionResponse_unstable | ImportSessionResponse_unstable | EncodeRecipeResponse_unstable | DecodeRecipeResponse_unstable | ScanRecipeResponse_unstable | ListRecipesResponse_unstable | SaveRecipeResponse_unstable | ParseRecipeResponse_unstable | RecipeToYamlResponse_unstable | GetSessionInfoResponse_unstable | CreateSourceResponse_unstable | ListSourcesResponse_unstable | UpdateSourceResponse_unstable | ExportSourceResponse_unstable | ImportSourcesResponse_unstable | DictationTranscribeResponse_unstable | DictationConfigResponse_unstable | DictationModelsListResponse_unstable | DictationModelDownloadProgressResponse_unstable | unknown; + result?: EmptyResponse | GetToolsResponse_unstable | GooseToolCallResponse_unstable | ReadResourceResponse_unstable | SteerSessionResponse_unstable | DiagnosticsGetResponse_unstable | GetConfigExtensionsResponse_unstable | GetAvailableExtensionsResponse_unstable | GetSessionExtensionsResponse_unstable | ListProvidersResponse_unstable | ProviderSupportedModelsListResponse_unstable | ProviderCatalogListResponse_unstable | ProviderSetupCatalogListResponse_unstable | ProviderCatalogTemplateResponse_unstable | CustomProviderCreateResponse_unstable | CustomProviderReadResponse_unstable | CustomProviderUpdateResponse_unstable | CustomProviderDeleteResponse_unstable | RefreshProviderInventoryResponse_unstable | ProviderConfigReadResponse_unstable | ProviderConfigStatusResponse_unstable | ProviderConfigChangeResponse_unstable | PreferencesReadResponse_unstable | DefaultsReadResponse_unstable | OnboardingImportScanResponse_unstable | OnboardingImportApplyResponse_unstable | ExportSessionResponse_unstable | ImportSessionResponse_unstable | EncodeRecipeResponse_unstable | DecodeRecipeResponse_unstable | ScanRecipeResponse_unstable | ListRecipesResponse_unstable | SaveRecipeResponse_unstable | ParseRecipeResponse_unstable | RecipeToYamlResponse_unstable | GetSessionInfoResponse_unstable | CreateSourceResponse_unstable | ListSourcesResponse_unstable | UpdateSourceResponse_unstable | ExportSourceResponse_unstable | ImportSourcesResponse_unstable | DictationTranscribeResponse_unstable | DictationConfigResponse_unstable | DictationModelsListResponse_unstable | DictationModelDownloadProgressResponse_unstable | unknown; } | { error: { code: number; diff --git a/ui/sdk/src/generated/zod.gen.ts b/ui/sdk/src/generated/zod.gen.ts index 3d5ef2c34d..f21a465bfa 100644 --- a/ui/sdk/src/generated/zod.gen.ts +++ b/ui/sdk/src/generated/zod.gen.ts @@ -458,6 +458,20 @@ export const zSteerSessionResponse_unstable = z.object({ messageId: z.string() }); +export const zDiagnosticsReportLevel = z.enum(['summary', 'full']); + +/** + * Generate a diagnostics report for a session. + */ +export const zDiagnosticsGetRequest_unstable = z.object({ + sessionId: z.string(), + level: zDiagnosticsReportLevel.optional().default('summary') +}); + +export const zDiagnosticsGetResponse_unstable = z.object({ + report: z.unknown() +}); + /** * Delete a session. */ @@ -1921,6 +1935,7 @@ export const zExtRequest = z.object({ zUpdateWorkingDirRequest_unstable, zSetSessionSystemPromptRequest_unstable, zSteerSessionRequest_unstable, + zDiagnosticsGetRequest_unstable, zDeleteSessionRequest, zGetConfigExtensionsRequest_unstable, zGetAvailableExtensionsRequest_unstable, @@ -2002,6 +2017,7 @@ export const zExtResponse = z.union([ zGooseToolCallResponse_unstable, zReadResourceResponse_unstable, zSteerSessionResponse_unstable, + zDiagnosticsGetResponse_unstable, zGetConfigExtensionsResponse_unstable, zGetAvailableExtensionsResponse_unstable, zGetSessionExtensionsResponse_unstable,