Skip to main content

Agent

Struct Agent 

Source
pub struct Agent { /* private fields */ }
Expand description

A stateful agent: configuration, a model transport, a tool set, and the running conversation. Drive it with Agent::send.

Implementations§

Source§

impl Agent

Source

pub fn new(config: Config) -> Result<Agent, Error>

Build an agent backed by an OpenAI-compatible endpoint (OpenRouter by default). The API key is taken from Config::api_key, then Config::api_key_cmd (P4: a credential-helper command, run via the shell — see run_api_key_cmd), then the configured environment variable (Config::api_key_env).

Source

pub fn with_provider(config: Config, provider: Box<dyn Provider>) -> Agent

Build an agent with an explicit provider and the built-in tools. Handy for tests (inject a mock provider) or custom transports.

Source

pub fn with_parts( config: Config, provider: Box<dyn Provider>, registry: ToolRegistry, ) -> Agent

Build an agent from all three parts.

Source

pub fn provider_arc(&self) -> Arc<dyn Provider>

A handle to this agent’s model transport, for sharing with subagents.

Source

pub fn config(&self) -> &Config

Read-only access to this agent’s resolved Config — e.g. so a caller (crates/cli’s attach_mcp) can consult Config::module_registry/Config::module_activation AFTER construction without having to separately thread the config through every call site that builds an Agent and later needs it again. Same trust boundary as every other already-public Agent accessor (history, provider_arc) — the caller is the same process that built this Config in the first place, not a new exposure surface.

Source

pub fn checkpoint_observer(&self) -> Option<&CheckpointObserver>

P5-9 (§2 module 20 checkpoint): this agent’s checkpoint engine, if Config::checkpoint_enabled is true and the shadow store opened successfully — None otherwise (the default-off case, or a graceful-degrade after an I/O failure). A caller (CLI/TUI/embedder) uses this to list/turn_diff/restore WITHOUT re-deriving the shadow-store root itself. Deliberately named checkpoint_observer, not checkpointSelf::checkpoint already names the unrelated in-memory conversation-position marker (see that method’s doc comment).

Source

pub fn lsp_manager(&self) -> Option<&LspManager>

P5-11 (§2 module 28 lsp): this agent’s LSP server registry, if Config::lsp_enabled is trueNone otherwise (the default-off case). impl Drop for Agent already covers production teardown via crate::lsp::LspManager::kill_all_sync (a real, group-killing OS process kill — see crate::lsp’s module doc). This accessor exists for an OPTIONAL caller (CLI/TUI/embedder) that manages its own Agent lifecycle and additionally wants to reach crate::lsp::LspManager::shutdown_all for a graceful LSP shutdown/exit handshake BEFORE dropping the agent — nothing calls shutdown_all automatically today.

Source

pub async fn run_subagent( &self, system: impl Into<String>, task: impl Into<String>, ) -> Result<String, Error>

Spawn a subagent that shares this agent’s model transport, runs task to completion with its own fresh conversation (seeded with system), and returns its final answer. The analog of Agent / spawn_agent.

Source

pub fn with_provider_arc(config: Config, provider: Arc<dyn Provider>) -> Agent

Like Self::with_provider but sharing an existing transport handle.

Source

pub fn run_in_background( self, prompt: impl Into<String>, ) -> JoinHandle<(Agent, Result<String, Error>)>
where Agent: Send + 'static,

Run a prompt on a background task, returning a handle that resolves to the final answer (and the agent, so the caller can continue it). The analog of background/async agent runs.

Source

pub fn resume(config: Config, session: Session) -> Result<Agent, Error>

Build an agent and seed it with a previously-recorded Session so it can continue where Claude Code or Codex left off.

Source

pub fn resume_recorded( config: Config, session: Session, sidecar_path: &Path, ) -> Result<Agent, Error>

Like Self::resume, but also begins recording (A2/A3): a fresh native-v2 sidecar is created at sidecar_path from session (header + session.raw verbatim — the imported prefix’s own fidelity), and every subsequent turn this agent produces is appended to it at full fidelity, independent of whatever cap_tool_output/maybe_compact (D6) do to history.

Invariant this establishes ONLY once Self::set_reduction_policy is also called (the D6/A7 supersession gate, Self::run_loop): at any instant, Session::from_native_str(sidecar).messages equals session.messages (the imported prefix) followed by every message appended since — i.e. self.history()[1..] (history[0] is this agent’s own system prompt, per Self::load_session; it is never part of session and is never written to the sidecar). Recording alone (no policy) leaves the gate off: cap_tool_output still runs on oversized tool results, and history can diverge from the sidecar for them — honestly, via the notice’s “full output in session sidecar” label, never silently.

