Skip to main content

lash_core/
lib.rs

1//! Runtime kernel for Lash.
2//!
3//! The process kernel intentionally understands `ToolCall`, `SessionTurn`, and
4//! `External` because those inputs carry runtime mechanisms core must enforce:
5//! tool orchestration, child-session turns, and externally completed work. New
6//! process runtimes should use `ProcessInput::Engine { kind, payload }` unless
7//! core must understand their semantics to enforce a kernel mechanism.
8//!
9//! Protocols follow the same boundary: core owns the `HostTurnProtocol` state
10//! shape and the `ProtocolDriverPlugin` slot, while external protocol crates
11//! provide the driver implementation.
12
13pub mod attachments;
14pub mod chronological;
15pub mod direct;
16pub mod llm;
17mod model;
18pub mod plugin;
19mod plugin_stack;
20mod protocol_build;
21pub mod provider;
22pub mod runtime;
23pub mod search;
24pub mod session;
25pub mod session_graph;
26pub mod session_model;
27mod stable_hash;
28pub mod store;
29#[cfg(any(test, feature = "testing"))]
30pub mod testing;
31pub mod tool_dispatch;
32mod tool_provider;
33pub mod tool_registry;
34mod tool_result;
35mod trace;
36pub mod triggers;
37
38pub use lash_sansio::sansio;
39
40pub const VERSION: &str = env!("CARGO_PKG_VERSION");
41pub const SANSIO_VERSION: &str = lash_sansio::VERSION;
42
43#[derive(Clone, Copy, Debug, PartialEq, Eq)]
44pub enum DurabilityTier {
45    Inline,
46    Durable,
47}
48
49// Re-exports
50pub use attachments::{
51    AttachmentStore, AttachmentStoreError, AttachmentStorePersistence, FileAttachmentStore,
52    InMemoryAttachmentStore, SessionScopedAttachmentStore, StoredAttachment,
53};
54pub use chronological::{
55    BorrowedChronologicalEntry, BorrowedChronologicalMessage, BorrowedChronologicalPayload,
56    ChronologicalEntry, ChronologicalPayload, ChronologicalProjection, visit_turn_view,
57};
58pub use direct::{
59    DirectJsonSchema, DirectLlmClient, DirectLlmError, DirectMessage, DirectOutputSpec, DirectPart,
60    DirectRequest, DirectRole,
61};
62pub use lash_sansio::llm::types::{
63    GenerationOptions, LlmOutputPart, LlmRequest, LlmResponse, LlmTerminalReason,
64};
65pub use lash_sansio::{
66    AcceptedInjectedTurnInput, AttachmentCreateMeta, AttachmentId, AttachmentMeta, AttachmentRef,
67    BaseRenderCache, CheckpointDelivery, CheckpointKind, CompactToolContract, EffectId,
68    ErrorEnvelope, ExecImage, ExecResponse, ImageMediaType, LashSchema, LlmCallError, MediaType,
69    Message, MessageOrigin, MessageRole, MessageSequence, ModelToolReturn, ModelToolReturnPart,
70    Part, PartKind, PluginMessage, PluginRuntimeEvent, PreparedPrompt, PromptBuildInput,
71    PromptBuiltin, PromptContext, PromptContribution, PromptContributionGate,
72    PromptContributionSet, PromptFingerprint, PromptLayer, PromptSlot, PromptSlotLayer,
73    PromptTemplate, PromptTemplateEntry, PromptTemplateSection, PruneState, RenderedPrompt,
74    ResolvedPromptLayer, Response, SchemaProjectionOverride, SessionEvent, TextProjectionMetadata,
75    TokenUsage, ToolActivation, ToolArgumentProjectionPolicy, ToolCallOutcome, ToolCallOutput,
76    ToolCallRecord, ToolCallStatus, ToolCancellation, ToolCatalog, ToolCatalogBuildInput,
77    ToolCatalogEntry, ToolContract, ToolControl, ToolDefinition, ToolFailure, ToolFailureClass,
78    ToolFailureSource, ToolId, ToolManifest, ToolOutputContract, ToolRetryDisposition,
79    ToolRetryPolicy, ToolScheduling, ToolValue, TurnCause, TurnFinish, TurnLimitFinalMessage,
80    TurnOutcome, TurnStop, append_assistant_text_part, build_prompt, build_tool_catalog,
81    build_turn, default_prompt_template, head_tail_truncate, messages_are_prompt_resume_safe,
82    normalized_response_parts, prompt_template_fingerprint, prompt_text_fingerprint,
83    prompt_tool_names_fingerprint, reasoning_part, render_turn_causes_prompt,
84    resolve_prompt_layers, shared_parts, validate_tool_input,
85};
86pub use protocol_build::ProtocolBuildInput;
87pub use tool_registry::{
88    PLUGIN_TOOL_SOURCE_ID, ReconfigureError, ToolRegistry, ToolRestoreReport, ToolSourceHandle,
89    ToolState, ToolStateEntry,
90};
91pub use tool_result::{CancelHint, PendingCompletion, TimeoutBehavior, ToolResult};
92pub use triggers::{
93    InMemoryTriggerStore, TriggerDeliveryReservation, TriggerEmitReport, TriggerEvent,
94    TriggerEventCatalog, TriggerEventKey, TriggerEventType, TriggerInputBinding,
95    TriggerOccurrenceRecord, TriggerOccurrenceRequest, TriggerRegistration, TriggerRouter,
96    TriggerStore, TriggerSubscriptionDraft, TriggerSubscriptionFilter, TriggerSubscriptionRecord,
97    TriggerTargetSummary, default_trigger_source_key, deterministic_delivery_process_id,
98    deterministic_occurrence_id, empty_trigger_source_key, trigger_event_type,
99    trigger_occurrence_request_hash, validate_trigger_occurrence_request,
100};
101#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
102pub struct ProtocolTurnOptions {
103    #[serde(default = "empty_protocol_turn_payload")]
104    pub payload: serde_json::Value,
105}
106
107fn empty_protocol_turn_payload() -> serde_json::Value {
108    serde_json::Value::Object(serde_json::Map::new())
109}
110
111impl Default for ProtocolTurnOptions {
112    fn default() -> Self {
113        Self::empty()
114    }
115}
116
117impl ProtocolTurnOptions {
118    pub fn empty() -> Self {
119        Self {
120            payload: serde_json::Value::Object(serde_json::Map::new()),
121        }
122    }
123
124    pub fn is_empty(&self) -> bool {
125        match &self.payload {
126            serde_json::Value::Object(map) => map.is_empty(),
127            _ => false,
128        }
129    }
130
131    pub fn merged_with_override(&self, override_options: &Self) -> Self {
132        match (&self.payload, &override_options.payload) {
133            (serde_json::Value::Object(base), serde_json::Value::Object(overrides)) => {
134                let mut payload = base.clone();
135                payload.extend(overrides.clone());
136                Self {
137                    payload: serde_json::Value::Object(payload),
138                }
139            }
140            _ => override_options.clone(),
141        }
142    }
143
144    pub fn typed<T>(value: T) -> Result<Self, serde_json::Error>
145    where
146        T: serde::Serialize,
147    {
148        Ok(Self {
149            payload: serde_json::to_value(value)?,
150        })
151    }
152
153    pub fn decode<T>(&self) -> Result<T, serde_json::Error>
154    where
155        T: serde::de::DeserializeOwned,
156    {
157        serde_json::from_value(self.payload.clone())
158    }
159}
160
161#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
162pub struct ProtocolDriverState {
163    pub plugin_id: String,
164    pub payload: serde_json::Value,
165}
166
167impl ProtocolDriverState {
168    pub fn new(plugin_id: impl Into<String>, payload: serde_json::Value) -> Self {
169        Self {
170            plugin_id: plugin_id.into(),
171            payload,
172        }
173    }
174}
175
176#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
177pub struct HostTurnProtocol;
178
179impl lash_sansio::TurnProtocol for HostTurnProtocol {
180    type Event = crate::session_model::ProtocolEvent;
181    type Termination = ProtocolTurnOptions;
182    type DriverState = ProtocolDriverState;
183}
184
185pub type Effect = lash_sansio::Effect<HostTurnProtocol>;
186pub type DriverAction = lash_sansio::DriverAction<HostTurnProtocol>;
187pub type DriverContextView<'a> = lash_sansio::DriverContextView<'a, HostTurnProtocol>;
188pub type TurnDriverConfig = lash_sansio::TurnDriverConfig<HostTurnProtocol>;
189pub type TurnDriverPreamble = lash_sansio::TurnDriverPreamble<HostTurnProtocol>;
190pub type ProjectorContext<'a> = lash_sansio::ProjectorContext<'a, HostTurnProtocol>;
191pub type PreparedTurnMachine = lash_sansio::PreparedTurnMachine<HostTurnProtocol>;
192pub type SansIoTurnInput = lash_sansio::SansIoTurnInput<HostTurnProtocol>;
193pub type TurnMachine = lash_sansio::TurnMachine<HostTurnProtocol>;
194pub type TurnMachineConfig = lash_sansio::TurnMachineConfig<HostTurnProtocol>;
195#[cfg(feature = "otel-trace")]
196pub use lash_trace::otel::{OtelTraceOptions, OtelTraceSink};
197pub use lash_trace::{
198    JsonlTraceSink, TraceAttachment, TraceBranchSelection, TraceContentBlock, TraceContext,
199    TraceError, TraceEvent, TraceLabelMetadata, TraceLevel, TraceLlmMessage, TraceLlmRequest,
200    TraceLlmResponse, TracePromptComponent, TraceProviderStreamEvent, TraceRecord,
201    TraceRuntimeScope, TraceRuntimeStreamEvent, TraceRuntimeSubject, TraceSink, TraceSinkError,
202    TraceTokenUsage, TraceToolSpec,
203};
204pub use llm::transport::{LlmTransportError, ProviderFailure, ProviderFailureKind};
205pub use model::{ModelLimits, ModelSpec};
206pub use plugin::{
207    AgentFrameAssignment, AgentFrameId, AgentFrameReason, AgentFrameRecord, AgentFrameStatus,
208    AppendSessionNodesRequest, AppendSessionNodesResult, AssistantResponseHookContext,
209    AssistantResponseTransform, AssistantStreamHookContext, AssistantStreamTransform,
210    CheckpointHookContext, CompactionContext, ContextCompaction, ContextCompactor, ContextError,
211    ContextRegistrations, DirectCompletion, DirectLlmCompletion, OpenAgentFrameRequest,
212    OpenAgentFrameResult, PersistentRuntimeServices, PluginCommand, PluginCommandContext,
213    PluginCommandOutcome, PluginCommandReceipt, PluginDirective, PluginError,
214    PluginExtensionContribution, PluginExtensions, PluginFactory, PluginHost, PluginLifecycleEvent,
215    PluginLifecycleEventHook, PluginOperation, PluginOperationDef, PluginOperationFailure,
216    PluginOperationInvokeError, PluginOperationKind, PluginOptions, PluginOwned, PluginQuery,
217    PluginQueryContext, PluginRegistrar, PluginRuntimeDirective, PluginSession,
218    PluginSessionContext, PluginSessionSnapshot, PluginSnapshotArtifact, PluginSnapshotEntry,
219    PluginSnapshotMeta, PluginSpec, PluginSpecFactory, PluginTask, PluginTaskContext,
220    PluginTaskOutcome, PluginTaskReceipt, PromptHookContext, ProtocolBeforeLlmCallContext,
221    ProtocolLlmCallAction, RuntimeServices, SessionAppendNode, SessionConfigChangedContext,
222    SessionContextOverlay, SessionCreateRequest, SessionGraphService, SessionHandle,
223    SessionLifecycleService, SessionParam, SessionPlugin, SessionPluginSource, SessionReadView,
224    SessionRelation, SessionSnapshot, SessionStartPoint, SessionStateChangedContext,
225    SessionStateService, SessionToolAccess, SessionTurnInput, SessionTurnRequest, SnapshotReader,
226    SnapshotWriter, SubagentSessionContext, ToolCatalogContribution, ToolResultProjectionContext,
227    ToolResultProjector, TriggerEventRegistrations, TurnContextTransform, TurnHookContext,
228    TurnResultHookContext, TurnResultSummary, TurnTransformContext, plugin_operation_def,
229};
230pub use plugin_stack::PluginStack;
231pub use provider::{
232    CacheRetention, EmptyProviderResolver, LlmTimeouts, MapProviderResolver, Provider,
233    ProviderBinding, ProviderComponents, ProviderFactory, ProviderHandle, ProviderModelPolicy,
234    ProviderOptions, ProviderResolutionError, ProviderSpec, RequestTimeout,
235    RuntimeProviderResolver, SingleProviderResolver, StaticModelPolicy,
236};
237#[cfg(any(test, feature = "testing"))]
238pub use runtime::TestLocalProcessRegistry;
239pub use runtime::{
240    AgentFrameRun, AssembledTurn, AssistantOutput, AwaitEventKey, AwaitEventWaitIdentity,
241    CausalRef, Clock, CodeOutputRecord, DefaultProcessCancelAbility, DeliveryPolicy,
242    DirectCompletionClient, DurableProcessWorker, DurableProcessWorkerConfig, DurableStoreFacet,
243    EffectHost, EmbeddedRuntimeBuilder, EmbeddedRuntimeHost, EventSink, ExecutionScope,
244    ExecutionSummary, ExternalCompletionError, InMemoryLiveReplayStore,
245    InMemoryLiveReplayStoreConfig, InMemoryProcessExecutionEnvStore, InMemorySessionStore,
246    InMemorySessionStoreFactory, InlineEffectHost, InlineProcessRunHandle,
247    InlineRuntimeEffectController, InputItem, LashRuntime, LiveReplayGap, LiveReplayGapReason,
248    LiveReplayResult, LiveReplayStore, LiveReplayStoreError, LiveReplaySubscribeResult,
249    LiveReplaySubscription, MergeKey, NoopEventSink, NoopTurnActivitySink, ObservedProcess,
250    ObservedProcessEvent, ObservedWorkItem, OutputState, PROCESS_LEASE_SCHEMA_VERSION,
251    ParkedSession, PendingTurnInput, PendingTurnInputDraft, ProcessAwaitOutput,
252    ProcessCancelAbility, ProcessCancelAllRequest, ProcessCancelRequest, ProcessCancelSource,
253    ProcessCancelSummary, ProcessEngine, ProcessEngineRegistry, ProcessEngineRunContext,
254    ProcessEngineRunGuard, ProcessEngineRuntimeContext, ProcessEngineValidationContext,
255    ProcessEvent, ProcessEventAppendPlan, ProcessEventAppendRequest, ProcessEventAppendResult,
256    ProcessEventType, ProcessExecutionContext, ProcessExecutionEnvRef, ProcessExecutionEnvSpec,
257    ProcessExecutionEnvStore, ProcessExternalRef, ProcessHandleDescriptor, ProcessHandleGrant,
258    ProcessHandleSummary, ProcessId, ProcessIdentity, ProcessInput, ProcessLease,
259    ProcessLeaseCompletion, ProcessLifecycleStatus, ProcessListFilter, ProcessListMode,
260    ProcessOpScope, ProcessOriginator, ProcessProvenance, ProcessRecord, ProcessRegistration,
261    ProcessRegistry, ProcessRunHandle, ProcessRuntimeHost, ProcessService,
262    ProcessSessionDeleteReport, ProcessSpawnProvenance, ProcessStartGrant, ProcessStartOptions,
263    ProcessStartRequest, ProcessStatus, ProcessStatusFilter, ProcessTerminalSemantics,
264    ProcessTerminalSpec, ProcessTerminalState, ProcessValueSelector, ProcessWake,
265    ProcessWakeDedupeKey, ProcessWakeDelivery, ProcessWakeSpec, ProcessWorkDriver,
266    ProcessWorkObserver, ProcessWorkSnapshot, PromptUsage, ProtocolSessionExtension,
267    ProtocolSessionExtensionHandle, ProtocolTurnExtension, ProtocolTurnExtensionHandle,
268    QueuedWorkDriver, QueuedWorkRunHandle, QueuedWorkRunRequest, Residency, Resolution,
269    ResolveOutcome, RuntimeEnvironment, RuntimeEnvironmentBuilder, RuntimeError, RuntimeErrorCode,
270    RuntimeHandle, RuntimeHostConfig, RuntimeObservation, ScopedEffectController, SessionCommand,
271    SessionCommandReceipt, SessionCursor, SessionCursorError, SessionObservation,
272    SessionObservationEvent, SessionObservationEventPayload, SessionObservationSubscription,
273    SessionProcessEventKind, SessionQueueEventKind, SessionResume, SessionRevision, SessionScope,
274    SessionScopeId, SessionStoreCreateRequest, SessionStoreFactory, SessionUsageReport, SlotPolicy,
275    SystemClock, TerminationPolicy, TokenLedgerEntry, ToolCallLaunch, TurnActivity, TurnActivityId,
276    TurnActivitySink, TurnContext, TurnEvent, TurnInput, TurnInputCheckpointBoundary,
277    TurnInputClaim, TurnInputClaimMode, TurnInputCompletion, TurnInputIngress, TurnInputState,
278    TurnIssue, TurnOptions, UnavailableProcessService, UsageReportRow, UsageTotals, WaitKind,
279    WaitState, apply_process_status_projection, current_epoch_ms, diff_token_ledger,
280    diff_usage_reports, ensure_durable_effect_input, epoch_ms_from_system_time,
281    process_signal_event_type, process_signal_name_from_event_type, process_signal_wait_key,
282    system_time_from_epoch_ms, validate_process_signal_name,
283};
284#[allow(unused_imports)]
285pub(crate) use runtime::{
286    LlmAttachmentSpec, ProcessEventSemantics, QUEUED_WORK_CLAIM_TTL_MS, QueuedCheckpointTurnInput,
287    QueuedCheckpointWork, QueuedTurnWork, QueuedWorkBatch, QueuedWorkBatchDraft, QueuedWorkClaim,
288    QueuedWorkClaimBoundary, QueuedWorkCompletion, QueuedWorkItem, QueuedWorkPayload,
289    RuntimeReplay, RuntimeScope, RuntimeSubject, TURN_INPUT_CLAIM_TTL_MS,
290    load_process_execution_env, materialize_process_event_semantics, persist_process_execution_env,
291    prepare_process_event_append, prepare_process_registration, process_event_invocation,
292    process_event_payload_hash, process_wake_batch_draft, process_wake_delivery,
293    process_wake_input_from_event_payload, process_wake_turn_cause, process_wake_turn_text,
294    require_event_replay,
295};
296pub use session_model::{
297    PLUGIN_RUNTIME_PROTOCOL_PLUGIN_ID, PersistedPluginRuntimeEvent,
298    plugin_runtime_event_from_protocol, plugin_runtime_protocol_event,
299};
300// Effect / process-control types consumed by external effect hosts (e.g.
301// lash-restate's workflows) and their integration tests. Kept on the public
302// surface; the rest of the runtime block above stays crate-internal.
303pub use runtime::{
304    LlmRequestSpec, ProcessCommand, ProcessEffectOutcome, ProcessEventSemanticsSpec,
305    RuntimeEffectCommand, RuntimeEffectController, RuntimeEffectControllerError,
306    RuntimeEffectEnvelope, RuntimeEffectKind, RuntimeEffectLocalExecutor, RuntimeEffectOutcome,
307    RuntimeInvocation, RuntimeSessionState, ToolAttemptEffectOutcome, ToolAttemptLaunch,
308    ToolBatchEffectOutcome,
309};
310pub use schemars::JsonSchema;
311pub use session::{
312    ExecRequest, InjectedTurnInput, RuntimeExecutionContext, Session, SessionError, ToolInvocation,
313    ToolInvocationReply,
314};
315pub use session_graph::{
316    PersistedSessionConfig, PersistedTurnState, SessionGraph, SessionMessageTreeNode,
317    SessionNodePayload, SessionNodeRecord,
318};
319pub use session_model::context::PreparedContext;
320pub use session_model::{ConversationRecord, ProtocolEvent, SessionEventRecord};
321pub use session_model::{RuntimeSessionPolicy, SessionPolicy, SessionSpec};
322pub use store::{
323    AttachmentIntent, AttachmentManifest, AttachmentManifestEntry, BlobRef, GcReport,
324    LeaseOwnerIdentity, LeaseOwnerLiveness, RuntimePersistence, SessionExecutionLease,
325    SessionExecutionLeaseClaimOutcome, SessionExecutionLeaseCompletion, SessionExecutionLeaseFence,
326    SessionMeta, SessionPickerInfo, SessionReadScope, StoreError, VacuumReport,
327};
328#[allow(unused_imports)]
329pub(crate) use store::{
330    GraphCommitDelta, PersistedSessionRead, RuntimeCommitResult, SessionCheckpoint,
331    SessionHeadMeta, ensure_supported_schema_version, load_persisted_session_state,
332    load_persisted_session_state_active_path,
333};
334pub use store::{
335    HydratedSessionCheckpoint, RuntimeCommit, RuntimeTurnCommitStamp, SessionHead,
336    refresh_persisted_session_state,
337};
338pub use tool_provider::{
339    PreparedToolBatch, PreparedToolBatchCall, PreparedToolCall, ProgressSender, SandboxMessage,
340    ToolCall, ToolChildExecutionTraceHook, ToolChildProcessStarted, ToolContext,
341    ToolDurableEffects, ToolExecutionGrant, ToolPrepareCall, ToolPrepareContext, ToolProvider,
342    ToolSessionAdmin, ToolSessionModel, ToolTriggerClient,
343};
344
345#[cfg(test)]
346mod tests {
347    use super::*;
348
349    #[test]
350    fn protocol_turn_options_missing_payload_deserializes_to_empty_object() {
351        let options: ProtocolTurnOptions =
352            serde_json::from_value(serde_json::json!({})).expect("deserialize options");
353
354        assert!(options.is_empty());
355        assert_eq!(options.payload, serde_json::json!({}));
356    }
357
358    #[test]
359    fn protocol_turn_options_explicit_null_is_not_empty() {
360        let options: ProtocolTurnOptions =
361            serde_json::from_value(serde_json::json!({ "payload": null }))
362                .expect("deserialize options");
363
364        assert!(!options.is_empty());
365        assert_eq!(options.payload, serde_json::Value::Null);
366    }
367
368    #[test]
369    fn root_exports_do_not_reintroduce_removed_session_state_shapes() {
370        let source = include_str!("lib.rs");
371        let removed_envelope = ["SessionState", "Envelope"].concat();
372        let removed_persisted = ["PersistedSession", "Snapshot"].concat();
373        let removed_history_rewriter = ["History", "Rewriter"].concat();
374        let removed_rewrite_trigger = ["Rewrite", "Trigger"].concat();
375        let removed_rewrite_context = ["Rewrite", "Context"].concat();
376        let removed_history_state = ["History", "State"].concat();
377        let removed_history_metadata = ["History", "Rewrite", "Metadata"].concat();
378
379        assert!(!source.contains(&removed_envelope));
380        assert!(!source.contains(&removed_persisted));
381        assert!(!source.contains(&removed_history_rewriter));
382        assert!(!source.contains(&removed_rewrite_trigger));
383        assert!(!source.contains(&removed_rewrite_context));
384        assert!(!source.contains(&removed_history_state));
385        assert!(!source.contains(&removed_history_metadata));
386    }
387
388    fn public_reexport_block(source: &str, module: &str) -> String {
389        let start = format!("pub use {module}::{{");
390        let mut block = String::new();
391        let mut collecting = false;
392        for line in source.lines() {
393            if line.trim_start().starts_with(&start) {
394                collecting = true;
395            }
396            if collecting {
397                block.push_str(line);
398                block.push('\n');
399                if line.trim_end() == "};" {
400                    break;
401                }
402            }
403        }
404        assert!(!block.is_empty(), "missing public {module} re-export block");
405        block
406    }
407
408    #[test]
409    fn root_runtime_exports_exclude_internal_runtime_records() {
410        let runtime_exports = public_reexport_block(include_str!("lib.rs"), "runtime");
411        for removed in [
412            "RuntimeEffectCommand",
413            "RuntimeEffectEnvelope",
414            "RuntimeEffectKind",
415            "RuntimeEffectOutcome",
416            "RuntimeInvocation",
417            "RuntimeScope",
418            "RuntimeSessionState",
419            "QueuedWorkBatch",
420            "QueuedWorkBatchDraft",
421            "QueuedWorkPayload",
422            "prepare_process_registration",
423            "process_wake_batch_draft",
424            "require_event_replay",
425        ] {
426            assert!(
427                !runtime_exports.contains(removed),
428                "runtime root export leaked {removed}"
429            );
430        }
431    }
432
433    #[test]
434    fn root_store_exports_exclude_wire_records() {
435        let store_exports = public_reexport_block(include_str!("lib.rs"), "store");
436        for removed in [
437            "SessionHead",
438            "SessionCheckpoint",
439            "RuntimeCommit",
440            "HydratedSessionCheckpoint",
441            "PersistedSessionRead",
442            "GraphCommitDelta",
443        ] {
444            assert!(
445                !store_exports.contains(removed),
446                "store root export leaked {removed}"
447            );
448        }
449    }
450
451    #[test]
452    fn removed_manager_and_host_trait_names_stay_removed() {
453        let removed_manager = ["Runtime", "Session", "Manager"].concat();
454        let removed_host = ["Runtime", "Session", "Host"].concat();
455        let sources = [
456            include_str!("runtime/session_manager/mod.rs"),
457            include_str!("plugin/runtime_host.rs"),
458            include_str!("tool_dispatch/context.rs"),
459            include_str!("tool_provider.rs"),
460        ];
461
462        for source in sources {
463            assert!(!source.contains(&removed_manager));
464            assert!(!source.contains(&removed_host));
465        }
466    }
467}