pub struct Session<'a> { /* private fields */ }Expand description
The durable state of an agent session: the scoped tool catalogue, the
resource-awareness map, and the conversation transcript — everything that
persists across turns. A once-mode / per-event run is a session of exactly
one turn (run_loop); a warm continue-session runs many turns over the
same transcript (RFC 0008 §spawn-vs-continue), each new event appended via
Session::deliver before another Session::run_turn.
Implementations§
Source§impl<'a> Session<'a>
impl<'a> Session<'a>
Sourcepub fn prepare(
servers: &'a [McpClient],
input: &LoopInput,
self_handler: &mut dyn SelfHandler,
) -> Result<Session<'a>, LoopAbort>
pub fn prepare( servers: &'a [McpClient], input: &LoopInput, self_handler: &mut dyn SelfHandler, ) -> Result<Session<'a>, LoopAbort>
Assemble a session: the tool catalogue (MCP tools + self-tools +
resource.read when resources exist; resources: list = awareness,
read = on-demand attention, RFC 0007 §resources), the resource awareness
note, and the opening transcript (system prompt + seed + the instruction
as the first user turn).
Sourcepub fn refresh_tools(
&mut self,
self_handler: &mut dyn SelfHandler,
) -> Result<(), LoopAbort>
pub fn refresh_tools( &mut self, self_handler: &mut dyn SelfHandler, ) -> Result<(), LoopAbort>
Rebuild the MCP side of the tool catalogue from the servers’ CURRENT
tools/list (the warm-session LIVE refresh, pivot Phase 7 follow-up):
called at a turn boundary after an inbound
notifications/tools/list_changed, so a long-lived continue-session
tracks a server whose tool set changed instead of holding a stale
catalogue for its whole life. Self-tools and resource.read are
re-merged; the transcript is untouched.
Sourcepub fn tools_len(&self) -> usize
pub fn tools_len(&self) -> usize
The current catalogue size (observability for the live refresh).
Sourcepub fn tool_class(&self, name: &str) -> ToolClass
pub fn tool_class(&self, name: &str) -> ToolClass
Classify a catalogue tool by its seam (pivot Phase 5.1 — name the class): a
name routed to an MCP server is ToolClass::Mcp (dispatched back to that
server); every other catalogue entry is agentd’s own
ToolClass::SelfControl surface (the self-tools + resource.read). The
routing map IS the MCP-tool set — the two classes are assembled by different
code paths ([build_catalogue] vs the SelfHandler merge) — so this is
the authoritative, testable boundary between “tools from a registered server”
and “agentd’s own orchestration primitives”. Callers pass a name from
Session::tools; a name absent from the catalogue still classifies as
SelfControl (it is, by definition, not a routed server tool), so classify
only names drawn from the catalogue.
Sourcepub fn tool_permitted(&self, name: &str) -> bool
pub fn tool_permitted(&self, name: &str) -> bool
Whether this session’s GRANT admits name (RFC 0009). Every grant must
admit it; an ungranted session (no parent narrowing) admits everything.
The catalogue is already filtered, so this is the second gate: it exists
for the model that names a tool anyway — hallucinated, or remembered from
a transcript written before a refresh_tools narrowed the set.
Sourcepub fn deliver(&mut self, content: &str)
pub fn deliver(&mut self, content: &str)
Append the next event as a new user turn — the delivery point for a warm continue-session (RFC 0008). The transcript (the model’s memory of the session) carries forward, so the next turn continues the conversation.
Sourcepub fn set_model(&mut self, model: &str)
pub fn set_model(&mut self, model: &str)
Adopt a new model for subsequent turns (RFC 0018 §5.3 model hot-swap). The
transcript is UNTOUCHED — only the model dialed for the NEXT turn changes;
a turn already in flight completes on the old model (finish-on-old). The
model is what each request’s model field carries.
Sourcepub fn model(&self) -> &str
pub fn model(&self) -> &str
The current model dialed for the next turn (RFC 0018 §5.3) — used to detect whether a swap actually changed the model (a repoint with no model change is always finish-on-old / invisible, §5.1).
Sourcepub fn transcript_len(&self) -> usize
pub fn transcript_len(&self) -> usize
The number of transcript messages so far — a cheap pre-turn marker for the
restart-turn policy (RFC 0018 §5.3): snapshot this before a turn, then
truncate_transcript back to it to discard
the swapped-turn’s appended messages and re-run from the same pre-turn state.
Sourcepub fn truncate_transcript(&mut self, len: usize)
pub fn truncate_transcript(&mut self, len: usize)
Truncate the transcript back to len (RFC 0018 §5.3 restart-turn): drop
every message a discarded turn appended, restoring the exact pre-turn
transcript so the turn can be re-run on the new model. A no-op if len
already ≥ the current length (never grows the transcript).
Sourcepub fn run_turn(
&mut self,
intel: &IntelClient,
self_handler: &mut dyn SelfHandler,
log: &Logger,
budget: &mut Budget,
cancel: Option<&Arc<AtomicBool>>,
) -> Result<(Outcome, Usage), LoopAbort>
pub fn run_turn( &mut self, intel: &IntelClient, self_handler: &mut dyn SelfHandler, log: &Logger, budget: &mut Budget, cancel: Option<&Arc<AtomicBool>>, ) -> Result<(Outcome, Usage), LoopAbort>
Run one turn: the ReAct loop over the persistent transcript until a
terminal status, bounded by budget. cancel is polled at each turn
boundary. Every assistant/tool message (including the final answer) is
appended to the transcript, so a subsequent turn continues the same
conversation.
Returns the turn’s Outcome together with the turn’s token Usage
(the sum of every model call in this turn — input_tokens/output_tokens).
The control layer rolls this DELTA up to the supervisor as
crate::subagent::protocol::AgentMsg::Usage so hierarchical token
accounting (agentd_tokens_total) is non-zero — but the loop itself never
touches the control channel (the up handle stays in control.rs).