diff --git a/crates/goose-server/src/openapi.rs b/crates/goose-server/src/openapi.rs index 1caa9ced49ce..7935a1acf4ac 100644 --- a/crates/goose-server/src/openapi.rs +++ b/crates/goose-server/src/openapi.rs @@ -355,11 +355,13 @@ derive_utoipa!(Icon as IconSchema); super::routes::config_management::get_pricing, super::routes::agent::start_agent, super::routes::agent::resume_agent, + super::routes::agent::stop_agent, super::routes::agent::restart_agent, super::routes::agent::update_working_dir, super::routes::agent::get_tools, super::routes::agent::read_resource, super::routes::agent::call_tool, + super::routes::agent::list_apps, super::routes::agent::update_from_session, super::routes::agent::agent_add_extension, super::routes::agent::agent_remove_extension, @@ -533,8 +535,11 @@ derive_utoipa!(Icon as IconSchema); super::routes::agent::ReadResourceResponse, super::routes::agent::CallToolRequest, super::routes::agent::CallToolResponse, + super::routes::agent::ListAppsRequest, + super::routes::agent::ListAppsResponse, super::routes::agent::StartAgentRequest, super::routes::agent::ResumeAgentRequest, + super::routes::agent::StopAgentRequest, super::routes::agent::RestartAgentRequest, super::routes::agent::UpdateWorkingDirRequest, super::routes::agent::UpdateFromSessionRequest, @@ -547,6 +552,8 @@ derive_utoipa!(Icon as IconSchema); super::tunnel::TunnelInfo, super::tunnel::TunnelState, super::routes::telemetry::TelemetryEventRequest, + goose::goose_apps::GooseApp, + goose::goose_apps::WindowProps, goose::goose_apps::McpAppResource, goose::goose_apps::CspMetadata, goose::goose_apps::UiMetadata, diff --git a/crates/goose-server/src/routes/agent.rs b/crates/goose-server/src/routes/agent.rs index 93d01319b304..9bb75ed5d9d8 100644 --- a/crates/goose-server/src/routes/agent.rs +++ b/crates/goose-server/src/routes/agent.rs @@ -11,6 +11,7 @@ use axum::{ Json, Router, }; use goose::agents::ExtensionLoadResult; +use goose::goose_apps::{fetch_mcp_apps, GooseApp, McpAppCache}; use base64::Engine; use goose::agents::ExtensionConfig; @@ -35,7 +36,7 @@ use std::path::PathBuf; use std::sync::atomic::Ordering; use std::sync::Arc; use tokio_util::sync::CancellationToken; -use tracing::error; +use tracing::{error, warn}; #[derive(Deserialize, utoipa::ToSchema)] pub struct UpdateFromSessionRequest { @@ -933,6 +934,87 @@ async fn call_tool( })) } +#[derive(Deserialize, utoipa::IntoParams, utoipa::ToSchema)] +pub struct ListAppsRequest { + session_id: Option, +} + +#[derive(Serialize, utoipa::ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct ListAppsResponse { + pub apps: Vec, +} + +#[utoipa::path( + get, + path = "/agent/list_apps", + params( + ListAppsRequest + ), + responses( + (status = 200, description = "List of apps retrieved successfully", body = ListAppsResponse), + (status = 401, description = "Unauthorized - Invalid or missing API key", body = ErrorResponse), + (status = 500, description = "Internal server error", body = ErrorResponse), + ), + security( + ("api_key" = []) + ), + tag = "Agent" +)] +async fn list_apps( + State(state): State>, + Query(params): Query, +) -> Result, ErrorResponse> { + let cache = McpAppCache::new().ok(); + + let Some(session_id) = params.session_id else { + let apps = cache + .as_ref() + .and_then(|c| c.list_apps().ok()) + .unwrap_or_default(); + return Ok(Json(ListAppsResponse { apps })); + }; + + let agent = state + .get_agent_for_route(session_id) + .await + .map_err(|status| ErrorResponse { + message: "Failed to get agent".to_string(), + status, + })?; + + let apps = fetch_mcp_apps(&agent.extension_manager) + .await + .map_err(|e| ErrorResponse { + message: format!("Failed to list apps: {}", e.message), + status: StatusCode::INTERNAL_SERVER_ERROR, + })?; + + if let Some(cache) = cache.as_ref() { + let active_extensions: std::collections::HashSet = apps + .iter() + .filter_map(|app| app.mcp_server.clone()) + .collect(); + + for extension_name in active_extensions { + if let Err(e) = cache.delete_extension_apps(&extension_name) { + warn!( + "Failed to clean cache for extension {}: {}", + extension_name, e + ); + } + } + + for app in &apps { + if let Err(e) = cache.store_app(app) { + warn!("Failed to cache app {}: {}", app.resource.name, e); + } + } + } + + Ok(Json(ListAppsResponse { apps })) +} + pub fn routes(state: Arc) -> Router { Router::new() .route("/agent/start", post(start_agent)) @@ -942,6 +1024,7 @@ pub fn routes(state: Arc) -> Router { .route("/agent/tools", get(get_tools)) .route("/agent/read_resource", post(read_resource)) .route("/agent/call_tool", post(call_tool)) + .route("/agent/list_apps", get(list_apps)) .route("/agent/update_provider", post(update_agent_provider)) .route("/agent/update_from_session", post(update_from_session)) .route("/agent/add_extension", post(agent_add_extension)) diff --git a/crates/goose/src/goose_apps/mod.rs b/crates/goose/src/goose_apps/mod.rs index 4fdeb773f2b4..b93bf27aee08 100644 --- a/crates/goose/src/goose_apps/mod.rs +++ b/crates/goose/src/goose_apps/mod.rs @@ -1,9 +1,203 @@ -//! goose Apps module -//! -//! This module contains types and utilities for working with goose Apps, -//! which are UI resources that can be rendered in an MCP server or native -//! goose apps, or something in between. - pub mod resource; +use crate::agents::ExtensionManager; +use crate::config::paths::Paths; +use rmcp::model::ErrorData; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use std::fs; +use std::path::PathBuf; +use tokio_util::sync::CancellationToken; +use tracing::warn; +use utoipa::ToSchema; + pub use resource::{CspMetadata, McpAppResource, ResourceMetadata, UiMetadata}; + +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct WindowProps { + pub width: u32, + pub height: u32, + pub resizable: bool, +} + +/// A Goose App combining MCP resource data with Goose-specific metadata +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct GooseApp { + #[serde(flatten)] + pub resource: McpAppResource, + #[serde(skip_serializing_if = "Option::is_none")] + pub mcp_server: Option, + #[serde(flatten, skip_serializing_if = "Option::is_none")] + pub window_props: Option, +} + +pub struct McpAppCache { + cache_dir: PathBuf, +} + +impl McpAppCache { + pub fn new() -> Result { + let config_dir = Paths::config_dir(); + let cache_dir = config_dir.join("mcp-apps-cache"); + Ok(Self { cache_dir }) + } + + fn cache_key(extension_name: &str, resource_uri: &str) -> String { + let input = format!("{}::{}", extension_name, resource_uri); + let hash = Sha256::digest(input.as_bytes()); + format!("{}_{:x}", extension_name, hash) + } + + pub fn list_apps(&self) -> Result, std::io::Error> { + let mut apps = Vec::new(); + + if !self.cache_dir.exists() { + return Ok(apps); + } + + for entry in fs::read_dir(&self.cache_dir)? { + let entry = entry?; + let path = entry.path(); + + if path.extension().and_then(|s| s.to_str()) == Some("json") { + match fs::read_to_string(&path) { + Ok(content) => match serde_json::from_str::(&content) { + Ok(app) => apps.push(app), + Err(e) => warn!("Failed to parse cached app from {:?}: {}", path, e), + }, + Err(e) => warn!("Failed to read cached app from {:?}: {}", path, e), + } + } + } + + Ok(apps) + } + + pub fn store_app(&self, app: &GooseApp) -> Result<(), std::io::Error> { + fs::create_dir_all(&self.cache_dir)?; + + if let Some(ref extension_name) = app.mcp_server { + let cache_key = Self::cache_key(extension_name, &app.resource.uri); + let app_path = self.cache_dir.join(format!("{}.json", cache_key)); + let json = serde_json::to_string_pretty(app).map_err(std::io::Error::other)?; + fs::write(app_path, json)?; + } + + Ok(()) + } + + pub fn get_app(&self, extension_name: &str, resource_uri: &str) -> Option { + let cache_key = Self::cache_key(extension_name, resource_uri); + let app_path = self.cache_dir.join(format!("{}.json", cache_key)); + + if !app_path.exists() { + return None; + } + + fs::read_to_string(&app_path) + .ok() + .and_then(|content| serde_json::from_str::(&content).ok()) + } + + pub fn delete_extension_apps(&self, extension_name: &str) -> Result { + let mut deleted_count = 0; + + if !self.cache_dir.exists() { + return Ok(0); + } + + for entry in fs::read_dir(&self.cache_dir)? { + let entry = entry?; + let path = entry.path(); + + if path.extension().and_then(|s| s.to_str()) == Some("json") { + if let Ok(content) = fs::read_to_string(&path) { + if let Ok(app) = serde_json::from_str::(&content) { + if app.mcp_server.as_deref() == Some(extension_name) + && fs::remove_file(&path).is_ok() + { + deleted_count += 1; + } + } + } + } + } + + Ok(deleted_count) + } +} + +pub async fn fetch_mcp_apps( + extension_manager: &ExtensionManager, +) -> Result, ErrorData> { + let mut apps = Vec::new(); + + let ui_resources = extension_manager.get_ui_resources().await?; + + for (extension_name, resource) in ui_resources { + match extension_manager + .read_resource(&resource.uri, &extension_name, CancellationToken::default()) + .await + { + Ok(read_result) => { + let mut html = String::new(); + for content in read_result.contents { + if let rmcp::model::ResourceContents::TextResourceContents { text, .. } = + content + { + html = text; + break; + } + } + + if !html.is_empty() { + let mcp_resource = McpAppResource { + uri: resource.uri.clone(), + name: format_resource_name(resource.name.clone()), + description: resource.description.clone(), + mime_type: "text/html;profile=mcp-app".to_string(), + text: Some(html), + blob: None, + meta: None, + }; + + let app = GooseApp { + resource: mcp_resource, + mcp_server: Some(extension_name), + window_props: Some(WindowProps { + width: 800, + height: 600, + resizable: true, + }), + }; + + apps.push(app); + } + } + Err(e) => { + warn!( + "Failed to read resource {} from {}: {}", + resource.uri, extension_name, e + ); + } + } + } + + Ok(apps) +} + +fn format_resource_name(name: String) -> String { + name.replace('_', " ") + .split_whitespace() + .map(|word| { + let mut chars = word.chars(); + match chars.next() { + None => String::new(), + Some(first) => first.to_uppercase().chain(chars).collect(), + } + }) + .collect::>() + .join(" ") +} diff --git a/ui/desktop/openapi.json b/ui/desktop/openapi.json index 8e0d67ce9feb..d27bdaabd338 100644 --- a/ui/desktop/openapi.json +++ b/ui/desktop/openapi.json @@ -128,6 +128,62 @@ } } }, + "/agent/list_apps": { + "get": { + "tags": [ + "Agent" + ], + "operationId": "list_apps", + "parameters": [ + { + "name": "session_id", + "in": "query", + "required": false, + "schema": { + "type": "string", + "nullable": true + } + } + ], + "responses": { + "200": { + "description": "List of apps retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListAppsResponse" + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing API key", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, "/agent/read_resource": { "post": { "tags": [ @@ -340,6 +396,45 @@ } } }, + "/agent/stop": { + "post": { + "tags": [ + "super::routes::agent" + ], + "operationId": "stop_agent", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StopAgentRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Agent stopped successfully", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "description": "Unauthorized - invalid secret key" + }, + "404": { + "description": "Session not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, "/agent/tools": { "get": { "tags": [ @@ -3762,6 +3857,31 @@ } } }, + "GooseApp": { + "allOf": [ + { + "$ref": "#/components/schemas/McpAppResource" + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/WindowProps" + } + ], + "nullable": true + }, + { + "type": "object", + "properties": { + "mcpServer": { + "type": "string", + "nullable": true + } + } + } + ], + "description": "A Goose App combining MCP resource data with Goose-specific metadata" + }, "Icon": { "type": "object", "required": [ @@ -3855,6 +3975,29 @@ } } }, + "ListAppsRequest": { + "type": "object", + "properties": { + "session_id": { + "type": "string", + "nullable": true + } + } + }, + "ListAppsResponse": { + "type": "object", + "required": [ + "apps" + ], + "properties": { + "apps": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GooseApp" + } + } + } + }, "ListRecipeResponse": { "type": "object", "required": [ @@ -5674,6 +5817,17 @@ } } }, + "StopAgentRequest": { + "type": "object", + "required": [ + "session_id" + ], + "properties": { + "session_id": { + "type": "string" + } + } + }, "SubRecipe": { "type": "object", "required": [ @@ -6279,6 +6433,29 @@ } } } + }, + "WindowProps": { + "type": "object", + "required": [ + "width", + "height", + "resizable" + ], + "properties": { + "height": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "resizable": { + "type": "boolean" + }, + "width": { + "type": "integer", + "format": "int32", + "minimum": 0 + } + } } } } diff --git a/ui/desktop/src/App.tsx b/ui/desktop/src/App.tsx index 5c1a575decbe..2c2cfba8a142 100644 --- a/ui/desktop/src/App.tsx +++ b/ui/desktop/src/App.tsx @@ -38,6 +38,8 @@ import PermissionSettingsView from './components/settings/permission/PermissionS import ExtensionsView, { ExtensionsViewOptions } from './components/extensions/ExtensionsView'; import RecipesView from './components/recipes/RecipesView'; +import AppsView from './components/apps/AppsView'; +import StandaloneAppView from './components/apps/StandaloneAppView'; import { View, ViewOptions } from './utils/navigationUtils'; import { useNavigation } from './hooks/useNavigation'; @@ -583,6 +585,7 @@ export function AppInner() { element={ setDidSelectProvider(true)} />} /> } /> + } /> } /> + } /> } /> } /> } /> diff --git a/ui/desktop/src/api/index.ts b/ui/desktop/src/api/index.ts index 6e3f95d53065..afff8c37ec1f 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, backupConfig, callTool, checkProvider, confirmToolAction, createCustomProvider, createRecipe, createSchedule, decodeRecipe, deleteRecipe, deleteSchedule, deleteSession, detectProvider, diagnostics, editMessage, encodeRecipe, exportSession, getCustomProvider, getExtensions, getPricing, getProviderModels, getSession, getSessionExtensions, getSessionInsights, getSlashCommands, getTools, getTunnelStatus, importSession, initConfig, inspectRunningJob, killRunningJob, listRecipes, listSchedules, listSessions, mcpUiProxy, type Options, parseRecipe, pauseSchedule, providers, readAllConfig, readConfig, readResource, recipeToYaml, recoverConfig, removeConfig, removeCustomProvider, removeExtension, reply, restartAgent, resumeAgent, runNowHandler, saveRecipe, scanRecipe, scheduleRecipe, sendTelemetryEvent, sessionsHandler, setConfigProvider, setRecipeSlashCommand, startAgent, startOpenrouterSetup, startTetrateSetup, startTunnel, status, stopTunnel, systemInfo, unpauseSchedule, updateAgentProvider, updateCustomProvider, updateFromSession, updateSchedule, 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, AuthorRequest, BackupConfigData, BackupConfigErrors, BackupConfigResponse, BackupConfigResponses, CallToolData, CallToolErrors, CallToolRequest, CallToolResponse, CallToolResponse2, CallToolResponses, ChatRequest, CheckProviderData, CheckProviderRequest, ClientOptions, CommandType, ConfigKey, ConfigKeyQuery, ConfigResponse, ConfirmToolActionData, ConfirmToolActionErrors, ConfirmToolActionRequest, ConfirmToolActionResponses, Content, Conversation, CreateCustomProviderData, CreateCustomProviderErrors, CreateCustomProviderResponse, CreateCustomProviderResponses, CreateRecipeData, CreateRecipeErrors, CreateRecipeRequest, CreateRecipeResponse, CreateRecipeResponse2, CreateRecipeResponses, CreateScheduleData, CreateScheduleErrors, CreateScheduleRequest, CreateScheduleResponse, CreateScheduleResponses, CspMetadata, DeclarativeProviderConfig, DecodeRecipeData, DecodeRecipeErrors, DecodeRecipeRequest, DecodeRecipeResponse, DecodeRecipeResponse2, DecodeRecipeResponses, DeleteRecipeData, DeleteRecipeErrors, DeleteRecipeRequest, DeleteRecipeResponse, DeleteRecipeResponses, DeleteScheduleData, DeleteScheduleErrors, DeleteScheduleResponse, DeleteScheduleResponses, DeleteSessionData, DeleteSessionErrors, DeleteSessionResponses, DetectProviderData, DetectProviderErrors, DetectProviderRequest, DetectProviderResponse, DetectProviderResponse2, DetectProviderResponses, DiagnosticsData, DiagnosticsErrors, DiagnosticsResponse, DiagnosticsResponses, EditMessageData, EditMessageErrors, EditMessageRequest, EditMessageResponse, EditMessageResponse2, EditMessageResponses, EditType, EmbeddedResource, EncodeRecipeData, EncodeRecipeErrors, EncodeRecipeRequest, EncodeRecipeResponse, EncodeRecipeResponse2, EncodeRecipeResponses, Envs, ErrorResponse, ExportSessionData, ExportSessionErrors, ExportSessionResponse, ExportSessionResponses, ExtensionConfig, ExtensionData, ExtensionEntry, ExtensionLoadResult, ExtensionQuery, ExtensionResponse, FrontendToolRequest, GetCustomProviderData, GetCustomProviderErrors, GetCustomProviderResponse, GetCustomProviderResponses, GetExtensionsData, GetExtensionsErrors, GetExtensionsResponse, GetExtensionsResponses, GetPricingData, GetPricingResponse, GetPricingResponses, GetProviderModelsData, GetProviderModelsErrors, GetProviderModelsResponse, GetProviderModelsResponses, GetSessionData, GetSessionErrors, GetSessionExtensionsData, GetSessionExtensionsErrors, GetSessionExtensionsResponse, GetSessionExtensionsResponses, GetSessionInsightsData, GetSessionInsightsErrors, GetSessionInsightsResponse, GetSessionInsightsResponses, GetSessionResponse, GetSessionResponses, GetSlashCommandsData, GetSlashCommandsResponse, GetSlashCommandsResponses, GetToolsData, GetToolsErrors, GetToolsQuery, GetToolsResponse, GetToolsResponses, GetTunnelStatusData, GetTunnelStatusResponse, GetTunnelStatusResponses, Icon, ImageContent, ImportSessionData, ImportSessionErrors, ImportSessionRequest, ImportSessionResponse, ImportSessionResponses, InitConfigData, InitConfigErrors, InitConfigResponse, InitConfigResponses, InspectJobResponse, InspectRunningJobData, InspectRunningJobErrors, InspectRunningJobResponse, InspectRunningJobResponses, JsonObject, KillJobResponse, KillRunningJobData, KillRunningJobResponses, ListRecipeResponse, ListRecipesData, ListRecipesErrors, ListRecipesResponse, ListRecipesResponses, ListSchedulesData, ListSchedulesErrors, ListSchedulesResponse, ListSchedulesResponse2, ListSchedulesResponses, ListSessionsData, ListSessionsErrors, ListSessionsResponse, ListSessionsResponses, LoadedProvider, McpAppResource, McpUiProxyData, McpUiProxyErrors, McpUiProxyResponses, Message, MessageContent, MessageEvent, MessageMetadata, ModelConfig, ModelInfo, ParseRecipeData, ParseRecipeError, ParseRecipeErrors, ParseRecipeRequest, ParseRecipeResponse, ParseRecipeResponse2, ParseRecipeResponses, PauseScheduleData, PauseScheduleErrors, PauseScheduleResponse, PauseScheduleResponses, PermissionLevel, PricingData, PricingQuery, PricingResponse, PrincipalType, ProviderDetails, ProviderEngine, ProviderMetadata, ProvidersData, ProvidersResponse, ProvidersResponse2, ProvidersResponses, 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, RecoverConfigData, RecoverConfigErrors, RecoverConfigResponse, RecoverConfigResponses, RedactedThinkingContent, RemoveConfigData, RemoveConfigErrors, RemoveConfigResponse, RemoveConfigResponses, RemoveCustomProviderData, RemoveCustomProviderErrors, RemoveCustomProviderResponse, RemoveCustomProviderResponses, RemoveExtensionData, RemoveExtensionErrors, RemoveExtensionRequest, RemoveExtensionResponse, RemoveExtensionResponses, ReplyData, ReplyErrors, ReplyResponse, ReplyResponses, ResourceContents, ResourceMetadata, Response, RestartAgentData, RestartAgentErrors, RestartAgentRequest, RestartAgentResponse, RestartAgentResponse2, RestartAgentResponses, ResumeAgentData, ResumeAgentErrors, ResumeAgentRequest, ResumeAgentResponse, ResumeAgentResponse2, ResumeAgentResponses, RetryConfig, Role, RunNowHandlerData, RunNowHandlerErrors, RunNowHandlerResponse, RunNowHandlerResponses, RunNowResponse, SaveRecipeData, SaveRecipeError, SaveRecipeErrors, SaveRecipeRequest, SaveRecipeResponse, SaveRecipeResponse2, SaveRecipeResponses, ScanRecipeData, ScanRecipeRequest, ScanRecipeResponse, ScanRecipeResponse2, ScanRecipeResponses, ScheduledJob, ScheduleRecipeData, ScheduleRecipeErrors, ScheduleRecipeRequest, ScheduleRecipeResponses, SendTelemetryEventData, SendTelemetryEventResponses, Session, SessionDisplayInfo, SessionExtensionsResponse, SessionInsights, SessionListResponse, SessionsHandlerData, SessionsHandlerErrors, SessionsHandlerResponse, SessionsHandlerResponses, SessionsQuery, SessionType, SetConfigProviderData, SetProviderRequest, SetRecipeSlashCommandData, SetRecipeSlashCommandErrors, SetRecipeSlashCommandResponses, SetSlashCommandRequest, Settings, SetupResponse, SlashCommand, SlashCommandsResponse, StartAgentData, StartAgentError, StartAgentErrors, StartAgentRequest, StartAgentResponse, StartAgentResponses, StartOpenrouterSetupData, StartOpenrouterSetupResponse, StartOpenrouterSetupResponses, StartTetrateSetupData, StartTetrateSetupResponse, StartTetrateSetupResponses, StartTunnelData, StartTunnelError, StartTunnelErrors, StartTunnelResponse, StartTunnelResponses, StatusData, StatusResponse, StatusResponses, StopTunnelData, StopTunnelError, StopTunnelErrors, StopTunnelResponses, SubRecipe, SuccessCheck, SystemInfo, SystemInfoData, SystemInfoResponse, SystemInfoResponses, SystemNotificationContent, SystemNotificationType, TelemetryEventRequest, TextContent, ThinkingContent, TokenState, Tool, ToolAnnotations, ToolConfirmationRequest, ToolInfo, ToolPermission, ToolRequest, ToolResponse, TunnelInfo, TunnelState, UiMetadata, UnpauseScheduleData, UnpauseScheduleErrors, UnpauseScheduleResponse, UnpauseScheduleResponses, UpdateAgentProviderData, UpdateAgentProviderErrors, UpdateAgentProviderResponses, UpdateCustomProviderData, UpdateCustomProviderErrors, UpdateCustomProviderRequest, UpdateCustomProviderResponse, UpdateCustomProviderResponses, UpdateFromSessionData, UpdateFromSessionErrors, UpdateFromSessionRequest, UpdateFromSessionResponses, UpdateProviderRequest, UpdateScheduleData, UpdateScheduleErrors, UpdateScheduleRequest, UpdateScheduleResponse, UpdateScheduleResponses, UpdateSessionNameData, UpdateSessionNameErrors, UpdateSessionNameRequest, UpdateSessionNameResponses, UpdateSessionUserRecipeValuesData, UpdateSessionUserRecipeValuesError, UpdateSessionUserRecipeValuesErrors, UpdateSessionUserRecipeValuesRequest, UpdateSessionUserRecipeValuesResponse, UpdateSessionUserRecipeValuesResponse2, UpdateSessionUserRecipeValuesResponses, UpdateWorkingDirData, UpdateWorkingDirErrors, UpdateWorkingDirRequest, UpdateWorkingDirResponses, UpsertConfigData, UpsertConfigErrors, UpsertConfigQuery, UpsertConfigResponse, UpsertConfigResponses, UpsertPermissionsData, UpsertPermissionsErrors, UpsertPermissionsQuery, UpsertPermissionsResponse, UpsertPermissionsResponses, ValidateConfigData, ValidateConfigErrors, ValidateConfigResponse, ValidateConfigResponses } from './types.gen'; +export { addExtension, agentAddExtension, agentRemoveExtension, backupConfig, callTool, checkProvider, confirmToolAction, createCustomProvider, createRecipe, createSchedule, decodeRecipe, deleteRecipe, deleteSchedule, deleteSession, detectProvider, diagnostics, editMessage, encodeRecipe, exportSession, getCustomProvider, getExtensions, getPricing, getProviderModels, getSession, getSessionExtensions, getSessionInsights, getSlashCommands, getTools, getTunnelStatus, importSession, initConfig, inspectRunningJob, killRunningJob, listApps, listRecipes, listSchedules, listSessions, mcpUiProxy, type Options, parseRecipe, pauseSchedule, providers, readAllConfig, readConfig, readResource, recipeToYaml, recoverConfig, removeConfig, removeCustomProvider, removeExtension, reply, restartAgent, resumeAgent, runNowHandler, saveRecipe, scanRecipe, scheduleRecipe, sendTelemetryEvent, sessionsHandler, setConfigProvider, setRecipeSlashCommand, startAgent, startOpenrouterSetup, startTetrateSetup, startTunnel, status, stopAgent, stopTunnel, systemInfo, unpauseSchedule, updateAgentProvider, updateCustomProvider, updateFromSession, updateSchedule, 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, AuthorRequest, BackupConfigData, BackupConfigErrors, BackupConfigResponse, BackupConfigResponses, CallToolData, CallToolErrors, CallToolRequest, CallToolResponse, CallToolResponse2, CallToolResponses, ChatRequest, CheckProviderData, CheckProviderRequest, ClientOptions, CommandType, ConfigKey, ConfigKeyQuery, ConfigResponse, ConfirmToolActionData, ConfirmToolActionErrors, ConfirmToolActionRequest, ConfirmToolActionResponses, Content, Conversation, CreateCustomProviderData, CreateCustomProviderErrors, CreateCustomProviderResponse, CreateCustomProviderResponses, CreateRecipeData, CreateRecipeErrors, CreateRecipeRequest, CreateRecipeResponse, CreateRecipeResponse2, CreateRecipeResponses, CreateScheduleData, CreateScheduleErrors, CreateScheduleRequest, CreateScheduleResponse, CreateScheduleResponses, CspMetadata, DeclarativeProviderConfig, DecodeRecipeData, DecodeRecipeErrors, DecodeRecipeRequest, DecodeRecipeResponse, DecodeRecipeResponse2, DecodeRecipeResponses, DeleteRecipeData, DeleteRecipeErrors, DeleteRecipeRequest, DeleteRecipeResponse, DeleteRecipeResponses, DeleteScheduleData, DeleteScheduleErrors, DeleteScheduleResponse, DeleteScheduleResponses, DeleteSessionData, DeleteSessionErrors, DeleteSessionResponses, DetectProviderData, DetectProviderErrors, DetectProviderRequest, DetectProviderResponse, DetectProviderResponse2, DetectProviderResponses, DiagnosticsData, DiagnosticsErrors, DiagnosticsResponse, DiagnosticsResponses, EditMessageData, EditMessageErrors, EditMessageRequest, EditMessageResponse, EditMessageResponse2, EditMessageResponses, EditType, EmbeddedResource, EncodeRecipeData, EncodeRecipeErrors, EncodeRecipeRequest, EncodeRecipeResponse, EncodeRecipeResponse2, EncodeRecipeResponses, Envs, ErrorResponse, ExportSessionData, ExportSessionErrors, ExportSessionResponse, ExportSessionResponses, ExtensionConfig, ExtensionData, ExtensionEntry, ExtensionLoadResult, ExtensionQuery, ExtensionResponse, FrontendToolRequest, GetCustomProviderData, GetCustomProviderErrors, GetCustomProviderResponse, GetCustomProviderResponses, GetExtensionsData, GetExtensionsErrors, GetExtensionsResponse, GetExtensionsResponses, GetPricingData, GetPricingResponse, GetPricingResponses, GetProviderModelsData, GetProviderModelsErrors, GetProviderModelsResponse, GetProviderModelsResponses, GetSessionData, GetSessionErrors, GetSessionExtensionsData, GetSessionExtensionsErrors, GetSessionExtensionsResponse, GetSessionExtensionsResponses, GetSessionInsightsData, GetSessionInsightsErrors, GetSessionInsightsResponse, GetSessionInsightsResponses, GetSessionResponse, GetSessionResponses, GetSlashCommandsData, GetSlashCommandsResponse, GetSlashCommandsResponses, GetToolsData, GetToolsErrors, GetToolsQuery, GetToolsResponse, GetToolsResponses, GetTunnelStatusData, GetTunnelStatusResponse, GetTunnelStatusResponses, GooseApp, Icon, ImageContent, ImportSessionData, ImportSessionErrors, ImportSessionRequest, ImportSessionResponse, ImportSessionResponses, InitConfigData, InitConfigErrors, InitConfigResponse, InitConfigResponses, InspectJobResponse, InspectRunningJobData, InspectRunningJobErrors, InspectRunningJobResponse, InspectRunningJobResponses, JsonObject, KillJobResponse, KillRunningJobData, KillRunningJobResponses, ListAppsData, ListAppsError, ListAppsErrors, ListAppsRequest, ListAppsResponse, ListAppsResponse2, ListAppsResponses, ListRecipeResponse, ListRecipesData, ListRecipesErrors, ListRecipesResponse, ListRecipesResponses, ListSchedulesData, ListSchedulesErrors, ListSchedulesResponse, ListSchedulesResponse2, ListSchedulesResponses, ListSessionsData, ListSessionsErrors, ListSessionsResponse, ListSessionsResponses, LoadedProvider, McpAppResource, McpUiProxyData, McpUiProxyErrors, McpUiProxyResponses, Message, MessageContent, MessageEvent, MessageMetadata, ModelConfig, ModelInfo, ParseRecipeData, ParseRecipeError, ParseRecipeErrors, ParseRecipeRequest, ParseRecipeResponse, ParseRecipeResponse2, ParseRecipeResponses, PauseScheduleData, PauseScheduleErrors, PauseScheduleResponse, PauseScheduleResponses, PermissionLevel, PricingData, PricingQuery, PricingResponse, PrincipalType, ProviderDetails, ProviderEngine, ProviderMetadata, ProvidersData, ProvidersResponse, ProvidersResponse2, ProvidersResponses, 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, RecoverConfigData, RecoverConfigErrors, RecoverConfigResponse, RecoverConfigResponses, RedactedThinkingContent, RemoveConfigData, RemoveConfigErrors, RemoveConfigResponse, RemoveConfigResponses, RemoveCustomProviderData, RemoveCustomProviderErrors, RemoveCustomProviderResponse, RemoveCustomProviderResponses, RemoveExtensionData, RemoveExtensionErrors, RemoveExtensionRequest, RemoveExtensionResponse, RemoveExtensionResponses, ReplyData, ReplyErrors, ReplyResponse, ReplyResponses, ResourceContents, ResourceMetadata, Response, RestartAgentData, RestartAgentErrors, RestartAgentRequest, RestartAgentResponse, RestartAgentResponse2, RestartAgentResponses, ResumeAgentData, ResumeAgentErrors, ResumeAgentRequest, ResumeAgentResponse, ResumeAgentResponse2, ResumeAgentResponses, RetryConfig, Role, RunNowHandlerData, RunNowHandlerErrors, RunNowHandlerResponse, RunNowHandlerResponses, RunNowResponse, SaveRecipeData, SaveRecipeError, SaveRecipeErrors, SaveRecipeRequest, SaveRecipeResponse, SaveRecipeResponse2, SaveRecipeResponses, ScanRecipeData, ScanRecipeRequest, ScanRecipeResponse, ScanRecipeResponse2, ScanRecipeResponses, ScheduledJob, ScheduleRecipeData, ScheduleRecipeErrors, ScheduleRecipeRequest, ScheduleRecipeResponses, SendTelemetryEventData, SendTelemetryEventResponses, Session, SessionDisplayInfo, SessionExtensionsResponse, SessionInsights, SessionListResponse, SessionsHandlerData, SessionsHandlerErrors, SessionsHandlerResponse, SessionsHandlerResponses, SessionsQuery, SessionType, SetConfigProviderData, SetProviderRequest, SetRecipeSlashCommandData, SetRecipeSlashCommandErrors, SetRecipeSlashCommandResponses, SetSlashCommandRequest, Settings, SetupResponse, SlashCommand, SlashCommandsResponse, StartAgentData, StartAgentError, StartAgentErrors, StartAgentRequest, StartAgentResponse, StartAgentResponses, 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, SystemInfo, SystemInfoData, SystemInfoResponse, SystemInfoResponses, SystemNotificationContent, SystemNotificationType, TelemetryEventRequest, TextContent, ThinkingContent, TokenState, Tool, ToolAnnotations, ToolConfirmationRequest, ToolInfo, ToolPermission, ToolRequest, ToolResponse, TunnelInfo, TunnelState, UiMetadata, UnpauseScheduleData, UnpauseScheduleErrors, UnpauseScheduleResponse, UnpauseScheduleResponses, UpdateAgentProviderData, UpdateAgentProviderErrors, UpdateAgentProviderResponses, UpdateCustomProviderData, UpdateCustomProviderErrors, UpdateCustomProviderRequest, UpdateCustomProviderResponse, UpdateCustomProviderResponses, UpdateFromSessionData, UpdateFromSessionErrors, UpdateFromSessionRequest, UpdateFromSessionResponses, UpdateProviderRequest, UpdateScheduleData, UpdateScheduleErrors, UpdateScheduleRequest, UpdateScheduleResponse, UpdateScheduleResponses, UpdateSessionNameData, UpdateSessionNameErrors, UpdateSessionNameRequest, UpdateSessionNameResponses, UpdateSessionUserRecipeValuesData, UpdateSessionUserRecipeValuesError, UpdateSessionUserRecipeValuesErrors, UpdateSessionUserRecipeValuesRequest, UpdateSessionUserRecipeValuesResponse, UpdateSessionUserRecipeValuesResponse2, UpdateSessionUserRecipeValuesResponses, UpdateWorkingDirData, UpdateWorkingDirErrors, UpdateWorkingDirRequest, UpdateWorkingDirResponses, UpsertConfigData, UpsertConfigErrors, UpsertConfigQuery, UpsertConfigResponse, UpsertConfigResponses, UpsertPermissionsData, UpsertPermissionsErrors, UpsertPermissionsQuery, UpsertPermissionsResponse, UpsertPermissionsResponses, ValidateConfigData, ValidateConfigErrors, ValidateConfigResponse, ValidateConfigResponses, WindowProps } from './types.gen'; diff --git a/ui/desktop/src/api/sdk.gen.ts b/ui/desktop/src/api/sdk.gen.ts index 05c10fec0ea0..c420e84bd65a 100644 --- a/ui/desktop/src/api/sdk.gen.ts +++ b/ui/desktop/src/api/sdk.gen.ts @@ -2,7 +2,7 @@ import type { Client, Options as Options2, TDataShape } from './client'; import { client } from './client.gen'; -import type { AddExtensionData, AddExtensionErrors, AddExtensionResponses, AgentAddExtensionData, AgentAddExtensionErrors, AgentAddExtensionResponses, AgentRemoveExtensionData, AgentRemoveExtensionErrors, AgentRemoveExtensionResponses, BackupConfigData, BackupConfigErrors, BackupConfigResponses, CallToolData, CallToolErrors, CallToolResponses, CheckProviderData, ConfirmToolActionData, ConfirmToolActionErrors, ConfirmToolActionResponses, CreateCustomProviderData, CreateCustomProviderErrors, CreateCustomProviderResponses, CreateRecipeData, CreateRecipeErrors, CreateRecipeResponses, CreateScheduleData, CreateScheduleErrors, CreateScheduleResponses, DecodeRecipeData, DecodeRecipeErrors, DecodeRecipeResponses, DeleteRecipeData, DeleteRecipeErrors, DeleteRecipeResponses, DeleteScheduleData, DeleteScheduleErrors, DeleteScheduleResponses, DeleteSessionData, DeleteSessionErrors, DeleteSessionResponses, DetectProviderData, DetectProviderErrors, DetectProviderResponses, DiagnosticsData, DiagnosticsErrors, DiagnosticsResponses, EditMessageData, EditMessageErrors, EditMessageResponses, EncodeRecipeData, EncodeRecipeErrors, EncodeRecipeResponses, ExportSessionData, ExportSessionErrors, ExportSessionResponses, GetCustomProviderData, GetCustomProviderErrors, GetCustomProviderResponses, GetExtensionsData, GetExtensionsErrors, GetExtensionsResponses, GetPricingData, GetPricingResponses, GetProviderModelsData, GetProviderModelsErrors, GetProviderModelsResponses, GetSessionData, GetSessionErrors, GetSessionExtensionsData, GetSessionExtensionsErrors, GetSessionExtensionsResponses, GetSessionInsightsData, GetSessionInsightsErrors, GetSessionInsightsResponses, GetSessionResponses, GetSlashCommandsData, GetSlashCommandsResponses, GetToolsData, GetToolsErrors, GetToolsResponses, GetTunnelStatusData, GetTunnelStatusResponses, ImportSessionData, ImportSessionErrors, ImportSessionResponses, InitConfigData, InitConfigErrors, InitConfigResponses, InspectRunningJobData, InspectRunningJobErrors, InspectRunningJobResponses, KillRunningJobData, KillRunningJobResponses, ListRecipesData, ListRecipesErrors, ListRecipesResponses, ListSchedulesData, ListSchedulesErrors, ListSchedulesResponses, ListSessionsData, ListSessionsErrors, ListSessionsResponses, McpUiProxyData, McpUiProxyErrors, McpUiProxyResponses, ParseRecipeData, ParseRecipeErrors, ParseRecipeResponses, PauseScheduleData, PauseScheduleErrors, PauseScheduleResponses, ProvidersData, ProvidersResponses, ReadAllConfigData, ReadAllConfigResponses, ReadConfigData, ReadConfigErrors, ReadConfigResponses, ReadResourceData, ReadResourceErrors, ReadResourceResponses, RecipeToYamlData, RecipeToYamlErrors, RecipeToYamlResponses, RecoverConfigData, RecoverConfigErrors, RecoverConfigResponses, RemoveConfigData, RemoveConfigErrors, RemoveConfigResponses, RemoveCustomProviderData, RemoveCustomProviderErrors, RemoveCustomProviderResponses, RemoveExtensionData, RemoveExtensionErrors, RemoveExtensionResponses, ReplyData, ReplyErrors, ReplyResponses, RestartAgentData, RestartAgentErrors, RestartAgentResponses, ResumeAgentData, ResumeAgentErrors, ResumeAgentResponses, RunNowHandlerData, RunNowHandlerErrors, RunNowHandlerResponses, SaveRecipeData, SaveRecipeErrors, SaveRecipeResponses, ScanRecipeData, ScanRecipeResponses, ScheduleRecipeData, ScheduleRecipeErrors, ScheduleRecipeResponses, SendTelemetryEventData, SendTelemetryEventResponses, SessionsHandlerData, SessionsHandlerErrors, SessionsHandlerResponses, SetConfigProviderData, SetRecipeSlashCommandData, SetRecipeSlashCommandErrors, SetRecipeSlashCommandResponses, StartAgentData, StartAgentErrors, StartAgentResponses, StartOpenrouterSetupData, StartOpenrouterSetupResponses, StartTetrateSetupData, StartTetrateSetupResponses, StartTunnelData, StartTunnelErrors, StartTunnelResponses, StatusData, StatusResponses, StopTunnelData, StopTunnelErrors, StopTunnelResponses, SystemInfoData, SystemInfoResponses, UnpauseScheduleData, UnpauseScheduleErrors, UnpauseScheduleResponses, UpdateAgentProviderData, UpdateAgentProviderErrors, UpdateAgentProviderResponses, UpdateCustomProviderData, UpdateCustomProviderErrors, UpdateCustomProviderResponses, UpdateFromSessionData, UpdateFromSessionErrors, UpdateFromSessionResponses, UpdateScheduleData, UpdateScheduleErrors, UpdateScheduleResponses, UpdateSessionNameData, UpdateSessionNameErrors, UpdateSessionNameResponses, UpdateSessionUserRecipeValuesData, UpdateSessionUserRecipeValuesErrors, UpdateSessionUserRecipeValuesResponses, UpdateWorkingDirData, UpdateWorkingDirErrors, UpdateWorkingDirResponses, UpsertConfigData, UpsertConfigErrors, UpsertConfigResponses, UpsertPermissionsData, UpsertPermissionsErrors, UpsertPermissionsResponses, ValidateConfigData, ValidateConfigErrors, ValidateConfigResponses } from './types.gen'; +import type { AddExtensionData, AddExtensionErrors, AddExtensionResponses, AgentAddExtensionData, AgentAddExtensionErrors, AgentAddExtensionResponses, AgentRemoveExtensionData, AgentRemoveExtensionErrors, AgentRemoveExtensionResponses, BackupConfigData, BackupConfigErrors, BackupConfigResponses, CallToolData, CallToolErrors, CallToolResponses, CheckProviderData, ConfirmToolActionData, ConfirmToolActionErrors, ConfirmToolActionResponses, CreateCustomProviderData, CreateCustomProviderErrors, CreateCustomProviderResponses, CreateRecipeData, CreateRecipeErrors, CreateRecipeResponses, CreateScheduleData, CreateScheduleErrors, CreateScheduleResponses, DecodeRecipeData, DecodeRecipeErrors, DecodeRecipeResponses, DeleteRecipeData, DeleteRecipeErrors, DeleteRecipeResponses, DeleteScheduleData, DeleteScheduleErrors, DeleteScheduleResponses, DeleteSessionData, DeleteSessionErrors, DeleteSessionResponses, DetectProviderData, DetectProviderErrors, DetectProviderResponses, DiagnosticsData, DiagnosticsErrors, DiagnosticsResponses, EditMessageData, EditMessageErrors, EditMessageResponses, EncodeRecipeData, EncodeRecipeErrors, EncodeRecipeResponses, ExportSessionData, ExportSessionErrors, ExportSessionResponses, GetCustomProviderData, GetCustomProviderErrors, GetCustomProviderResponses, GetExtensionsData, GetExtensionsErrors, GetExtensionsResponses, GetPricingData, GetPricingResponses, GetProviderModelsData, GetProviderModelsErrors, GetProviderModelsResponses, GetSessionData, GetSessionErrors, GetSessionExtensionsData, GetSessionExtensionsErrors, GetSessionExtensionsResponses, GetSessionInsightsData, GetSessionInsightsErrors, GetSessionInsightsResponses, GetSessionResponses, GetSlashCommandsData, GetSlashCommandsResponses, GetToolsData, GetToolsErrors, GetToolsResponses, GetTunnelStatusData, GetTunnelStatusResponses, ImportSessionData, ImportSessionErrors, ImportSessionResponses, InitConfigData, InitConfigErrors, InitConfigResponses, InspectRunningJobData, InspectRunningJobErrors, InspectRunningJobResponses, KillRunningJobData, KillRunningJobResponses, ListAppsData, ListAppsErrors, ListAppsResponses, ListRecipesData, ListRecipesErrors, ListRecipesResponses, ListSchedulesData, ListSchedulesErrors, ListSchedulesResponses, ListSessionsData, ListSessionsErrors, ListSessionsResponses, McpUiProxyData, McpUiProxyErrors, McpUiProxyResponses, ParseRecipeData, ParseRecipeErrors, ParseRecipeResponses, PauseScheduleData, PauseScheduleErrors, PauseScheduleResponses, ProvidersData, ProvidersResponses, ReadAllConfigData, ReadAllConfigResponses, ReadConfigData, ReadConfigErrors, ReadConfigResponses, ReadResourceData, ReadResourceErrors, ReadResourceResponses, RecipeToYamlData, RecipeToYamlErrors, RecipeToYamlResponses, RecoverConfigData, RecoverConfigErrors, RecoverConfigResponses, RemoveConfigData, RemoveConfigErrors, RemoveConfigResponses, RemoveCustomProviderData, RemoveCustomProviderErrors, RemoveCustomProviderResponses, RemoveExtensionData, RemoveExtensionErrors, RemoveExtensionResponses, ReplyData, ReplyErrors, ReplyResponses, RestartAgentData, RestartAgentErrors, RestartAgentResponses, ResumeAgentData, ResumeAgentErrors, ResumeAgentResponses, RunNowHandlerData, RunNowHandlerErrors, RunNowHandlerResponses, SaveRecipeData, SaveRecipeErrors, SaveRecipeResponses, ScanRecipeData, ScanRecipeResponses, ScheduleRecipeData, ScheduleRecipeErrors, ScheduleRecipeResponses, SendTelemetryEventData, SendTelemetryEventResponses, SessionsHandlerData, SessionsHandlerErrors, SessionsHandlerResponses, SetConfigProviderData, SetRecipeSlashCommandData, SetRecipeSlashCommandErrors, SetRecipeSlashCommandResponses, StartAgentData, StartAgentErrors, StartAgentResponses, StartOpenrouterSetupData, StartOpenrouterSetupResponses, StartTetrateSetupData, StartTetrateSetupResponses, StartTunnelData, StartTunnelErrors, StartTunnelResponses, StatusData, StatusResponses, StopAgentData, StopAgentErrors, StopAgentResponses, StopTunnelData, StopTunnelErrors, StopTunnelResponses, SystemInfoData, SystemInfoResponses, UnpauseScheduleData, UnpauseScheduleErrors, UnpauseScheduleResponses, UpdateAgentProviderData, UpdateAgentProviderErrors, UpdateAgentProviderResponses, UpdateCustomProviderData, UpdateCustomProviderErrors, UpdateCustomProviderResponses, UpdateFromSessionData, UpdateFromSessionErrors, UpdateFromSessionResponses, UpdateScheduleData, UpdateScheduleErrors, UpdateScheduleResponses, UpdateSessionNameData, UpdateSessionNameErrors, UpdateSessionNameResponses, UpdateSessionUserRecipeValuesData, UpdateSessionUserRecipeValuesErrors, UpdateSessionUserRecipeValuesResponses, UpdateWorkingDirData, UpdateWorkingDirErrors, UpdateWorkingDirResponses, UpsertConfigData, UpsertConfigErrors, UpsertConfigResponses, UpsertPermissionsData, UpsertPermissionsErrors, UpsertPermissionsResponses, ValidateConfigData, ValidateConfigErrors, ValidateConfigResponses } from './types.gen'; export type Options = Options2 & { /** @@ -45,6 +45,8 @@ export const callTool = (options: Options< } }); +export const listApps = (options?: Options) => (options?.client ?? client).get({ url: '/agent/list_apps', ...options }); + export const readResource = (options: Options) => (options.client ?? client).post({ url: '/agent/read_resource', ...options, @@ -90,6 +92,15 @@ export const startAgent = (options: Option } }); +export const stopAgent = (options: Options) => (options.client ?? client).post({ + url: '/agent/stop', + ...options, + headers: { + 'Content-Type': 'application/json', + ...options.headers + } +}); + export const getTools = (options: Options) => (options.client ?? client).get({ url: '/agent/tools', ...options }); export const updateFromSession = (options: Options) => (options.client ?? client).post({ diff --git a/ui/desktop/src/api/types.gen.ts b/ui/desktop/src/api/types.gen.ts index e100560eae7c..6a2e2e9fc64d 100644 --- a/ui/desktop/src/api/types.gen.ts +++ b/ui/desktop/src/api/types.gen.ts @@ -364,6 +364,13 @@ export type GetToolsQuery = { session_id: string; }; +/** + * A Goose App combining MCP resource data with Goose-specific metadata + */ +export type GooseApp = McpAppResource & (WindowProps | null) & { + mcpServer?: string | null; +}; + export type Icon = { mimeType?: string; sizes?: Array; @@ -399,6 +406,14 @@ export type KillJobResponse = { message: string; }; +export type ListAppsRequest = { + session_id?: string | null; +}; + +export type ListAppsResponse = { + apps: Array; +}; + export type ListRecipeResponse = { manifests: Array; }; @@ -967,6 +982,10 @@ export type StartAgentRequest = { working_dir: string; }; +export type StopAgentRequest = { + session_id: string; +}; + export type SubRecipe = { description?: string | null; name: string; @@ -1193,6 +1212,12 @@ export type UpsertPermissionsQuery = { tool_permissions: Array; }; +export type WindowProps = { + height: number; + resizable: boolean; + width: number; +}; + export type ConfirmToolActionData = { body: ConfirmToolActionRequest; path?: never; @@ -1284,6 +1309,37 @@ export type CallToolResponses = { export type CallToolResponse2 = CallToolResponses[keyof CallToolResponses]; +export type ListAppsData = { + body?: never; + path?: never; + query?: { + session_id?: string | null; + }; + url: '/agent/list_apps'; +}; + +export type ListAppsErrors = { + /** + * Unauthorized - Invalid or missing API key + */ + 401: ErrorResponse; + /** + * Internal server error + */ + 500: ErrorResponse; +}; + +export type ListAppsError = ListAppsErrors[keyof ListAppsErrors]; + +export type ListAppsResponses = { + /** + * List of apps retrieved successfully + */ + 200: ListAppsResponse; +}; + +export type ListAppsResponse2 = ListAppsResponses[keyof ListAppsResponses]; + export type ReadResourceData = { body: ReadResourceRequest; path?: never; @@ -1445,6 +1501,37 @@ export type StartAgentResponses = { export type StartAgentResponse = StartAgentResponses[keyof StartAgentResponses]; +export type StopAgentData = { + body: StopAgentRequest; + path?: never; + query?: never; + url: '/agent/stop'; +}; + +export type StopAgentErrors = { + /** + * Unauthorized - invalid secret key + */ + 401: unknown; + /** + * Session not found + */ + 404: unknown; + /** + * Internal server error + */ + 500: unknown; +}; + +export type StopAgentResponses = { + /** + * Agent stopped successfully + */ + 200: string; +}; + +export type StopAgentResponse = StopAgentResponses[keyof StopAgentResponses]; + export type GetToolsData = { body?: never; path?: never; diff --git a/ui/desktop/src/components/GooseSidebar/AppSidebar.tsx b/ui/desktop/src/components/GooseSidebar/AppSidebar.tsx index b91b21adf015..02787717ff7f 100644 --- a/ui/desktop/src/components/GooseSidebar/AppSidebar.tsx +++ b/ui/desktop/src/components/GooseSidebar/AppSidebar.tsx @@ -1,5 +1,5 @@ -import React, { useEffect, useRef } from 'react'; -import { FileText, Clock, Home, Puzzle, History } from 'lucide-react'; +import React, { useEffect, useRef, useState } from 'react'; +import { FileText, Clock, Home, Puzzle, History, AppWindow } from 'lucide-react'; import { useNavigate, useSearchParams } from 'react-router-dom'; import { SidebarContent, @@ -16,6 +16,7 @@ import { ViewOptions, View } from '../../utils/navigationUtils'; import { useChatContext } from '../../contexts/ChatContext'; import { DEFAULT_CHAT_TITLE } from '../../contexts/ChatContext'; import EnvironmentBadge from './EnvironmentBadge'; +import { listApps } from '../../api'; interface SidebarProps { onSelectSession: (sessionId: string) => void; @@ -84,6 +85,13 @@ const menuItems: NavigationEntry[] = [ icon: Puzzle, tooltip: 'Manage your extensions', }, + { + type: 'item', + path: '/apps', + label: 'Apps', + icon: AppWindow, + tooltip: 'Browse and launch MCP apps', + }, { type: 'separator' }, { type: 'item', @@ -100,6 +108,7 @@ const AppSidebar: React.FC = ({ currentPath }) => { const chatContext = useChatContext(); const lastSessionIdRef = useRef(null); const currentSessionId = currentPath === '/pair' ? searchParams.get('resumeSessionId') : null; + const [hasApps, setHasApps] = useState(false); useEffect(() => { if (currentSessionId) { @@ -108,12 +117,19 @@ const AppSidebar: React.FC = ({ currentPath }) => { }, [currentSessionId]); useEffect(() => { - const timer = setTimeout(() => { - // setIsVisible(true); - }, 100); - - return () => clearTimeout(timer); - }, []); + const checkApps = async () => { + try { + const response = await listApps({ + throwOnError: true, + }); + setHasApps((response.data?.apps || []).length > 0); + } catch (err) { + console.warn('Failed to check for apps:', err); + } + }; + + checkApps(); + }, [currentPath]); useEffect(() => { const currentItem = menuItems.find( @@ -179,10 +195,19 @@ const AppSidebar: React.FC = ({ currentPath }) => { ); }; + const visibleMenuItems = menuItems.filter((entry) => { + if (entry.type === 'item' && entry.path === '/apps') { + return hasApps; + } + return true; + }); + return ( <> - {menuItems.map((entry, index) => renderMenuItem(entry, index))} + + {visibleMenuItems.map((entry, index) => renderMenuItem(entry, index))} + diff --git a/ui/desktop/src/components/McpApps/McpAppRenderer.tsx b/ui/desktop/src/components/McpApps/McpAppRenderer.tsx index 993142575192..e3df201c114d 100644 --- a/ui/desktop/src/components/McpApps/McpAppRenderer.tsx +++ b/ui/desktop/src/components/McpApps/McpAppRenderer.tsx @@ -24,12 +24,14 @@ import { readResource, callTool } from '../../api'; interface McpAppRendererProps { resourceUri: string; extensionName: string; - sessionId: string; + sessionId?: string | null; toolInput?: ToolInput; toolInputPartial?: ToolInputPartial; toolResult?: ToolResult; toolCancelled?: ToolCancelled; append?: (text: string) => void; + fullscreen?: boolean; + cachedHtml?: string; } interface ResourceData { @@ -47,9 +49,11 @@ export default function McpAppRenderer({ toolResult, toolCancelled, append, + fullscreen = false, + cachedHtml, }: McpAppRendererProps) { const [resource, setResource] = useState({ - html: null, + html: cachedHtml || null, csp: null, prefersBorder: true, }); @@ -57,6 +61,10 @@ export default function McpAppRenderer({ const [iframeHeight, setIframeHeight] = useState(DEFAULT_IFRAME_HEIGHT); useEffect(() => { + if (!sessionId) { + return; + } + const fetchResource = async () => { try { const response = await readResource({ @@ -73,19 +81,25 @@ export default function McpAppRenderer({ | { ui?: { csp?: CspMetadata; prefersBorder?: boolean } } | undefined; - setResource({ - html: content.text, - csp: meta?.ui?.csp || null, - prefersBorder: meta?.ui?.prefersBorder ?? true, - }); + if (content.text !== cachedHtml) { + setResource({ + html: content.text, + csp: meta?.ui?.csp || null, + prefersBorder: meta?.ui?.prefersBorder ?? true, + }); + } } } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to load resource'); + if (!cachedHtml) { + setError(err instanceof Error ? err.message : 'Failed to load resource'); + } else { + console.warn('Failed to fetch fresh resource, using cached version:', err); + } } }; fetchResource(); - }, [resourceUri, extensionName, sessionId]); + }, [resourceUri, extensionName, sessionId, cachedHtml]); const handleMcpRequest = useCallback( async ( @@ -93,6 +107,12 @@ export default function McpAppRenderer({ params: Record = {}, _id?: string | number ): Promise => { + // Methods that require a session + const requiresSession = ['tools/call', 'resources/read']; + if (requiresSession.includes(method) && !sessionId) { + throw new Error('Session not initialized for MCP request'); + } + switch (method) { case 'ui/open-link': { const { url } = params as McpMethodParams['ui/open-link']; @@ -121,7 +141,7 @@ export default function McpAppRenderer({ const fullToolName = `${extensionName}__${name}`; const response = await callTool({ body: { - session_id: sessionId, + session_id: sessionId!, name: fullToolName, arguments: args || {}, }, @@ -139,7 +159,7 @@ export default function McpAppRenderer({ const { uri } = params as McpMethodParams['resources/read']; const response = await readResource({ body: { - session_id: sessionId, + session_id: sessionId!, uri, extension_name: extensionName, }, @@ -193,6 +213,33 @@ export default function McpAppRenderer({ ); } + if (fullscreen) { + return proxyUrl ? ( +