mirror of
https://github.com/aaif-goose/goose.git
synced 2026-07-03 14:10:03 +02:00
Nicer API
This commit is contained in:
@@ -26,8 +26,7 @@ use crate::commands::session::{handle_session_list, handle_session_remove};
|
||||
use crate::recipes::extract_from_cli::extract_recipe_info_from_cli;
|
||||
use crate::recipes::recipe::{explain_recipe, render_recipe_as_yaml};
|
||||
use crate::session::{build_session, SessionBuilderConfig, SessionSettings};
|
||||
use goose::session::session_manager::SessionType;
|
||||
use goose::session::SessionManager;
|
||||
use goose::session::{SessionManager, SessionType};
|
||||
use goose_bench::bench_config::BenchRunConfig;
|
||||
use goose_bench::runners::bench_runner::BenchRunner;
|
||||
use goose_bench::runners::eval_runner::EvalRunner;
|
||||
@@ -97,7 +96,6 @@ async fn get_or_create_session_id(
|
||||
std::env::current_dir()?,
|
||||
"CLI Session".to_string(),
|
||||
SessionType::User,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
Ok(Some(session.id))
|
||||
@@ -120,7 +118,6 @@ async fn get_or_create_session_id(
|
||||
std::env::current_dir()?,
|
||||
name.clone(),
|
||||
SessionType::User,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -143,7 +140,6 @@ async fn get_or_create_session_id(
|
||||
std::env::current_dir()?,
|
||||
"CLI Session".to_string(),
|
||||
SessionType::User,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
Ok(Some(session.id))
|
||||
|
||||
@@ -9,8 +9,7 @@ use goose::conversation::message::{Message, MessageContent};
|
||||
use goose::conversation::Conversation;
|
||||
use goose::mcp_utils::ToolResult;
|
||||
use goose::providers::create;
|
||||
use goose::session::session_manager::SessionType;
|
||||
use goose::session::SessionManager;
|
||||
use goose::session::{SessionManager, SessionType};
|
||||
use rmcp::model::{CallToolResult, RawContent, ResourceContents, Role};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs;
|
||||
@@ -230,7 +229,6 @@ impl GooseAcpAgent {
|
||||
std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")),
|
||||
"ACP Session".to_string(),
|
||||
SessionType::Hidden,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -571,7 +569,6 @@ impl acp::Agent for GooseAcpAgent {
|
||||
std::env::current_dir().unwrap_or_default(),
|
||||
"ACP Session".to_string(), // just an initial name - may be replaced by maybe_update_name
|
||||
SessionType::User,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -1456,7 +1456,6 @@ pub async fn configure_tool_permissions_dialog() -> anyhow::Result<()> {
|
||||
std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")),
|
||||
"Tool Permission Configuration".to_string(),
|
||||
SessionType::Hidden,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -135,7 +135,6 @@ pub async fn handle_term_init(
|
||||
working_dir,
|
||||
"Goose Term Session".to_string(),
|
||||
SessionType::Terminal,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -15,8 +15,7 @@ use base64::Engine;
|
||||
use futures::{sink::SinkExt, stream::StreamExt};
|
||||
use goose::agents::{Agent, AgentEvent};
|
||||
use goose::conversation::message::Message as GooseMessage;
|
||||
use goose::session::session_manager::SessionType;
|
||||
use goose::session::SessionManager;
|
||||
use goose::session::{SessionManager, SessionType};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::{net::SocketAddr, sync::Arc};
|
||||
@@ -157,7 +156,6 @@ pub async fn handle_web(
|
||||
std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")),
|
||||
"Web Agent Initialization".to_string(),
|
||||
SessionType::Hidden,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -246,7 +244,6 @@ async fn serve_index(uri: Uri) -> Result<Redirect, (http::StatusCode, String)> {
|
||||
std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")),
|
||||
"Web session".to_string(),
|
||||
SessionType::User,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map_err(|err| (http::StatusCode::INTERNAL_SERVER_ERROR, err.to_string()))?;
|
||||
|
||||
@@ -9,8 +9,7 @@ use anyhow::Result;
|
||||
use goose::agents::Agent;
|
||||
use goose::model::ModelConfig;
|
||||
use goose::providers::{create, testprovider::TestProvider};
|
||||
use goose::session::session_manager::SessionType;
|
||||
use goose::session::SessionManager;
|
||||
use goose::session::{SessionManager, SessionType};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
@@ -221,7 +220,6 @@ where
|
||||
PathBuf::default(),
|
||||
"scenario-runner".to_string(),
|
||||
SessionType::Hidden,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -11,9 +11,7 @@ use goose::providers::create;
|
||||
use goose::recipe::{Response, SubRecipe};
|
||||
|
||||
use goose::agents::extension::PlatformExtensionContext;
|
||||
use goose::session::session_manager::SessionType;
|
||||
use goose::session::SessionManager;
|
||||
use goose::session::{EnabledExtensionsState, ExtensionState};
|
||||
use goose::session::{EnabledExtensionsState, ExtensionState, SessionManager, SessionType};
|
||||
use rustyline::EditMode;
|
||||
use std::collections::HashSet;
|
||||
use std::process;
|
||||
@@ -154,7 +152,6 @@ async fn offer_extension_debugging_help(
|
||||
std::env::current_dir()?,
|
||||
"CLI Session".to_string(),
|
||||
SessionType::Hidden,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -345,7 +342,6 @@ pub async fn build_session(session_config: SessionBuilderConfig) -> CliSession {
|
||||
working_dir,
|
||||
"CLI Session".to_string(),
|
||||
SessionType::Hidden,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect("Could not create session");
|
||||
|
||||
@@ -19,8 +19,7 @@ use goose::prompt_template::render_global_file;
|
||||
use goose::providers::create;
|
||||
use goose::recipe::Recipe;
|
||||
use goose::recipe_deeplink;
|
||||
use goose::session::session_manager::SessionType;
|
||||
use goose::session::{Session, SessionManager};
|
||||
use goose::session::{Session, SessionManager, SessionType};
|
||||
use goose::{
|
||||
agents::{extension::ToolInfo, extension_manager::get_parameter_names},
|
||||
config::permission::PermissionLevel,
|
||||
@@ -175,17 +174,20 @@ async fn start_agent(
|
||||
let counter = state.session_counter.fetch_add(1, Ordering::SeqCst) + 1;
|
||||
let name = format!("New session {}", counter);
|
||||
|
||||
let mut session =
|
||||
SessionManager::create_session(PathBuf::from(&working_dir), name, SessionType::User, None)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Failed to create session: {}", err);
|
||||
goose::posthog::emit_error("session_create_failed", &err.to_string());
|
||||
ErrorResponse {
|
||||
message: format!("Failed to create session: {}", err),
|
||||
status: StatusCode::BAD_REQUEST,
|
||||
}
|
||||
})?;
|
||||
let mut session = SessionManager::create_session(
|
||||
PathBuf::from(&working_dir),
|
||||
name,
|
||||
SessionType::User,
|
||||
)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Failed to create session: {}", err);
|
||||
goose::posthog::emit_error("session_create_failed", &err.to_string());
|
||||
ErrorResponse {
|
||||
message: format!("Failed to create session: {}", err),
|
||||
status: StatusCode::BAD_REQUEST,
|
||||
}
|
||||
})?;
|
||||
|
||||
if let Some(recipe) = original_recipe {
|
||||
SessionManager::update_session(&session.id)
|
||||
|
||||
@@ -5,8 +5,7 @@ use goose::config::{DEFAULT_EXTENSION_DESCRIPTION, DEFAULT_EXTENSION_TIMEOUT};
|
||||
use goose::conversation::message::Message;
|
||||
use goose::providers::create_with_named_model;
|
||||
use goose::providers::databricks::DATABRICKS_DEFAULT_MODEL;
|
||||
use goose::session::session_manager::SessionType;
|
||||
use goose::session::SessionManager;
|
||||
use goose::session::{SessionManager, SessionType};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[tokio::main]
|
||||
@@ -21,7 +20,6 @@ async fn main() -> anyhow::Result<()> {
|
||||
PathBuf::default(),
|
||||
"max-turn-test".to_string(),
|
||||
SessionType::Hidden,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -433,7 +433,7 @@ impl Agent {
|
||||
session: &Session,
|
||||
) -> (String, Result<ToolCallResult, ErrorData>) {
|
||||
// Prevent subagents from creating other subagents
|
||||
if session.session_type == SessionType::SubAgent && tool_call.name == SUBAGENT_TOOL_NAME {
|
||||
if matches!(session.session_type, SessionType::SubAgent { .. }) && tool_call.name == SUBAGENT_TOOL_NAME {
|
||||
return (
|
||||
request_id,
|
||||
Err(ErrorData::new(
|
||||
@@ -657,14 +657,10 @@ impl Agent {
|
||||
return false;
|
||||
}
|
||||
if let Some(ref session_id) = self.extension_manager.get_context().await.session_id {
|
||||
if matches!(
|
||||
SessionManager::get_session(session_id, false)
|
||||
.await
|
||||
.ok()
|
||||
.map(|session| session.session_type),
|
||||
Some(SessionType::SubAgent)
|
||||
) {
|
||||
return false;
|
||||
if let Ok(session) = SessionManager::get_session(session_id, false).await {
|
||||
if matches!(session.session_type, SessionType::SubAgent { .. }) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
!self
|
||||
|
||||
@@ -18,8 +18,6 @@ use crate::providers::toolshim::{
|
||||
|
||||
use crate::agents::code_execution_extension::EXTENSION_NAME as CODE_EXECUTION_EXTENSION;
|
||||
use crate::session::SessionManager;
|
||||
#[cfg(test)]
|
||||
use crate::session::SessionType;
|
||||
use rmcp::model::Tool;
|
||||
|
||||
fn coerce_value(s: &str, schema: &Value) -> Value {
|
||||
@@ -444,8 +442,7 @@ mod tests {
|
||||
let session = SessionManager::create_session(
|
||||
std::path::PathBuf::default(),
|
||||
"test-prepare-tools".to_string(),
|
||||
SessionType::Hidden,
|
||||
None,
|
||||
crate::session::SessionType::Hidden,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ use crate::providers;
|
||||
use crate::recipe::build_recipe::build_recipe_from_template;
|
||||
use crate::recipe::local_recipes::load_local_recipe_file;
|
||||
use crate::recipe::{Recipe, SubRecipe};
|
||||
use crate::session::SessionManager;
|
||||
use crate::session::{SessionManager, SessionType};
|
||||
|
||||
pub const SUBAGENT_TOOL_NAME: &str = "subagent";
|
||||
|
||||
@@ -245,8 +245,9 @@ async fn execute_subagent(
|
||||
let session = SessionManager::create_session(
|
||||
working_dir,
|
||||
"Subagent task".to_string(),
|
||||
crate::session::session_manager::SessionType::SubAgent,
|
||||
Some(task_config.parent_session_id.clone()),
|
||||
SessionType::SubAgent {
|
||||
parent_session_id: task_config.parent_session_id.clone(),
|
||||
},
|
||||
)
|
||||
.await
|
||||
.map_err(|e| ErrorData {
|
||||
|
||||
@@ -22,8 +22,7 @@ use crate::posthog;
|
||||
use crate::providers::create;
|
||||
use crate::recipe::Recipe;
|
||||
use crate::scheduler_trait::SchedulerTrait;
|
||||
use crate::session::session_manager::SessionType;
|
||||
use crate::session::{Session, SessionManager};
|
||||
use crate::session::{Session, SessionManager, SessionType};
|
||||
|
||||
type RunningTasksMap = HashMap<String, CancellationToken>;
|
||||
type JobsMap = HashMap<String, (JobId, ScheduledJob)>;
|
||||
@@ -744,7 +743,6 @@ async fn execute_job(
|
||||
std::env::current_dir()?,
|
||||
format!("Scheduled job: {}", job.id),
|
||||
SessionType::Scheduled,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -23,12 +23,11 @@ pub const CURRENT_SCHEMA_VERSION: i32 = 7;
|
||||
pub const SESSIONS_FOLDER: &str = "sessions";
|
||||
pub const DB_NAME: &str = "sessions.db";
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, ToSchema, PartialEq, Eq)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum SessionType {
|
||||
User,
|
||||
Scheduled,
|
||||
SubAgent,
|
||||
SubAgent { parent_session_id: String },
|
||||
Hidden,
|
||||
Terminal,
|
||||
}
|
||||
@@ -39,33 +38,109 @@ impl Default for SessionType {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SessionType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
impl SessionType {
|
||||
/// Get the type string for database storage
|
||||
pub fn type_string(&self) -> &str {
|
||||
match self {
|
||||
SessionType::User => write!(f, "user"),
|
||||
SessionType::SubAgent => write!(f, "sub_agent"),
|
||||
SessionType::Hidden => write!(f, "hidden"),
|
||||
SessionType::Scheduled => write!(f, "scheduled"),
|
||||
SessionType::Terminal => write!(f, "terminal"),
|
||||
SessionType::User => "user",
|
||||
SessionType::SubAgent { .. } => "sub_agent",
|
||||
SessionType::Hidden => "hidden",
|
||||
SessionType::Scheduled => "scheduled",
|
||||
SessionType::Terminal => "terminal",
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract parent_session_id if this is a SubAgent
|
||||
pub fn parent_session_id(&self) -> Option<&str> {
|
||||
match self {
|
||||
SessionType::SubAgent { parent_session_id } => Some(parent_session_id),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reconstruct SessionType from database columns
|
||||
pub fn from_db(type_str: &str, parent_id: Option<String>) -> Result<Self> {
|
||||
match type_str {
|
||||
"user" => Ok(SessionType::User),
|
||||
"sub_agent" => Ok(SessionType::SubAgent {
|
||||
parent_session_id: parent_id.ok_or_else(|| {
|
||||
anyhow::anyhow!("SubAgent session type requires parent_session_id")
|
||||
})?,
|
||||
}),
|
||||
"hidden" => Ok(SessionType::Hidden),
|
||||
"scheduled" => Ok(SessionType::Scheduled),
|
||||
"terminal" => Ok(SessionType::Terminal),
|
||||
_ => Err(anyhow::anyhow!("Invalid session type: {}", type_str)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for SessionType {
|
||||
type Err = anyhow::Error;
|
||||
impl std::fmt::Display for SessionType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.type_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
// Custom serialization to maintain JSON compatibility (serialize as simple string)
|
||||
impl Serialize for SessionType {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_str(self.type_string())
|
||||
}
|
||||
}
|
||||
|
||||
// Custom deserialization - for JSON, we don't have parent_id, so we use a placeholder
|
||||
// The actual parent_id will come from the Session.parent_session_id field
|
||||
impl<'de> Deserialize<'de> for SessionType {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
match s.as_str() {
|
||||
"user" => Ok(SessionType::User),
|
||||
"sub_agent" => Ok(SessionType::SubAgent),
|
||||
"sub_agent" => {
|
||||
// When deserializing from JSON, we don't have the parent_id yet
|
||||
// It will be populated from Session.parent_session_id field
|
||||
Ok(SessionType::SubAgent {
|
||||
parent_session_id: String::new(),
|
||||
})
|
||||
}
|
||||
"hidden" => Ok(SessionType::Hidden),
|
||||
"scheduled" => Ok(SessionType::Scheduled),
|
||||
"terminal" => Ok(SessionType::Terminal),
|
||||
_ => Err(anyhow::anyhow!("Invalid session type: {}", s)),
|
||||
_ => Err(serde::de::Error::custom(format!(
|
||||
"Invalid session type: {}",
|
||||
s
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Manual ToSchema implementation for SessionType since it serializes as a string
|
||||
impl utoipa::ToSchema<'_> for SessionType {
|
||||
fn schema() -> (
|
||||
&'static str,
|
||||
utoipa::openapi::RefOr<utoipa::openapi::schema::Schema>,
|
||||
) {
|
||||
(
|
||||
"SessionType",
|
||||
utoipa::openapi::ObjectBuilder::new()
|
||||
.schema_type(utoipa::openapi::SchemaType::String)
|
||||
.enum_values(Some(vec![
|
||||
"user",
|
||||
"scheduled",
|
||||
"sub_agent",
|
||||
"hidden",
|
||||
"terminal",
|
||||
]))
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
static SESSION_STORAGE: OnceCell<Arc<SessionStorage>> = OnceCell::const_new();
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
|
||||
@@ -273,8 +348,8 @@ impl SessionManager {
|
||||
working_dir: PathBuf,
|
||||
name: String,
|
||||
session_type: SessionType,
|
||||
parent_session_id: Option<String>,
|
||||
) -> Result<Session> {
|
||||
let parent_session_id = session_type.parent_session_id().map(String::from);
|
||||
Self::instance()
|
||||
.await?
|
||||
.create_session(working_dir, name, session_type, parent_session_id)
|
||||
@@ -445,47 +520,35 @@ impl Session {
|
||||
}
|
||||
|
||||
impl sqlx::FromRow<'_, sqlx::sqlite::SqliteRow> for Session {
|
||||
fn from_row(row: &sqlx::sqlite::SqliteRow) -> Result<Self, sqlx::Error> {
|
||||
fn from_row(row: &sqlx::sqlite::SqliteRow) -> sqlx::Result<Self> {
|
||||
use sqlx::Row;
|
||||
|
||||
let recipe_json: Option<String> = row.try_get("recipe_json")?;
|
||||
let recipe = recipe_json.and_then(|json| serde_json::from_str(&json).ok());
|
||||
let session_type_str: String = row.try_get("session_type")?;
|
||||
let parent_session_id: Option<String> = row.try_get("parent_session_id")?;
|
||||
|
||||
let user_recipe_values_json: Option<String> = row.try_get("user_recipe_values_json")?;
|
||||
let user_recipe_values =
|
||||
user_recipe_values_json.and_then(|json| serde_json::from_str(&json).ok());
|
||||
|
||||
let model_config_json: Option<String> = row.try_get("model_config_json").ok().flatten();
|
||||
let model_config = model_config_json.and_then(|json| serde_json::from_str(&json).ok());
|
||||
|
||||
let parent_session_id: Option<String> = row.try_get("parent_session_id").ok().flatten();
|
||||
|
||||
let name: String = {
|
||||
let name_val: String = row.try_get("name").unwrap_or_default();
|
||||
if !name_val.is_empty() {
|
||||
name_val
|
||||
} else {
|
||||
row.try_get("description").unwrap_or_default()
|
||||
}
|
||||
};
|
||||
|
||||
let user_set_name = row.try_get("user_set_name").unwrap_or(false);
|
||||
|
||||
let session_type_str: String = row
|
||||
.try_get("session_type")
|
||||
.unwrap_or_else(|_| "user".to_string());
|
||||
let session_type = session_type_str.parse().unwrap_or_default();
|
||||
let session_type = SessionType::from_db(&session_type_str, parent_session_id.clone())
|
||||
.map_err(|e| sqlx::Error::ColumnDecode {
|
||||
index: "session_type".to_string(),
|
||||
source: Box::new(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
e.to_string(),
|
||||
)),
|
||||
})?;
|
||||
|
||||
Ok(Session {
|
||||
id: row.try_get("id")?,
|
||||
working_dir: PathBuf::from(row.try_get::<String, _>("working_dir")?),
|
||||
name,
|
||||
user_set_name,
|
||||
working_dir: row.try_get::<String, _>("working_dir")?.into(),
|
||||
name: row
|
||||
.try_get::<Option<String>, _>("name")?
|
||||
.or_else(|| row.try_get("description").ok())
|
||||
.unwrap_or_default(),
|
||||
user_set_name: row.try_get("user_set_name")?,
|
||||
session_type,
|
||||
created_at: row.try_get("created_at")?,
|
||||
updated_at: row.try_get("updated_at")?,
|
||||
extension_data: serde_json::from_str(&row.try_get::<String, _>("extension_data")?)
|
||||
.unwrap_or_default(),
|
||||
extension_data: row.try_get::<String, _>("extension_data").and_then(|s| {
|
||||
serde_json::from_str(&s).map_err(|e| sqlx::Error::Decode(Box::new(e)))
|
||||
})?,
|
||||
total_tokens: row.try_get("total_tokens")?,
|
||||
input_tokens: row.try_get("input_tokens")?,
|
||||
output_tokens: row.try_get("output_tokens")?,
|
||||
@@ -493,12 +556,18 @@ impl sqlx::FromRow<'_, sqlx::sqlite::SqliteRow> for Session {
|
||||
accumulated_input_tokens: row.try_get("accumulated_input_tokens")?,
|
||||
accumulated_output_tokens: row.try_get("accumulated_output_tokens")?,
|
||||
schedule_id: row.try_get("schedule_id")?,
|
||||
recipe,
|
||||
user_recipe_values,
|
||||
conversation: None,
|
||||
message_count: row.try_get("message_count").unwrap_or(0) as usize,
|
||||
provider_name: row.try_get("provider_name").ok().flatten(),
|
||||
model_config,
|
||||
recipe: row
|
||||
.try_get::<Option<String>, _>("recipe_json")?
|
||||
.and_then(|s| serde_json::from_str(&s).ok()),
|
||||
user_recipe_values: row
|
||||
.try_get::<Option<String>, _>("user_recipe_values_json")?
|
||||
.and_then(|s| serde_json::from_str(&s).ok()),
|
||||
conversation: None, // Populated separately
|
||||
message_count: row.try_get::<i64, _>("message_count").unwrap_or(0) as usize,
|
||||
provider_name: row.try_get("provider_name")?,
|
||||
model_config: row
|
||||
.try_get::<Option<String>, _>("model_config_json")?
|
||||
.and_then(|s| serde_json::from_str(&s).ok()),
|
||||
parent_session_id,
|
||||
})
|
||||
}
|
||||
@@ -1271,7 +1340,9 @@ impl SessionStorage {
|
||||
fn build_recursive_export<'a>(
|
||||
&'a self,
|
||||
session: Session,
|
||||
) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<RecursiveSessionExport>> + Send + 'a>> {
|
||||
) -> std::pin::Pin<
|
||||
Box<dyn std::future::Future<Output = Result<RecursiveSessionExport>> + Send + 'a>,
|
||||
> {
|
||||
Box::pin(async move {
|
||||
// Query for all sub-agent sessions
|
||||
let subagent_sessions = sqlx::query_as::<_, Session>(
|
||||
@@ -1374,12 +1445,7 @@ impl SessionStorage {
|
||||
|
||||
// Import parent session first
|
||||
let parent_session = self
|
||||
.import_session_with_parent(
|
||||
recursive_import.session,
|
||||
None,
|
||||
&mut id_mapping,
|
||||
&mut tx,
|
||||
)
|
||||
.import_session_with_parent(recursive_import.session, None, &mut id_mapping, &mut tx)
|
||||
.await?;
|
||||
|
||||
// Import all sub-agents recursively
|
||||
@@ -1825,7 +1891,9 @@ mod tests {
|
||||
.create_session(
|
||||
PathBuf::from("/tmp/test"),
|
||||
"Subagent session".to_string(),
|
||||
SessionType::SubAgent,
|
||||
SessionType::SubAgent {
|
||||
parent_session_id: parent.id.clone(),
|
||||
},
|
||||
Some(parent.id.clone()),
|
||||
)
|
||||
.await
|
||||
@@ -1878,7 +1946,9 @@ mod tests {
|
||||
.create_session(
|
||||
PathBuf::from("/tmp/test"),
|
||||
"Subagent 1".to_string(),
|
||||
SessionType::SubAgent,
|
||||
SessionType::SubAgent {
|
||||
parent_session_id: parent.id.clone(),
|
||||
},
|
||||
Some(parent.id.clone()),
|
||||
)
|
||||
.await
|
||||
@@ -1902,7 +1972,9 @@ mod tests {
|
||||
.create_session(
|
||||
PathBuf::from("/tmp/test"),
|
||||
"Subagent 2".to_string(),
|
||||
SessionType::SubAgent,
|
||||
SessionType::SubAgent {
|
||||
parent_session_id: parent.id.clone(),
|
||||
},
|
||||
Some(parent.id.clone()),
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -302,8 +302,8 @@ mod tests {
|
||||
use goose::model::ModelConfig;
|
||||
use goose::providers::base::{Provider, ProviderMetadata, ProviderUsage, Usage};
|
||||
use goose::providers::errors::ProviderError;
|
||||
use goose::session::session_manager::SessionType;
|
||||
use goose::session::SessionManager;
|
||||
|
||||
use goose::session::{SessionManager, SessionType};
|
||||
use rmcp::model::{CallToolRequestParam, Tool};
|
||||
use rmcp::object;
|
||||
use std::path::PathBuf;
|
||||
@@ -379,7 +379,6 @@ mod tests {
|
||||
PathBuf::default(),
|
||||
"max-turn-test".to_string(),
|
||||
SessionType::Hidden,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user