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, Clock, 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 ProcessEventAppendPlan, ProcessEventAppendRequest, ProcessEventAppendResult, ProcessEventType,
255 ProcessExecutionContext, ProcessExecutionEnvRef, ProcessExecutionEnvSpec,
256 ProcessExecutionEnvStore, ProcessExternalRef, ProcessHandleDescriptor, ProcessHandleGrant,
257 ProcessHandleSummary, ProcessId, ProcessIdentity, ProcessInput, ProcessLease,
258 ProcessLeaseCompletion, ProcessLifecycleStatus, ProcessListFilter, ProcessListMode,
259 ProcessOpScope, ProcessOriginator, ProcessProvenance, ProcessRecord, ProcessRegistration,
260 ProcessRegistry, ProcessRunHandle, ProcessRuntimeHost, ProcessService,
261 ProcessSessionDeleteReport, ProcessSpawnProvenance, ProcessStartGrant, ProcessStartOptions,
262 ProcessStartRequest, ProcessStatus, ProcessStatusFilter, ProcessTerminalSemantics,
263 ProcessTerminalSpec, ProcessTerminalState, ProcessValueSelector, ProcessWake,
264 ProcessWakeDedupeKey, ProcessWakeDelivery, ProcessWakeSpec, ProcessWorkDriver,
265 ProcessWorkObserver, ProcessWorkSnapshot, PromptUsage, ProtocolSessionExtension,
266 ProtocolSessionExtensionHandle, ProtocolTurnExtension, ProtocolTurnExtensionHandle,
267 QueuedWorkDriver, QueuedWorkRunHandle, QueuedWorkRunRequest, Residency, Resolution,
268 ResolveOutcome, RuntimeEnvironment, RuntimeEnvironmentBuilder, RuntimeError, RuntimeErrorCode,
269 RuntimeHandle, 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 SystemClock, TerminationPolicy, TokenLedgerEntry, ToolCallLaunch, TurnActivity, TurnActivityId,
275 TurnActivitySink, TurnContext, TurnEvent, TurnInput, TurnIssue, TurnOptions,
276 UnavailableProcessService, UsageReportRow, UsageTotals, WaitKind, WaitState,
277 apply_process_status_projection, current_epoch_ms, diff_token_ledger, diff_usage_reports,
278 ensure_durable_effect_input, epoch_ms_from_system_time, process_signal_event_type,
279 process_signal_name_from_event_type, process_signal_wait_key, system_time_from_epoch_ms,
280 validate_process_signal_name,
281};
282#[allow(unused_imports)]
283pub(crate) use runtime::{
284 LlmAttachmentSpec, ProcessEventSemantics, QUEUED_WORK_CLAIM_TTL_MS, QueuedCheckpointWork,
285 QueuedTurnWork, QueuedWorkBatch, QueuedWorkBatchDraft, QueuedWorkClaim,
286 QueuedWorkClaimBoundary, QueuedWorkCompletion, QueuedWorkItem, QueuedWorkPayload,
287 RuntimeReplay, RuntimeScope, RuntimeSubject, load_process_execution_env,
288 materialize_process_event_semantics, persist_process_execution_env,
289 prepare_process_event_append, prepare_process_registration, process_event_invocation,
290 process_event_payload_hash, process_wake_batch_draft, process_wake_delivery,
291 process_wake_input_from_event_payload, process_wake_turn_cause, process_wake_turn_text,
292 require_event_replay,
293};
294pub use runtime::{
298 LlmRequestSpec, ProcessCommand, ProcessEffectOutcome, ProcessEventSemanticsSpec,
299 RuntimeEffectCommand, RuntimeEffectController, RuntimeEffectControllerError,
300 RuntimeEffectEnvelope, RuntimeEffectKind, RuntimeEffectLocalExecutor, RuntimeEffectOutcome,
301 RuntimeInvocation, RuntimeSessionState, ToolBatchEffectOutcome,
302};
303pub use schemars::JsonSchema;
304pub use session::{
305 ExecRequest, InjectedTurnInput, RuntimeExecutionContext, Session, SessionError, ToolInvocation,
306 ToolInvocationReply,
307};
308pub use session_graph::{
309 PersistedSessionConfig, PersistedTurnState, SessionGraph, SessionMessageTreeNode,
310 SessionNodePayload, SessionNodeRecord,
311};
312pub use session_model::context::PreparedContext;
313pub use session_model::{ConversationRecord, ProtocolEvent, SessionEventRecord};
314pub use session_model::{RuntimeSessionPolicy, SessionPolicy, SessionSpec};
315pub use store::{
316 AttachmentIntent, AttachmentManifest, AttachmentManifestEntry, BlobRef, GcReport,
317 RuntimePersistence, SessionMeta, SessionPickerInfo, SessionReadScope, StoreError, VacuumReport,
318};
319#[allow(unused_imports)]
320pub(crate) use store::{
321 GraphCommitDelta, PersistedSessionRead, RuntimeCommitResult, SessionCheckpoint,
322 SessionHeadMeta, ensure_supported_schema_version, load_persisted_session_state,
323 load_persisted_session_state_active_path,
324};
325pub use store::{
326 HydratedSessionCheckpoint, RuntimeCommit, RuntimeTurnCommitStamp, SessionHead,
327 refresh_persisted_session_state,
328};
329pub use tool_provider::{
330 PreparedToolBatch, PreparedToolBatchCall, PreparedToolCall, ProgressSender, SandboxMessage,
331 ToolCall, ToolChildExecutionTraceHook, ToolChildProcessStarted, ToolContext,
332 ToolDurableEffects, ToolPrepareCall, ToolPrepareContext, ToolProvider, ToolSessionAdmin,
333 ToolSessionModel, ToolTriggerClient,
334};
335
336#[cfg(test)]
337mod tests {
338 use super::*;
339
340 #[test]
341 fn protocol_turn_options_missing_payload_deserializes_to_empty_object() {
342 let options: ProtocolTurnOptions =
343 serde_json::from_value(serde_json::json!({})).expect("deserialize options");
344
345 assert!(options.is_empty());
346 assert_eq!(options.payload, serde_json::json!({}));
347 }
348
349 #[test]
350 fn protocol_turn_options_explicit_null_is_not_empty() {
351 let options: ProtocolTurnOptions =
352 serde_json::from_value(serde_json::json!({ "payload": null }))
353 .expect("deserialize options");
354
355 assert!(!options.is_empty());
356 assert_eq!(options.payload, serde_json::Value::Null);
357 }
358
359 #[test]
360 fn root_exports_do_not_reintroduce_removed_session_state_shapes() {
361 let source = include_str!("lib.rs");
362 let removed_envelope = ["SessionState", "Envelope"].concat();
363 let removed_persisted = ["PersistedSession", "Snapshot"].concat();
364 let removed_history_rewriter = ["History", "Rewriter"].concat();
365 let removed_rewrite_trigger = ["Rewrite", "Trigger"].concat();
366 let removed_rewrite_context = ["Rewrite", "Context"].concat();
367 let removed_history_state = ["History", "State"].concat();
368 let removed_history_metadata = ["History", "Rewrite", "Metadata"].concat();
369
370 assert!(!source.contains(&removed_envelope));
371 assert!(!source.contains(&removed_persisted));
372 assert!(!source.contains(&removed_history_rewriter));
373 assert!(!source.contains(&removed_rewrite_trigger));
374 assert!(!source.contains(&removed_rewrite_context));
375 assert!(!source.contains(&removed_history_state));
376 assert!(!source.contains(&removed_history_metadata));
377 }
378
379 fn public_reexport_block(source: &str, module: &str) -> String {
380 let start = format!("pub use {module}::{{");
381 let mut block = String::new();
382 let mut collecting = false;
383 for line in source.lines() {
384 if line.trim_start().starts_with(&start) {
385 collecting = true;
386 }
387 if collecting {
388 block.push_str(line);
389 block.push('\n');
390 if line.trim_end() == "};" {
391 break;
392 }
393 }
394 }
395 assert!(!block.is_empty(), "missing public {module} re-export block");
396 block
397 }
398
399 #[test]
400 fn root_runtime_exports_exclude_internal_runtime_records() {
401 let runtime_exports = public_reexport_block(include_str!("lib.rs"), "runtime");
402 for removed in [
403 "RuntimeEffectCommand",
404 "RuntimeEffectEnvelope",
405 "RuntimeEffectKind",
406 "RuntimeEffectOutcome",
407 "RuntimeInvocation",
408 "RuntimeScope",
409 "RuntimeSessionState",
410 "QueuedWorkBatch",
411 "QueuedWorkBatchDraft",
412 "QueuedWorkPayload",
413 "prepare_process_registration",
414 "process_wake_batch_draft",
415 "require_event_replay",
416 ] {
417 assert!(
418 !runtime_exports.contains(removed),
419 "runtime root export leaked {removed}"
420 );
421 }
422 }
423
424 #[test]
425 fn root_store_exports_exclude_wire_records() {
426 let store_exports = public_reexport_block(include_str!("lib.rs"), "store");
427 for removed in [
428 "SessionHead",
429 "SessionCheckpoint",
430 "RuntimeCommit",
431 "HydratedSessionCheckpoint",
432 "PersistedSessionRead",
433 "GraphCommitDelta",
434 ] {
435 assert!(
436 !store_exports.contains(removed),
437 "store root export leaked {removed}"
438 );
439 }
440 }
441
442 #[test]
443 fn removed_manager_and_host_trait_names_stay_removed() {
444 let removed_manager = ["Runtime", "Session", "Manager"].concat();
445 let removed_host = ["Runtime", "Session", "Host"].concat();
446 let sources = [
447 include_str!("runtime/session_manager/mod.rs"),
448 include_str!("plugin/runtime_host.rs"),
449 include_str!("tool_dispatch/context.rs"),
450 include_str!("tool_provider.rs"),
451 ];
452
453 for source in sources {
454 assert!(!source.contains(&removed_manager));
455 assert!(!source.contains(&removed_host));
456 }
457 }
458}