1pub 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
49pub use attachments::{
51 AttachmentReclamationReport, AttachmentStore, AttachmentStoreError, AttachmentStorePersistence,
52 FileAttachmentStore, InMemoryAttachmentStore, SessionScopedAttachmentStore, StoredAttachment,
53 reclaim_orphaned_attachments,
54};
55pub use chronological::{
56 BorrowedChronologicalEntry, BorrowedChronologicalMessage, BorrowedChronologicalPayload,
57 ChronologicalEntry, ChronologicalPayload, ChronologicalProjection, visit_turn_view,
58};
59pub use direct::{
60 DirectJsonSchema, DirectLlmClient, DirectLlmError, DirectMessage, DirectOutputSpec, DirectPart,
61 DirectRequest, DirectRole,
62};
63pub use lash_sansio::llm::types::{
64 GenerationOptions, LlmOutputPart, LlmRequest, LlmRequestScope, LlmResponse, LlmTerminalReason,
65};
66pub use lash_sansio::{
67 AcceptedInjectedTurnInput, AttachmentCreateMeta, AttachmentId, AttachmentMeta, AttachmentRef,
68 BaseRenderCache, CheckpointDelivery, CheckpointKind, CompactToolContract, EffectId,
69 ErrorEnvelope, ExecImage, ExecResponse, ImageMediaType, LashSchema, LlmCallError, MediaType,
70 Message, MessageOrigin, MessageRole, MessageSequence, ModelToolReturn, ModelToolReturnPart,
71 Part, PartKind, PluginMessage, PluginRuntimeEvent, PreparedPrompt, ProjectionMode,
72 PromptBuildInput, PromptBuiltin, PromptContext, PromptContribution, PromptContributionGate,
73 PromptContributionSet, PromptFingerprint, PromptLayer, PromptSlot, PromptSlotLayer,
74 PromptTemplate, PromptTemplateEntry, PromptTemplateSection, ProviderSchemaCapabilities,
75 PruneState, RenderedPrompt, ResolvedPromptLayer, ResolvedSchema, Response, SchemaContract,
76 SchemaDialect, SchemaProjectionOverride, SchemaProjectionPolicy, SchemaPurpose,
77 SchemaResolutionError, SchemaResolutionRequest, SessionEvent, TextProjectionMetadata,
78 TokenUsage, ToolActivation, ToolArgumentProjectionPolicy, ToolCallOutcome, ToolCallOutput,
79 ToolCallRecord, ToolCallStatus, ToolCancellation, ToolCatalog, ToolCatalogBuildInput,
80 ToolCatalogEntry, ToolContract, ToolControl, ToolDefinition, ToolFailure, ToolFailureClass,
81 ToolFailureSource, ToolId, ToolManifest, ToolOutputContract, ToolRetryDisposition,
82 ToolRetryPolicy, ToolScheduling, ToolValue, TurnCause, TurnFinish, TurnLimitFinalMessage,
83 TurnOutcome, TurnStop, append_assistant_text_part, build_prompt, build_tool_catalog,
84 build_turn, default_prompt_template, head_tail_truncate, messages_are_prompt_resume_safe,
85 normalized_response_parts, project_anthropic_bedrock_schema, project_for_dialect,
86 prompt_template_fingerprint, prompt_text_fingerprint, prompt_tool_names_fingerprint,
87 reasoning_part, render_turn_causes_prompt, resolve_prompt_layers, resolve_schema, shared_parts,
88 validate_tool_input, visible_response_parts, visible_response_text_from_parts,
89};
90pub use protocol_build::ProtocolBuildInput;
91pub use tool_registry::{
92 PLUGIN_TOOL_SOURCE_ID, ReconfigureError, ToolRegistry, ToolRestoreReport, ToolSourceHandle,
93 ToolState, ToolStateEntry,
94};
95pub use tool_result::{CancelHint, PendingCompletion, TimeoutBehavior, ToolResult};
96pub use triggers::{
97 InMemoryTriggerStore, TriggerDeliveryReservation, TriggerEmitReport, TriggerEvent,
98 TriggerEventCatalog, TriggerEventKey, TriggerEventType, TriggerInputBinding,
99 TriggerOccurrenceRecord, TriggerOccurrenceRequest, TriggerRegistration, TriggerRouter,
100 TriggerStore, TriggerSubscriptionDraft, TriggerSubscriptionFilter, TriggerSubscriptionRecord,
101 TriggerTargetSummary, default_trigger_source_key, deterministic_delivery_process_id,
102 deterministic_occurrence_id, empty_trigger_source_key, trigger_event_type,
103 trigger_occurrence_request_hash, validate_trigger_occurrence_request,
104};
105pub const PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION: u32 = 1;
106
107#[derive(Clone, Debug, serde::Serialize)]
108pub struct ProtocolTurnOptions {
109 pub schema_version: u32,
110 pub payload: serde_json::Value,
111}
112
113fn empty_protocol_turn_payload() -> serde_json::Value {
114 serde_json::Value::Object(serde_json::Map::new())
115}
116
117#[derive(Debug, thiserror::Error)]
118pub enum ProtocolTurnOptionsError {
119 #[error(
120 "protocol turn options are missing schema_version and were written by unsupported pre-versioned state (expected {expected})"
121 )]
122 MissingSchemaVersion { expected: u32 },
123 #[error(
124 "protocol turn options schema_version {actual} is not supported by this binary (expected {expected})"
125 )]
126 UnsupportedSchemaVersion { actual: u32, expected: u32 },
127 #[error(
128 "protocol turn options schema_version {actual} is invalid (expected integer {expected})"
129 )]
130 InvalidSchemaVersion { actual: String, expected: u32 },
131 #[error("failed to decode protocol turn options payload: {0}")]
132 Decode(#[source] serde_json::Error),
133}
134
135fn parse_protocol_turn_options_schema_version(
136 value: Option<serde_json::Value>,
137) -> Result<u32, ProtocolTurnOptionsError> {
138 let expected = PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION;
139 let Some(value) = value else {
140 return Err(ProtocolTurnOptionsError::MissingSchemaVersion { expected });
141 };
142 let Some(actual) = value
143 .as_u64()
144 .and_then(|version| u32::try_from(version).ok())
145 else {
146 return Err(ProtocolTurnOptionsError::InvalidSchemaVersion {
147 actual: value.to_string(),
148 expected,
149 });
150 };
151 ensure_protocol_turn_options_schema_version(actual)?;
152 Ok(actual)
153}
154
155fn ensure_protocol_turn_options_schema_version(
156 actual: u32,
157) -> Result<(), ProtocolTurnOptionsError> {
158 let expected = PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION;
159 if actual == expected {
160 Ok(())
161 } else {
162 Err(ProtocolTurnOptionsError::UnsupportedSchemaVersion { actual, expected })
163 }
164}
165
166impl<'de> serde::Deserialize<'de> for ProtocolTurnOptions {
167 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
168 where
169 D: serde::Deserializer<'de>,
170 {
171 #[derive(serde::Deserialize)]
172 struct ProtocolTurnOptionsWire {
173 schema_version: Option<serde_json::Value>,
174 #[serde(default = "empty_protocol_turn_payload")]
175 payload: serde_json::Value,
176 }
177
178 let wire = ProtocolTurnOptionsWire::deserialize(deserializer)?;
179 let schema_version = parse_protocol_turn_options_schema_version(wire.schema_version)
180 .map_err(serde::de::Error::custom)?;
181 Ok(Self {
182 schema_version,
183 payload: wire.payload,
184 })
185 }
186}
187
188impl Default for ProtocolTurnOptions {
189 fn default() -> Self {
190 Self::empty()
191 }
192}
193
194impl ProtocolTurnOptions {
195 pub fn empty() -> Self {
196 Self {
197 schema_version: PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION,
198 payload: serde_json::Value::Object(serde_json::Map::new()),
199 }
200 }
201
202 pub fn from_payload(payload: serde_json::Value) -> Self {
203 Self {
204 schema_version: PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION,
205 payload,
206 }
207 }
208
209 pub fn is_empty(&self) -> bool {
210 match &self.payload {
211 serde_json::Value::Object(map) => map.is_empty(),
212 _ => false,
213 }
214 }
215
216 pub fn merged_with_override(&self, override_options: &Self) -> Self {
217 match (&self.payload, &override_options.payload) {
218 (serde_json::Value::Object(base), serde_json::Value::Object(overrides)) => {
219 let mut payload = base.clone();
220 payload.extend(overrides.clone());
221 Self {
222 schema_version: PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION,
223 payload: serde_json::Value::Object(payload),
224 }
225 }
226 _ => override_options.clone(),
227 }
228 }
229
230 pub fn typed<T>(value: T) -> Result<Self, serde_json::Error>
231 where
232 T: serde::Serialize,
233 {
234 Ok(Self {
235 schema_version: PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION,
236 payload: serde_json::to_value(value)?,
237 })
238 }
239
240 pub fn decode<T>(&self) -> Result<T, ProtocolTurnOptionsError>
241 where
242 T: serde::de::DeserializeOwned,
243 {
244 ensure_protocol_turn_options_schema_version(self.schema_version)?;
245 serde_json::from_value(self.payload.clone()).map_err(ProtocolTurnOptionsError::Decode)
246 }
247}
248
249#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
250pub struct ProtocolDriverState {
251 pub plugin_id: String,
252 pub payload: serde_json::Value,
253}
254
255impl ProtocolDriverState {
256 pub fn new(plugin_id: impl Into<String>, payload: serde_json::Value) -> Self {
257 Self {
258 plugin_id: plugin_id.into(),
259 payload,
260 }
261 }
262}
263
264#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
265pub struct HostTurnProtocol;
266
267impl lash_sansio::TurnProtocol for HostTurnProtocol {
268 type Event = crate::session_model::ProtocolEvent;
269 type Termination = ProtocolTurnOptions;
270 type DriverState = ProtocolDriverState;
271}
272
273pub type Effect = lash_sansio::Effect<HostTurnProtocol>;
274pub type DriverAction = lash_sansio::DriverAction<HostTurnProtocol>;
275pub type DriverContextView<'a> = lash_sansio::DriverContextView<'a, HostTurnProtocol>;
276pub type TurnDriverConfig = lash_sansio::TurnDriverConfig<HostTurnProtocol>;
277pub type TurnDriverPreamble = lash_sansio::TurnDriverPreamble<HostTurnProtocol>;
278pub type ProjectorContext<'a> = lash_sansio::ProjectorContext<'a, HostTurnProtocol>;
279pub type PreparedTurnMachine = lash_sansio::PreparedTurnMachine<HostTurnProtocol>;
280pub type SansIoTurnInput = lash_sansio::SansIoTurnInput<HostTurnProtocol>;
281pub type TurnMachine = lash_sansio::TurnMachine<HostTurnProtocol>;
282pub type TurnMachineConfig = lash_sansio::TurnMachineConfig<HostTurnProtocol>;
283#[cfg(feature = "otel-trace")]
284pub use lash_trace::otel::{OtelTraceOptions, OtelTraceSink};
285pub use lash_trace::{
286 JsonlTraceSink, TraceAttachment, TraceBranchSelection, TraceContentBlock, TraceContext,
287 TraceError, TraceEvent, TraceLabelMetadata, TraceLevel, TraceLlmMessage, TraceLlmRequest,
288 TraceLlmResponse, TracePromptComponent, TraceProviderStreamEvent, TraceRecord,
289 TraceRuntimeScope, TraceRuntimeStreamEvent, TraceRuntimeSubject, TraceSink, TraceSinkError,
290 TraceTokenUsage, TraceToolSpec,
291};
292pub use llm::transport::{LlmTransportError, ProviderFailure, ProviderFailureKind};
293pub use model::{ModelLimits, ModelSpec};
294pub use plugin::{
295 AgentFrameAssignment, AgentFrameId, AgentFrameReason, AgentFrameRecord, AgentFrameStatus,
296 AppendSessionNodesRequest, AppendSessionNodesResult, AssistantResponseHookContext,
297 AssistantResponseTransform, AssistantStreamHookContext, AssistantStreamTransform,
298 CheckpointHookContext, CompactionContext, ContextCompaction, ContextCompactor, ContextError,
299 ContextRegistrations, DirectCompletion, DirectLlmCompletion, OpenAgentFrameRequest,
300 OpenAgentFrameResult, PersistentRuntimeServices, PluginCommand, PluginCommandContext,
301 PluginCommandOutcome, PluginCommandReceipt, PluginDirective, PluginError,
302 PluginExtensionContribution, PluginExtensions, PluginFactory, PluginHost, PluginLifecycleEvent,
303 PluginLifecycleEventHook, PluginOperation, PluginOperationDef, PluginOperationFailure,
304 PluginOperationInvokeError, PluginOperationKind, PluginOptions, PluginOwned, PluginQuery,
305 PluginQueryContext, PluginRegistrar, PluginRuntimeDirective, PluginSession,
306 PluginSessionContext, PluginSessionSnapshot, PluginSnapshotArtifact, PluginSnapshotEntry,
307 PluginSnapshotMeta, PluginSpec, PluginSpecFactory, PluginTask, PluginTaskContext,
308 PluginTaskOutcome, PluginTaskReceipt, ProcessEngineContributionContext, PromptHookContext,
309 ProtocolBeforeLlmCallContext, ProtocolLlmCallAction, RuntimeServices, SessionAppendNode,
310 SessionConfigChangedContext, SessionContextOverlay, SessionCreateRequest, SessionGraphService,
311 SessionHandle, SessionLifecycleService, SessionParam, SessionPlugin, SessionPluginSource,
312 SessionReadView, SessionRelation, SessionSnapshot, SessionStartPoint,
313 SessionStateChangedContext, SessionStateService, SessionToolAccess, SessionTurnInput,
314 SessionTurnRequest, SnapshotReader, SnapshotWriter, SubagentSessionContext,
315 ToolCatalogContribution, ToolResultProjectionContext, ToolResultProjector,
316 TriggerEventRegistrations, TurnContextTransform, TurnHookContext, TurnResultHookContext,
317 TurnResultSummary, TurnTransformContext, plugin_operation_def,
318};
319pub use plugin_stack::PluginStack;
320pub use provider::{
321 CacheRetention, EmptyProviderResolver, LlmTimeouts, MapProviderResolver, Provider,
322 ProviderBinding, ProviderComponents, ProviderFactory, ProviderHandle, ProviderModelPolicy,
323 ProviderOptions, ProviderResolutionError, ProviderSpec, RequestTimeout,
324 RuntimeProviderResolver, SingleProviderResolver, StaticModelPolicy,
325};
326#[cfg(any(test, feature = "testing"))]
327pub use runtime::TestLocalProcessRegistry;
328pub use runtime::{
329 AbandonEvidence, AbandonRequest, AbandonWriter, AgentFrameRun, AssembledTurn, AssistantOutput,
330 AwaitEventKey, AwaitEventResolver, AwaitEventWaitIdentity, CausalRef, Clock, CodeOutputRecord,
331 DefaultProcessCancelAbility, DeliveryPolicy, DirectCompletionClient, DurableProcessWorker,
332 DurableProcessWorkerConfig, DurableStoreFacet, EffectHost, EmbeddedRuntimeBuilder,
333 EmbeddedRuntimeHost, EventSink, ExecutionScope, ExecutionSummary, ExternalCompletionError,
334 InMemoryLiveReplayStore, InMemoryLiveReplayStoreConfig, InMemoryProcessExecutionEnvStore,
335 InMemorySessionStore, InMemorySessionStoreFactory, InlineEffectHost, InlineProcessRunHandle,
336 InlineRuntimeEffectController, InputItem, LashRuntime, LiveReplayGap, LiveReplayGapReason,
337 LiveReplayResult, LiveReplayStore, LiveReplayStoreError, LiveReplaySubscribeResult,
338 LiveReplaySubscription, MergeKey, NoopEventSink, NoopTurnActivitySink, ObservedProcess,
339 ObservedProcessEvent, ObservedWorkItem, OutputState, PROCESS_LEASE_SCHEMA_VERSION,
340 ParkedSession, PendingTurnInput, PendingTurnInputCancelOutcome, PendingTurnInputCancelResult,
341 PendingTurnInputCancelTarget, PendingTurnInputClaimDiagnostics, PendingTurnInputDraft,
342 PendingTurnInputSuffixCancelOutcome, ProcessAttach, ProcessAwaitOutput, ProcessAwaiter,
343 ProcessCancelAbility, ProcessCancelAllRequest, ProcessCancelRequest, ProcessCancelSource,
344 ProcessCancelSummary, ProcessChangeHub, ProcessDrainReport, ProcessEngine,
345 ProcessEngineRegistry, ProcessEngineRunContext, ProcessEngineRunGuard,
346 ProcessEngineRuntimeContext, ProcessEngineValidationContext, ProcessEvent,
347 ProcessEventAppendPlan, ProcessEventAppendRequest, ProcessEventAppendResult, ProcessEventSink,
348 ProcessEventType, ProcessExecutionContext, ProcessExecutionEnvRef, ProcessExecutionEnvSpec,
349 ProcessExecutionEnvStore, ProcessExternalRef, ProcessHandleDescriptor, ProcessHandleGrant,
350 ProcessHandleSummary, ProcessId, ProcessIdentity, ProcessInput, ProcessLease,
351 ProcessLeaseClaimOutcome, ProcessLeaseCompletion, ProcessLifecycleStatus, ProcessListFilter,
352 ProcessListMode, ProcessOpScope, ProcessOriginator, ProcessProvenance, ProcessPruneReport,
353 ProcessRecord, ProcessRegistration, ProcessRegistry, ProcessRunHandle, ProcessRuntimeHost,
354 ProcessService, ProcessSessionDeleteReport, ProcessSpawnProvenance, ProcessStartGrant,
355 ProcessStartOptions, ProcessStartRequest, ProcessStarted, ProcessStatus, ProcessStatusFilter,
356 ProcessTerminalSemantics, ProcessTerminalSpec, ProcessTerminalState, ProcessValueSelector,
357 ProcessWake, ProcessWakeDedupeKey, ProcessWakeDelivery, ProcessWakeDeliveryRequest,
358 ProcessWakeSpec, ProcessWorkDriver, ProcessWorkObserver, ProcessWorkSnapshot, PromptUsage,
359 ProtocolSessionExtension, ProtocolSessionExtensionHandle, ProtocolTurnExtension,
360 ProtocolTurnExtensionHandle, QueuedWorkDriver, QueuedWorkRunHandle, QueuedWorkRunRequest,
361 RecoveryDisposition, Residency, Resolution, ResolveOutcome, RuntimeEnvironment,
362 RuntimeEnvironmentBuilder, RuntimeError, RuntimeErrorCode, RuntimeHandle, RuntimeHostConfig,
363 RuntimeObservation, ScopedEffectController, SessionCommand, SessionCommandReceipt,
364 SessionCursor, SessionCursorError, SessionObservation, SessionObservationEvent,
365 SessionObservationEventPayload, SessionObservationSubscription, SessionProcessEventKind,
366 SessionQueueEventKind, SessionResume, SessionRevision, SessionScope, SessionScopeId,
367 SessionStoreCreateRequest, SessionStoreFactory, SessionUsageReport, SlotPolicy, SystemClock,
368 TerminationPolicy, TokenLedgerEntry, ToolCallLaunch, TurnActivity, TurnActivityId,
369 TurnActivitySink, TurnContext, TurnEvent, TurnInput, TurnInputCheckpointBoundary,
370 TurnInputClaim, TurnInputClaimMode, TurnInputCompletion, TurnInputIngress, TurnInputState,
371 TurnIssue, TurnOptions, UnavailableProcessService, UsageReportRow, UsageTotals, WaitKind,
372 WaitState, apply_process_status_projection, current_epoch_ms, diff_token_ledger,
373 diff_usage_reports, ensure_durable_effect_input, epoch_ms_from_system_time,
374 process_signal_event_type, process_signal_name_from_event_type, process_signal_wait_key,
375 process_wake_delivery, system_time_from_epoch_ms, validate_process_signal_name,
376 watch_process_registry, watch_process_registry_with_sink,
377};
378#[allow(unused_imports)]
379pub(crate) use runtime::{
380 LlmAttachmentSpec, ProcessEventSemantics, QueuedCheckpointTurnInput, QueuedCheckpointWork,
381 QueuedTurnWork, QueuedWorkBatch, QueuedWorkBatchDraft, QueuedWorkClaim,
382 QueuedWorkClaimBoundary, QueuedWorkCompletion, QueuedWorkItem, QueuedWorkPayload,
383 RuntimeReplay, RuntimeScope, RuntimeSubject, load_process_execution_env,
384 materialize_process_event_semantics, persist_process_execution_env,
385 prepare_process_event_append, prepare_process_registration, process_event_invocation,
386 process_event_payload_hash, process_wake_batch_draft, process_wake_input_from_event_payload,
387 process_wake_turn_cause, process_wake_turn_text, require_event_replay,
388};
389pub use session_model::{
390 PLUGIN_RUNTIME_PROTOCOL_PLUGIN_ID, PersistedPluginRuntimeEvent,
391 plugin_runtime_event_from_protocol, plugin_runtime_protocol_event,
392};
393pub use runtime::{
397 LlmRequestSpec, ProcessCommand, ProcessEffectOutcome, ProcessEventSemanticsSpec,
398 RuntimeEffectCommand, RuntimeEffectController, RuntimeEffectControllerError,
399 RuntimeEffectEnvelope, RuntimeEffectKind, RuntimeEffectLocalExecutor, RuntimeEffectOutcome,
400 RuntimeInvocation, RuntimeSessionState, ToolAttemptEffectOutcome, ToolAttemptLaunch,
401 ToolBatchEffectOutcome,
402};
403pub use schemars::JsonSchema;
404pub(crate) use session::RuntimeExecutionTracing;
405pub use session::{
406 ExecRequest, InjectedTurnInput, RuntimeExecutionContext, Session, SessionError, ToolInvocation,
407 ToolInvocationReply,
408};
409pub use session_graph::{
410 PersistedSessionConfig, PersistedTurnState, SessionGraph, SessionMessageTreeNode,
411 SessionNodePayload, SessionNodeRecord,
412};
413pub use session_model::context::PreparedContext;
414pub use session_model::{ConversationRecord, ProtocolEvent, SessionEventRecord};
415pub use session_model::{RuntimeSessionPolicy, SessionPolicy, SessionSpec};
416pub use store::{
417 AttachmentIntent, AttachmentManifest, AttachmentManifestEntry, BlobRef, GcReport,
418 LeaseOwnerIdentity, LeaseOwnerLiveness, LeaseTimings, LeaseTimingsError, QueuedWorkStore,
419 RuntimePersistence, SessionCommitStore, SessionExecutionLease,
420 SessionExecutionLeaseClaimOutcome, SessionExecutionLeaseCompletion, SessionExecutionLeaseFence,
421 SessionExecutionLeaseStore, SessionMeta, SessionPickerInfo, SessionReadScope, StoreError,
422 StoreMaintenance, TurnInputStore, VacuumReport,
423};
424#[allow(unused_imports)]
425pub(crate) use store::{
426 GraphCommitDelta, PersistedSessionRead, RuntimeCommitResult, SessionCheckpoint,
427 SessionHeadMeta, ensure_supported_schema_version, load_persisted_session_state,
428 load_persisted_session_state_active_path,
429};
430pub use store::{
431 HydratedSessionCheckpoint, RuntimeCommit, RuntimeTurnCommitStamp, SessionHead,
432 refresh_persisted_session_state,
433};
434pub use tool_provider::{
435 PreparedToolBatch, PreparedToolBatchCall, PreparedToolCall, ProgressSender, SandboxMessage,
436 ToolCall, ToolChildExecutionTraceHook, ToolChildProcessStarted, ToolContext,
437 ToolDurableEffects, ToolExecutionGrant, ToolPrepareCall, ToolPrepareContext, ToolProvider,
438 ToolSessionAdmin, ToolSessionModel, ToolSessionProcessAdmin, ToolTriggerClient,
439};
440
441#[cfg(test)]
442mod tests {
443 use super::*;
444
445 #[test]
446 fn protocol_turn_options_missing_payload_deserializes_to_empty_object() {
447 let options: ProtocolTurnOptions = serde_json::from_value(serde_json::json!({
448 "schema_version": PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION
449 }))
450 .expect("deserialize options");
451
452 assert!(options.is_empty());
453 assert_eq!(options.schema_version, PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION);
454 assert_eq!(options.payload, serde_json::json!({}));
455 }
456
457 #[test]
458 fn protocol_turn_options_explicit_null_is_not_empty() {
459 let options: ProtocolTurnOptions = serde_json::from_value(serde_json::json!({
460 "schema_version": PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION,
461 "payload": null
462 }))
463 .expect("deserialize options");
464
465 assert!(!options.is_empty());
466 assert_eq!(options.payload, serde_json::Value::Null);
467 }
468
469 #[test]
470 fn protocol_turn_options_missing_schema_version_rejects_preversioned_state() {
471 let err =
472 serde_json::from_value::<ProtocolTurnOptions>(serde_json::json!({ "payload": {} }))
473 .expect_err("pre-versioned options should fail");
474
475 assert!(
476 err.to_string().contains(
477 "missing schema_version and were written by unsupported pre-versioned state"
478 ),
479 "{err}"
480 );
481 }
482
483 #[test]
484 fn protocol_turn_options_unsupported_schema_version_rejects_state() {
485 let err = serde_json::from_value::<ProtocolTurnOptions>(serde_json::json!({
486 "schema_version": PROTOCOL_TURN_OPTIONS_SCHEMA_VERSION + 1,
487 "payload": {}
488 }))
489 .expect_err("unsupported options version should fail");
490
491 assert!(
492 err.to_string().contains("is not supported by this binary"),
493 "{err}"
494 );
495 }
496
497 #[test]
498 fn root_exports_do_not_reintroduce_removed_session_state_shapes() {
499 let source = include_str!("lib.rs");
500 let removed_envelope = ["SessionState", "Envelope"].concat();
501 let removed_persisted = ["PersistedSession", "Snapshot"].concat();
502 let removed_history_rewriter = ["History", "Rewriter"].concat();
503 let removed_rewrite_trigger = ["Rewrite", "Trigger"].concat();
504 let removed_rewrite_context = ["Rewrite", "Context"].concat();
505 let removed_history_state = ["History", "State"].concat();
506 let removed_history_metadata = ["History", "Rewrite", "Metadata"].concat();
507
508 assert!(!source.contains(&removed_envelope));
509 assert!(!source.contains(&removed_persisted));
510 assert!(!source.contains(&removed_history_rewriter));
511 assert!(!source.contains(&removed_rewrite_trigger));
512 assert!(!source.contains(&removed_rewrite_context));
513 assert!(!source.contains(&removed_history_state));
514 assert!(!source.contains(&removed_history_metadata));
515 }
516
517 fn public_reexport_block(source: &str, module: &str) -> String {
518 let start = format!("pub use {module}::{{");
519 let mut block = String::new();
520 let mut collecting = false;
521 for line in source.lines() {
522 if line.trim_start().starts_with(&start) {
523 collecting = true;
524 }
525 if collecting {
526 block.push_str(line);
527 block.push('\n');
528 if line.trim_end() == "};" {
529 break;
530 }
531 }
532 }
533 assert!(!block.is_empty(), "missing public {module} re-export block");
534 block
535 }
536
537 #[test]
538 fn root_runtime_exports_exclude_internal_runtime_records() {
539 let runtime_exports = public_reexport_block(include_str!("lib.rs"), "runtime");
540 for removed in [
541 "RuntimeEffectCommand",
542 "RuntimeEffectEnvelope",
543 "RuntimeEffectKind",
544 "RuntimeEffectOutcome",
545 "RuntimeInvocation",
546 "RuntimeScope",
547 "RuntimeSessionState",
548 "QueuedWorkBatch",
549 "QueuedWorkBatchDraft",
550 "QueuedWorkPayload",
551 "prepare_process_registration",
552 "process_wake_batch_draft",
553 "require_event_replay",
554 ] {
555 assert!(
556 !runtime_exports.contains(removed),
557 "runtime root export leaked {removed}"
558 );
559 }
560 }
561
562 #[test]
563 fn root_store_exports_exclude_wire_records() {
564 let store_exports = public_reexport_block(include_str!("lib.rs"), "store");
565 for removed in [
566 "SessionHead",
567 "SessionCheckpoint",
568 "RuntimeCommit",
569 "HydratedSessionCheckpoint",
570 "PersistedSessionRead",
571 "GraphCommitDelta",
572 ] {
573 assert!(
574 !store_exports.contains(removed),
575 "store root export leaked {removed}"
576 );
577 }
578 }
579
580 #[test]
581 fn removed_manager_and_host_trait_names_stay_removed() {
582 let removed_manager = ["Runtime", "Session", "Manager"].concat();
583 let removed_host = ["Runtime", "Session", "Host"].concat();
584 let sources = [
585 include_str!("runtime/session_manager/mod.rs"),
586 include_str!("plugin/runtime_host.rs"),
587 include_str!("tool_dispatch/context.rs"),
588 include_str!("tool_provider.rs"),
589 ];
590
591 for source in sources {
592 assert!(!source.contains(&removed_manager));
593 assert!(!source.contains(&removed_host));
594 }
595 }
596}