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