Source

pub fn set_recorder(&mut self, w: SidecarWriter)

Install (or replace) this agent’s sidecar recorder (A3).

Source

pub fn set_reduction_policy(&mut self, policy: ReductionPolicy)

Install (or replace) this agent’s reduction policy (A5/A7/A10). Once set, every provider request is built from a projected view of history[1..] (reduce::project_messages) rather than history verbatim — history itself is never shrunk or mutated by this; only the request view does.

Source

pub fn reduction_policy(&self) -> Option<&ReductionPolicy>

This agent’s reduction policy, if one is installed.

Source

pub fn set_schema_tier(&mut self, tier: SchemaTier)

Change the global tool-schema tier (TR-8/T5) mid-session. Takes effect starting with the NEXT request this agent builds. Under CachePlan::ImportedPrefix, the first request built after a change is flagged as a cache-bust event and its cache-control annotation is skipped for that one request (see [provider::tier_change_is_cache_bust], consulted in Self::build_request_messages) — normal annotation resumes on the next request if the tier doesn’t change again.

Source

pub fn set_tool_schema_tier( &mut self, name: impl Into<String>, tier: SchemaTier, )

Override the schema tier for a single tool (TR-8/T5) mid-session, same cache-bust interaction as Self::set_schema_tier.

Source

