feat: sessions api, view & resume prev sessions (#1453)

* Centralize session files to goose::session module
* Write session metadata and messages in jsonl
* Refactor CLI build_session to use goose::session functions
* Track session's token usage by adding optional session_id in agent.reply(...)
* NOTE: Only sessions saved through the updates goose::session functions will show up in GUI

Co-authored-by: Bradley Axen <baxen@squareup.com>
This commit is contained in:
Salman Mohammed
2025-03-03 11:49:15 -05:00
committed by GitHub
parent 68b8c5d19d
commit 9ae9045584
25 changed files with 1413 additions and 257 deletions

View File

@@ -2,16 +2,16 @@ use console::style;
use goose::agents::extension::ExtensionError;
use goose::agents::AgentFactory;
use goose::config::{Config, ExtensionManager};
use goose::session;
use goose::session::Identifier;
use mcp_client::transport::Error as McpClientError;
use std::path::PathBuf;
use std::process;
use super::output;
use super::storage;
use super::Session;
pub async fn build_session(
identifier: Option<storage::Identifier>,
identifier: Option<Identifier>,
resume: bool,
extensions: Vec<String>,
builtins: Vec<String>,
@@ -65,7 +65,7 @@ pub async fn build_session(
// Handle session file resolution and resuming
let session_file = if resume {
if let Some(identifier) = identifier {
let session_file = storage::get_path(identifier);
let session_file = session::get_path(identifier);
if !session_file.exists() {
output::render_error(&format!(
"Cannot resume session {} - no such session exists",
@@ -76,7 +76,7 @@ pub async fn build_session(
session_file
} else {
// Try to resume most recent session
match storage::get_most_recent_session() {
match session::get_most_recent_session() {
Ok(file) => file,
Err(_) => {
output::render_error("Cannot resume - no previous sessions found");
@@ -88,10 +88,11 @@ pub async fn build_session(
// Create new session with provided name/path or generated name
let id = match identifier {
Some(identifier) => identifier,
None => storage::Identifier::Name(generate_session_name()),
None => Identifier::Name(session::generate_session_id()),
};
let session_file = storage::get_path(id);
create_new_session_file(session_file)
// Just get the path - file will be created when needed
session::get_path(id)
};
// Create new session
@@ -130,20 +131,3 @@ pub async fn build_session(
output::display_session_info(resume, &provider_name, &model, &session_file);
session
}
fn generate_session_name() -> String {
use rand::{distributions::Alphanumeric, Rng};
rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(8)
.map(char::from)
.collect()
}
fn create_new_session_file(session_file: PathBuf) -> PathBuf {
if session_file.exists() {
eprintln!("Session '{:?}' already exists", session_file);
process::exit(1);
}
session_file
}