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