1pub mod attachments;
2pub mod chronological;
3pub mod direct;
4pub mod lashlang_bridge;
5pub mod llm;
6mod model;
7pub mod plugin;
8mod plugin_stack;
9mod protocol_build;
10pub mod provider;
11pub mod runtime;
12pub mod search;
13pub mod session;
14pub mod session_graph;
15pub mod session_model;
16mod stable_hash;
17pub mod store;
18#[cfg(any(test, feature = "testing"))]
19pub mod testing;
20pub mod tool_dispatch;
21mod tool_provider;
22pub mod tool_registry;
23mod tool_result;
24mod trace;
25pub mod triggers;
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 lash_sansio::llm::types::{
49 GenerationOptions, LlmOutputPart, LlmRequest, LlmResponse, LlmTerminalReason,
50};
51pub use lash_sansio::{
52 AcceptedInjectedTurnInput, AttachmentCreateMeta, AttachmentId, AttachmentMeta, AttachmentRef,
53 BaseRenderCache, CheckpointDelivery, CheckpointKind, CompactToolContract, EffectId,
54 ErrorEnvelope, ExecImage, ExecResponse, ImageMediaType, LashSchema, LashlangToolBinding,
55 LlmCallError, MediaType, Message, MessageOrigin, MessageRole, MessageSequence, ModelToolReturn,
56 ModelToolReturnPart, Part, PartKind, PluginMessage, PluginRuntimeEvent, PreparedPrompt,
57 PromptBuildInput, PromptBuiltin, PromptContext, PromptContribution, PromptContributionGate,
58 PromptContributionSet, PromptFingerprint, PromptLayer, PromptSlot, PromptSlotLayer,
59 PromptTemplate, PromptTemplateEntry, PromptTemplateSection, PruneState, RenderedPrompt,
60 ResolvedLashlangToolBinding, ResolvedPromptLayer, Response, SchemaProjectionOverride,
61 SessionEvent, TextProjectionMetadata, TokenUsage, ToolActivation, ToolArgumentProjectionPolicy,
62 ToolAvailability, ToolAvailabilityConfig, ToolCallOutcome, ToolCallOutput, ToolCallRecord,
63 ToolCallStatus, ToolCancellation, ToolCatalog, ToolCatalogBuildInput, ToolCatalogEntry,
64 ToolCatalogOverride, ToolContract, ToolControl, ToolDefinition, ToolFailure, ToolFailureClass,
65 ToolFailureSource, ToolId, ToolManifest, ToolOutputContract, ToolRetryDisposition,
66 ToolRetryPolicy, ToolScheduling, ToolValue, TurnCause, TurnFinish, TurnLimitFinalMessage,
67 TurnOutcome, TurnStop, append_assistant_text_part, build_prompt, build_tool_catalog,
68 build_turn, default_prompt_template, head_tail_truncate, messages_are_prompt_resume_safe,
69 normalized_response_parts, prompt_template_fingerprint, prompt_text_fingerprint,
70 prompt_tool_names_fingerprint, reasoning_part, render_turn_causes_prompt,
71 resolve_prompt_layers, shared_parts, validate_tool_input,
72};
73pub use lashlang::{DurabilityTier, InMemoryLashlangArtifactStore, LashlangArtifactStore};
74pub use protocol_build::ProtocolBuildInput;
75pub use tool_registry::{
76 ReconfigureError, ToolRegistry, ToolRestoreReport, ToolSourceHandle, ToolState, ToolStateEntry,
77};
78pub use tool_result::{CancelHint, PendingCompletion, TimeoutBehavior, ToolResult};
79pub use triggers::{
80 InMemoryTriggerStore, TriggerDeliveryReservation, TriggerEmitReport, TriggerEvent,
81 TriggerEventCatalog, TriggerEventKey, TriggerEventType, TriggerOccurrenceRecord,
82 TriggerOccurrenceRequest, TriggerRegistration, TriggerRouter, TriggerStore,
83 TriggerSubscriptionDraft, TriggerSubscriptionFilter, TriggerSubscriptionRecord,
84 TriggerTargetSummary, default_trigger_source_key, deterministic_delivery_process_id,
85 deterministic_occurrence_id, empty_trigger_source_key, trigger_event_type,
86 trigger_occurrence_request_hash, validate_payload, validate_trigger_occurrence_request,
87};
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, OpenAgentFrameRequest,
203 OpenAgentFrameResult, PersistentRuntimeServices, PluginAction, PluginActionContext,
204 PluginActionDef, PluginActionFailure, PluginActionInvokeError, PluginActionKind,
205 PluginDirective, PluginError, PluginFactory, PluginHost, PluginLifecycleEvent,
206 PluginLifecycleEventHook, PluginOptions, PluginOwned, PluginRegistrar, PluginSession,
207 PluginSessionContext, PluginSessionSnapshot, PluginSnapshotArtifact, PluginSnapshotEntry,
208 PluginSnapshotMeta, PluginSpec, PluginSpecFactory, PromptHookContext,
209 ProtocolBeforeLlmCallContext, ProtocolLlmCallAction, RuntimeServices, SessionAppendNode,
210 SessionConfigChangedContext, SessionContextOverlay, SessionCreateRequest, SessionGraphService,
211 SessionHandle, SessionLifecycleService, SessionParam, SessionPlugin, SessionPluginSource,
212 SessionReadView, SessionRelation, SessionSnapshot, SessionStartPoint,
213 SessionStateChangedContext, SessionStateService, SessionToolAccess, SessionTurnInput,
214 SessionTurnRequest, SnapshotReader, SnapshotWriter, SubagentSessionContext,
215 ToolCatalogContribution, ToolDiscoveryContext, ToolDiscoveryContribution,
216 ToolDiscoveryContributor, ToolDiscoveryToolContribution, ToolResultProjectionContext,
217 ToolResultProjector, TriggerEventRegistrations, TurnContextTransform, TurnHookContext,
218 TurnResultHookContext, 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, AwaitEventKey, AwaitEventWaitIdentity,
231 CausalRef, CodeOutputRecord, DefaultProcessCancelAbility, DeliveryPolicy,
232 DirectCompletionClient, DurableProcessWorker, DurableProcessWorkerConfig, DurableStoreFacet,
233 EffectHost, EmbeddedRuntimeBuilder, EmbeddedRuntimeHost, EventSink, ExecutionScope,
234 ExecutionSummary, ExternalCompletionError, InMemoryLiveReplayStore,
235 InMemoryLiveReplayStoreConfig, InMemorySessionStore, InMemorySessionStoreFactory,
236 InlineEffectHost, InlineProcessRunHandle, InlineRuntimeEffectController, InputItem,
237 LashRuntime, LiveReplayGap, LiveReplayGapReason, LiveReplayResult, LiveReplayStore,
238 LiveReplayStoreError, LiveReplaySubscribeResult, LiveReplaySubscription, MergeKey,
239 NoopEventSink, NoopTurnActivitySink, ObservedProcess, ObservedProcessEvent, ObservedWorkItem,
240 OutputState, PROCESS_LEASE_SCHEMA_VERSION, ParkedSession, ProcessAwaitOutput,
241 ProcessCancelAbility, ProcessCancelAllRequest, ProcessCancelRequest, ProcessCancelSource,
242 ProcessCancelSummary, ProcessEvent, ProcessEventAppendRequest, ProcessEventAppendResult,
243 ProcessEventType, ProcessExecutionContext, ProcessExecutionEnvRef, ProcessExecutionEnvSpec,
244 ProcessExternalRef, ProcessHandleDescriptor, ProcessHandleGrant, ProcessHandleSummary,
245 ProcessId, ProcessInput, ProcessLease, ProcessLeaseCompletion, ProcessLifecycleStatus,
246 ProcessListFilter, ProcessListMode, ProcessOpScope, ProcessOriginator, ProcessProvenance,
247 ProcessRecord, ProcessRegistration, ProcessRegistry, ProcessRunHandle, ProcessRuntimeHost,
248 ProcessService, ProcessSessionDeleteReport, ProcessSpawnProvenance, ProcessStartGrant,
249 ProcessStartOptions, ProcessStartRequest, ProcessStatus, ProcessStatusFilter,
250 ProcessTerminalSemantics, ProcessTerminalSpec, ProcessTerminalState, ProcessValueSelector,
251 ProcessWake, ProcessWakeDedupeKey, ProcessWakeDelivery, ProcessWakeSpec, ProcessWorkDriver,
252 ProcessWorkObserver, ProcessWorkPoke, ProcessWorkRunner, ProcessWorkSnapshot, PromptUsage,
253 ProtocolSessionExtension, ProtocolSessionExtensionHandle, ProtocolTurnExtension,
254 ProtocolTurnExtensionHandle, QueuedWorkPoke, QueuedWorkRunHandle, QueuedWorkRunOutcome,
255 QueuedWorkRunRequest, QueuedWorkRunner, Residency, Resolution, ResolveOutcome,
256 RuntimeEnvironment, RuntimeEnvironmentBuilder, RuntimeError, RuntimeErrorCode, RuntimeHandle,
257 RuntimeHostConfig, RuntimeObservation, ScopedEffectController, SessionCommand,
258 SessionCommandReceipt, SessionCursor, SessionCursorError, SessionObservation,
259 SessionObservationEvent, SessionObservationEventPayload, SessionObservationSubscription,
260 SessionProcessEventKind, SessionQueueEventKind, SessionResume, SessionRevision, SessionScope,
261 SessionScopeId, SessionStoreCreateRequest, SessionStoreFactory, SessionUsageReport, SlotPolicy,
262 TerminationPolicy, TokenLedgerEntry, ToolCallLaunch, TurnActivity, TurnActivityId,
263 TurnActivitySink, TurnContext, TurnEvent, TurnInput, TurnIssue, TurnOptions,
264 UnavailableProcessService, UsageReportRow, UsageTotals, WaitKind, WaitState, current_epoch_ms,
265 diff_token_ledger, 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, ToolDurableEffects,
319 ToolLashlangExecutionCallSite, ToolPrepareCall, ToolPrepareContext, ToolProvider,
320 ToolSessionAdmin, ToolSessionModel, ToolTriggerClient,
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}