pub struct Session {
pub id: String,
pub title: Option<String>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub metadata: SessionMetadata,
pub agent: String,
pub messages: Vec<Message>,
pub tool_uses: Vec<ToolUse>,
pub usage: Usage,
pub max_steps: Option<usize>,
pub bus: Option<Arc<AgentBus>>,
}Expand description
A conversation session.
See the session module docs for a usage overview.
Fields§
§id: StringUUID identifying this session on disk.
title: Option<String>Optional human-readable title. Auto-generated from the first user
message when absent; see Session::generate_title.
created_at: DateTime<Utc>When the session was first created.
updated_at: DateTime<Utc>When the session was last modified.
metadata: SessionMetadataDurable session configuration.
Serialized before Self::messages so cheap workspace-match
prefiltering (see [crate::session::header::SessionHeader]) can
avoid lexing past the transcript.
agent: StringName of the agent persona that owns this session.
messages: Vec<Message>Ordered conversation transcript.
tool_uses: Vec<ToolUse>Per-tool-call audit records.
usage: UsageAggregate token usage across all completions in this session.
max_steps: Option<usize>Maximum agentic loop steps. None falls back to
DEFAULT_MAX_STEPS.
bus: Option<Arc<AgentBus>>Optional bus for publishing agent thinking/reasoning.
Implementations§
Source§impl Session
impl Session
Sourcepub async fn new() -> Result<Self>
pub async fn new() -> Result<Self>
Create a new empty session rooted at the current working directory.
§Errors
Returns an error if the current working directory cannot be resolved.
§Examples
use codetether_agent::session::Session;
let session = Session::new().await.unwrap();
assert!(!session.id.is_empty());
assert_eq!(session.agent, "build");
assert!(session.messages.is_empty());Sourcepub fn with_bus(self, bus: Arc<AgentBus>) -> Self
pub fn with_bus(self, bus: Arc<AgentBus>) -> Self
Attach an agent bus for publishing agent thinking/reasoning events.
Sourcepub fn apply_config(
&mut self,
config: &Config,
registry: Option<&ProviderRegistry>,
)
pub fn apply_config( &mut self, config: &Config, registry: Option<&ProviderRegistry>, )
Seed session metadata from a loaded crate::config::Config.
Currently copies crate::config::Config::rlm into
SessionMetadata::rlm so RLM compaction and tool-output routing
honour user-configured thresholds, iteration limits, and model
selectors.
Also attempts to resolve [RlmConfig::subcall_model] against the
given provider registry. When resolution succeeds the resolved
provider is cached on SessionMetadata (not serialised) so
every AutoProcessContext built from this session can cheaply
reference it. On failure the subcall provider is left as None
and the resolution failure is logged.
Idempotent: re-applying the same config is a no-op.
§Examples
use codetether_agent::config::Config;
use codetether_agent::session::Session;
let cfg = Config::default();
let mut session = Session::new().await.unwrap();
session.apply_config(&cfg, None);
assert_eq!(session.metadata.rlm.mode, cfg.rlm.mode);Sourcepub fn resolve_subcall_provider(&mut self, registry: &ProviderRegistry)
pub fn resolve_subcall_provider(&mut self, registry: &ProviderRegistry)
Attempt to resolve [RlmConfig::subcall_model] against the given
provider registry, storing the result on metadata.
Called by session helpers right before building an
AutoProcessContext if
subcall_provider is still None but subcall_model is configured.
This deferred resolution avoids requiring the registry at session
creation time.
§Errors
Does not return errors — resolution failure is logged.
Sourcepub fn set_agent_name(&mut self, agent_name: impl Into<String>)
pub fn set_agent_name(&mut self, agent_name: impl Into<String>)
Set the agent persona owning this session. Also updates the provenance record so audit logs reflect the new agent.
Sourcepub fn attach_worker_task_provenance(&mut self, worker_id: &str, task_id: &str)
pub fn attach_worker_task_provenance(&mut self, worker_id: &str, task_id: &str)
Tag the session as having been dispatched by a specific A2A worker for a specific task.
Sourcepub fn attach_claim_provenance(&mut self, claim: &ClaimProvenance)
pub fn attach_claim_provenance(&mut self, claim: &ClaimProvenance)
Attach a claim-provenance record to the session’s execution provenance.
Sourcepub fn add_message(&mut self, message: Message)
pub fn add_message(&mut self, message: Message)
Append a message to the transcript and bump updated_at.
Source§impl Session
impl Session
Sourcepub async fn load(id: &str) -> Result<Self>
pub async fn load(id: &str) -> Result<Self>
Load an existing session by its UUID.
§Errors
Returns an error if the session file does not exist or the JSON is malformed.
Sourcepub async fn last_for_directory(workspace: Option<&Path>) -> Result<Self>
pub async fn last_for_directory(workspace: Option<&Path>) -> Result<Self>
Load the most recent session, optionally scoped to a workspace directory.
When workspace is Some, only considers sessions created in that
directory. When None, returns the most recent session globally.
§Errors
Returns an error if no sessions exist (or, with workspace set,
none match the requested directory).
Sourcepub async fn last_for_directory_tail(
workspace: Option<&Path>,
window: usize,
) -> Result<TailLoad>
pub async fn last_for_directory_tail( workspace: Option<&Path>, window: usize, ) -> Result<TailLoad>
Like Self::last_for_directory but keeps only the last window
messages and tool uses in memory, returning a TailLoad with the
number of entries that were dropped. Use this when resuming very
large sessions where the full transcript would exhaust memory.
Implementation: the entire scan runs on a single blocking thread.
For each candidate (newest-mtime first) we do a cheap
[SessionHeader] parse to compare metadata.directory; only the
matching file pays for a full tail parse.
Sourcepub async fn last() -> Result<Self>
pub async fn last() -> Result<Self>
Load the most recent session globally (unscoped).
Kept for legacy compatibility; prefer
Session::last_for_directory.
Sourcepub async fn save(&self) -> Result<()>
pub async fn save(&self) -> Result<()>
Persist the session to disk as JSON. Creates the sessions directory on demand.
Performance:
- Serialization runs on the blocking thread pool so a large session
doesn’t stall the async reactor during
serde_jsonformatting. - Writes compact JSON (no pretty-printing): ~30% less CPU to serialize, ~30–40% smaller on disk, and correspondingly faster to load and mmap-scan on resume. Session files are machine-owned — humans never hand-edit them — so indentation is pure overhead.
- Write is atomic (tmp + rename) so a crash mid-save leaves the
previous session intact, and the mmap prefilter in
[
file_contains_finder] cannot observe a torn buffer.
Source§impl Session
impl Session
Sourcepub async fn prompt(&mut self, message: &str) -> Result<SessionResult>
pub async fn prompt(&mut self, message: &str) -> Result<SessionResult>
Execute a prompt and return the final text answer (non-streaming).
This loads the provider registry from Vault on every call, which is
fine for one-shot CLI use but expensive for the TUI — the TUI uses
Session::prompt_with_events with a shared registry instead.
§Errors
Returns an error if no providers are configured, the model cannot be resolved, or the agentic loop exhausts its retry budgets.
Sourcepub async fn prompt_with_events(
&mut self,
message: &str,
event_tx: Sender<SessionEvent>,
registry: Arc<ProviderRegistry>,
) -> Result<SessionResult>
pub async fn prompt_with_events( &mut self, message: &str, event_tx: Sender<SessionEvent>, registry: Arc<ProviderRegistry>, ) -> Result<SessionResult>
Process a user message with real-time event streaming for UI updates.
Accepts a pre-loaded
ProviderRegistry to avoid
re-fetching secrets from Vault on every message.
Sourcepub async fn prompt_with_events_and_images(
&mut self,
message: &str,
images: Vec<ImageAttachment>,
event_tx: Sender<SessionEvent>,
registry: Arc<ProviderRegistry>,
) -> Result<SessionResult>
pub async fn prompt_with_events_and_images( &mut self, message: &str, images: Vec<ImageAttachment>, event_tx: Sender<SessionEvent>, registry: Arc<ProviderRegistry>, ) -> Result<SessionResult>
Execute a prompt with optional image attachments and stream events.
Images must be base64-encoded data URLs.
Source§impl Session
impl Session
Source§impl Session
impl Session
Sourcepub async fn generate_title(&mut self) -> Result<()>
pub async fn generate_title(&mut self) -> Result<()>
Generate a title from the first user message if one is not already set.
Sourcepub async fn regenerate_title(&mut self) -> Result<()>
pub async fn regenerate_title(&mut self) -> Result<()>
Regenerate the title from the first user message, even if already set.
Sourcepub fn clear_title(&mut self)
pub fn clear_title(&mut self)
Clear the title, allowing it to be regenerated on the next call to
Session::generate_title.
Sourcepub async fn on_context_change(&mut self, regenerate_title: bool) -> Result<()>
pub async fn on_context_change(&mut self, regenerate_title: bool) -> Result<()>
React to a context change (directory change, model change, etc.).
Bumps updated_at and optionally regenerates the title.
Trait Implementations§
Source§impl<'de> Deserialize<'de> for Session
impl<'de> Deserialize<'de> for Session
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Auto Trait Implementations§
impl Freeze for Session
impl !RefUnwindSafe for Session
impl Send for Session
impl Sync for Session
impl Unpin for Session
impl UnsafeUnpin for Session
impl !UnwindSafe for Session
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request