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, 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, ProcessAwaitOutput, ProcessCancelAbility, ProcessCancelAllRequest,
252 ProcessCancelRequest, ProcessCancelSource, ProcessCancelSummary, ProcessEngine,
253 ProcessEngineRegistry, ProcessEngineRunContext, ProcessEngineRunGuard,
254 ProcessEngineRuntimeContext, ProcessEngineValidationContext, ProcessEvent,
255 ProcessEventAppendPlan, ProcessEventAppendRequest, ProcessEventAppendResult, ProcessEventType,
256 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, TurnIssue, TurnOptions,
277 UnavailableProcessService, UsageReportRow, UsageTotals, WaitKind, WaitState,
278 apply_process_status_projection, current_epoch_ms, diff_token_ledger, diff_usage_reports,
279 ensure_durable_effect_input, epoch_ms_from_system_time, process_signal_event_type,
280 process_signal_name_from_event_type, process_signal_wait_key, system_time_from_epoch_ms,
281 validate_process_signal_name,
282};
283#[allow(unused_imports)]
284pub(crate) use runtime::{
285 LlmAttachmentSpec, ProcessEventSemantics, QUEUED_WORK_CLAIM_TTL_MS, QueuedCheckpointWork,
286 QueuedTurnWork, QueuedWorkBatch, QueuedWorkBatchDraft, QueuedWorkClaim,
287 QueuedWorkClaimBoundary, QueuedWorkCompletion, QueuedWorkItem, QueuedWorkPayload,
288 RuntimeReplay, RuntimeScope, RuntimeSubject, load_process_execution_env,
289 materialize_process_event_semantics, persist_process_execution_env,
290 prepare_process_event_append, prepare_process_registration, process_event_invocation,
291 process_event_payload_hash, process_wake_batch_draft, process_wake_delivery,
292 process_wake_input_from_event_payload, process_wake_turn_cause, process_wake_turn_text,
293 require_event_replay,
294};
295pub use session_model::{
296 PLUGIN_RUNTIME_PROTOCOL_PLUGIN_ID, PersistedPluginRuntimeEvent,
297 plugin_runtime_event_from_protocol, plugin_runtime_protocol_event,
298};
299pub use runtime::{
303 LlmRequestSpec, ProcessCommand, ProcessEffectOutcome, ProcessEventSemanticsSpec,
304 RuntimeEffectCommand, RuntimeEffectController, RuntimeEffectControllerError,
305 RuntimeEffectEnvelope, RuntimeEffectKind, RuntimeEffectLocalExecutor, RuntimeEffectOutcome,
306 RuntimeInvocation, RuntimeSessionState, ToolAttemptEffectOutcome, ToolAttemptLaunch,
307 ToolBatchEffectOutcome,
308};
309pub use schemars::JsonSchema;
310pub use session::{
311 ExecRequest, InjectedTurnInput, RuntimeExecutionContext, Session, SessionError, ToolInvocation,
312 ToolInvocationReply,
313};
314pub use session_graph::{
315 PersistedSessionConfig, PersistedTurnState, SessionGraph, SessionMessageTreeNode,
316 SessionNodePayload, SessionNodeRecord,
317};
318pub use session_model::context::PreparedContext;
319pub use session_model::{ConversationRecord, ProtocolEvent, SessionEventRecord};
320pub use session_model::{RuntimeSessionPolicy, SessionPolicy, SessionSpec};
321pub use store::{
322 AttachmentIntent, AttachmentManifest, AttachmentManifestEntry, BlobRef, GcReport,
323 RuntimePersistence, SessionExecutionLease, SessionExecutionLeaseCompletion,
324 SessionExecutionLeaseFence, SessionMeta, SessionPickerInfo, SessionReadScope, StoreError,
325 VacuumReport,
326};
327#[allow(unused_imports)]
328pub(crate) use store::{
329 GraphCommitDelta, PersistedSessionRead, RuntimeCommitResult, SessionCheckpoint,
330 SessionHeadMeta, ensure_supported_schema_version, load_persisted_session_state,
331 load_persisted_session_state_active_path,
332};
333pub use store::{
334 HydratedSessionCheckpoint, RuntimeCommit, RuntimeTurnCommitStamp, SessionHead,
335 refresh_persisted_session_state,
336};
337pub use tool_provider::{
338 PreparedToolBatch, PreparedToolBatchCall, PreparedToolCall, ProgressSender, SandboxMessage,
339 ToolCall, ToolChildExecutionTraceHook, ToolChildProcessStarted, ToolContext,
340 ToolDurableEffects, ToolExecutionGrant, ToolPrepareCall, ToolPrepareContext, ToolProvider,
341 ToolSessionAdmin, ToolSessionModel, ToolTriggerClient,
342};
343
344#[cfg(test)]
345mod tests {
346 use super::*;
347
348 #[test]
349 fn protocol_turn_options_missing_payload_deserializes_to_empty_object() {
350 let options: ProtocolTurnOptions =
351 serde_json::from_value(serde_json::json!({})).expect("deserialize options");
352
353 assert!(options.is_empty());
354 assert_eq!(options.payload, serde_json::json!({}));
355 }
356
357 #[test]
358 fn protocol_turn_options_explicit_null_is_not_empty() {
359 let options: ProtocolTurnOptions =
360 serde_json::from_value(serde_json::json!({ "payload": null }))
361 .expect("deserialize options");
362
363 assert!(!options.is_empty());
364 assert_eq!(options.payload, serde_json::Value::Null);
365 }
366
367 #[test]
368 fn root_exports_do_not_reintroduce_removed_session_state_shapes() {
369 let source = include_str!("lib.rs");
370 let removed_envelope = ["SessionState", "Envelope"].concat();
371 let removed_persisted = ["PersistedSession", "Snapshot"].concat();
372 let removed_history_rewriter = ["History", "Rewriter"].concat();
373 let removed_rewrite_trigger = ["Rewrite", "Trigger"].concat();
374 let removed_rewrite_context = ["Rewrite", "Context"].concat();
375 let removed_history_state = ["History", "State"].concat();
376 let removed_history_metadata = ["History", "Rewrite", "Metadata"].concat();
377
378 assert!(!source.contains(&removed_envelope));
379 assert!(!source.contains(&removed_persisted));
380 assert!(!source.contains(&removed_history_rewriter));
381 assert!(!source.contains(&removed_rewrite_trigger));
382 assert!(!source.contains(&removed_rewrite_context));
383 assert!(!source.contains(&removed_history_state));
384 assert!(!source.contains(&removed_history_metadata));
385 }
386
387 fn public_reexport_block(source: &str, module: &str) -> String {
388 let start = format!("pub use {module}::{{");
389 let mut block = String::new();
390 let mut collecting = false;
391 for line in source.lines() {
392 if line.trim_start().starts_with(&start) {
393 collecting = true;
394 }
395 if collecting {
396 block.push_str(line);
397 block.push('\n');
398 if line.trim_end() == "};" {
399 break;
400 }
401 }
402 }
403 assert!(!block.is_empty(), "missing public {module} re-export block");
404 block
405 }
406
407 #[test]
408 fn root_runtime_exports_exclude_internal_runtime_records() {
409 let runtime_exports = public_reexport_block(include_str!("lib.rs"), "runtime");
410 for removed in [
411 "RuntimeEffectCommand",
412 "RuntimeEffectEnvelope",
413 "RuntimeEffectKind",
414 "RuntimeEffectOutcome",
415 "RuntimeInvocation",
416 "RuntimeScope",
417 "RuntimeSessionState",
418 "QueuedWorkBatch",
419 "QueuedWorkBatchDraft",
420 "QueuedWorkPayload",
421 "prepare_process_registration",
422 "process_wake_batch_draft",
423 "require_event_replay",
424 ] {
425 assert!(
426 !runtime_exports.contains(removed),
427 "runtime root export leaked {removed}"
428 );
429 }
430 }
431
432 #[test]
433 fn root_store_exports_exclude_wire_records() {
434 let store_exports = public_reexport_block(include_str!("lib.rs"), "store");
435 for removed in [
436 "SessionHead",
437 "SessionCheckpoint",
438 "RuntimeCommit",
439 "HydratedSessionCheckpoint",
440 "PersistedSessionRead",
441 "GraphCommitDelta",
442 ] {
443 assert!(
444 !store_exports.contains(removed),
445 "store root export leaked {removed}"
446 );
447 }
448 }
449
450 #[test]
451 fn removed_manager_and_host_trait_names_stay_removed() {
452 let removed_manager = ["Runtime", "Session", "Manager"].concat();
453 let removed_host = ["Runtime", "Session", "Host"].concat();
454 let sources = [
455 include_str!("runtime/session_manager/mod.rs"),
456 include_str!("plugin/runtime_host.rs"),
457 include_str!("tool_dispatch/context.rs"),
458 include_str!("tool_provider.rs"),
459 ];
460
461 for source in sources {
462 assert!(!source.contains(&removed_manager));
463 assert!(!source.contains(&removed_host));
464 }
465 }
466}