pub fn set_span_summarizer( &mut self, summarizer: impl SpanSummarizer + Send + Sync + 'static, )

Install (or replace) this agent’s TR-7 span summarizer — the injectable side-call Self::build_request_messages uses to turn an A10 TurnsCleared span into an LLM-written summary paragraph when policy.summarize_cleared_turns is on. Installing one alone changes nothing: ReductionPolicy::summarize_cleared_turns (off by default) is the actual gate, so tests/callers that want the deterministic stub can simply never call this.

Source

pub fn prepare_cleared_turns_summary( &self, msgs: &[ChatMessage], policy: &ReductionPolicy, prior: &ReductionLog, ) -> Option<PreparedClearSummary>

Prepare TR-7 metadata with this agent’s installed summarizer for a projection performed by an outer driver before session history/log are loaded (the CLI foreign-resume preflight). None preserves the deterministic fallback when the gate is off, no summarizer exists, the span is below the cost floor, or the side-call fails.

Source

pub fn set_event_sink(&mut self, sink: Box<dyn Fn(AgentEvent) + Send + Sync>)

P5-4: install (or replace) this agent’s crate::EventSink AFTER construction — Config::event_sink is otherwise only set at Config-build time (before Agent::new), which is too early for a tui embedder that only knows it’s activating (and needs to replace whatever print-mode/REPL sink was already installed with one that feeds its own render loop instead of writing straight to stdout) once it already holds a live Agent. Mirrors [Self:: set_permissions_approval_handler]’s “installing one alone changes nothing beyond what already consults Config::event_sink” pattern — this is a plain replacement, not a new activation gate.

Source

pub fn set_permissions_approval_handler( &mut self, handler: impl PermissionsApprovalHandler + 'static, )

P5-1: install (or replace) this agent’s permissions-engine approval handler — see crate::permissions::PermissionsApprovalHandler. This is the non-interactive decision seam a CLI/TUI/SDK embedder implements for the Ask-tier prompt; the TUI’s actual interactive UI is a separate module (P5 row 4), not built here. Installing one alone changes nothing: Config::permissions_enabled (off by default) is the actual gate — with no handler installed, every Ask-tier decision denies (fail-closed, see that trait’s doc comment).

P5-10 (§2 module 12, escalation = "ask"): the SAME handler also backs a sandbox-unenforceable ask decision (crate::sandbox::decide_fs‘s approval parameter) — one installed seam serves both permissions.rulesAsk tier and permissions.sandbox’s escalation = "ask", rather than requiring an embedder to install two near-identical handlers. Kept in sync on self.ctx (not just self.permissions_approval_handler) because BashTool::execute/PersistentShellTool::execute only ever see &ToolContext, never &Agent — see ToolContext:: sandbox_approval_handler’s doc comment.

Source

pub fn set_legacy_approval_handler( &mut self, handler: Box<dyn Fn(&ToolCall) -> bool + Send + Sync>, )

Install the compatibility approval seam used when the composable permissions engine is disabled. SDK-owned interactive frontends call this alongside Self::set_permissions_approval_handler so the same authenticated request channel works under either policy engine; the selected engine remains entirely a configuration decision.

Source

pub fn set_subagent_store( &mut self, store: Arc<SessionStore>, session_name: impl Into<String>, )

P5-3 (§2 module 9 D5 “subagent transcripts… persisted + linked”): install a crate::store::SessionStore (+ this agent’s own session name in it) so spawn_subagent persists each child’s transcript (via crate::store::SessionStore::save_subagent_transcript) and lineage record (via crate::store::SessionStore::save_subagent_lineage) once the child finishes. Installing one alone changes nothing about whether spawning WORKS — Config::subagents_enabled is the actual gate; this only controls whether a completed spawn’s transcript additionally lands on disk.

Source

pub fn set_claude_runtime_manifest(&mut self, manifest: ClaudeRuntimeManifest)

Seed the Claude runtime manifest reconstructed during resume.

Installing state enables the matching Claude runtime tool schemas so a disk-reloaded continuation does not lose that vocabulary, but never starts a timer by itself. The supplied execution posture is preserved: an embedding scheduler may deliberately activate before installing it.

Source

pub fn restore_claude_project_agents(&mut self) -> Result<usize, Error>

Reinstall project-scoped Claude named-agent definitions when a Supercode continuation carrying a Claude runtime manifest is reopened from disk. The manifest is the durable capability marker; definitions themselves remain authoritative in <cwd>/.claude/agents/*.md.

Source

pub fn claude_runtime_manifest(&self) -> Option<&ClaudeRuntimeManifest>

Current imported Claude runtime state, including paused mutations made by Cron*/ScheduleWakeup, for persistence by the embedding loop.

Source

pub fn claude_runtime_manifest_mut( &mut self, ) -> Option<&mut ClaudeRuntimeManifest>

Mutable access for an embedding scheduler driver to atomically claim due events and persist the resulting manifest. Merely borrowing this state does not start a timer; execution remains the driver’s explicit responsibility.

Source

pub fn set_child_approval_handler_factory( &mut self, factory: impl Fn(String, Arc<Mutex<Vec<QueuedApproval>>>) -> Arc<dyn PermissionsApprovalHandler> + Send + Sync + 'static, )

P5-4 (tui, closes the P5-3 §2.2 C6 deferred chain): install a factory this agent’s Self::run_spawn_subagent calls (with the fresh child’s own id and this agent’s shared Self::pending_child_approvals queue) to build the PermissionsApprovalHandler a background_prompts = "parent" child gets, INSTEAD of the default crate::subagents::ParentQueueApprovalHandler. Installing one alone changes nothing about whether background spawning works — Config::subagents_background_prompts being crate::subagents::BackgroundPromptsPolicy::Parent is the actual gate that reaches this factory at all; a Parent-policy child spawned before this is installed (or on an agent that never installs it) still gets the immediate-deny default, unchanged.

Security note. The factory only controls WHICH handler answers an Ask-tier request — it can never widen what gets asked in the first place: crate::permissions::approval::resolve_ask only calls a handler’s ask when the rule engine has already resolved the call to Ask (Deny short-circuits before any handler is consulted; Allow never needs one), so a parent’s “allow” answer here can only grant what the policy already routed to a prompt — never override a Deny the engine already decided.

Source

pub fn pending_child_approvals(&self) -> Vec<QueuedApproval>

P5-3 (§2.2 C6 “parent-surfaced queue”): every approval request a background_prompts = "parent" child has raised so far, oldest first — a read-only audit view, not a mutable queue the caller answers. Under P5-3’s own default handler (no P5-4 TUI factory installed) every entry here WAS already resolved Deny (a background call can’t wait for an answer with no handler installed) — but once a crate::tui::TuiChildApprovalHandler factory is installed (P5-4, Self::set_child_approval_handler_factory), the underlying call genuinely blocks and may resolve Allow/AllowForSession; this method still records the SAME entry for the audit trail either way, so “queued here” no longer implies “was denied” in general — see crate::subagents::QueuedApproval’s doc comment.

Source

pub fn set_session_titler( &mut self, titler: impl SessionTitler + Send + Sync + 'static, )

P4b: install (or replace) this agent’s auto-title side-call — see crate::session_title::SessionTitler. Installing one alone changes nothing: Config::auto_title (off by default) is the actual gate a caller should consult before calling Self::auto_title.

Source

pub fn auto_title(&self) -> Option<String>

P4b: produce a title for this agent’s current conversation via the installed Self::set_session_titler side-call. Returns None (never panics, never blocks longer than the titler itself does) if no titler is installed, or the side-call itself declined (see crate::session_title::auto_title). Does NOT consult Config::auto_title itself — that gate is the caller’s responsibility, matching Self::span_summarizer’s precedent of keeping the mechanism and the policy gate separate.

Source

pub fn usage_records(&self) -> &[UsageRecord]

P4b (§1.6, catalog §4a “persisted per-turn usage records”): every crate::usage_log::UsageRecord this agent has accumulated so far.

Source

pub fn save_usage_log( &self, store: &SessionStore, name: &str, ) -> Result<(), Error>

P4b: persist this agent’s accumulated usage log to store under name — a thin wrapper over crate::store::SessionStore::save_usage_log so callers don’t need to import both types.

Source

pub fn queue_steer(&self, message: impl Into<String>)

P4b (§1.7, pi§3 semantics): queue a mid-turn steering message — delivered “after current tool calls” (pi’s phrasing): at the top of Self::run_loop’s NEXT iteration, before the next model request is built, regardless of whether this turn is still mid-flight with pending tool calls. Drained per Config::steering_mode.

Source

pub fn queue_follow_up(&mut self, message: impl Into<String>)

P4b: queue a follow-up message — delivered “at idle” (pi’s phrasing): only once Self::run_loop would otherwise return a final answer (no more tool calls pending). Drained per Config::follow_up_mode.

Source

pub fn queued_steer_count(&self) -> usize

P4b: how many steering messages are currently queued (mid-turn + follow-up combined) — mostly for tests/diagnostics.

Source

pub fn reduction_log(&self) -> &ReductionLog

The accumulating reduction log (A5) — every reduction applied to any projected request view so far. Combined with a full-fidelity sidecar Session, this is enough to reduce::invert any projected view back to the exact original.

Source

pub fn set_context_limit(&mut self, limit: u64)

PARITY-18 D4 — arm the per-send context guard: Self::run_loop will refuse (via Error::ContextLimitExceeded) to build and issue ANY request — the first or any later turn — whose crate::tokens::context_guard verdict is “does not fit” against limit. Call this once the target model’s context-window size is known (resume --reduced’s preflight already computes it). Leaving this unset (the default) is a no-op: no guard runs, exactly today’s pre-PARITY-18 behavior.

Source

pub fn context_limit(&self) -> Option<u64>

This agent’s armed context limit, if Self::set_context_limit has been called.

Source

pub fn model(&self) -> &str

The model identifier this agent sends on its next request (Config::model, as of construction/resume or the last Self::set_model call).

Source

pub fn set_model(&mut self, model: impl Into<String>)

UX-30 dev/02 — switch the model this agent sends, starting with the NEXT request it builds (and every one after, until changed again). Self::run_loop reads self.config.model fresh on every request (see its ChatRequest construction), so this alone is enough — there is no cached/baked-in copy anywhere else to also update. Takes effect immediately; safe to call only between turns (the REPL’s /model picker runs at the prompt, never mid-turn). Touches nothing else: history, the sidecar, and reduction state are exactly as untouched as Self::set_schema_tier leaves them for a mid-session tier change.

P4c-review note: this is the LOW-LEVEL primitive — it swaps Config::model and nothing else. It does NOT run dep 8’s reasoning-artifact filter (reduce::rehydrate::filter_reasoning_artifacts) and does NOT create a crate::model_change::ModelChangeRecord, so calling it directly for a mid-session handoff between two DIFFERENT models leaves model-A’s reasoning artifacts in history for model-B to inherit. Self::switch_model is the safe superset — gated by Config::model_switch_allow_switch, it filters and records the switch before delegating to this method — and is what callers performing a governed mid-session model switch should use instead.

Source

pub fn switch_model(&mut self, model: impl Into<String>)

P4c (§1.10/§3.1 core.model_switch.allow_switch, D9 row, dep 8, design’s “core NEW-significant” item): the mid-session model switch — a superset of Self::set_model gated by Config::model_switch_allow_switch.

allow_switch = false (the default): EXACTLY Self::set_model — same single field write, nothing else touched, no crate::model_change::ModelChangeRecord created. Byte-identical to calling set_model directly.

allow_switch = true: additionally, before the swap takes effect, runs reduce::rehydrate::filter_reasoning_artifacts over Self::history — model-A’s reasoning/thinking artifacts (any crate::message::ChatMessage::metadata key in reduce::rehydrate::REASONING_METADATA_KEYS, any content_parts block whose "type" is in reduce::rehydrate::REASONING_CONTENT_PART_TYPES) are stripped BEFORE model-B ever builds a request from this history — then appends a typed, translatable crate::model_change::ModelChangeRecord to Self::model_change_records (persist it via Self::save_model_change_log). A switch TO the current model (model == Self::model()) is treated as a no-op — still exactly set_model’s mechanics, no record for a switch that didn’t actually change anything (and nothing to filter FOR, since there was no handoff).

Source

pub fn model_change_records(&self) -> &[ModelChangeRecord]

P4c: every crate::model_change::ModelChangeRecord this agent has accumulated so far (via Self::switch_model with allow_switch on). Empty when the knob is off or no switch has happened yet.

Source

pub fn save_model_change_log( &self, store: &SessionStore, name: &str, ) -> Result<(), Error>

P4c: persist this agent’s accumulated model-change log to store under name — the crate::model_change::ModelChangeRecord analog of Self::save_usage_log.

Source

pub fn git_metadata(&self) -> Option<&GitMetadataRecord>

P4e (§1.6/§3.1 core.session.git_metadata, catalog:331): this agent’s captured git provenance, if Config::session_git_metadata was on at construction and the best-effort probe found a repo.

Source

pub fn save_git_metadata( &self, store: &SessionStore, name: &str, ) -> Result<(), Error>

P4e: persist this agent’s captured git metadata to store under name — a thin wrapper over crate::store::SessionStore::save_git_metadata, the crate::git_metadata::GitMetadataRecord analog of Self::save_usage_log. A no-op (Ok(()), nothing written) when Self::git_metadata is None.

Source

pub fn session_persist(&self) -> bool

P4e DEFECT-FIX (independent Fable-5 review of P4e: core.session.persist had a Config field and CLI plumbing at ConfigProfileConfig but no consumer at all): whether a CLI caller’s session-store save sites (persist_session, persist_full_view) should actually write to disk. true (the default) is byte-identical to pre-fix behavior — every session persists. false makes a session ephemeral: it runs exactly as before, but no <name>.jsonl/sidecar family is ever written for it. A plain getter, same posture as Self::model — this crate itself never reads or enforces it; the CLI’s save sites do.

Source

pub fn session_name(&self) -> Option<&str>

P4e DEFECT-FIX (independent Fable-5 review of P4e: core.session.name had a Config field and CLI plumbing but no consumer): the caller-configured session name, if [core.session] name was set. None (the default) leaves session naming exactly as before — mint_session_name’s auto-generated <tag>-<adjective>-<noun> shape. A plain getter, same posture as Self::session_persist.

Source

pub fn request_issued(&self) -> bool

PARITY-18 D3 — whether this agent has actually issued at least one live request to its Provider so far (set the instant Self::run_loop reaches its real send site, regardless of whether that call then succeeds or fails). Callers should report “request sent” from THIS, never from having merely passed the context guard or having called Self::send — either of those can happen with zero requests actually issued (a guard refusal, an interactive session quit before any turn completes).

Source

pub fn cache_established(&self) -> bool

P5-2 (§2.2 C2): whether this agent currently considers its CachePlan::ImportedPrefix cache entry warm — mirrors Self::request_issued’s read-only-observability precedent, so a caller (or a test) can confirm Self::register_tool’s C2 invalidation actually took effect without reaching into private state.

Source

pub fn imported_prefix_len(&self) -> Option<usize>

B7: length of the imported-prefix protected by CachePlan::ImportedPrefix (this agent’s own system message plus every message of a previously-imported session), set by Self::load_session. None until a session has been loaded.

Source

pub fn set_reduction_log(&mut self, log: ReductionLog)

Replace this agent’s accumulating reduction log (C4: /expand//reduce mutate the log directly via reduce::invert_one/reduce::project_messages and must feed the result back here so the next request build or persist sees the updated state instead of silently recomputing from an empty log). Also lets a caller (resume_cmd, C1) seed the log with the initial projection it already computed for the entry banner, so reduction_log() reflects reality even before this agent’s first send() (which is otherwise the only place build_request_messages populates it).

Source

pub fn load_session(&mut self, session: Session)

Replace the conversation with a loaded session, keeping this agent’s own system prompt at the front. The session’s own system/developer turns are preserved after it for context.

Source

pub fn save_transcript(&self, path: impl AsRef<Path>) -> Result<(), Error>

Persist the live conversation to path as JSONL (one ChatMessage per line) so the session can be resumed later — supercode’s own sessions become first-class, resumable artifacts.

Source

pub fn load_transcript(&mut self, path: impl AsRef<Path>) -> Result<(), Error>

Restore a conversation previously written with Self::save_transcript, replacing the current history.

Source

pub fn checkpoint(&self) -> usize

Take a checkpoint of the current conversation position. Pass it to Self::rewind_to to discard everything sent since (the rewind/undo analog of fork/checkpoint).

Source

pub fn rewind_to(&mut self, checkpoint: usize)

Rewind the conversation to a Self::checkpoint, discarding later turns.

Source

pub async fn send_with_files( &mut self, text: impl Into<String>, files: &[PathBuf], ) -> Result<String, Error>

Send a message with file inputs attached — the --file / -i analog. Each file’s contents are injected into the prompt: UTF-8 text inline, binary (e.g. images) noted with a size marker. (Native image vision would additionally require multimodal content parts.)

Source

pub async fn send_with_images( &mut self, text: impl Into<String>, image_urls: &[String], ) -> Result<String, Error>

Send a message with image inputs to a vision model — the -i/--image analog. image_urls may be https://… links or data:image/…;base64,… URLs; they’re attached as multimodal image_url content parts.

Source

pub fn expand_prompt(&self, input: &str) -> String

Expand a /<name> <args> slash command against the registered prompt templates ({args} is replaced with the trailing text). Non-matching input is returned unchanged.

Source

pub async fn expand_prompt_async(&self, input: &str) -> String

P5-2 (§2 module 15 D7 row 4 “prompts-as-commands”): like Self::expand_prompt, but also consults MCP-server-sourced prompts registered via Self::register_mcp_prompt when the local Config::prompts table has no match — a live prompts/get round-trip, which is why this is async and Self::expand_prompt itself stays synchronous (its public sync signature is unchanged, for every existing caller that doesn’t need MCP prompts).

Argument mapping (a scope decision, not a protocol requirement — the MCP spec leaves “how does free CLI text become named prompt arguments” to the client): a prompt with zero or one declared arguments gets the whole trailing text (empty string if the prompt takes no arguments and none was given); a prompt with two or more declared arguments expects key=value pairs, whitespace-separated (/mcp__server__prompt lang=rust topic=async) — an unparseable pair (no =) is simply skipped, never a hard error (matches this method’s “non-matching input passes through” fail-open posture for the LOCAL-prompt case above).

Source

pub fn register_mcp_prompt( &mut self, command_name: impl Into<String>, source: impl SdkPromptSource + 'static, )

P5-2 (§2 module 15 D7 row 4): register an MCP server’s prompt as a slash-command source — command_name MUST already be the namespaced mcp__<server>__<prompt> form (crate::mcp::McpServerHandle::prompts produces exactly that shape); this method does not re-namespace or validate it, so a caller that hands it a bare name defeats the collision protection crate::mcp::McpPromptSource’s doc comment describes. Overwrites any prior registration under the same command name (re-attaching the same server replaces its own earlier prompt list; this can never touch a NON-mcp__-prefixed key, i.e. never a local Config::prompts entry).

Source

pub fn append_system_note(&mut self, text: &str)

P5-2 (§2 module 15 D7 row 5 “instructions”): fold an MCP server’s initialize-time instructions (or any other free-text note) into this agent’s system message — the context-assembly site every other core.*/capabilities.* prompt-section append already uses (Self::with_parts), except this one fires AFTER construction (attaching MCP servers happens once the agent already exists — see crates/cli/src/main.rs’s attach_mcp). A no-op if history is somehow empty or its first message isn’t a system message (never true for an Agent built via Self::new/Self::with_parts, but checked rather than assumed).

Source

pub fn maybe_compact(&mut self) -> bool

Compact the conversation if it has grown past the configured threshold.

Re-founded (A10): with a ReductionPolicy installed (Self::set_reduction_policy), this no longer touches self.history at all. It derives policy.clear_turns_older_than from compact_after_messages so the next projected request view (reduce::project_messages, built in Self::run_loop) collapses the old turns into one reversible TurnsCleared stub instead — history() and the sidecar keep every message forever; only the view shrinks. Returns whether the live (unreduced) history currently exceeds the threshold, i.e. whether a clearing will actually be visible in the next projected view.

Legacy path (no policy) — LOSSY, kept only for byte-identical backward compatibility (D6): destructively rewrites self.history, permanently discarding the dropped middle turns (replaced by a single non-reversible summary marker that becomes their SOLE remaining copy — exactly the lossy compaction this reduction layer differentiates against). Once a sidecar/recorder or a ReductionPolicy is in play, prefer installing a policy so this method takes the re-founded path above instead.

Source

pub fn register_tool(&mut self, tool: impl Tool + 'static)

Register an additional tool (e.g. your own capability).

P5-2 (§2.2 C2 “connect invalidates cache prefix”): registering a tool AFTER this agent has already issued a request (Self::request_issued) changes the tools schema every subsequent request carries — the exact prefix-churn shape C2 describes, MCP-sourced or not. Resets Self::cache_established so the next cache-warmth check (provider::cache_cold_reason) doesn’t wrongly assume the entry is still warm. A no-op call before the first request (the common case: attach_mcp registers tools once at startup, before any turn runs) changes nothing — byte-identical to today.

Source

pub fn history(&self) -> &[ChatMessage]

The current conversation, including the system prompt.

Source

pub async fn send( &mut self, user_input: impl Into<String>, ) -> Result<String, Error>

Send a user message and run the loop until the model produces a final answer (text with no tool calls) or the iteration budget is exhausted.

Source

pub fn tool_schemas(&self) -> Vec<ToolSchema>

The tool-schema array this agent would advertise on its NEXT request, exactly as Self::run_loop computes it. Public (PARITY-18 D1) so a caller can measure the real request-token cost of an agent’s tool surface — including the current crate::config::ToolAdvertising mode’s core/deferred split and the synthetic tool_search/expand_reduction/sidecar_search schemas — BEFORE ever calling Self::send, e.g. for a preflight context-guard check.

Source

pub fn turn_count(&self) -> usize

Number of non-system messages exchanged so far.

Source

pub fn total_output_tokens(&self) -> u64

Cumulative output (completion) tokens reported by the provider across every send on this agent. Zero if the provider reports no usage.

Trait Implementations§

Source§

impl Drop for Agent

P5-3 safety hardening (Fable-5 review, MEDIUM-LOW “orphaned billed spend”): a dropped parent must not leave a detached background child running against a REAL provider. Without this, a parent dropped mid-run (the caller’s own process exits the scope, panics, or simply stops polling) leaves every still-running BackgroundSubagent::handle as an orphaned tokio::spawn task: nothing had ever awaited or aborted it, so it runs to its own (max_iterations-bounded) completion regardless — bounded but real provider spend nobody is paying attention to.

.abort() on a tokio::task::JoinHandle is safe to call unconditionally, including on an ALREADY-finished task (a documented no-op there — see tokio’s JoinHandle::abort docs) — so this never needs to distinguish “still running” from “already done”; a background child that already finished and is merely awaiting a subagent_status reap is untouched in practice (aborting a finished task changes nothing observable). For a task still mid-flight, tokio cancels it at its next .await point, which drops that future in place — including the _guard: ConcurrencyGuard moved into it at spawn time (see Self::run_spawn_subagent’s tokio::spawn body) — so the concurrency-gauge slot is released exactly the same way a normal completion releases it (ConcurrencyGuard’s own Drop, in crate::subagents). No separate cleanup call site to forget.

Deliberately does NOT touch [Self::pending_child_approvals] or Self::subagent_store — this is purely “stop burning provider calls on behalf of a caller who’s gone”, not a transcript-persistence path (a child aborted mid-flight has no finished result to persist; see this build’s named residual on abort-time transcript loss).

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more
Source§

impl From<Agent> for SdkAgent

Source§

fn from(agent: Agent) -> SdkAgent

Converts to this type from the input type.

Auto Trait Implementations§

§

impl !Freeze for Agent

§

impl !RefUnwindSafe for Agent

§

impl !UnwindSafe for Agent

§

impl Send for Agent

§

impl Sync for Agent

§

impl Unpin for Agent

§

impl UnsafeUnpin for Agent

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more