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 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, ToolAvailability,
76 ToolAvailabilityConfig, ToolCallOutcome, ToolCallOutput, ToolCallRecord, ToolCallStatus,
77 ToolCancellation, ToolCatalog, ToolCatalogBuildInput, ToolCatalogEntry, ToolCatalogOverride,
78 ToolContract, ToolControl, ToolDefinition, ToolFailure, ToolFailureClass, ToolFailureSource,
79 ToolId, ToolManifest, ToolOutputContract, ToolRetryDisposition, ToolRetryPolicy,
80 ToolScheduling, ToolValue, TurnCause, TurnFinish, TurnLimitFinalMessage, TurnOutcome, TurnStop,
81 append_assistant_text_part, build_prompt, build_tool_catalog, build_turn,
82 default_prompt_template, head_tail_truncate, messages_are_prompt_resume_safe,
83 normalized_response_parts, prompt_template_fingerprint, prompt_text_fingerprint,
84 prompt_tool_names_fingerprint, reasoning_part, render_turn_causes_prompt,
85 resolve_prompt_layers, shared_parts, validate_tool_input,
86};
87pub use protocol_build::ProtocolBuildInput;
88pub use tool_registry::{
89 ReconfigureError, ToolRegistry, ToolRestoreReport, ToolSourceHandle, 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, PluginAction, PluginActionContext,
213 PluginActionDef, PluginActionFailure, PluginActionInvokeError, PluginActionKind,
214 PluginDirective, PluginError, PluginExtensionContribution, PluginExtensions, PluginFactory,
215 PluginHost, PluginLifecycleEvent, PluginLifecycleEventHook, PluginOptions, PluginOwned,
216 PluginRegistrar, PluginSession, PluginSessionContext, PluginSessionSnapshot,
217 PluginSnapshotArtifact, PluginSnapshotEntry, PluginSnapshotMeta, PluginSpec, PluginSpecFactory,
218 PromptHookContext, ProtocolBeforeLlmCallContext, ProtocolLlmCallAction, RuntimeServices,
219 SessionAppendNode, SessionConfigChangedContext, SessionContextOverlay, SessionCreateRequest,
220 SessionGraphService, SessionHandle, SessionLifecycleService, SessionParam, SessionPlugin,
221 SessionPluginSource, SessionReadView, SessionRelation, SessionSnapshot, SessionStartPoint,
222 SessionStateChangedContext, SessionStateService, SessionToolAccess, SessionTurnInput,
223 SessionTurnRequest, SnapshotReader, SnapshotWriter, SubagentSessionContext,
224 ToolCatalogContribution, ToolDiscoveryContext, ToolDiscoveryContribution,
225 ToolDiscoveryContributor, ToolDiscoveryToolContribution, ToolResultProjectionContext,
226 ToolResultProjector, TriggerEventRegistrations, TurnContextTransform, TurnHookContext,
227 TurnResultHookContext, TurnResultSummary, TurnTransformContext, plugin_action_def,
228};
229pub use plugin_stack::PluginStack;
230pub use provider::{
231 CacheRetention, EmptyProviderResolver, LlmTimeouts, MapProviderResolver, Provider,
232 ProviderBinding, ProviderComponents, ProviderFactory, ProviderHandle, ProviderModelPolicy,
233 ProviderOptions, ProviderResolutionError, ProviderSpec, RequestTimeout,
234 RuntimeProviderResolver, SingleProviderResolver, StaticModelPolicy,
235};
236#[cfg(any(test, feature = "testing"))]
237pub use runtime::TestLocalProcessRegistry;
238pub use runtime::{
239 AgentFrameRun, AssembledTurn, AssistantOutput, AwaitEventKey, AwaitEventWaitIdentity,
240 CausalRef, CodeOutputRecord, DefaultProcessCancelAbility, DeliveryPolicy,
241 DirectCompletionClient, DurableProcessWorker, DurableProcessWorkerConfig, DurableStoreFacet,
242 EffectHost, EmbeddedRuntimeBuilder, EmbeddedRuntimeHost, EventSink, ExecutionScope,
243 ExecutionSummary, ExternalCompletionError, InMemoryLiveReplayStore,
244 InMemoryLiveReplayStoreConfig, InMemoryProcessExecutionEnvStore, InMemorySessionStore,
245 InMemorySessionStoreFactory, InlineEffectHost, InlineProcessRunHandle,
246 InlineRuntimeEffectController, InputItem, LashRuntime, LiveReplayGap, LiveReplayGapReason,
247 LiveReplayResult, LiveReplayStore, LiveReplayStoreError, LiveReplaySubscribeResult,
248 LiveReplaySubscription, MergeKey, NoopEventSink, NoopTurnActivitySink, ObservedProcess,
249 ObservedProcessEvent, ObservedWorkItem, OutputState, PROCESS_LEASE_SCHEMA_VERSION,
250 ParkedSession, ProcessAwaitOutput, ProcessCancelAbility, ProcessCancelAllRequest,
251 ProcessCancelRequest, ProcessCancelSource, ProcessCancelSummary, ProcessEngine,
252 ProcessEngineRegistry, ProcessEngineRunContext, ProcessEngineRunGuard,
253 ProcessEngineRuntimeContext, ProcessEngineValidationContext, ProcessEvent,
254 ProcessEventAppendRequest, ProcessEventAppendResult, ProcessEventType, ProcessExecutionContext,
255 ProcessExecutionEnvRef, ProcessExecutionEnvSpec, ProcessExecutionEnvStore, ProcessExternalRef,
256 ProcessHandleDescriptor, ProcessHandleGrant, ProcessHandleSummary, ProcessId, ProcessIdentity,
257 ProcessInput, ProcessLease, ProcessLeaseCompletion, ProcessLifecycleStatus, ProcessListFilter,
258 ProcessListMode, ProcessOpScope, ProcessOriginator, ProcessProvenance, ProcessRecord,
259 ProcessRegistration, ProcessRegistry, ProcessRunHandle, ProcessRuntimeHost, ProcessService,
260 ProcessSessionDeleteReport, ProcessSpawnProvenance, ProcessStartGrant, ProcessStartOptions,
261 ProcessStartRequest, ProcessStatus, ProcessStatusFilter, ProcessTerminalSemantics,
262 ProcessTerminalSpec, ProcessTerminalState, ProcessValueSelector, ProcessWake,
263 ProcessWakeDedupeKey, ProcessWakeDelivery, ProcessWakeSpec, ProcessWorkDriver,
264 ProcessWorkObserver, ProcessWorkPoke, ProcessWorkRunner, ProcessWorkSnapshot, PromptUsage,
265 ProtocolSessionExtension, ProtocolSessionExtensionHandle, ProtocolTurnExtension,
266 ProtocolTurnExtensionHandle, QueuedWorkPoke, QueuedWorkRunHandle, QueuedWorkRunOutcome,
267 QueuedWorkRunRequest, QueuedWorkRunner, Residency, Resolution, ResolveOutcome,
268 RuntimeEnvironment, RuntimeEnvironmentBuilder, RuntimeError, RuntimeErrorCode, RuntimeHandle,
269 RuntimeHostConfig, RuntimeObservation, ScopedEffectController, SessionCommand,
270 SessionCommandReceipt, SessionCursor, SessionCursorError, SessionObservation,
271 SessionObservationEvent, SessionObservationEventPayload, SessionObservationSubscription,
272 SessionProcessEventKind, SessionQueueEventKind, SessionResume, SessionRevision, SessionScope,
273 SessionScopeId, SessionStoreCreateRequest, SessionStoreFactory, SessionUsageReport, SlotPolicy,
274 TerminationPolicy, TokenLedgerEntry, ToolCallLaunch, TurnActivity, TurnActivityId,
275 TurnActivitySink, TurnContext, TurnEvent, TurnInput, TurnIssue, TurnOptions,
276 UnavailableProcessService, UsageReportRow, UsageTotals, WaitKind, WaitState, current_epoch_ms,
277 diff_token_ledger, diff_usage_reports, ensure_durable_effect_input, epoch_ms_from_system_time,
278 process_signal_event_type, process_signal_name_from_event_type, process_signal_wait_key,
279 system_time_from_epoch_ms, validate_process_signal_name,
280};
281#[allow(unused_imports)]
282pub(crate) use runtime::{
283 LlmAttachmentSpec, PreparedProcessEventAppend, ProcessEventSemantics, QUEUED_WORK_CLAIM_TTL_MS,
284 QueuedCheckpointWork, QueuedTurnWork, QueuedWorkBatch, QueuedWorkBatchDraft, QueuedWorkClaim,
285 QueuedWorkClaimBoundary, QueuedWorkCompletion, QueuedWorkItem, QueuedWorkPayload,
286 RuntimeReplay, RuntimeScope, RuntimeSubject, load_process_execution_env,
287 materialize_process_event_semantics, persist_process_execution_env,
288 prepare_process_event_append, prepare_process_registration, process_event_invocation,
289 process_event_payload_hash, process_wake_batch_draft, process_wake_delivery,
290 process_wake_input_from_event_payload, process_wake_turn_cause, process_wake_turn_text,
291 require_event_replay,
292};
293pub use runtime::{
297 LlmRequestSpec, ProcessCommand, ProcessEffectOutcome, ProcessEventSemanticsSpec,
298 RuntimeEffectCommand, RuntimeEffectController, RuntimeEffectControllerError,
299 RuntimeEffectEnvelope, RuntimeEffectKind, RuntimeEffectLocalExecutor, RuntimeEffectOutcome,
300 RuntimeInvocation, RuntimeSessionState,
301};
302pub use schemars::JsonSchema;
303pub use session::{
304 ExecRequest, InjectedTurnInput, RuntimeExecutionContext, Session, SessionError, ToolInvocation,
305 ToolInvocationReply,
306};
307pub use session_graph::{
308 PersistedSessionConfig, PersistedTurnState, SessionGraph, SessionMessageTreeNode,
309 SessionNodePayload, SessionNodeRecord,
310};
311pub use session_model::context::PreparedContext;
312pub use session_model::{ConversationRecord, ProtocolEvent, SessionEventRecord};
313pub use session_model::{RuntimeSessionPolicy, SessionPolicy, SessionSpec};
314pub use store::{
315 AttachmentIntent, AttachmentManifest, AttachmentManifestEntry, BlobRef, GcReport,
316 RuntimePersistence, SessionMeta, SessionPickerInfo, SessionReadScope, StoreError, VacuumReport,
317};
318#[allow(unused_imports)]
319pub(crate) use store::{
320 GraphCommitDelta, PersistedSessionRead, RuntimeCommitResult, SessionCheckpoint,
321 SessionHeadMeta, ensure_supported_schema_version, load_persisted_session_state,
322 load_persisted_session_state_active_path,
323};
324pub use store::{
325 HydratedSessionCheckpoint, RuntimeCommit, RuntimeTurnCommitStamp, SessionHead,
326 refresh_persisted_session_state,
327};
328pub use tool_provider::{
329 PreparedToolCall, ProgressSender, SandboxMessage, ToolCall, ToolChildExecutionTraceHook,
330 ToolChildProcessStarted, ToolContext, ToolDurableEffects, ToolPrepareCall, ToolPrepareContext,
331 ToolProvider, ToolSessionAdmin, ToolSessionModel, ToolTriggerClient,
332};
333
334#[cfg(test)]
335mod tests {
336 use super::*;
337
338 #[test]
339 fn protocol_turn_options_missing_payload_deserializes_to_empty_object() {
340 let options: ProtocolTurnOptions =
341 serde_json::from_value(serde_json::json!({})).expect("deserialize options");
342
343 assert!(options.is_empty());
344 assert_eq!(options.payload, serde_json::json!({}));
345 }
346
347 #[test]
348 fn protocol_turn_options_explicit_null_is_not_empty() {
349 let options: ProtocolTurnOptions =
350 serde_json::from_value(serde_json::json!({ "payload": null }))
351 .expect("deserialize options");
352
353 assert!(!options.is_empty());
354 assert_eq!(options.payload, serde_json::Value::Null);
355 }
356
357 #[test]
358 fn root_exports_do_not_reintroduce_removed_session_state_shapes() {
359 let source = include_str!("lib.rs");
360 let removed_envelope = ["SessionState", "Envelope"].concat();
361 let removed_persisted = ["PersistedSession", "Snapshot"].concat();
362 let removed_history_rewriter = ["History", "Rewriter"].concat();
363 let removed_rewrite_trigger = ["Rewrite", "Trigger"].concat();
364 let removed_rewrite_context = ["Rewrite", "Context"].concat();
365 let removed_history_state = ["History", "State"].concat();
366 let removed_history_metadata = ["History", "Rewrite", "Metadata"].concat();
367
368 assert!(!source.contains(&removed_envelope));
369 assert!(!source.contains(&removed_persisted));
370 assert!(!source.contains(&removed_history_rewriter));
371 assert!(!source.contains(&removed_rewrite_trigger));
372 assert!(!source.contains(&removed_rewrite_context));
373 assert!(!source.contains(&removed_history_state));
374 assert!(!source.contains(&removed_history_metadata));
375 }
376
377 fn public_reexport_block(source: &str, module: &str) -> String {
378 let start = format!("pub use {module}::{{");
379 let mut block = String::new();
380 let mut collecting = false;
381 for line in source.lines() {
382 if line.trim_start().starts_with(&start) {
383 collecting = true;
384 }
385 if collecting {
386 block.push_str(line);
387 block.push('\n');
388 if line.trim_end() == "};" {
389 break;
390 }
391 }
392 }
393 assert!(!block.is_empty(), "missing public {module} re-export block");
394 block
395 }
396
397 #[test]
398 fn root_runtime_exports_exclude_internal_runtime_records() {
399 let runtime_exports = public_reexport_block(include_str!("lib.rs"), "runtime");
400 for removed in [
401 "RuntimeEffectCommand",
402 "RuntimeEffectEnvelope",
403 "RuntimeEffectKind",
404 "RuntimeEffectOutcome",
405 "RuntimeInvocation",
406 "RuntimeScope",
407 "RuntimeSessionState",
408 "QueuedWorkBatch",
409 "QueuedWorkBatchDraft",
410 "QueuedWorkPayload",
411 "prepare_process_registration",
412 "process_wake_batch_draft",
413 "require_event_replay",
414 ] {
415 assert!(
416 !runtime_exports.contains(removed),
417 "runtime root export leaked {removed}"
418 );
419 }
420 }
421
422 #[test]
423 fn root_store_exports_exclude_wire_records() {
424 let store_exports = public_reexport_block(include_str!("lib.rs"), "store");
425 for removed in [
426 "SessionHead",
427 "SessionCheckpoint",
428 "RuntimeCommit",
429 "HydratedSessionCheckpoint",
430 "PersistedSessionRead",
431 "GraphCommitDelta",
432 ] {
433 assert!(
434 !store_exports.contains(removed),
435 "store root export leaked {removed}"
436 );
437 }
438 }
439
440 #[test]
441 fn removed_manager_and_host_trait_names_stay_removed() {
442 let removed_manager = ["Runtime", "Session", "Manager"].concat();
443 let removed_host = ["Runtime", "Session", "Host"].concat();
444 let sources = [
445 include_str!("runtime/session_manager/mod.rs"),
446 include_str!("plugin/runtime_host.rs"),
447 include_str!("tool_dispatch/context.rs"),
448 include_str!("tool_provider.rs"),
449 ];
450
451 for source in sources {
452 assert!(!source.contains(&removed_manager));
453 assert!(!source.contains(&removed_host));
454 }
455 }
456}