Create / edit recipe form unification and improvements (#4693)
This commit is contained in:
@@ -6,7 +6,6 @@ use goose::config::ExtensionEntry;
|
||||
use goose::conversation::Conversation;
|
||||
use goose::permission::permission_confirmation::PrincipalType;
|
||||
use goose::providers::base::{ConfigKey, ModelInfo, ProviderMetadata};
|
||||
|
||||
use goose::session::{Session, SessionInsights};
|
||||
use rmcp::model::{
|
||||
Annotations, Content, EmbeddedResource, Icon, ImageContent, JsonObject, RawAudioContent,
|
||||
@@ -353,6 +352,7 @@ derive_utoipa!(Icon as IconSchema);
|
||||
super::routes::session::get_session_insights,
|
||||
super::routes::session::update_session_description,
|
||||
super::routes::session::delete_session,
|
||||
super::routes::session::update_session_user_recipe_values,
|
||||
super::routes::schedule::create_schedule,
|
||||
super::routes::schedule::list_schedules,
|
||||
super::routes::schedule::delete_schedule,
|
||||
@@ -391,6 +391,7 @@ derive_utoipa!(Icon as IconSchema);
|
||||
super::routes::context::ContextManageResponse,
|
||||
super::routes::session::SessionListResponse,
|
||||
super::routes::session::UpdateSessionDescriptionRequest,
|
||||
super::routes::session::UpdateSessionUserRecipeValuesRequest,
|
||||
Message,
|
||||
MessageContent,
|
||||
MessageMetadata,
|
||||
|
||||
@@ -4,10 +4,10 @@ use std::sync::Arc;
|
||||
|
||||
use axum::routing::get;
|
||||
use axum::{extract::State, http::StatusCode, routing::post, Json, Router};
|
||||
use goose::conversation::{message::Message, Conversation};
|
||||
use goose::recipe::recipe_library;
|
||||
use goose::recipe::Recipe;
|
||||
use goose::recipe_deeplink;
|
||||
use goose::session::SessionManager;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
@@ -18,16 +18,10 @@ use crate::state::AppState;
|
||||
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
pub struct CreateRecipeRequest {
|
||||
messages: Vec<Message>,
|
||||
// Required metadata
|
||||
title: String,
|
||||
description: String,
|
||||
session_id: String,
|
||||
// Optional fields
|
||||
#[serde(default)]
|
||||
activities: Option<Vec<String>>,
|
||||
#[serde(default)]
|
||||
author: Option<AuthorRequest>,
|
||||
session_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, ToSchema)]
|
||||
@@ -127,25 +121,38 @@ async fn create_recipe(
|
||||
Json(request): Json<CreateRecipeRequest>,
|
||||
) -> Result<Json<CreateRecipeResponse>, StatusCode> {
|
||||
tracing::info!(
|
||||
"Recipe creation request received with {} messages",
|
||||
request.messages.len()
|
||||
"Recipe creation request received for session_id: {}",
|
||||
request.session_id
|
||||
);
|
||||
|
||||
// Load messages from session
|
||||
let session = match SessionManager::get_session(&request.session_id, true).await {
|
||||
Ok(session) => session,
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to get session: {}", e);
|
||||
return Err(StatusCode::INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
};
|
||||
|
||||
let conversation = match session.conversation {
|
||||
Some(conversation) => conversation,
|
||||
None => {
|
||||
let error_message = "Session has no conversation".to_string();
|
||||
let error_response = CreateRecipeResponse {
|
||||
recipe: None,
|
||||
error: Some(error_message),
|
||||
};
|
||||
return Ok(Json(error_response));
|
||||
}
|
||||
};
|
||||
|
||||
let agent = state.get_agent_for_route(request.session_id).await?;
|
||||
|
||||
// Create base recipe from agent state and messages
|
||||
let recipe_result = agent
|
||||
.create_recipe(Conversation::new_unvalidated(request.messages))
|
||||
.await;
|
||||
let recipe_result = agent.create_recipe(conversation).await;
|
||||
|
||||
match recipe_result {
|
||||
Ok(mut recipe) => {
|
||||
recipe.title = request.title;
|
||||
recipe.description = request.description;
|
||||
if request.activities.is_some() {
|
||||
recipe.activities = request.activities
|
||||
};
|
||||
|
||||
if let Some(author_req) = request.author {
|
||||
recipe.author = Some(goose::recipe::Author {
|
||||
contact: author_req.contact,
|
||||
@@ -160,7 +167,11 @@ async fn create_recipe(
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Error details: {:?}", e);
|
||||
Err(StatusCode::BAD_REQUEST)
|
||||
let error_response = CreateRecipeResponse {
|
||||
recipe: None,
|
||||
error: Some(format!("Failed to create recipe: {}", e)),
|
||||
};
|
||||
Ok(Json(error_response))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,7 +252,7 @@ async fn scan_recipe(
|
||||
async fn list_recipes(
|
||||
State(state): State<Arc<AppState>>,
|
||||
) -> Result<Json<ListRecipeResponse>, StatusCode> {
|
||||
let recipe_manifest_with_paths = get_all_recipes_manifests().unwrap();
|
||||
let recipe_manifest_with_paths = get_all_recipes_manifests().unwrap_or_default();
|
||||
let mut recipe_file_hash_map = HashMap::new();
|
||||
let recipe_manifest_responses = recipe_manifest_with_paths
|
||||
.iter()
|
||||
|
||||
@@ -8,6 +8,7 @@ use axum::{
|
||||
use goose::session::session_manager::SessionInsights;
|
||||
use goose::session::{Session, SessionManager};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
@@ -25,6 +26,13 @@ pub struct UpdateSessionDescriptionRequest {
|
||||
description: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct UpdateSessionUserRecipeValuesRequest {
|
||||
/// Recipe parameter values entered by the user
|
||||
user_recipe_values: HashMap<String, String>,
|
||||
}
|
||||
|
||||
const MAX_DESCRIPTION_LENGTH: usize = 200;
|
||||
|
||||
#[utoipa::path(
|
||||
@@ -128,6 +136,38 @@ async fn update_session_description(
|
||||
Ok(StatusCode::OK)
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
put,
|
||||
path = "/sessions/{session_id}/user_recipe_values",
|
||||
request_body = UpdateSessionUserRecipeValuesRequest,
|
||||
params(
|
||||
("session_id" = String, Path, description = "Unique identifier for the session")
|
||||
),
|
||||
responses(
|
||||
(status = 200, description = "Session user recipe values updated successfully"),
|
||||
(status = 401, description = "Unauthorized - Invalid or missing API key"),
|
||||
(status = 404, description = "Session not found"),
|
||||
(status = 500, description = "Internal server error")
|
||||
),
|
||||
security(
|
||||
("api_key" = [])
|
||||
),
|
||||
tag = "Session Management"
|
||||
)]
|
||||
// Update session user recipe parameter values
|
||||
async fn update_session_user_recipe_values(
|
||||
Path(session_id): Path<String>,
|
||||
Json(request): Json<UpdateSessionUserRecipeValuesRequest>,
|
||||
) -> Result<StatusCode, StatusCode> {
|
||||
SessionManager::update_session(&session_id)
|
||||
.user_recipe_values(Some(request.user_recipe_values))
|
||||
.apply()
|
||||
.await
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
|
||||
Ok(StatusCode::OK)
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
path = "/sessions/{session_id}",
|
||||
@@ -169,5 +209,9 @@ pub fn routes(state: Arc<AppState>) -> Router {
|
||||
"/sessions/{session_id}/description",
|
||||
put(update_session_description),
|
||||
)
|
||||
.route(
|
||||
"/sessions/{session_id}/user_recipe_values",
|
||||
put(update_session_user_recipe_values),
|
||||
)
|
||||
.with_state(state)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user