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