diff --git a/crates/goose-cli/src/cli.rs b/crates/goose-cli/src/cli.rs index 83cc474e33..96c4cf2270 100644 --- a/crates/goose-cli/src/cli.rs +++ b/crates/goose-cli/src/cli.rs @@ -322,15 +322,37 @@ async fn get_or_create_session_id( let session_manager = SessionManager::instance(); - let Some(id) = identifier else { - return if resume { + let resolved_id = if resume { + let Some(id) = identifier else { let sessions = session_manager.list_sessions().await?; let session_id = sessions .first() .map(|s| s.id.clone()) .ok_or_else(|| anyhow::anyhow!("No session found to resume"))?; - Ok(Some(session_id)) + return Ok(Some(session_id)); + }; + + if let Some(session_id) = id.session_id { + session_id + } else if let Some(name) = id.name { + let sessions = session_manager.list_sessions().await?; + sessions + .into_iter() + .find(|s| s.name == name || s.id == name) + .map(|s| s.id) + .ok_or_else(|| anyhow::anyhow!("No session found with name '{}'", name))? + } else if let Some(path) = id.path { + path.file_stem() + .and_then(|s| s.to_str()) + .map(|s| s.to_string()) + .ok_or_else(|| { + anyhow::anyhow!("Could not extract session ID from path: {:?}", path) + })? } else { + return Err(anyhow::anyhow!("Invalid identifier")); + } + } else { + let Some(id) = identifier else { let session = session_manager .create_session( std::env::current_dir()?, @@ -338,58 +360,39 @@ async fn get_or_create_session_id( SessionType::User, ) .await?; - Ok(Some(session.id)) + return Ok(Some(session.id)); }; - }; - if let Some(session_id) = id.session_id { - Ok(Some(session_id)) - } else if let Some(name) = id.name { - if resume { - let sessions = session_manager.list_sessions().await?; - let session_id = sessions - .into_iter() - .find(|s| s.name == name || s.id == name) - .map(|s| s.id) - .ok_or_else(|| anyhow::anyhow!("No session found with name '{}'", name))?; - Ok(Some(session_id)) - } else { - let session = session_manager - .create_session(std::env::current_dir()?, name.clone(), SessionType::User) - .await?; + if id.session_id.is_some() { + return Err(anyhow::anyhow!("Cannot use --session-id without --resume")); + } + let has_user_provided_name = id.name.is_some(); + let name = id.name.unwrap_or_else(|| "CLI Session".to_string()); + let session = session_manager + .create_session(std::env::current_dir()?, name.clone(), SessionType::User) + .await?; + + if has_user_provided_name { session_manager .update(&session.id) .user_provided_name(name) .apply() .await?; - - Ok(Some(session.id)) } - } else if let Some(path) = id.path { - let session_id = path - .file_stem() - .and_then(|s| s.to_str()) - .map(|s| s.to_string()) - .ok_or_else(|| anyhow::anyhow!("Could not extract session ID from path: {:?}", path))?; - Ok(Some(session_id)) - } else { - let session = session_manager - .create_session( - std::env::current_dir()?, - "CLI Session".to_string(), - SessionType::User, - ) - .await?; - Ok(Some(session.id)) - } + + return Ok(Some(session.id)); + }; + + Ok(Some(resolved_id)) } async fn lookup_session_id(identifier: Identifier) -> Result { + let session_manager = SessionManager::instance(); + if let Some(session_id) = identifier.session_id { Ok(session_id) } else if let Some(name) = identifier.name { - let session_manager = SessionManager::instance(); let sessions = session_manager.list_sessions().await?; sessions .into_iter() @@ -722,6 +725,15 @@ enum Command { )] resume: bool, + /// Fork a previous session (creates new session with copied history) + #[arg( + long, + requires = "resume", + help = "Fork a previous session (creates new session with copied history)", + long_help = "Create a new session by copying all messages from a previous session. Must be used with --resume. If --name or --session-id is provided, forks that specific session. Otherwise forks the most recently used session." + )] + fork: bool, + /// Show message history when resuming #[arg( long, @@ -1047,6 +1059,7 @@ async fn handle_session_subcommand(command: SessionCommand) -> Result<()> { async fn handle_interactive_session( identifier: Option, resume: bool, + fork: bool, history: bool, session_opts: SessionOptions, extension_opts: ExtensionOptions, @@ -1056,7 +1069,13 @@ async fn handle_interactive_session( } let session_start = std::time::Instant::now(); - let session_type = if resume { "resumed" } else { "new" }; + let session_type = if fork { + "forked" + } else if resume { + "resumed" + } else { + "new" + }; tracing::info!( counter.goose.session_starts = 1, @@ -1076,11 +1095,21 @@ async fn handle_interactive_session( } } - let session_id = get_or_create_session_id(identifier, resume, false).await?; + let mut session_id = get_or_create_session_id(identifier, resume, false).await?; + + if fork { + if let Some(id) = session_id { + let session_manager = SessionManager::instance(); + let original = session_manager.get_session(&id, false).await?; + let copied = session_manager.copy_session(&id, original.name).await?; + session_id = Some(copied.id); + } + } let mut session: crate::CliSession = build_session(SessionBuilderConfig { session_id, resume, + fork, no_session: false, extensions: extension_opts.extensions, streamable_http_extensions: extension_opts.streamable_http_extensions, @@ -1099,7 +1128,7 @@ async fn handle_interactive_session( }) .await; - if resume && history { + if (resume || fork) && history { session.render_message_history(); } @@ -1283,6 +1312,7 @@ async fn handle_run_command( let mut session = build_session(SessionBuilderConfig { session_id, resume: run_behavior.resume, + fork: false, no_session: run_behavior.no_session, extensions: extension_opts.extensions, streamable_http_extensions: extension_opts.streamable_http_extensions, @@ -1407,6 +1437,7 @@ async fn handle_default_session() -> Result<()> { let mut session = build_session(SessionBuilderConfig { session_id, resume: false, + fork: false, no_session: false, extensions: Vec::new(), streamable_http_extensions: Vec::new(), @@ -1458,12 +1489,20 @@ pub async fn cli() -> anyhow::Result<()> { command: None, identifier, resume, + fork, history, session_opts, extension_opts, }) => { - handle_interactive_session(identifier, resume, history, session_opts, extension_opts) - .await + handle_interactive_session( + identifier, + resume, + fork, + history, + session_opts, + extension_opts, + ) + .await } Some(Command::Project {}) => { handle_project_default()?; diff --git a/crates/goose-cli/src/commands/bench.rs b/crates/goose-cli/src/commands/bench.rs index bac2ef88ed..d614c0049b 100644 --- a/crates/goose-cli/src/commands/bench.rs +++ b/crates/goose-cli/src/commands/bench.rs @@ -37,6 +37,7 @@ pub async fn agent_generator( let base_session = build_session(SessionBuilderConfig { session_id: Some(session_id), resume: false, + fork: false, no_session: false, extensions: requirements.external, streamable_http_extensions: requirements.streamable_http, diff --git a/crates/goose-cli/src/session/builder.rs b/crates/goose-cli/src/session/builder.rs index 4ecc96ea38..788456446a 100644 --- a/crates/goose-cli/src/session/builder.rs +++ b/crates/goose-cli/src/session/builder.rs @@ -82,6 +82,8 @@ pub struct SessionBuilderConfig { pub session_id: Option, /// Whether to resume an existing session pub resume: bool, + /// Whether to fork an existing session (creates a copy of the original/existing session then resumes the copy) + pub fork: bool, /// Whether to run without a session file pub no_session: bool, /// List of stdio extension commands to add @@ -121,6 +123,7 @@ impl Default for SessionBuilderConfig { SessionBuilderConfig { session_id: None, resume: false, + fork: false, no_session: false, extensions: Vec::new(), streamable_http_extensions: Vec::new(), @@ -659,6 +662,7 @@ mod tests { let config = SessionBuilderConfig { session_id: None, resume: false, + fork: false, no_session: false, extensions: vec!["echo test".to_string()], streamable_http_extensions: vec!["http://localhost:8080/mcp".to_string()], @@ -705,6 +709,7 @@ mod tests { assert!(config.scheduled_job_id.is_none()); assert!(!config.interactive); assert!(!config.quiet); + assert!(!config.fork); } #[tokio::test] diff --git a/crates/goose-server/src/openapi.rs b/crates/goose-server/src/openapi.rs index be4634b17d..3cc8cac406 100644 --- a/crates/goose-server/src/openapi.rs +++ b/crates/goose-server/src/openapi.rs @@ -380,7 +380,7 @@ derive_utoipa!(Icon as IconSchema); super::routes::session::export_session, super::routes::session::import_session, super::routes::session::update_session_user_recipe_values, - super::routes::session::edit_message, + super::routes::session::fork_session, super::routes::session::get_session_extensions, super::routes::schedule::create_schedule, super::routes::schedule::list_schedules, @@ -442,9 +442,8 @@ derive_utoipa!(Icon as IconSchema); super::routes::session::UpdateSessionNameRequest, super::routes::session::UpdateSessionUserRecipeValuesRequest, super::routes::session::UpdateSessionUserRecipeValuesResponse, - super::routes::session::EditType, - super::routes::session::EditMessageRequest, - super::routes::session::EditMessageResponse, + super::routes::session::ForkRequest, + super::routes::session::ForkResponse, super::routes::session::SessionExtensionsResponse, Message, MessageContent, diff --git a/crates/goose-server/src/routes/session.rs b/crates/goose-server/src/routes/session.rs index f9ac4278be..c214c86f4c 100644 --- a/crates/goose-server/src/routes/session.rs +++ b/crates/goose-server/src/routes/session.rs @@ -51,28 +51,17 @@ pub struct ImportSessionRequest { json: String, } -#[derive(Debug, Deserialize, ToSchema)] -#[serde(rename_all = "lowercase")] -pub enum EditType { - Fork, - Edit, -} - #[derive(Deserialize, ToSchema)] #[serde(rename_all = "camelCase")] -pub struct EditMessageRequest { - timestamp: i64, - #[serde(default = "default_edit_type")] - edit_type: EditType, -} - -fn default_edit_type() -> EditType { - EditType::Fork +pub struct ForkRequest { + timestamp: Option, + truncate: bool, + copy: bool, } #[derive(Serialize, ToSchema)] #[serde(rename_all = "camelCase")] -pub struct EditMessageResponse { +pub struct ForkResponse { session_id: String, } @@ -369,16 +358,16 @@ async fn import_session( #[utoipa::path( post, - path = "/sessions/{session_id}/edit_message", - request_body = EditMessageRequest, + path = "/sessions/{session_id}/fork", + request_body = ForkRequest, params( ("session_id" = String, Path, description = "Unique identifier for the session") ), responses( - (status = 200, description = "Session prepared for editing - frontend should submit the edited message", body = EditMessageResponse), - (status = 400, description = "Bad request - Invalid message timestamp"), + (status = 200, description = "Session forked successfully", body = ForkResponse), + (status = 400, description = "Bad request - truncate=true requires timestamp"), (status = 401, description = "Unauthorized - Invalid or missing API key"), - (status = 404, description = "Session or message not found"), + (status = 404, description = "Session not found"), (status = 500, description = "Internal server error") ), security( @@ -386,51 +375,75 @@ async fn import_session( ), tag = "Session Management" )] -async fn edit_message( +async fn fork_session( State(state): State>, Path(session_id): Path, - Json(request): Json, -) -> Result, StatusCode> { - let manager = state.session_manager(); - match request.edit_type { - EditType::Fork => { - let new_session = manager - .copy_session(&session_id, "(edited)".to_string()) - .await - .map_err(|e| { - tracing::error!("Failed to copy session: {}", e); - goose::posthog::emit_error("session_copy_failed", &e.to_string()); - StatusCode::INTERNAL_SERVER_ERROR - })?; - - manager - .truncate_conversation(&new_session.id, request.timestamp) - .await - .map_err(|e| { - tracing::error!("Failed to truncate conversation: {}", e); - goose::posthog::emit_error("session_truncate_failed", &e.to_string()); - StatusCode::INTERNAL_SERVER_ERROR - })?; - - Ok(Json(EditMessageResponse { - session_id: new_session.id, - })) - } - EditType::Edit => { - manager - .truncate_conversation(&session_id, request.timestamp) - .await - .map_err(|e| { - tracing::error!("Failed to truncate conversation: {}", e); - goose::posthog::emit_error("session_truncate_failed", &e.to_string()); - StatusCode::INTERNAL_SERVER_ERROR - })?; - - Ok(Json(EditMessageResponse { - session_id: session_id.clone(), - })) - } + Json(request): Json, +) -> Result, ErrorResponse> { + if request.truncate && request.timestamp.is_none() { + return Err(ErrorResponse { + message: "truncate=true requires a timestamp".to_string(), + status: StatusCode::BAD_REQUEST, + }); } + + let session_manager = state.session_manager(); + + let target_session_id = if request.copy { + let original = session_manager + .get_session(&session_id, false) + .await + .map_err(|e| { + tracing::error!("Failed to get session: {}", e); + goose::posthog::emit_error("session_get_failed", &e.to_string()); + ErrorResponse { + message: if e.to_string().contains("not found") { + format!("Session {} not found", session_id) + } else { + format!("Failed to get session: {}", e) + }, + status: if e.to_string().contains("not found") { + StatusCode::NOT_FOUND + } else { + StatusCode::INTERNAL_SERVER_ERROR + }, + } + })?; + + let copied = session_manager + .copy_session(&session_id, original.name) + .await + .map_err(|e| { + tracing::error!("Failed to copy session: {}", e); + goose::posthog::emit_error("session_copy_failed", &e.to_string()); + ErrorResponse { + message: format!("Failed to copy session: {}", e), + status: StatusCode::INTERNAL_SERVER_ERROR, + } + })?; + + copied.id + } else { + session_id.clone() + }; + + if request.truncate { + session_manager + .truncate_conversation(&target_session_id, request.timestamp.unwrap_or(0)) + .await + .map_err(|e| { + tracing::error!("Failed to truncate conversation: {}", e); + goose::posthog::emit_error("session_truncate_failed", &e.to_string()); + ErrorResponse { + message: format!("Failed to truncate conversation: {}", e), + status: StatusCode::INTERNAL_SERVER_ERROR, + } + })?; + } + + Ok(Json(ForkResponse { + session_id: target_session_id, + })) } #[derive(Serialize, ToSchema)] @@ -487,7 +500,7 @@ pub fn routes(state: Arc) -> Router { "/sessions/{session_id}/user_recipe_values", put(update_session_user_recipe_values), ) - .route("/sessions/{session_id}/edit_message", post(edit_message)) + .route("/sessions/{session_id}/fork", post(fork_session)) .route( "/sessions/{session_id}/extensions", get(get_session_extensions), diff --git a/crates/goose/src/session/session_manager.rs b/crates/goose/src/session/session_manager.rs index 7523ccc337..4b59c0b1a9 100644 --- a/crates/goose/src/session/session_manager.rs +++ b/crates/goose/src/session/session_manager.rs @@ -1285,14 +1285,23 @@ impl SessionStorage { ) .await?; - session_manager + let mut builder = session_manager .update(&new_session.id) .extension_data(original_session.extension_data) .schedule_id(original_session.schedule_id) .recipe(original_session.recipe) - .user_recipe_values(original_session.user_recipe_values) - .apply() - .await?; + .user_recipe_values(original_session.user_recipe_values); + + // Preserve provider and model config from original session + if let Some(provider_name) = original_session.provider_name { + builder = builder.provider_name(provider_name); + } + + if let Some(model_config) = original_session.model_config { + builder = builder.model_config(model_config); + } + + builder.apply().await?; if let Some(conversation) = original_session.conversation { self.replace_conversation(&new_session.id, &conversation) diff --git a/ui/desktop/openapi.json b/ui/desktop/openapi.json index 267cdfa8a6..de6e90d72a 100644 --- a/ui/desktop/openapi.json +++ b/ui/desktop/openapi.json @@ -2472,64 +2472,6 @@ ] } }, - "/sessions/{session_id}/edit_message": { - "post": { - "tags": [ - "Session Management" - ], - "operationId": "edit_message", - "parameters": [ - { - "name": "session_id", - "in": "path", - "description": "Unique identifier for the session", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EditMessageRequest" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "Session prepared for editing - frontend should submit the edited message", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EditMessageResponse" - } - } - } - }, - "400": { - "description": "Bad request - Invalid message timestamp" - }, - "401": { - "description": "Unauthorized - Invalid or missing API key" - }, - "404": { - "description": "Session or message not found" - }, - "500": { - "description": "Internal server error" - } - }, - "security": [ - { - "api_key": [] - } - ] - } - }, "/sessions/{session_id}/export": { "get": { "tags": [ @@ -2620,6 +2562,64 @@ ] } }, + "/sessions/{session_id}/fork": { + "post": { + "tags": [ + "Session Management" + ], + "operationId": "fork_session", + "parameters": [ + { + "name": "session_id", + "in": "path", + "description": "Unique identifier for the session", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ForkRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Session forked successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ForkResponse" + } + } + } + }, + "400": { + "description": "Bad request - truncate=true requires timestamp" + }, + "401": { + "description": "Unauthorized - Invalid or missing API key" + }, + "404": { + "description": "Session not found" + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, "/sessions/{session_id}/name": { "put": { "tags": [ @@ -3453,39 +3453,6 @@ } } }, - "EditMessageRequest": { - "type": "object", - "required": [ - "timestamp" - ], - "properties": { - "editType": { - "$ref": "#/components/schemas/EditType" - }, - "timestamp": { - "type": "integer", - "format": "int64" - } - } - }, - "EditMessageResponse": { - "type": "object", - "required": [ - "sessionId" - ], - "properties": { - "sessionId": { - "type": "string" - } - } - }, - "EditType": { - "type": "string", - "enum": [ - "fork", - "edit" - ] - }, "EmbeddedResource": { "type": "object", "required": [ @@ -3961,6 +3928,37 @@ } } }, + "ForkRequest": { + "type": "object", + "required": [ + "truncate", + "copy" + ], + "properties": { + "copy": { + "type": "boolean" + }, + "timestamp": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "truncate": { + "type": "boolean" + } + } + }, + "ForkResponse": { + "type": "object", + "required": [ + "sessionId" + ], + "properties": { + "sessionId": { + "type": "string" + } + } + }, "FrontendToolRequest": { "type": "object", "required": [ diff --git a/ui/desktop/src/api/index.ts b/ui/desktop/src/api/index.ts index aa0b2b31fe..e1118ac1a3 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, getPrompt, getPrompts, 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, resetPrompt, restartAgent, resumeAgent, runNowHandler, savePrompt, 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, GetPromptData, GetPromptErrors, GetPromptResponse, GetPromptResponses, GetPromptsData, GetPromptsResponse, GetPromptsResponses, 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, PromptContentResponse, PromptsListResponse, 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, 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, SavePromptData, SavePromptErrors, SavePromptRequest, SavePromptResponse, SavePromptResponses, 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, Template, 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'; +export { addExtension, agentAddExtension, agentRemoveExtension, backupConfig, callTool, checkProvider, confirmToolAction, createCustomProvider, createRecipe, createSchedule, decodeRecipe, deleteRecipe, deleteSchedule, deleteSession, detectProvider, diagnostics, encodeRecipe, exportSession, forkSession, getCustomProvider, getExtensions, getPricing, getPrompt, getPrompts, 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, resetPrompt, restartAgent, resumeAgent, runNowHandler, savePrompt, 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, EmbeddedResource, EncodeRecipeData, EncodeRecipeErrors, EncodeRecipeRequest, EncodeRecipeResponse, EncodeRecipeResponse2, EncodeRecipeResponses, Envs, ErrorResponse, ExportSessionData, ExportSessionErrors, ExportSessionResponse, ExportSessionResponses, ExtensionConfig, ExtensionData, ExtensionEntry, ExtensionLoadResult, ExtensionQuery, ExtensionResponse, ForkRequest, ForkResponse, ForkSessionData, ForkSessionErrors, ForkSessionResponse, ForkSessionResponses, FrontendToolRequest, GetCustomProviderData, GetCustomProviderErrors, GetCustomProviderResponse, GetCustomProviderResponses, GetExtensionsData, GetExtensionsErrors, GetExtensionsResponse, GetExtensionsResponses, GetPricingData, GetPricingResponse, GetPricingResponses, GetPromptData, GetPromptErrors, GetPromptResponse, GetPromptResponses, GetPromptsData, GetPromptsResponse, GetPromptsResponses, 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, PromptContentResponse, PromptsListResponse, 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, 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, SavePromptData, SavePromptErrors, SavePromptRequest, SavePromptResponse, SavePromptResponses, 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, Template, 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 2026f2d8f0..db9f8d7250 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, GetPromptData, GetPromptErrors, GetPromptResponses, GetPromptsData, GetPromptsResponses, 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, ResetPromptData, ResetPromptErrors, ResetPromptResponses, RestartAgentData, RestartAgentErrors, RestartAgentResponses, ResumeAgentData, ResumeAgentErrors, ResumeAgentResponses, RunNowHandlerData, RunNowHandlerErrors, RunNowHandlerResponses, SavePromptData, SavePromptErrors, SavePromptResponses, 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'; +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, EncodeRecipeData, EncodeRecipeErrors, EncodeRecipeResponses, ExportSessionData, ExportSessionErrors, ExportSessionResponses, ForkSessionData, ForkSessionErrors, ForkSessionResponses, GetCustomProviderData, GetCustomProviderErrors, GetCustomProviderResponses, GetExtensionsData, GetExtensionsErrors, GetExtensionsResponses, GetPricingData, GetPricingResponses, GetPromptData, GetPromptErrors, GetPromptResponses, GetPromptsData, GetPromptsResponses, 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, ResetPromptData, ResetPromptErrors, ResetPromptResponses, RestartAgentData, RestartAgentErrors, RestartAgentResponses, ResumeAgentData, ResumeAgentErrors, ResumeAgentResponses, RunNowHandlerData, RunNowHandlerErrors, RunNowHandlerResponses, SavePromptData, SavePromptErrors, SavePromptResponses, 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 & { /** @@ -428,8 +428,12 @@ export const deleteSession = (options: Opt export const getSession = (options: Options) => (options.client ?? client).get({ url: '/sessions/{session_id}', ...options }); -export const editMessage = (options: Options) => (options.client ?? client).post({ - url: '/sessions/{session_id}/edit_message', +export const exportSession = (options: Options) => (options.client ?? client).get({ url: '/sessions/{session_id}/export', ...options }); + +export const getSessionExtensions = (options: Options) => (options.client ?? client).get({ url: '/sessions/{session_id}/extensions', ...options }); + +export const forkSession = (options: Options) => (options.client ?? client).post({ + url: '/sessions/{session_id}/fork', ...options, headers: { 'Content-Type': 'application/json', @@ -437,10 +441,6 @@ export const editMessage = (options: Optio } }); -export const exportSession = (options: Options) => (options.client ?? client).get({ url: '/sessions/{session_id}/export', ...options }); - -export const getSessionExtensions = (options: Options) => (options.client ?? client).get({ url: '/sessions/{session_id}/extensions', ...options }); - export const updateSessionName = (options: Options) => (options.client ?? client).put({ url: '/sessions/{session_id}/name', ...options, diff --git a/ui/desktop/src/api/types.gen.ts b/ui/desktop/src/api/types.gen.ts index 63a51b16aa..bcef9d17ec 100644 --- a/ui/desktop/src/api/types.gen.ts +++ b/ui/desktop/src/api/types.gen.ts @@ -189,17 +189,6 @@ export type DetectProviderResponse = { provider_name: string; }; -export type EditMessageRequest = { - editType?: EditType; - timestamp: number; -}; - -export type EditMessageResponse = { - sessionId: string; -}; - -export type EditType = 'fork' | 'edit'; - export type EmbeddedResource = { _meta?: { [key: string]: unknown; @@ -352,6 +341,16 @@ export type ExtensionResponse = { warnings?: Array; }; +export type ForkRequest = { + copy: boolean; + timestamp?: number | null; + truncate: boolean; +}; + +export type ForkResponse = { + sessionId: string; +}; + export type FrontendToolRequest = { id: string; toolCall: { @@ -3178,46 +3177,6 @@ export type GetSessionResponses = { export type GetSessionResponse = GetSessionResponses[keyof GetSessionResponses]; -export type EditMessageData = { - body: EditMessageRequest; - path: { - /** - * Unique identifier for the session - */ - session_id: string; - }; - query?: never; - url: '/sessions/{session_id}/edit_message'; -}; - -export type EditMessageErrors = { - /** - * Bad request - Invalid message timestamp - */ - 400: unknown; - /** - * Unauthorized - Invalid or missing API key - */ - 401: unknown; - /** - * Session or message not found - */ - 404: unknown; - /** - * Internal server error - */ - 500: unknown; -}; - -export type EditMessageResponses = { - /** - * Session prepared for editing - frontend should submit the edited message - */ - 200: EditMessageResponse; -}; - -export type EditMessageResponse2 = EditMessageResponses[keyof EditMessageResponses]; - export type ExportSessionData = { body?: never; path: { @@ -3290,6 +3249,46 @@ export type GetSessionExtensionsResponses = { export type GetSessionExtensionsResponse = GetSessionExtensionsResponses[keyof GetSessionExtensionsResponses]; +export type ForkSessionData = { + body: ForkRequest; + path: { + /** + * Unique identifier for the session + */ + session_id: string; + }; + query?: never; + url: '/sessions/{session_id}/fork'; +}; + +export type ForkSessionErrors = { + /** + * Bad request - truncate=true requires timestamp + */ + 400: unknown; + /** + * Unauthorized - Invalid or missing API key + */ + 401: unknown; + /** + * Session not found + */ + 404: unknown; + /** + * Internal server error + */ + 500: unknown; +}; + +export type ForkSessionResponses = { + /** + * Session forked successfully + */ + 200: ForkResponse; +}; + +export type ForkSessionResponse = ForkSessionResponses[keyof ForkSessionResponses]; + export type UpdateSessionNameData = { body: UpdateSessionNameRequest; path: { diff --git a/ui/desktop/src/components/ChatInput.tsx b/ui/desktop/src/components/ChatInput.tsx index a91e4507b4..659d469400 100644 --- a/ui/desktop/src/components/ChatInput.tsx +++ b/ui/desktop/src/components/ChatInput.tsx @@ -1,6 +1,6 @@ import { AppEvents } from '../constants/events'; import React, { useRef, useState, useEffect, useMemo, useCallback } from 'react'; -import { Bug, ScrollText, ChefHat } from 'lucide-react'; +import { Bug, ChefHat, ScrollText } from 'lucide-react'; import { Tooltip, TooltipContent, TooltipTrigger } from './ui/Tooltip'; import { Button } from './ui/button'; import type { View } from '../utils/navigationUtils'; diff --git a/ui/desktop/src/components/sessions/SessionListView.tsx b/ui/desktop/src/components/sessions/SessionListView.tsx index c4cebdacd2..a2178b1671 100644 --- a/ui/desktop/src/components/sessions/SessionListView.tsx +++ b/ui/desktop/src/components/sessions/SessionListView.tsx @@ -11,6 +11,7 @@ import { Download, Upload, ExternalLink, + Copy, Puzzle, } from 'lucide-react'; import { Card } from '../ui/card'; @@ -28,6 +29,7 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../ui/ import { deleteSession, exportSession, + forkSession, importSession, listSessions, Session, @@ -436,6 +438,25 @@ const SessionListView: React.FC = React.memo( setShowDeleteConfirmation(true); }, []); + const handleDuplicateSession = useCallback( + async (session: Session) => { + try { + await forkSession({ + path: { session_id: session.id }, + body: { truncate: false, copy: true }, + throwOnError: true, + }); + toast.success(`Session "${session.name}" duplicated successfully`); + await loadSessions(); + } catch (error) { + console.error('Error duplicating session:', error); + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + toast.error(`Failed to duplicate session: ${errorMessage}`); + } + }, + [loadSessions] + ); + const handleConfirmDelete = useCallback(async () => { if (!sessionToDelete) return; @@ -530,27 +551,37 @@ const SessionListView: React.FC = React.memo( const SessionItem = React.memo(function SessionItem({ session, onEditClick, + onDuplicateClick, onDeleteClick, onExportClick, onOpenInNewWindow, }: { session: Session; onEditClick: (session: Session) => void; + onDuplicateClick: (session: Session) => void; onDeleteClick: (session: Session) => void; onExportClick: (session: Session, e: React.MouseEvent) => void; onOpenInNewWindow: (session: Session, e: React.MouseEvent) => void; }) { const handleEditClick = useCallback( (e: React.MouseEvent) => { - e.stopPropagation(); // Prevent card click + e.stopPropagation(); onEditClick(session); }, [onEditClick, session] ); + const handleDuplicateClick = useCallback( + (e: React.MouseEvent) => { + e.stopPropagation(); + onDuplicateClick(session); + }, + [onDuplicateClick, session] + ); + const handleDeleteClick = useCallback( (e: React.MouseEvent) => { - e.stopPropagation(); // Prevent card click + e.stopPropagation(); onDeleteClick(session); }, [onDeleteClick, session] @@ -605,6 +636,13 @@ const SessionListView: React.FC = React.memo( > +