Skip to main content

a3s_code_core/
agent_api.rs

1//! Agent Facade API
2//!
3//! High-level, ergonomic API for using A3S Code as an embedded library.
4//!
5//! ## Example
6//!
7//! ```rust,no_run
8//! use a3s_code_core::Agent;
9//!
10//! # async fn run() -> anyhow::Result<()> {
11//! let agent = Agent::new("agent.acl").await?;
12//! let session = agent.session_async("/my-project", None).await?;
13//! let result = session.send("Explain the auth module", None).await?;
14//! println!("{}", result.text);
15//! # Ok(())
16//! # }
17//! ```
18
19use crate::agent::{AgentConfig, AgentEvent, AgentResult};
20use crate::commands::CommandRegistry;
21use crate::config::CodeConfig;
22use crate::error::Result;
23use crate::hitl::PendingConfirmationInfo;
24use crate::llm::{LlmClient, Message};
25use crate::prompts::{PlanningMode, SystemPromptSlots};
26use crate::queue::{
27    ExternalTask, ExternalTaskResult, LaneHandlerConfig, SessionLane, SessionQueueConfig,
28    SessionQueueStats,
29};
30use crate::tools::{ToolContext, ToolExecutor};
31use a3s_lane::{DeadLetter, MetricsSnapshot};
32use a3s_memory::MemoryStore;
33use std::collections::HashMap;
34use std::path::{Path, PathBuf};
35use std::sync::{Arc, RwLock};
36use tokio::sync::mpsc;
37use tokio::task::JoinHandle;
38mod agent_binding;
39mod agent_bootstrap;
40mod agent_facade;
41mod agent_loop_runtime;
42mod agent_sessions;
43mod capabilities;
44mod capability_facade;
45mod command_runtime;
46mod conversation_runtime;
47pub(crate) use conversation_runtime::{
48    ExactRecoveryError, ExactRecoveryPreparation, PreparedExactRecovery,
49};
50mod direct_tool_facade;
51mod direct_tools;
52mod governance_facade;
53mod hook_control;
54mod project_instructions;
55mod projected_flow;
56mod projected_host_capability;
57mod projected_ui;
58mod run_admission;
59mod run_facade;
60mod run_hook_executor;
61mod run_lifecycle;
62mod runtime;
63mod runtime_checkpoints;
64mod runtime_events;
65mod session_builder;
66mod session_clock;
67mod session_close;
68mod session_commands;
69mod session_config;
70mod session_extensions;
71mod session_facade;
72mod session_hitl;
73mod session_options;
74mod session_persistence;
75mod session_queue;
76mod session_runs;
77mod session_runtime;
78mod session_sandbox;
79mod session_save;
80mod session_verification;
81mod session_view;
82mod workflow_facade;
83pub use agent_facade::{Agent, SessionBuilder};
84use direct_tools::DirectToolRuntime;
85use hook_control::HookControl;
86pub use projected_flow::ProjectedFlowHandle;
87pub use projected_ui::ProjectedUiHandle;
88use runtime_events::ActiveToolState;
89use session_close::SessionCloseHandle;
90use session_extensions::SessionExtensionRuntime;
91use session_hitl::HitlControl;
92use session_queue::QueueControl;
93use session_runs::RunControl;
94use session_verification::VerificationRuntime;
95use session_view::SessionView;
96
97/// Canonicalize a path, stripping the Windows `\\?\` UNC prefix to avoid
98/// polluting workspace strings throughout the system (prompts, session data, etc.).
99fn safe_canonicalize(path: &Path) -> PathBuf {
100    match std::fs::canonicalize(path) {
101        Ok(p) => strip_unc_prefix(p),
102        Err(_) => path.to_path_buf(),
103    }
104}
105
106/// Strip the Windows extended-length path prefix (`\\?\`) that `canonicalize()` adds.
107/// On non-Windows this is a no-op.
108fn strip_unc_prefix(path: PathBuf) -> PathBuf {
109    #[cfg(windows)]
110    {
111        let s = path.to_string_lossy();
112        if let Some(stripped) = s.strip_prefix(r"\\?\") {
113            return PathBuf::from(stripped);
114        }
115    }
116    path
117}
118
119// ============================================================================
120// ToolCallResult
121// ============================================================================
122
123/// Result of a direct tool execution (no LLM).
124#[derive(Debug, Clone)]
125pub struct ToolCallResult {
126    pub name: String,
127    pub output: String,
128    pub exit_code: i32,
129    pub metadata: Option<serde_json::Value>,
130    /// Structured discriminant for tool failures. `None` when the tool
131    /// either succeeded or failed without a typed reason (the message in
132    /// `output` is then the only diagnostic). Populated for known
133    /// kinds such as `VersionConflict` so SDK callers can branch on the
134    /// `type` field instead of regex-matching `output`.
135    pub error_kind: Option<crate::tools::ToolErrorKind>,
136}
137
138/// Result of admitting a host-selected run identity for detached execution.
139///
140/// `Started` owns a supervisor task that drains the ordinary Code event stream
141/// into the authoritative run store. Dropping the handle detaches the task;
142/// call [`AgentSession::close`] for graceful cancellation and cleanup.
143pub enum AgentRunSpawn {
144    Started {
145        snapshot: crate::run::RunSnapshot,
146        worker: JoinHandle<()>,
147    },
148    Replayed {
149        snapshot: crate::run::RunSnapshot,
150    },
151}
152
153impl AgentRunSpawn {
154    pub const fn replayed(&self) -> bool {
155        matches!(self, Self::Replayed { .. })
156    }
157
158    pub fn snapshot(&self) -> &crate::run::RunSnapshot {
159        match self {
160            Self::Started { snapshot, .. } | Self::Replayed { snapshot } => snapshot,
161        }
162    }
163}
164
165// ============================================================================
166// ReadFileOptions
167// ============================================================================
168
169/// Optional line-range controls for direct `read` tool calls.
170#[derive(Debug, Clone, Copy, Default)]
171pub struct ReadFileOptions {
172    /// 0-indexed line offset to start reading from.
173    pub offset: Option<usize>,
174    /// Maximum number of lines to read.
175    pub limit: Option<usize>,
176}
177
178// ============================================================================
179// SessionOptions
180// ============================================================================
181
182/// Optional per-session overrides.
183#[derive(Clone, Default)]
184pub struct SessionOptions {
185    /// Override the default model. Format: `"provider/model"` (e.g., `"openai/gpt-4o"`).
186    pub model: Option<String>,
187    /// Priority used for top-level operations created by this session.
188    pub task_priority: crate::task_scheduler::TaskPriority,
189    /// Extra directories to scan for agent files.
190    /// Merged with any global `agent_dirs` from [`CodeConfig`].
191    pub agent_dirs: Vec<PathBuf>,
192    /// Reproducible disposable workers registered for task delegation.
193    /// Explicit session workers override agents loaded from directories by name.
194    pub worker_agents: Vec<crate::subagent::WorkerAgentSpec>,
195    /// Optional queue configuration for lane-based tool execution.
196    ///
197    /// When set, enables priority-based tool scheduling with parallel execution
198    /// of read-only (Query-lane) tools, DLQ, metrics, and external task handling.
199    pub queue_config: Option<SessionQueueConfig>,
200    /// Optional per-session web-search configuration.
201    ///
202    /// When set, this value overrides the agent-level `CodeConfig.search`
203    /// configuration for every built-in search/download/web-fetch tool in the
204    /// session. Keeping the value on `SessionOptions` makes the complete
205    /// search surface available to language SDKs without requiring callers to
206    /// rewrite an ACL file.
207    pub search_config: Option<crate::config::SearchConfig>,
208    /// Optional security provider for taint tracking and output sanitization
209    pub security_provider: Option<Arc<dyn crate::security::SecurityProvider>>,
210    /// Optional host-supplied LLM client.
211    ///
212    /// When set, it is used directly, overriding the `provider/model`
213    /// factory resolution — the one Action-layer backend that was previously
214    /// only injectable in test code. Lets a host plug in a provider the
215    /// built-in factory does not cover, a deterministic record/replay client,
216    /// or an HTTP-layer proxy/audit wrapper. Mirrors `workspace_services`.
217    pub llm_client: Option<Arc<dyn crate::llm::LlmClient>>,
218    /// Optional context providers for RAG
219    pub context_providers: Vec<Arc<dyn crate::context::ContextProvider>>,
220    /// One exact-generation cognitive package supplied by the embedding host.
221    ///
222    /// This is separate from general-purpose RAG providers: Code persists the
223    /// immutable package binding and treats provider failure as fatal. The host
224    /// retains A3S Use lease, Registry, installation, and lifecycle authority.
225    pub cognitive_context: Option<crate::cognitive_context::CognitiveContextSession>,
226    /// Optional confirmation manager for HITL
227    pub confirmation_manager: Option<Arc<dyn crate::hitl::ConfirmationProvider>>,
228    /// Optional confirmation policy (will be used to create ConfirmationManager if confirmation_manager is not set)
229    pub confirmation_policy: Option<crate::hitl::ConfirmationPolicy>,
230    /// Optional permission checker
231    pub permission_checker: Option<Arc<dyn crate::permissions::PermissionChecker>>,
232    /// Serializable permission policy used to build the checker, when available.
233    pub permission_policy: Option<crate::permissions::PermissionPolicy>,
234    /// Enable planning
235    pub planning_mode: PlanningMode,
236    /// Enable goal tracking
237    pub goal_tracking: bool,
238    /// Extra directories to scan for skill files (*.md).
239    /// Merged with any global `skill_dirs` from [`CodeConfig`].
240    pub skill_dirs: Vec<PathBuf>,
241    /// Optional skill registry for instruction injection
242    pub skill_registry: Option<Arc<crate::skills::SkillRegistry>>,
243    /// Whether active skill `allowed-tools` restrict ordinary session tool calls.
244    ///
245    /// Defaults to false so ordinary tools continue through permission policy,
246    /// hooks, and HITL. Set true to restore the legacy global active-skill
247    /// restriction behavior.
248    pub enforce_active_skill_tool_restrictions: Option<bool>,
249    /// Custom memory store override for long-term memory persistence.
250    ///
251    /// Sessions resolve a default store when this is not set.
252    pub memory_store: Option<Arc<dyn MemoryStore>>,
253    /// Optional exact V2 durable-memory binding.
254    ///
255    /// Shadow mode never recalls V2 nodes. Active recall additionally requires
256    /// explicit evidence-backed activation and records final context admission.
257    /// The live repository remains runtime-only; its secret-free namespace,
258    /// mode, recall policy, and retrieval profile are persisted for exact
259    /// resume validation.
260    pub durable_memory: Option<crate::durable_memory::DurableMemorySession>,
261    /// Host observers notified after successful durable memory writes.
262    pub memory_observers: Vec<Arc<dyn crate::memory::MemoryObserver>>,
263    /// Typed built-in and host jobs plus shutdown limits for owned memory maintenance.
264    ///
265    /// This runtime-only option is not persisted. A resumed session must inject
266    /// semantic refresh and custom consolidation schedules again.
267    pub memory_maintenance: crate::memory::MemoryMaintenanceOptions,
268    /// Deferred file memory directory — constructed async in `build_session()`
269    pub(crate) file_memory_dir: Option<PathBuf>,
270    /// Optional session store for persistence
271    pub session_store: Option<Arc<dyn crate::store::SessionStore>>,
272    /// Host-owned destination for exact live tool-boundary checkpoints.
273    ///
274    /// This extension does not replace the Session store. Code captures one
275    /// canonical `SessionSnapshotV1` and its matching logical resume boundary,
276    /// then hands the immutable export to this sink. Host storage policy and
277    /// cross-process fencing remain outside Code.
278    pub session_checkpoint_export_sink:
279        Option<Arc<dyn crate::session_checkpoint::SessionCheckpointExportSink>>,
280    /// Deferred file session-store directory, initialized by the async builder.
281    pub(crate) file_session_store_dir: Option<PathBuf>,
282    /// Explicit session ID (auto-generated if not set)
283    pub session_id: Option<String>,
284    /// Multi-tenant identifier. Framework only transports this string;
285    /// the host decides what "tenant" means and how to
286    /// aggregate/bill on it. Emitted to hooks/traces, persisted in
287    /// `SessionData`, never interpreted by core.
288    pub tenant_id: Option<String>,
289    /// Identity of the principal that triggered this session (user id,
290    /// service account, etc). Treated as opaque.
291    pub principal: Option<String>,
292    /// Logical identifier of the agent template / definition the session
293    /// was instantiated from. Lets the host aggregate sessions by
294    /// "which agent recipe" independent of the concrete session id.
295    pub agent_template_id: Option<String>,
296    /// Distributed-trace correlation id. Propagated through hooks/traces
297    /// so a session's events join with upstream/downstream work in the
298    /// host's observability pipeline.
299    pub correlation_id: Option<String>,
300    /// Optional host-supplied budget / quota guard. The framework calls
301    /// into it before each LLM call (and reports actuals after) so the
302    /// host can refuse or rate-limit at the cluster level. Default is
303    /// `None` (no enforcement — equivalent to
304    /// [`NoopBudgetGuard`](crate::budget::NoopBudgetGuard)).
305    pub budget_guard: Option<Arc<dyn crate::budget::BudgetGuard>>,
306    /// Optional host-provided ID/Clock pair. Replaces the default
307    /// random-UUID + wall-clock pair, enabling deterministic replay
308    /// on another node. `None` keeps pre-P2 behaviour.
309    pub host_env: Option<Arc<crate::host_env::HostEnv>>,
310    /// Optional FIFO retention caps on the session's in-memory stores
311    /// (run records, run events, trace events, terminal subagent
312    /// tasks). `None` selects [`SessionRetentionLimits::default`](crate::retention::SessionRetentionLimits::default),
313    /// which is finite. Pass [`SessionRetentionLimits::unbounded`](crate::retention::SessionRetentionLimits::unbounded)
314    /// explicitly to retain everything.
315    pub retention_limits: Option<crate::retention::SessionRetentionLimits>,
316    /// Optional structured JSONL trajectory config.
317    ///
318    /// When set, a3s-code records user prompts, LLM turns, tool calls,
319    /// tool observations, token usage, and execution end status for RL
320    /// training or service data collection. If unset, the same config can
321    /// be enabled by `A3S_CODE_TRAJECTORY_PATH`.
322    pub rl_trajectory: Option<crate::rl_trajectory::RlTrajectoryConfig>,
323    /// Request token-level log probabilities from compatible LLM providers.
324    ///
325    /// This is off by default because many public providers reject logprob
326    /// requests with tool calls. Training/evaluation harnesses using compatible
327    /// OpenAI-style backends can enable it explicitly.
328    pub llm_logprobs: Option<bool>,
329    /// Number of alternative token logprobs to request per generated token.
330    pub llm_top_logprobs: Option<usize>,
331    /// Auto-save after each completed `send()` or default-history `stream()` call.
332    pub auto_save: bool,
333    /// Optional artifact retention limits for large tool/program outputs.
334    pub artifact_store_limits: Option<crate::tools::ArtifactStoreLimits>,
335    /// Host-authorized immutable content adapter for original Tool content.
336    ///
337    /// The adapter is session-scoped and Rust-only. Its secret-free binding is
338    /// persisted; a resumed session must re-inject the exact same binding.
339    pub immutable_content_adapter: Option<crate::tools::ImmutableContentAdapterSession>,
340    /// Host-pinned deterministic policy for projecting large tool results.
341    ///
342    /// `None` selects the conservative compatibility profile. The resolved
343    /// policy is persisted and cannot drift when the session is resumed.
344    pub tool_result_transform_policy: Option<crate::tools::ToolResultTransformPolicyV1>,
345    /// Typed model-facing Tool presentation policy.
346    ///
347    /// The resolved value is frozen per Run and persisted for exact resume.
348    /// It never changes the Session's governed executor or A3S Use generation.
349    pub tool_presentation_profile: Option<crate::tools::ToolPresentationProfileV1>,
350    /// Max consecutive parse errors before aborting (overrides default of 2).
351    /// `None` uses the `AgentConfig` default.
352    pub max_parse_retries: Option<u32>,
353    /// Per-tool execution timeout in milliseconds.
354    /// `None` = no timeout (default).
355    pub tool_timeout_ms: Option<u64>,
356    /// Per-model API HTTP timeout in milliseconds.
357    /// `None` = no timeout (default).
358    pub llm_api_timeout_ms: Option<u64>,
359    /// Circuit-breaker threshold: max consecutive LLM API failures before
360    /// aborting in non-streaming mode (overrides default of 3).
361    /// `None` uses the `AgentConfig` default.
362    pub circuit_breaker_threshold: Option<u32>,
363    /// Max consecutive identical tool signatures before the guard turns the
364    /// duplicate call into a failed tool observation.
365    ///
366    /// `None` uses the `AgentConfig` default. Hosts can raise this for long
367    /// research sessions where repeating a read/search with the same arguments
368    /// is wasteful but should not make the whole run brittle.
369    pub duplicate_tool_call_threshold: Option<u32>,
370    /// Optional custom sandbox implementation.
371    ///
372    /// Local sessions install the A3S native sandbox by default. When set, this
373    /// handle replaces that default for `bash` tool commands. The host
374    /// application constructs and owns the custom implementation (for example,
375    /// an A3S Box-backed handle).
376    pub sandbox_handle: Option<Arc<dyn crate::sandbox::BashSandbox>>,
377    /// Optional host-provided workspace backend.
378    ///
379    /// When set, built-in tools such as `read`, `write`, `ls`, and `bash`
380    /// execute against these workspace capabilities instead of assuming the
381    /// server-local filesystem. This is the primary extension point for DFS,
382    /// browser, container, and remote workspace deployments.
383    pub workspace_services: Option<Arc<crate::workspace::WorkspaceServices>>,
384    /// Optional session-owned semantic workspace retrieval configuration.
385    ///
386    /// Construction is asynchronous and ephemeral. Source chunks stay in the
387    /// workspace catalog, vectors stay in memory, and no vector state is
388    /// serialized with the session snapshot.
389    pub workspace_retrieval: Option<crate::workspace::WorkspaceRetrievalOptions>,
390    /// Enable auto-compaction when context usage exceeds threshold.
391    pub auto_compact: bool,
392    /// Context usage percentage threshold for auto-compaction (0.0 - 1.0).
393    /// Default: 0.80 (80%).
394    pub auto_compact_threshold: Option<f32>,
395    /// Model context window used for automatic compaction accounting.
396    ///
397    /// When omitted, the configured model's declared context limit is used,
398    /// falling back to the agent default when the model has no declaration.
399    pub max_context_tokens: Option<usize>,
400    /// Inject a continuation message when the LLM stops without completing the task.
401    /// `None` uses the `AgentConfig` default (true).
402    pub continuation_enabled: Option<bool>,
403    /// Maximum continuation injections per execution.
404    /// `None` uses the `AgentConfig` default (3).
405    pub max_continuation_turns: Option<u32>,
406    /// Maximum execution time in milliseconds.
407    /// `None` = no timeout (default).
408    /// When set, the execution loop will abort if it exceeds this duration.
409    pub max_execution_time_ms: Option<u64>,
410    /// Optional MCP manager for connecting to external MCP servers.
411    ///
412    /// When set, all tools from connected MCP servers are registered and
413    /// available during agent execution with names like `mcp__server__tool`.
414    pub mcp_manager: Option<Arc<crate::mcp::manager::McpManager>>,
415    /// Sampling temperature (0.0–1.0). Overrides the provider default.
416    pub temperature: Option<f32>,
417    /// Extended thinking budget in tokens (Anthropic only).
418    pub thinking_budget: Option<usize>,
419    /// Per-session tool round limit override.
420    ///
421    /// When set, overrides the agent-level `max_tool_rounds` for this session only.
422    /// Maps directly from [`AgentDefinition::max_steps`](crate::subagent::AgentDefinition::max_steps)
423    /// when creating sessions
424    /// via [`Agent::session_for_agent`].
425    pub max_tool_rounds: Option<usize>,
426    /// Per-session parallel fan-out limit override.
427    ///
428    /// Applies to delegated `task` fan-out, the legacy `parallel_task` alias,
429    /// plan wave execution, and safe parallel write batches.
430    pub max_parallel_tasks: Option<usize>,
431    /// Per-session automatic subagent delegation override.
432    pub auto_delegation: Option<crate::config::AutoDelegationConfig>,
433    /// Per-session switch for model-visible manual child-agent tools.
434    ///
435    /// This overlays the effective automatic delegation config instead of
436    /// replacing it, so callers can hide `task` and its compatibility alias
437    /// while preserving other delegation settings.
438    pub manual_delegation_enabled: Option<bool>,
439    /// Per-session kill switch for automatic parallel child-agent fan-out.
440    ///
441    /// This overlays the effective automatic delegation config instead of
442    /// replacing it, so callers can disable auto fan-out without disabling
443    /// automatic delegation itself.
444    pub auto_parallel_delegation: Option<bool>,
445    /// Slot-based system prompt customization.
446    ///
447    /// When set, overrides the agent-level prompt slots for this session.
448    /// Users can customize role, guidelines, response style, and extra instructions
449    /// without losing the core agentic capabilities.
450    pub prompt_slots: Option<SystemPromptSlots>,
451    /// Optional external hook executor.
452    ///
453    /// When set, it replaces the built-in `HookEngine` for this session.
454    pub hook_executor: Option<Arc<dyn crate::hooks::HookExecutor>>,
455}
456
457// ============================================================================
458// AgentSession
459// ============================================================================
460
461/// Workspace-bound session. All LLM and tool operations happen here.
462///
463/// History is automatically accumulated after each `send()` call and after
464/// `stream()` completes when no custom history is supplied.
465/// Use `history()` to retrieve the current conversation log.
466///
467/// Conversation operations are single-flight, including slash commands and
468/// checkpoint resume. An overlapping call returns
469/// [`CodeError::SessionBusy`](crate::error::CodeError::SessionBusy) immediately.
470/// A streaming operation remains active until its returned handle completes.
471pub struct AgentSession {
472    llm_client: Arc<dyn LlmClient>,
473    /// Provider-reported generation capacity shared by every loop and
474    /// host-direct tool call created for this session.
475    model_generation_admission: crate::llm::ModelGenerationAdmission,
476    /// Agent-wide execution admission shared across sibling sessions.
477    task_scheduler: Arc<crate::task_scheduler::TaskScheduler>,
478    /// Base priority for this session's top-level operations.
479    task_priority: crate::task_scheduler::TaskPriority,
480    tool_executor: Arc<ToolExecutor>,
481    /// Session-owned atomic host capability catalog. A Run pins one immutable
482    /// generation before its model definitions and executor are assembled.
483    capability_catalog: Arc<crate::capability::CapabilityCatalog>,
484    tool_context: ToolContext,
485    config: AgentConfig,
486    tool_result_transform_policy: crate::tools::ToolResultTransformPolicyV1,
487    /// Host provider plus the durable exact-generation package binding.
488    cognitive_context: Option<crate::cognitive_context::CognitiveContextSession>,
489    /// General-purpose providers supplied by the embedding host before Code
490    /// adds its own workspace-instruction and Skill-catalog providers.
491    /// Projected Knowledge must not silently compose with this ambient RAG
492    /// surface.
493    host_context_provider_names: std::collections::BTreeSet<String>,
494    workspace: PathBuf,
495    /// Unique session identifier.
496    session_id: String,
497    /// Internal conversation history, auto-updated after each `send()` and default-history `stream()`.
498    history: Arc<RwLock<Vec<Message>>>,
499    /// Fail-fast single-flight admission for transcript-affecting operations.
500    run_admission: Arc<run_admission::RunAdmission>,
501    /// Optional lane queue for priority-based tool execution.
502    command_queue: Option<Arc<crate::session_lane_queue::SessionLaneQueue>>,
503    /// Long-term memory handle.
504    ///
505    /// Built sessions resolve a default memory store. This remains optional for
506    /// compatibility with lower-level/manual construction paths.
507    memory: Option<Arc<crate::memory::AgentMemory>>,
508    /// Optional session store for persistence.
509    session_store: Option<Arc<dyn crate::store::SessionStore>>,
510    /// Host-owned destination for same-boundary portable checkpoints.
511    session_checkpoint_export_sink:
512        Option<Arc<dyn crate::session_checkpoint::SessionCheckpointExportSink>>,
513    /// Runtime-owned fields used to build lossless persistence generations.
514    persistence_state: Arc<RwLock<session_persistence::SessionPersistenceState>>,
515    /// Auto-save after each completed `send()` or default-history `stream()`.
516    auto_save: bool,
517    /// Hook engine for lifecycle event interception.
518    hook_engine: Arc<crate::hooks::HookEngine>,
519    /// Optional external hook executor. When set, replaces `hook_engine` as the
520    /// executor passed to each `AgentLoop`.
521    hook_executor: Option<Arc<dyn crate::hooks::HookExecutor>>,
522    /// Deferred init warning: emitted as PersistenceFailed on first send() if set.
523    init_warning: Option<String>,
524    /// Slash command registry for `/command` dispatch.
525    /// Uses interior mutability so commands can be registered on a shared `Arc<AgentSession>`.
526    command_registry: std::sync::Mutex<CommandRegistry>,
527    /// Model identifier for display (e.g., "anthropic/claude-sonnet-4-20250514").
528    model_name: String,
529    /// Session-private MCP manager used by live add/remove operations.
530    mcp_manager: Arc<crate::mcp::manager::McpManager>,
531    /// Read-only MCP sources inherited from the parent agent and session options.
532    inherited_mcp_managers: Vec<Arc<crate::mcp::manager::McpManager>>,
533    /// Ordered MCP capability sources inherited by delegated child runs.
534    mcp_managers: Vec<Arc<crate::mcp::manager::McpManager>>,
535    /// Shared agent registry — populated at session creation; extended via register_agent_dir().
536    agent_registry: Arc<crate::subagent::AgentRegistry>,
537    /// Cancellation token for the current operation (send/stream).
538    /// Stored so that cancel() can abort ongoing LLM calls.
539    cancel_token: Arc<tokio::sync::Mutex<Option<tokio_util::sync::CancellationToken>>>,
540    /// ID of the run currently attached to the active cancellation token.
541    current_run_id: Arc<tokio::sync::Mutex<Option<String>>>,
542    /// In-memory run snapshots and event replay buffer for this session.
543    run_store: Arc<crate::run::InMemoryRunStore>,
544    /// Materialized view of delegated subagent task lifecycle, populated from runtime events.
545    subagent_tasks: Arc<crate::subagent_task_tracker::InMemorySubagentTaskTracker>,
546    /// Currently executing tools observed from runtime events.
547    active_tools: Arc<tokio::sync::RwLock<HashMap<String, ActiveToolState>>>,
548    /// Compact execution traces for this session.
549    trace_sink: crate::trace::InMemoryTraceSink,
550    /// Structured completion evidence collected from agent and explicit verification runs.
551    verification_reports: Arc<RwLock<Vec<crate::verification::VerificationReport>>>,
552    /// Set once `close()` has been called. Subsequent send/stream calls
553    /// fast-fail with [`crate::error::CodeError::SessionClosed`].
554    closed: Arc<std::sync::atomic::AtomicBool>,
555    /// Session-level parent cancellation token.
556    ///
557    /// Every in-flight run (blocking send, stream, delegated subagent task)
558    /// derives its per-operation token from this one via `child_token()`,
559    /// so `session_cancel.cancel()` cascades to all of them. `close()` fires
560    /// this token first, after which any new `child_token()` returns an
561    /// already-cancelled token (defending against close/spawn races).
562    pub(crate) session_cancel: tokio_util::sync::CancellationToken,
563    /// Optional asynchronous semantic workspace index owned by this session.
564    workspace_retrieval: Option<Arc<crate::workspace::WorkspaceRetrievalRuntime>>,
565    /// Shared `Arc`-handle used by both [`AgentSession::close`] and the
566    /// parent [`Agent`]'s registry. The handle bundles every field needed
567    /// to perform the close sequence so the two entry points cannot drift.
568    close_handle: Arc<SessionCloseHandle>,
569    /// Runtime-mutable override for the budget guard. When set, takes
570    /// precedence over `config.budget_guard` on the next agent-loop
571    /// build. Lets SDK callers (Node especially) install a host-side
572    /// guard after `session()` has returned without ever putting a
573    /// JS callable into `SessionOptions`.
574    runtime_budget_guard: std::sync::Mutex<Option<Arc<dyn crate::budget::BudgetGuard>>>,
575    /// Multi-tenant label. Framework only carries the string; semantics
576    /// belong to the host.
577    pub(crate) tenant_id: Option<String>,
578    /// Principal that triggered the session (user / service / etc.).
579    pub(crate) principal: Option<String>,
580    /// Logical identifier of the agent template the session was
581    /// instantiated from.
582    pub(crate) agent_template_id: Option<String>,
583    /// Distributed-trace correlation id propagated to hooks / traces.
584    pub(crate) correlation_id: Option<String>,
585}
586
587// ============================================================================
588// Tests
589// ============================================================================
590
591#[cfg(test)]
592mod capability_runtime_tests;
593#[cfg(test)]
594mod replacement_tests;
595#[cfg(test)]
596mod retrieval_qa_tests;
597#[cfg(test)]
598mod retrieval_tests;
599#[cfg(test)]
600mod tests;