pub mod attachments;
pub mod chronological;
pub mod direct;
pub mod llm;
mod model;
pub mod plugin;
mod plugin_stack;
mod protocol_build;
pub mod provider;
pub mod runtime;
pub mod search;
pub mod session;
pub mod session_graph;
pub mod session_model;
mod stable_hash;
pub mod store;
#[cfg(any(test, feature = "testing"))]
pub mod testing;
pub mod tool_dispatch;
mod tool_provider;
pub mod tool_registry;
mod tool_result;
mod trace;
pub mod triggers;
pub use lash_sansio::sansio;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub const SANSIO_VERSION: &str = lash_sansio::VERSION;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DurabilityTier {
Inline,
Durable,
}
pub use attachments::{
AttachmentReclamationReport, AttachmentStore, AttachmentStoreError, AttachmentStorePersistence,
FileAttachmentStore, InMemoryAttachmentStore, SessionScopedAttachmentStore, StoredAttachment,
reclaim_orphaned_attachments,
};
pub use chronological::{
BorrowedChronologicalEntry, BorrowedChronologicalMessage, BorrowedChronologicalPayload,
ChronologicalEntry, ChronologicalPayload, ChronologicalProjection, visit_turn_view,
};
pub use direct::{
DirectJsonSchema, DirectLlmClient, DirectLlmError, DirectMessage, DirectOutputSpec, DirectPart,
DirectRequest, DirectRole,
};
pub use lash_sansio::llm::types::{
GenerationOptions, LlmOutputPart, LlmRequest, LlmRequestScope, LlmResponse, LlmTerminalReason,
};
pub use lash_sansio::{
AcceptedInjectedTurnInput, AttachmentCreateMeta, AttachmentId, AttachmentMeta, AttachmentRef,
BaseRenderCache, CheckpointDelivery, CheckpointKind, CompactToolContract, EffectId,
ErrorEnvelope, ExecImage, ExecResponse, ImageMediaType, LashSchema, LlmCallError, MediaType,
Message, MessageOrigin, MessageRole, MessageSequence, ModelToolReturn, ModelToolReturnPart,
Part, PartKind, PluginMessage, PluginRuntimeEvent, PreparedPrompt, ProjectionMode,
PromptBuildInput, PromptBuiltin, PromptContext, PromptContribution, PromptContributionGate,
PromptContributionSet, PromptFingerprint, PromptLayer, PromptSlot, PromptSlotLayer,
PromptTemplate, PromptTemplateEntry, PromptTemplateSection, ProviderSchemaCapabilities,
PruneState, RenderedPrompt, ResolvedPromptLayer, ResolvedSchema, Response, SchemaContract,
SchemaDialect, SchemaProjectionOverride, SchemaProjectionPolicy, SchemaPurpose,
SchemaResolutionError, SchemaResolutionRequest, SessionEvent, TextProjectionMetadata,
TokenUsage, ToolActivation, ToolArgumentProjectionPolicy, ToolCallOutcome, ToolCallOutput,
ToolCallRecord, ToolCallStatus, ToolCancellation, ToolCatalog, ToolCatalogBuildInput,
ToolCatalogEntry, ToolContract, ToolControl, ToolDefinition, ToolFailure, ToolFailureClass,
ToolFailureSource, ToolId, ToolManifest, ToolOutputContract, ToolRetryDisposition,
ToolRetryPolicy, ToolScheduling, ToolValue, TurnCause, TurnFinish, TurnLimitFinalMessage,
TurnOutcome, TurnStop, append_assistant_text_part, build_prompt, build_tool_catalog,
build_turn, default_prompt_template, head_tail_truncate, messages_are_prompt_resume_safe,
normalized_response_parts, project_anthropic_bedrock_schema, project_for_dialect,
prompt_template_fingerprint, prompt_text_fingerprint, prompt_tool_names_fingerprint,
reasoning_part, render_turn_causes_prompt, resolve_prompt_layers, resolve_schema, shared_parts,
validate_tool_input, visible_response_parts, visible_response_text_from_parts,
};
pub use protocol_build::ProtocolBuildInput;
pub use tool_registry::{
PLUGIN_TOOL_SOURCE_ID, ReconfigureError, ToolRegistry, ToolRestoreReport, ToolSourceHandle,
ToolState, ToolStateEntry,
};
pub use tool_result::{CancelHint, PendingCompletion, TimeoutBehavior, ToolResult};
pub use triggers::{
InMemoryTriggerStore, TriggerDeliveryReservation, TriggerEmitReport, TriggerEvent,
TriggerEventCatalog, TriggerEventKey, TriggerEventType, TriggerInputBinding,
TriggerOccurrenceRecord, TriggerOccurrenceRequest, TriggerRegistration, TriggerRouter,
TriggerStore, TriggerSubscriptionDraft, TriggerSubscriptionFilter, TriggerSubscriptionRecord,
TriggerTargetSummary, default_trigger_source_key, deterministic_delivery_process_id,
deterministic_occurrence_id, empty_trigger_source_key, trigger_event_type,
trigger_occurrence_request_hash, validate_trigger_occurrence_request,
};
pub const PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION: u32 = 1;
#[derive(Clone, Debug, serde::Serialize)]
pub struct ProtocolTurnOptions {
pub schema_version: u32,
pub payload: serde_json::Value,
}
fn empty_protocol_turn_payload() -> serde_json::Value {
serde_json::Value::Object(serde_json::Map::new())
}
#[derive(Debug, thiserror::Error)]
pub enum ProtocolTurnOptionsError {
#[error(
"protocol turn options are missing schema_version and were written by unsupported pre-versioned state (expected {expected})"
)]
MissingSchemaVersion { expected: u32 },
#[error(
"protocol turn options schema_version {actual} is not supported by this binary (expected {expected})"
)]
UnsupportedSchemaVersion { actual: u32, expected: u32 },
#[error(
"protocol turn options schema_version {actual} is invalid (expected integer {expected})"
)]
InvalidSchemaVersion { actual: String, expected: u32 },
#[error("failed to decode protocol turn options payload: {0}")]
Decode(#[source] serde_json::Error),
}
fn parse_protocol_turn_options_schema_version(
value: Option<serde_json::Value>,
) -> Result<u32, ProtocolTurnOptionsError> {
let expected = PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION;
let Some(value) = value else {
return Err(ProtocolTurnOptionsError::MissingSchemaVersion { expected });
};
let Some(actual) = value
.as_u64()
.and_then(|version| u32::try_from(version).ok())
else {
return Err(ProtocolTurnOptionsError::InvalidSchemaVersion {
actual: value.to_string(),
expected,
});
};
ensure_protocol_turn_options_schema_version(actual)?;
Ok(actual)
}
fn ensure_protocol_turn_options_schema_version(
actual: u32,
) -> Result<(), ProtocolTurnOptionsError> {
let expected = PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION;
if actual == expected {
Ok(())
} else {
Err(ProtocolTurnOptionsError::UnsupportedSchemaVersion { actual, expected })
}
}
impl<'de> serde::Deserialize<'de> for ProtocolTurnOptions {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
#[derive(serde::Deserialize)]
struct ProtocolTurnOptionsWire {
schema_version: Option<serde_json::Value>,
#[serde(default = "empty_protocol_turn_payload")]
payload: serde_json::Value,
}
let wire = ProtocolTurnOptionsWire::deserialize(deserializer)?;
let schema_version = parse_protocol_turn_options_schema_version(wire.schema_version)
.map_err(serde::de::Error::custom)?;
Ok(Self {
schema_version,
payload: wire.payload,
})
}
}
impl Default for ProtocolTurnOptions {
fn default() -> Self {
Self::empty()
}
}
impl ProtocolTurnOptions {
pub fn empty() -> Self {
Self {
schema_version: PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION,
payload: serde_json::Value::Object(serde_json::Map::new()),
}
}
pub fn from_payload(payload: serde_json::Value) -> Self {
Self {
schema_version: PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION,
payload,
}
}
pub fn is_empty(&self) -> bool {
match &self.payload {
serde_json::Value::Object(map) => map.is_empty(),
_ => false,
}
}
pub fn merged_with_override(&self, override_options: &Self) -> Self {
match (&self.payload, &override_options.payload) {
(serde_json::Value::Object(base), serde_json::Value::Object(overrides)) => {
let mut payload = base.clone();
payload.extend(overrides.clone());
Self {
schema_version: PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION,
payload: serde_json::Value::Object(payload),
}
}
_ => override_options.clone(),
}
}
pub fn typed<T>(value: T) -> Result<Self, serde_json::Error>
where
T: serde::Serialize,
{
Ok(Self {
schema_version: PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION,
payload: serde_json::to_value(value)?,
})
}
pub fn decode<T>(&self) -> Result<T, ProtocolTurnOptionsError>
where
T: serde::de::DeserializeOwned,
{
ensure_protocol_turn_options_schema_version(self.schema_version)?;
serde_json::from_value(self.payload.clone()).map_err(ProtocolTurnOptionsError::Decode)
}
}
#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
pub struct ProtocolDriverState {
pub plugin_id: String,
pub payload: serde_json::Value,
}
impl ProtocolDriverState {
pub fn new(plugin_id: impl Into<String>, payload: serde_json::Value) -> Self {
Self {
plugin_id: plugin_id.into(),
payload,
}
}
}
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct HostTurnProtocol;
impl lash_sansio::TurnProtocol for HostTurnProtocol {
type Event = crate::session_model::ProtocolEvent;
type Termination = ProtocolTurnOptions;
type DriverState = ProtocolDriverState;
}
pub type Effect = lash_sansio::Effect<HostTurnProtocol>;
pub type DriverAction = lash_sansio::DriverAction<HostTurnProtocol>;
pub type DriverContextView<'a> = lash_sansio::DriverContextView<'a, HostTurnProtocol>;
pub type TurnDriverConfig = lash_sansio::TurnDriverConfig<HostTurnProtocol>;
pub type TurnDriverPreamble = lash_sansio::TurnDriverPreamble<HostTurnProtocol>;
pub type ProjectorContext<'a> = lash_sansio::ProjectorContext<'a, HostTurnProtocol>;
pub type PreparedTurnMachine = lash_sansio::PreparedTurnMachine<HostTurnProtocol>;
pub type SansIoTurnInput = lash_sansio::SansIoTurnInput<HostTurnProtocol>;
pub type TurnMachine = lash_sansio::TurnMachine<HostTurnProtocol>;
pub type TurnMachineConfig = lash_sansio::TurnMachineConfig<HostTurnProtocol>;
#[cfg(feature = "otel-trace")]
pub use lash_trace::otel::{OtelTraceOptions, OtelTraceSink};
pub use lash_trace::{
JsonlTraceSink, TraceAttachment, TraceBranchSelection, TraceContentBlock, TraceContext,
TraceError, TraceEvent, TraceLabelMetadata, TraceLevel, TraceLlmMessage, TraceLlmRequest,
TraceLlmResponse, TracePromptComponent, TraceProviderStreamEvent, TraceRecord,
TraceRuntimeScope, TraceRuntimeStreamEvent, TraceRuntimeSubject, TraceSink, TraceSinkError,
TraceTokenUsage, TraceToolSpec,
};
pub use llm::transport::{LlmTransportError, ProviderFailure, ProviderFailureKind};
pub use model::{ModelLimits, ModelSpec};
pub use plugin::{
AgentFrameAssignment, AgentFrameId, AgentFrameReason, AgentFrameRecord, AgentFrameStatus,
AppendSessionNodesRequest, AppendSessionNodesResult, AssistantResponseHookContext,
AssistantResponseTransform, AssistantStreamHookContext, AssistantStreamTransform,
CheckpointHookContext, CompactionContext, ContextCompaction, ContextCompactor, ContextError,
ContextRegistrations, DirectCompletion, DirectLlmCompletion, OpenAgentFrameRequest,
OpenAgentFrameResult, PersistentRuntimeServices, PluginCommand, PluginCommandContext,
PluginCommandOutcome, PluginCommandReceipt, PluginDirective, PluginError,
PluginExtensionContribution, PluginExtensions, PluginFactory, PluginHost, PluginLifecycleEvent,
PluginLifecycleEventHook, PluginOperation, PluginOperationDef, PluginOperationFailure,
PluginOperationInvokeError, PluginOperationKind, PluginOptions, PluginOwned, PluginQuery,
PluginQueryContext, PluginRegistrar, PluginRuntimeDirective, PluginSession,
PluginSessionContext, PluginSessionSnapshot, PluginSnapshotArtifact, PluginSnapshotEntry,
PluginSnapshotMeta, PluginSpec, PluginSpecFactory, PluginTask, PluginTaskContext,
PluginTaskOutcome, PluginTaskReceipt, ProcessEngineContributionContext, PromptHookContext,
ProtocolBeforeLlmCallContext, ProtocolLlmCallAction, RuntimeServices, SessionAppendNode,
SessionConfigChangedContext, SessionContextOverlay, SessionCreateRequest, SessionGraphService,
SessionHandle, SessionLifecycleService, SessionParam, SessionPlugin, SessionPluginSource,
SessionReadView, SessionRelation, SessionSnapshot, SessionStartPoint,
SessionStateChangedContext, SessionStateService, SessionToolAccess, SessionTurnInput,
SessionTurnRequest, SnapshotReader, SnapshotWriter, SubagentSessionContext,
ToolCatalogContribution, ToolResultProjectionContext, ToolResultProjector,
TriggerEventRegistrations, TurnContextTransform, TurnHookContext, TurnResultHookContext,
TurnResultSummary, TurnTransformContext, plugin_operation_def,
};
pub use plugin_stack::PluginStack;
pub use provider::{
CacheRetention, EmptyProviderResolver, LlmTimeouts, MapProviderResolver, Provider,
ProviderBinding, ProviderComponents, ProviderFactory, ProviderHandle, ProviderModelPolicy,
ProviderOptions, ProviderResolutionError, ProviderSpec, RequestTimeout,
RuntimeProviderResolver, SingleProviderResolver, StaticModelPolicy,
};
#[cfg(any(test, feature = "testing"))]
pub use runtime::TestLocalProcessRegistry;
pub use runtime::{
AbandonEvidence, AbandonRequest, AbandonWriter, AgentFrameRun, AssembledTurn, AssistantOutput,
AwaitEventKey, AwaitEventResolver, AwaitEventWaitIdentity, CausalRef, Clock, CodeOutputRecord,
DefaultProcessCancelAbility, DeliveryPolicy, DirectCompletionClient, DurableProcessWorker,
DurableProcessWorkerConfig, DurableStoreFacet, EffectHost, EmbeddedRuntimeBuilder,
EmbeddedRuntimeHost, EventSink, ExecutionScope, ExecutionSummary, ExternalCompletionError,
InMemoryLiveReplayStore, InMemoryLiveReplayStoreConfig, InMemoryProcessExecutionEnvStore,
InMemorySessionStore, InMemorySessionStoreFactory, InlineEffectHost, InlineProcessRunHandle,
InlineRuntimeEffectController, InputItem, LashRuntime, LiveReplayGap, LiveReplayGapReason,
LiveReplayResult, LiveReplayStore, LiveReplayStoreError, LiveReplaySubscribeResult,
LiveReplaySubscription, MergeKey, NoopEventSink, NoopTurnActivitySink, ObservedProcess,
ObservedProcessEvent, ObservedWorkItem, OutputState, PROCESS_LEASE_SCHEMA_VERSION,
ParkedSession, PendingTurnInput, PendingTurnInputCancelOutcome, PendingTurnInputCancelResult,
PendingTurnInputCancelTarget, PendingTurnInputClaimDiagnostics, PendingTurnInputDraft,
PendingTurnInputSuffixCancelOutcome, ProcessAttach, ProcessAwaitOutput, ProcessAwaiter,
ProcessCancelAbility, ProcessCancelAllRequest, ProcessCancelRequest, ProcessCancelSource,
ProcessCancelSummary, ProcessChangeHub, ProcessDrainReport, ProcessEngine,
ProcessEngineRegistry, ProcessEngineRunContext, ProcessEngineRunGuard,
ProcessEngineRuntimeContext, ProcessEngineValidationContext, ProcessEvent,
ProcessEventAppendPlan, ProcessEventAppendRequest, ProcessEventAppendResult, ProcessEventSink,
ProcessEventType, ProcessExecutionContext, ProcessExecutionEnvRef, ProcessExecutionEnvSpec,
ProcessExecutionEnvStore, ProcessExternalRef, ProcessHandleDescriptor, ProcessHandleGrant,
ProcessHandleSummary, ProcessId, ProcessIdentity, ProcessInput, ProcessLease,
ProcessLeaseClaimOutcome, ProcessLeaseCompletion, ProcessLifecycleStatus, ProcessListFilter,
ProcessListMode, ProcessOpScope, ProcessOriginator, ProcessProvenance, ProcessPruneReport,
ProcessRecord, ProcessRegistration, ProcessRegistry, ProcessRunHandle, ProcessRuntimeHost,
ProcessService, ProcessSessionDeleteReport, ProcessSpawnProvenance, ProcessStartGrant,
ProcessStartOptions, ProcessStartRequest, ProcessStarted, ProcessStatus, ProcessStatusFilter,
ProcessTerminalSemantics, ProcessTerminalSpec, ProcessTerminalState, ProcessValueSelector,
ProcessWake, ProcessWakeDedupeKey, ProcessWakeDelivery, ProcessWakeDeliveryRequest,
ProcessWakeSpec, ProcessWorkDriver, ProcessWorkObserver, ProcessWorkSnapshot, PromptUsage,
ProtocolSessionExtension, ProtocolSessionExtensionHandle, ProtocolTurnExtension,
ProtocolTurnExtensionHandle, QueuedWorkDriver, QueuedWorkRunHandle, QueuedWorkRunRequest,
RecoveryDisposition, Residency, Resolution, ResolveOutcome, RuntimeEnvironment,
RuntimeEnvironmentBuilder, RuntimeError, RuntimeErrorCode, RuntimeHandle, RuntimeHostConfig,
RuntimeObservation, ScopedEffectController, SessionCommand, SessionCommandReceipt,
SessionCursor, SessionCursorError, SessionObservation, SessionObservationEvent,
SessionObservationEventPayload, SessionObservationSubscription, SessionProcessEventKind,
SessionQueueEventKind, SessionResume, SessionRevision, SessionScope, SessionScopeId,
SessionStoreCreateRequest, SessionStoreFactory, SessionUsageReport, SlotPolicy, SystemClock,
TerminationPolicy, TokenLedgerEntry, ToolCallLaunch, TurnActivity, TurnActivityId,
TurnActivitySink, TurnContext, TurnEvent, TurnInput, TurnInputCheckpointBoundary,
TurnInputClaim, TurnInputClaimMode, TurnInputCompletion, TurnInputIngress, TurnInputState,
TurnIssue, TurnOptions, UnavailableProcessService, UsageReportRow, UsageTotals, WaitKind,
WaitState, apply_process_status_projection, current_epoch_ms, diff_token_ledger,
diff_usage_reports, ensure_durable_effect_input, epoch_ms_from_system_time,
process_signal_event_type, process_signal_name_from_event_type, process_signal_wait_key,
process_wake_delivery, system_time_from_epoch_ms, validate_process_signal_name,
watch_process_registry, watch_process_registry_with_sink,
};
#[allow(unused_imports)]
pub(crate) use runtime::{
LlmAttachmentSpec, ProcessEventSemantics, QueuedCheckpointTurnInput, QueuedCheckpointWork,
QueuedTurnWork, QueuedWorkBatch, QueuedWorkBatchDraft, QueuedWorkClaim,
QueuedWorkClaimBoundary, QueuedWorkCompletion, QueuedWorkItem, QueuedWorkPayload,
RuntimeReplay, RuntimeScope, RuntimeSubject, load_process_execution_env,
materialize_process_event_semantics, persist_process_execution_env,
prepare_process_event_append, prepare_process_registration, process_event_invocation,
process_event_payload_hash, process_wake_batch_draft, process_wake_input_from_event_payload,
process_wake_turn_cause, process_wake_turn_text, require_event_replay,
};
pub use session_model::{
PLUGIN_RUNTIME_PROTOCOL_PLUGIN_ID, PersistedPluginRuntimeEvent,
plugin_runtime_event_from_protocol, plugin_runtime_protocol_event,
};
pub use runtime::{
LlmRequestSpec, ProcessCommand, ProcessEffectOutcome, ProcessEventSemanticsSpec,
RuntimeEffectCommand, RuntimeEffectController, RuntimeEffectControllerError,
RuntimeEffectEnvelope, RuntimeEffectKind, RuntimeEffectLocalExecutor, RuntimeEffectOutcome,
RuntimeInvocation, RuntimeSessionState, ToolAttemptEffectOutcome, ToolAttemptLaunch,
ToolBatchEffectOutcome,
};
pub use schemars::JsonSchema;
pub(crate) use session::RuntimeExecutionTracing;
pub use session::{
ExecRequest, InjectedTurnInput, RuntimeExecutionContext, Session, SessionError, ToolInvocation,
ToolInvocationReply,
};
pub use session_graph::{
PersistedSessionConfig, PersistedTurnState, SessionGraph, SessionMessageTreeNode,
SessionNodePayload, SessionNodeRecord,
};
pub use session_model::context::PreparedContext;
pub use session_model::{ConversationRecord, ProtocolEvent, SessionEventRecord};
pub use session_model::{RuntimeSessionPolicy, SessionPolicy, SessionSpec};
pub use store::{
AttachmentIntent, AttachmentManifest, AttachmentManifestEntry, BlobRef, GcReport,
LeaseOwnerIdentity, LeaseOwnerLiveness, LeaseTimings, LeaseTimingsError, QueuedWorkStore,
RuntimePersistence, SessionCommitStore, SessionExecutionLease,
SessionExecutionLeaseClaimOutcome, SessionExecutionLeaseCompletion, SessionExecutionLeaseFence,
SessionExecutionLeaseStore, SessionMeta, SessionPickerInfo, SessionReadScope, StoreError,
StoreMaintenance, TurnInputStore, VacuumReport,
};
#[allow(unused_imports)]
pub(crate) use store::{
GraphCommitDelta, PersistedSessionRead, RuntimeCommitResult, SessionCheckpoint,
SessionHeadMeta, ensure_supported_schema_version, load_persisted_session_state,
load_persisted_session_state_active_path,
};
pub use store::{
HydratedSessionCheckpoint, RuntimeCommit, RuntimeTurnCommitStamp, SessionHead,
refresh_persisted_session_state,
};
pub use tool_provider::{
PreparedToolBatch, PreparedToolBatchCall, PreparedToolCall, ProgressSender, SandboxMessage,
ToolCall, ToolChildExecutionTraceHook, ToolChildProcessStarted, ToolContext,
ToolDurableEffects, ToolExecutionGrant, ToolPrepareCall, ToolPrepareContext, ToolProvider,
ToolSessionAdmin, ToolSessionModel, ToolSessionProcessAdmin, ToolTriggerClient,
};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn protocol_turn_options_missing_payload_deserializes_to_empty_object() {
let options: ProtocolTurnOptions = serde_json::from_value(serde_json::json!({
"schema_version": PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION
}))
.expect("deserialize options");
assert!(options.is_empty());
assert_eq!(options.schema_version, PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION);
assert_eq!(options.payload, serde_json::json!({}));
}
#[test]
fn protocol_turn_options_explicit_null_is_not_empty() {
let options: ProtocolTurnOptions = serde_json::from_value(serde_json::json!({
"schema_version": PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION,
"payload": null
}))
.expect("deserialize options");
assert!(!options.is_empty());
assert_eq!(options.payload, serde_json::Value::Null);
}
#[test]
fn protocol_turn_options_missing_schema_version_rejects_preversioned_state() {
let err =
serde_json::from_value::<ProtocolTurnOptions>(serde_json::json!({ "payload": {} }))
.expect_err("pre-versioned options should fail");
assert!(
err.to_string().contains(
"missing schema_version and were written by unsupported pre-versioned state"
),
"{err}"
);
}
#[test]
fn protocol_turn_options_unsupported_schema_version_rejects_state() {
let err = serde_json::from_value::<ProtocolTurnOptions>(serde_json::json!({
"schema_version": PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION + 1,
"payload": {}
}))
.expect_err("unsupported options version should fail");
assert!(
err.to_string().contains("is not supported by this binary"),
"{err}"
);
}
#[test]
fn root_exports_do_not_reintroduce_removed_session_state_shapes() {
let source = include_str!("lib.rs");
let removed_envelope = ["SessionState", "Envelope"].concat();
let removed_persisted = ["PersistedSession", "Snapshot"].concat();
let removed_history_rewriter = ["History", "Rewriter"].concat();
let removed_rewrite_trigger = ["Rewrite", "Trigger"].concat();
let removed_rewrite_context = ["Rewrite", "Context"].concat();
let removed_history_state = ["History", "State"].concat();
let removed_history_metadata = ["History", "Rewrite", "Metadata"].concat();
assert!(!source.contains(&removed_envelope));
assert!(!source.contains(&removed_persisted));
assert!(!source.contains(&removed_history_rewriter));
assert!(!source.contains(&removed_rewrite_trigger));
assert!(!source.contains(&removed_rewrite_context));
assert!(!source.contains(&removed_history_state));
assert!(!source.contains(&removed_history_metadata));
}
fn public_reexport_block(source: &str, module: &str) -> String {
let start = format!("pub use {module}::{{");
let mut block = String::new();
let mut collecting = false;
for line in source.lines() {
if line.trim_start().starts_with(&start) {
collecting = true;
}
if collecting {
block.push_str(line);
block.push('\n');
if line.trim_end() == "};" {
break;
}
}
}
assert!(!block.is_empty(), "missing public {module} re-export block");
block
}
#[test]
fn root_runtime_exports_exclude_internal_runtime_records() {
let runtime_exports = public_reexport_block(include_str!("lib.rs"), "runtime");
for removed in [
"RuntimeEffectCommand",
"RuntimeEffectEnvelope",
"RuntimeEffectKind",
"RuntimeEffectOutcome",
"RuntimeInvocation",
"RuntimeScope",
"RuntimeSessionState",
"QueuedWorkBatch",
"QueuedWorkBatchDraft",
"QueuedWorkPayload",
"prepare_process_registration",
"process_wake_batch_draft",
"require_event_replay",
] {
assert!(
!runtime_exports.contains(removed),
"runtime root export leaked {removed}"
);
}
}
#[test]
fn root_store_exports_exclude_wire_records() {
let store_exports = public_reexport_block(include_str!("lib.rs"), "store");
for removed in [
"SessionHead",
"SessionCheckpoint",
"RuntimeCommit",
"HydratedSessionCheckpoint",
"PersistedSessionRead",
"GraphCommitDelta",
] {
assert!(
!store_exports.contains(removed),
"store root export leaked {removed}"
);
}
}
#[test]
fn removed_manager_and_host_trait_names_stay_removed() {
let removed_manager = ["Runtime", "Session", "Manager"].concat();
let removed_host = ["Runtime", "Session", "Host"].concat();
let sources = [
include_str!("runtime/session_manager/mod.rs"),
include_str!("plugin/runtime_host.rs"),
include_str!("tool_dispatch/context.rs"),
include_str!("tool_provider.rs"),
];
for source in sources {
assert!(!source.contains(&removed_manager));
assert!(!source.contains(&removed_host));
}
}
}