1pub mod attachments;
2pub mod chronological;
3pub mod direct;
4pub mod host_events;
5pub mod lashlang_bridge;
6pub mod llm;
7mod model;
8pub mod plugin;
9mod plugin_stack;
10mod protocol_build;
11pub mod provider;
12pub mod runtime;
13pub mod search;
14pub mod session;
15pub mod session_graph;
16pub mod session_model;
17mod stable_hash;
18pub mod store;
19#[cfg(any(test, feature = "testing"))]
20pub mod testing;
21pub mod tool_dispatch;
22mod tool_provider;
23pub mod tool_registry;
24mod tool_result;
25mod trace;
26
27pub use lash_sansio::sansio;
28
29pub const VERSION: &str = env!("CARGO_PKG_VERSION");
30pub const SANSIO_VERSION: &str = lash_sansio::VERSION;
31
32pub use attachments::{
34 AttachmentStore, AttachmentStoreError, AttachmentStorePersistence, InMemoryAttachmentStore,
35 SessionScopedAttachmentStore, StoredAttachment,
36};
37pub use chronological::{
41 BorrowedChronologicalEntry, BorrowedChronologicalMessage, BorrowedChronologicalPayload,
42 ChronologicalEntry, ChronologicalPayload, ChronologicalProjection, visit_turn_view,
43};
44pub use direct::{
45 DirectJsonSchema, DirectLlmClient, DirectLlmError, DirectMessage, DirectOutputSpec, DirectPart,
46 DirectRequest, DirectRole,
47};
48pub use host_events::{
49 HostEvent, HostEventCatalog, HostEventEmitReport, HostEventKey, HostEventOccurrenceRecord,
50 HostEventOccurrenceRequest, HostEventRouter, HostEventStore, InMemoryHostEventStore,
51 TriggerDeliveryReservation, TriggerRegistration, TriggerSourceType, TriggerSubscriptionDraft,
52 TriggerSubscriptionFilter, TriggerSubscriptionRecord, TriggerTargetSummary,
53 default_host_event_source_key, deterministic_delivery_process_id, deterministic_occurrence_id,
54 empty_host_event_source_key, host_event_occurrence_request_hash, host_event_source_type,
55 validate_host_event_occurrence_request,
56};
57pub use lash_sansio::llm::types::{
58 GenerationOptions, LlmOutputPart, LlmRequest, LlmResponse, LlmTerminalReason,
59};
60pub use lash_sansio::{
61 AcceptedInjectedTurnInput, AttachmentCreateMeta, AttachmentId, AttachmentMeta, AttachmentRef,
62 BaseRenderCache, CheckpointDelivery, CheckpointKind, CompactToolContract, EffectId,
63 ErrorEnvelope, ExecImage, ExecResponse, ImageMediaType, LashSchema, LlmCallError, MediaType,
64 Message, MessageOrigin, MessageRole, MessageSequence, ModelToolReturn, ModelToolReturnPart,
65 Part, PartKind, PluginMessage, PluginRuntimeEvent, PreparedPrompt, PromptBuildInput,
66 PromptBuiltin, PromptContext, PromptContribution, PromptContributionGate,
67 PromptContributionSet, PromptFingerprint, PromptLayer, PromptSlot, PromptSlotLayer,
68 PromptTemplate, PromptTemplateEntry, PromptTemplateSection, PruneState, RenderedPrompt,
69 ResolvedPromptLayer, Response, SchemaProjectionOverride, SessionEvent, TextProjectionMetadata,
70 TokenUsage, ToolActivation, ToolAgentExecutableSurface, ToolAgentSurface,
71 ToolArgumentProjectionPolicy, ToolAvailability, ToolAvailabilityConfig, ToolCallOutcome,
72 ToolCallOutput, ToolCallRecord, ToolCallStatus, ToolCancellation, ToolContract, ToolControl,
73 ToolDefinition, ToolFailure, ToolFailureClass, ToolFailureSource, ToolId, ToolManifest,
74 ToolOutputContract, ToolRetryDisposition, ToolRetryPolicy, ToolScheduling, ToolSurface,
75 ToolSurfaceBuildInput, ToolSurfaceEntry, ToolSurfaceOverride, ToolValue, TurnCause, TurnFinish,
76 TurnLimitFinalMessage, TurnOutcome, TurnStop, append_assistant_text_part, build_prompt,
77 build_tool_surface, build_turn, default_prompt_template, head_tail_truncate,
78 messages_are_prompt_resume_safe, normalized_response_parts, prompt_template_fingerprint,
79 prompt_text_fingerprint, prompt_tool_names_fingerprint, reasoning_part,
80 render_turn_causes_prompt, resolve_prompt_layers, shared_parts, validate_tool_input,
81};
82pub use lashlang::{DurabilityTier, InMemoryLashlangArtifactStore, LashlangArtifactStore};
83pub use protocol_build::ProtocolBuildInput;
84pub use tool_registry::{
85 ReconfigureError, ToolRegistry, ToolSourceHandle, ToolState, ToolStateEntry,
86};
87pub use tool_result::ToolResult;
88#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
89pub struct ProtocolTurnOptions {
90 #[serde(default = "empty_protocol_turn_payload")]
91 pub payload: serde_json::Value,
92}
93
94fn empty_protocol_turn_payload() -> serde_json::Value {
95 serde_json::Value::Object(serde_json::Map::new())
96}
97
98impl Default for ProtocolTurnOptions {
99 fn default() -> Self {
100 Self::empty()
101 }
102}
103
104impl ProtocolTurnOptions {
105 pub fn empty() -> Self {
106 Self {
107 payload: serde_json::Value::Object(serde_json::Map::new()),
108 }
109 }
110
111 pub fn is_empty(&self) -> bool {
112 match &self.payload {
113 serde_json::Value::Object(map) => map.is_empty(),
114 _ => false,
115 }
116 }
117
118 pub fn merged_with_override(&self, override_options: &Self) -> Self {
119 match (&self.payload, &override_options.payload) {
120 (serde_json::Value::Object(base), serde_json::Value::Object(overrides)) => {
121 let mut payload = base.clone();
122 payload.extend(overrides.clone());
123 Self {
124 payload: serde_json::Value::Object(payload),
125 }
126 }
127 _ => override_options.clone(),
128 }
129 }
130
131 pub fn typed<T>(value: T) -> Result<Self, serde_json::Error>
132 where
133 T: serde::Serialize,
134 {
135 Ok(Self {
136 payload: serde_json::to_value(value)?,
137 })
138 }
139
140 pub fn decode<T>(&self) -> Result<T, serde_json::Error>
141 where
142 T: serde::de::DeserializeOwned,
143 {
144 serde_json::from_value(self.payload.clone())
145 }
146}
147
148#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
149pub struct ProtocolDriverState {
150 pub plugin_id: String,
151 pub payload: serde_json::Value,
152}
153
154impl ProtocolDriverState {
155 pub fn new(plugin_id: impl Into<String>, payload: serde_json::Value) -> Self {
156 Self {
157 plugin_id: plugin_id.into(),
158 payload,
159 }
160 }
161}
162
163#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
164pub struct HostTurnProtocol;
165
166impl lash_sansio::TurnProtocol for HostTurnProtocol {
167 type Event = crate::session_model::ProtocolEvent;
168 type Termination = ProtocolTurnOptions;
169 type DriverState = ProtocolDriverState;
170}
171
172pub type Effect = lash_sansio::Effect<HostTurnProtocol>;
173pub type DriverAction = lash_sansio::DriverAction<HostTurnProtocol>;
174pub type DriverContextView<'a> = lash_sansio::DriverContextView<'a, HostTurnProtocol>;
175pub type TurnDriverConfig = lash_sansio::TurnDriverConfig<HostTurnProtocol>;
176pub type TurnDriverPreamble = lash_sansio::TurnDriverPreamble<HostTurnProtocol>;
177pub type ProjectorContext<'a> = lash_sansio::ProjectorContext<'a, HostTurnProtocol>;
178pub type PreparedTurnMachine = lash_sansio::PreparedTurnMachine<HostTurnProtocol>;
179pub type SansIoTurnInput = lash_sansio::SansIoTurnInput<HostTurnProtocol>;
180pub type TurnMachine = lash_sansio::TurnMachine<HostTurnProtocol>;
181pub type TurnMachineConfig = lash_sansio::TurnMachineConfig<HostTurnProtocol>;
182#[cfg(feature = "otel-trace")]
183pub use lash_trace::otel::{OtelTraceOptions, OtelTraceSink};
184pub use lash_trace::{
185 JsonlTraceSink, TraceAttachment, TraceBranchSelection, TraceContentBlock, TraceContext,
186 TraceError, TraceEvent, TraceLabelMetadata, TraceLashlangChildExecution,
187 TraceLashlangEdgeSelection, TraceLashlangExecutionEvent, TraceLashlangExecutionIdentity,
188 TraceLashlangGraph, TraceLashlangGraphChildLink, TraceLashlangGraphEdge,
189 TraceLashlangGraphNode, TraceLashlangGraphStore, TraceLashlangMap, TraceLashlangMapEdge,
190 TraceLashlangMapNode, TraceLashlangNodeStatus, TraceLashlangStatus, TraceLevel,
191 TraceLlmMessage, TraceLlmRequest, TraceLlmResponse, TracePromptComponent,
192 TraceProviderStreamEvent, TraceRecord, TraceRuntimeScope, TraceRuntimeStreamEvent,
193 TraceRuntimeSubject, TraceSink, TraceSinkError, TraceTokenUsage, TraceToolSpec,
194};
195pub use llm::transport::{LlmTransportError, ProviderFailure, ProviderFailureKind};
196pub use model::{ModelLimits, ModelSpec};
197pub use plugin::{
198 AgentFrameAssignment, AgentFrameId, AgentFrameReason, AgentFrameRecord, AgentFrameStatus,
199 AppendSessionNodesRequest, AppendSessionNodesResult, AssistantResponseHookContext,
200 AssistantResponseTransform, AssistantStreamHookContext, AssistantStreamTransform,
201 CheckpointHookContext, CompactionContext, ContextCompaction, ContextCompactor, ContextError,
202 ContextRegistrations, DirectCompletion, DirectLlmCompletion, HostEventRegistrations,
203 OpenAgentFrameRequest, OpenAgentFrameResult, PersistentRuntimeServices, PluginAction,
204 PluginActionContext, PluginActionDef, PluginActionFailure, PluginActionInvokeError,
205 PluginActionKind, PluginDirective, PluginError, PluginFactory, PluginHost,
206 PluginLifecycleEvent, PluginLifecycleEventHook, PluginOptions, PluginOwned, PluginRegistrar,
207 PluginSession, PluginSessionContext, PluginSessionSnapshot, PluginSnapshotArtifact,
208 PluginSnapshotEntry, PluginSnapshotMeta, PluginSpec, PluginSpecFactory, PromptHookContext,
209 ProtocolBeforeLlmCallContext, ProtocolLlmCallAction, RuntimeServices, SessionAppendNode,
210 SessionConfigChangedContext, SessionContextSurface, SessionCreateRequest, SessionGraphService,
211 SessionHandle, SessionLifecycleService, SessionParam, SessionPlugin, SessionPluginSource,
212 SessionReadView, SessionRelation, SessionSnapshot, SessionStartPoint,
213 SessionStateChangedContext, SessionStateService, SessionToolAccess, SessionTurnInput,
214 SessionTurnRequest, SnapshotReader, SnapshotWriter, SubagentSessionContext,
215 ToolDiscoveryContext, ToolDiscoveryContribution, ToolDiscoveryContributor,
216 ToolDiscoveryToolContribution, ToolResultProjectionContext, ToolResultProjector,
217 ToolSurfaceContribution, TurnContextTransform, TurnHookContext, TurnResultHookContext,
218 TurnResultSummary, TurnTransformContext, plugin_action_def,
219};
220pub use plugin_stack::PluginStack;
221pub use provider::{
222 CacheRetention, EmptyProviderResolver, LlmTimeouts, MapProviderResolver, Provider,
223 ProviderBinding, ProviderComponents, ProviderFactory, ProviderHandle, ProviderModelPolicy,
224 ProviderOptions, ProviderResolutionError, ProviderSpec, ProviderThinkingPolicy, RequestTimeout,
225 RuntimeProviderResolver, SingleProviderResolver, StaticModelPolicy,
226};
227#[cfg(any(test, feature = "testing"))]
228pub use runtime::TestLocalProcessRegistry;
229pub use runtime::{
230 AgentFrameRun, AssembledTurn, AssistantOutput, CausalRef, CodeOutputRecord,
231 DefaultProcessCancelAbility, DeliveryPolicy, DirectCompletionClient, DurableProcessWorker,
232 DurableProcessWorkerConfig, DurableStoreFacet, EffectHost, EffectScope, EmbeddedRuntimeBuilder,
233 EmbeddedRuntimeHost, EventSink, ExecutionSummary, InMemoryLiveReplayStore,
234 InMemoryLiveReplayStoreConfig, InMemorySessionStore, InMemorySessionStoreFactory,
235 InlineEffectHost, InlineProcessRunHandle, InlineRuntimeEffectController, InputItem,
236 LashRuntime, LiveReplayGap, LiveReplayGapReason, LiveReplayResult, LiveReplayStore,
237 LiveReplayStoreError, LiveReplaySubscribeResult, LiveReplaySubscription, MergeKey,
238 NoopEventSink, NoopTurnActivitySink, ObservedProcess, ObservedProcessEvent, ObservedWorkItem,
239 OutputState, PROCESS_LEASE_SCHEMA_VERSION, ParkedSession, ProcessAwaitOutput,
240 ProcessCancelAbility, ProcessCancelAllRequest, ProcessCancelRequest, ProcessCancelSource,
241 ProcessCancelSummary, ProcessDefinitionSelector, ProcessDefinitionSummary, ProcessEvent,
242 ProcessEventAppendRequest, ProcessEventAppendResult, ProcessEventType, ProcessExecutionContext,
243 ProcessExternalRef, ProcessHandleDescriptor, ProcessHandleGrant, ProcessHandleSummary,
244 ProcessId, ProcessInput, ProcessLease, ProcessLeaseCompletion, ProcessLifecycleStatus,
245 ProcessListFilter, ProcessListMode, ProcessOpScope, ProcessProvenance, ProcessRecord,
246 ProcessRegistration, ProcessRegistry, ProcessRunHandle, ProcessRuntimeHost, ProcessScope,
247 ProcessScopeId, ProcessService, ProcessSessionDeleteReport, ProcessStartGrant,
248 ProcessStartOptions, ProcessStartRequest, ProcessStatus, ProcessStatusFilter,
249 ProcessTerminalSemantics, ProcessTerminalSpec, ProcessTerminalState, ProcessValueSelector,
250 ProcessWake, ProcessWakeDedupeKey, ProcessWakeDelivery, ProcessWakeSpec, ProcessWorkDriver,
251 ProcessWorkObserver, ProcessWorkPoke, ProcessWorkRunner, ProcessWorkSnapshot, PromptUsage,
252 ProtocolSessionExtension, ProtocolSessionExtensionHandle, ProtocolTurnExtension,
253 ProtocolTurnExtensionHandle, QueuedWorkPoke, QueuedWorkRunHandle, QueuedWorkRunOutcome,
254 QueuedWorkRunRequest, QueuedWorkRunner, Residency, RuntimeEnvironment,
255 RuntimeEnvironmentBuilder, RuntimeError, RuntimeErrorCode, RuntimeHandle, RuntimeHostConfig,
256 RuntimeObservation, ScopedEffectController, SessionCommand, SessionCommandReceipt,
257 SessionCursor, SessionCursorError, SessionObservation, SessionObservationEvent,
258 SessionObservationEventPayload, SessionObservationSubscription, SessionProcessEventKind,
259 SessionQueueEventKind, SessionResume, SessionRevision, SessionStoreCreateRequest,
260 SessionStoreFactory, SessionUsageReport, SlotPolicy, TerminationPolicy, TokenLedgerEntry,
261 TurnActivity, TurnActivityId, TurnActivitySink, TurnContext, TurnEvent, TurnInput, TurnIssue,
262 TurnOptions, UnavailableProcessService, UsageReportRow, UsageTotals, current_epoch_ms,
263 diff_token_ledger, diff_usage_reports, ensure_durable_effect_input, epoch_ms_from_system_time,
264 lashlang_process_event_types, system_time_from_epoch_ms,
265};
266#[allow(unused_imports)]
267pub(crate) use runtime::{
268 LlmAttachmentSpec, PreparedProcessEventAppend, ProcessEventSemantics, QUEUED_WORK_CLAIM_TTL_MS,
269 QueuedCheckpointWork, QueuedTurnWork, QueuedWorkBatch, QueuedWorkBatchDraft, QueuedWorkClaim,
270 QueuedWorkClaimBoundary, QueuedWorkCompletion, QueuedWorkItem, QueuedWorkPayload,
271 RuntimeReplay, RuntimeScope, RuntimeSubject, materialize_process_event_semantics,
272 prepare_process_event_append, prepare_process_registration, process_event_invocation,
273 process_event_payload_hash, process_wake_batch_draft, process_wake_delivery,
274 process_wake_input_from_event_payload, process_wake_turn_cause, process_wake_turn_text,
275 require_event_replay,
276};
277pub use runtime::{
281 LlmRequestSpec, ProcessCommand, ProcessEffectOutcome, ProcessEventSemanticsSpec,
282 RuntimeEffectCommand, RuntimeEffectController, RuntimeEffectControllerError,
283 RuntimeEffectEnvelope, RuntimeEffectKind, RuntimeEffectLocalExecutor, RuntimeEffectOutcome,
284 RuntimeInvocation, RuntimeSessionState,
285};
286pub use schemars::JsonSchema;
287pub use session::{
288 ExecRequest, InjectedTurnInput, RuntimeExecutionContext, Session, SessionError, ToolInvocation,
289 ToolInvocationReply,
290};
291pub use session_graph::{
292 PersistedSessionConfig, PersistedTurnState, SessionGraph, SessionMessageTreeNode,
293 SessionNodePayload, SessionNodeRecord,
294};
295pub use session_model::context::PreparedContext;
296pub use session_model::{ConversationRecord, ProtocolEvent, SessionEventRecord};
297pub use session_model::{RuntimeSessionPolicy, SessionPolicy, SessionSpec};
298pub use store::{
299 AttachmentIntent, AttachmentManifest, AttachmentManifestEntry, BlobRef, GcReport,
300 RuntimePersistence, SessionMeta, SessionPickerInfo, SessionReadScope, StoreError, VacuumReport,
301};
302#[allow(unused_imports)]
303pub(crate) use store::{
304 GraphCommitDelta, PersistedSessionRead, RuntimeCommitResult, SessionCheckpoint,
305 SessionHeadMeta, ensure_supported_schema_version, load_persisted_session_state,
306 load_persisted_session_state_active_path,
307};
308pub use store::{
309 HydratedSessionCheckpoint, RuntimeCommit, RuntimeTurnCommitStamp, SessionHead,
310 refresh_persisted_session_state,
311};
312pub use tool_provider::{
313 PreparedToolCall, ProgressSender, SandboxMessage, ToolCall, ToolContext, ToolHostEventControl,
314 ToolLashlangExecutionCallSite, ToolPrepareCall, ToolPrepareContext, ToolProvider,
315 ToolSessionControl, ToolSessionModel,
316};
317
318#[cfg(test)]
319mod tests {
320 use super::*;
321
322 #[test]
323 fn protocol_turn_options_missing_payload_deserializes_to_empty_object() {
324 let options: ProtocolTurnOptions =
325 serde_json::from_value(serde_json::json!({})).expect("deserialize options");
326
327 assert!(options.is_empty());
328 assert_eq!(options.payload, serde_json::json!({}));
329 }
330
331 #[test]
332 fn protocol_turn_options_explicit_null_is_not_empty() {
333 let options: ProtocolTurnOptions =
334 serde_json::from_value(serde_json::json!({ "payload": null }))
335 .expect("deserialize options");
336
337 assert!(!options.is_empty());
338 assert_eq!(options.payload, serde_json::Value::Null);
339 }
340
341 #[test]
342 fn root_exports_do_not_reintroduce_removed_session_state_shapes() {
343 let source = include_str!("lib.rs");
344 let removed_envelope = ["SessionState", "Envelope"].concat();
345 let removed_persisted = ["PersistedSession", "Snapshot"].concat();
346 let removed_history_rewriter = ["History", "Rewriter"].concat();
347 let removed_rewrite_trigger = ["Rewrite", "Trigger"].concat();
348 let removed_rewrite_context = ["Rewrite", "Context"].concat();
349 let removed_history_state = ["History", "State"].concat();
350 let removed_history_metadata = ["History", "Rewrite", "Metadata"].concat();
351
352 assert!(!source.contains(&removed_envelope));
353 assert!(!source.contains(&removed_persisted));
354 assert!(!source.contains(&removed_history_rewriter));
355 assert!(!source.contains(&removed_rewrite_trigger));
356 assert!(!source.contains(&removed_rewrite_context));
357 assert!(!source.contains(&removed_history_state));
358 assert!(!source.contains(&removed_history_metadata));
359 }
360
361 fn public_reexport_block(source: &str, module: &str) -> String {
362 let start = format!("pub use {module}::{{");
363 let mut block = String::new();
364 let mut collecting = false;
365 for line in source.lines() {
366 if line.trim_start().starts_with(&start) {
367 collecting = true;
368 }
369 if collecting {
370 block.push_str(line);
371 block.push('\n');
372 if line.trim_end() == "};" {
373 break;
374 }
375 }
376 }
377 assert!(!block.is_empty(), "missing public {module} re-export block");
378 block
379 }
380
381 #[test]
382 fn root_runtime_exports_exclude_internal_runtime_records() {
383 let runtime_exports = public_reexport_block(include_str!("lib.rs"), "runtime");
384 for removed in [
385 "RuntimeEffectCommand",
386 "RuntimeEffectEnvelope",
387 "RuntimeEffectKind",
388 "RuntimeEffectOutcome",
389 "RuntimeInvocation",
390 "RuntimeScope",
391 "RuntimeSessionState",
392 "QueuedWorkBatch",
393 "QueuedWorkBatchDraft",
394 "QueuedWorkPayload",
395 "prepare_process_registration",
396 "process_wake_batch_draft",
397 "require_event_replay",
398 ] {
399 assert!(
400 !runtime_exports.contains(removed),
401 "runtime root export leaked {removed}"
402 );
403 }
404 }
405
406 #[test]
407 fn root_store_exports_exclude_wire_records() {
408 let store_exports = public_reexport_block(include_str!("lib.rs"), "store");
409 for removed in [
410 "SessionHead",
411 "SessionCheckpoint",
412 "RuntimeCommit",
413 "HydratedSessionCheckpoint",
414 "PersistedSessionRead",
415 "GraphCommitDelta",
416 ] {
417 assert!(
418 !store_exports.contains(removed),
419 "store root export leaked {removed}"
420 );
421 }
422 }
423
424 #[test]
425 fn removed_manager_and_host_trait_names_stay_removed() {
426 let removed_manager = ["Runtime", "Session", "Manager"].concat();
427 let removed_host = ["Runtime", "Session", "Host"].concat();
428 let sources = [
429 include_str!("runtime/session_manager/mod.rs"),
430 include_str!("plugin/runtime_host.rs"),
431 include_str!("tool_dispatch/context.rs"),
432 include_str!("tool_provider.rs"),
433 ];
434
435 for source in sources {
436 assert!(!source.contains(&removed_manager));
437 assert!(!source.contains(&removed_host));
438 }
439 }
440}