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