1#![cfg_attr(
18 test,
19 allow(
20 dead_code,
21 unused_imports,
22 clippy::expect_used,
23 clippy::large_futures,
24 clippy::needless_borrow,
25 clippy::panic,
26 clippy::redundant_closure_for_method_calls,
27 clippy::redundant_clone,
28 clippy::type_complexity,
29 clippy::unnecessary_to_owned,
30 clippy::unwrap_used
31 )
32)]
33
34#[cfg(target_arch = "wasm32")]
35pub mod tokio {
36 pub use tokio_with_wasm::alias::*;
37}
38
39#[cfg(not(target_arch = "wasm32"))]
40pub use ::tokio;
41
42pub mod accept;
43pub mod auth_machine;
44pub mod coalescing;
45pub mod comms_bridge;
46pub mod comms_drain;
47pub mod comms_trust_reconcile;
48pub mod completion;
49pub mod composition;
50pub(crate) mod control_plane;
51pub mod delivery_inbox;
52pub mod driver;
53pub(crate) mod effect;
54#[doc(hidden)]
55pub mod generated;
56pub mod handles;
57pub mod identifiers;
58pub mod ingress_types;
59pub mod input;
60pub mod input_ledger;
61pub mod input_scope;
62pub mod input_state;
63pub mod interrupt_public_result;
64pub mod meerkat_machine;
65pub(crate) mod meerkat_machine_types;
66pub mod member_live;
67pub mod member_observation;
68pub mod mob_adapter;
69pub mod mob_operator_authority;
70pub mod ops_lifecycle;
71pub mod peer_handling_mode;
72pub mod policy;
73pub mod policy_table;
74#[allow(unused_imports)]
75#[path = "generated/protocol_auth_lease_lifecycle_publication.rs"]
76pub mod protocol_auth_lease_lifecycle_publication;
77#[allow(unused_imports)]
78#[path = "generated/protocol_auth_release_oauth_flow_drain.rs"]
79pub mod protocol_auth_release_oauth_flow_drain;
80#[allow(unused_imports)]
81#[path = "generated/protocol_comms_trust_reconcile.rs"]
82pub mod protocol_comms_trust_reconcile;
83#[allow(unused_imports)]
84#[path = "generated/protocol_supervisor_trust_publish.rs"]
85pub mod protocol_supervisor_trust_publish;
86#[allow(unused_imports)]
87#[path = "generated/protocol_supervisor_trust_revoke.rs"]
88pub mod protocol_supervisor_trust_revoke;
89pub(crate) mod queue;
90pub mod runtime_event;
91pub(crate) mod runtime_loop;
92pub mod runtime_state;
93pub mod service_ext;
94pub(crate) mod silent_intent;
95pub mod store;
96pub mod terminal_status;
97pub mod traits;
98
99use meerkat_core::lifecycle::run_primitive::RuntimeTurnMetadata as RuntimeStampedTurnMetadata;
100use std::any::Any;
101use std::sync::Arc;
102
103pub(crate) struct SessionRuntimeBindingsAuthority {
104 pub(crate) session_id: meerkat_core::SessionId,
105 pub(crate) epoch_id: meerkat_core::RuntimeEpochId,
106 pub(crate) dsl_authority: Arc<std::sync::Mutex<meerkat_machine::dsl::MeerkatMachineAuthority>>,
107 pub(crate) teardown_gate: Arc<handles::HandleTeardownGate>,
108 pub(crate) materialization_claim_id: Option<uuid::Uuid>,
109 pub(crate) materialization_claim_state:
110 Arc<std::sync::Mutex<RuntimeActorMaterializationClaimState>>,
111 pub(crate) legacy_actor_materialization_generation: Option<u64>,
116 pub(crate) release_materialization_claim_on_drop: bool,
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq)]
120pub(crate) enum RuntimeActorMaterializationClaimPhase {
121 Vacant,
122 Prepared,
123 Staged,
124 ActorCreating,
125 ActorMaterializedPendingCommit,
126 RetainedActor,
127 Aborting,
128}
129
130pub(crate) struct RuntimeActorMaterializationClaimState {
131 pub(crate) current: Option<uuid::Uuid>,
132 pub(crate) phase: RuntimeActorMaterializationClaimPhase,
133 pub(crate) rollback_registration_available: bool,
139 pub(crate) legacy_capability_generation: u64,
143 pub(crate) changed: Arc<crate::tokio::sync::Notify>,
144}
145
146impl RuntimeActorMaterializationClaimState {
147 pub(crate) fn new(rollback_registration_available: bool) -> Self {
148 Self {
149 current: None,
150 phase: RuntimeActorMaterializationClaimPhase::Vacant,
151 rollback_registration_available,
152 legacy_capability_generation: 0,
153 changed: Arc::new(crate::tokio::sync::Notify::new()),
154 }
155 }
156
157 pub(crate) fn exact_claim_is(
158 &self,
159 claim_id: uuid::Uuid,
160 phases: &[RuntimeActorMaterializationClaimPhase],
161 ) -> bool {
162 self.current == Some(claim_id) && phases.contains(&self.phase)
163 }
164}
165
166impl Drop for SessionRuntimeBindingsAuthority {
167 fn drop(&mut self) {
168 if !self.release_materialization_claim_on_drop {
169 return;
170 }
171 let Some(claim_id) = self.materialization_claim_id else {
172 return;
173 };
174 let changed = {
175 let mut state = self
176 .materialization_claim_state
177 .lock()
178 .unwrap_or_else(std::sync::PoisonError::into_inner);
179 if !state.exact_claim_is(
180 claim_id,
181 &[
182 RuntimeActorMaterializationClaimPhase::Prepared,
183 RuntimeActorMaterializationClaimPhase::Staged,
184 ],
185 ) {
186 return;
187 }
188 state.current = None;
189 state.phase = RuntimeActorMaterializationClaimPhase::Vacant;
190 Arc::clone(&state.changed)
191 };
192 changed.notify_waiters();
193 }
194}
195
196#[allow(clippy::too_many_arguments)]
199pub(crate) fn session_runtime_bindings_authority(
200 session_id: meerkat_core::SessionId,
201 epoch_id: meerkat_core::RuntimeEpochId,
202 dsl_authority: Arc<std::sync::Mutex<meerkat_machine::dsl::MeerkatMachineAuthority>>,
203 teardown_gate: Arc<handles::HandleTeardownGate>,
204 materialization_claim_id: Option<uuid::Uuid>,
205 materialization_claim_state: Arc<std::sync::Mutex<RuntimeActorMaterializationClaimState>>,
206 legacy_actor_materialization_generation: Option<u64>,
207 release_materialization_claim_on_drop: bool,
208) -> Arc<dyn Any + Send + Sync> {
209 Arc::new(SessionRuntimeBindingsAuthority {
210 session_id,
211 epoch_id,
212 dsl_authority,
213 teardown_gate,
214 materialization_claim_id,
215 materialization_claim_state,
216 legacy_actor_materialization_generation,
217 release_materialization_claim_on_drop,
218 })
219}
220
221#[allow(clippy::too_many_arguments)]
222pub(crate) fn local_session_runtime_bindings_authority(
223 session_id: meerkat_core::SessionId,
224 epoch_id: meerkat_core::RuntimeEpochId,
225 dsl_authority: Arc<std::sync::Mutex<meerkat_machine::dsl::MeerkatMachineAuthority>>,
226 teardown_gate: Arc<handles::HandleTeardownGate>,
227 materialization_claim_id: Option<uuid::Uuid>,
228 materialization_claim_state: Arc<std::sync::Mutex<RuntimeActorMaterializationClaimState>>,
229 legacy_actor_materialization_generation: Option<u64>,
230 release_materialization_claim_on_drop: bool,
231) -> Arc<dyn Any + Send + Sync> {
232 session_runtime_bindings_authority(
233 session_id,
234 epoch_id,
235 dsl_authority,
236 teardown_gate,
237 materialization_claim_id,
238 materialization_claim_state,
239 legacy_actor_materialization_generation,
240 release_materialization_claim_on_drop,
241 )
242}
243
244pub fn session_runtime_bindings_have_machine_authority(
245 bindings: &meerkat_core::SessionRuntimeBindings,
246) -> bool {
247 bindings
248 .__runtime_authority()
249 .is::<SessionRuntimeBindingsAuthority>()
250}
251
252#[derive(Debug, thiserror::Error)]
253pub enum RuntimeActorMaterializationError {
254 #[error("invalid runtime binding materialization authority: {0}")]
255 InvalidAuthority(String),
256 #[error("runtime binding registration no longer admits actor materialization")]
257 RegistrationClosed,
258}
259
260pub struct RuntimeActorMaterializationPermit {
268 claim_id: uuid::Uuid,
269 claim_state: Arc<std::sync::Mutex<RuntimeActorMaterializationClaimState>>,
270 session_id: meerkat_core::SessionId,
271 epoch_id: meerkat_core::RuntimeEpochId,
272 dsl_authority: Arc<std::sync::Mutex<meerkat_machine::dsl::MeerkatMachineAuthority>>,
273 teardown_gate: Arc<handles::HandleTeardownGate>,
274 previous_phase: RuntimeActorMaterializationClaimPhase,
275 transactional: bool,
276 phase_policy: RuntimeActorMaterializationPhasePolicy,
277 _mutation_guard: Option<crate::tokio::sync::OwnedMutexGuard<()>>,
278 committed: bool,
279}
280
281#[derive(Debug, Clone, Copy, PartialEq, Eq)]
282enum RuntimeActorMaterializationPhasePolicy {
283 RejectRetired,
284 RequireArchivedRevivalBoundary,
285}
286
287impl RuntimeActorMaterializationPermit {
288 pub fn commit(mut self) -> Result<(), RuntimeActorMaterializationError> {
289 let generated_authority = self
290 .dsl_authority
291 .lock()
292 .unwrap_or_else(std::sync::PoisonError::into_inner);
293 validate_materialization_registration_authority(
294 &self.session_id,
295 &self.epoch_id,
296 &self.teardown_gate,
297 &generated_authority,
298 self.phase_policy,
299 )?;
300 let mut state = self
301 .claim_state
302 .lock()
303 .unwrap_or_else(std::sync::PoisonError::into_inner);
304 if !state.exact_claim_is(
305 self.claim_id,
306 &[RuntimeActorMaterializationClaimPhase::ActorCreating],
307 ) {
308 return Err(RuntimeActorMaterializationError::RegistrationClosed);
309 }
310 let changed = if self.transactional {
311 state.phase = RuntimeActorMaterializationClaimPhase::ActorMaterializedPendingCommit;
312 None
313 } else {
314 state.current = None;
315 state.phase = RuntimeActorMaterializationClaimPhase::RetainedActor;
316 state.rollback_registration_available = false;
317 Some(Arc::clone(&state.changed))
318 };
319 self.committed = true;
320 drop(state);
321 if let Some(changed) = changed {
322 changed.notify_waiters();
323 }
324 Ok(())
325 }
326}
327
328impl Drop for RuntimeActorMaterializationPermit {
329 fn drop(&mut self) {
330 if self.committed {
331 return;
332 }
333 let mut state = self
334 .claim_state
335 .lock()
336 .unwrap_or_else(std::sync::PoisonError::into_inner);
337 if state.exact_claim_is(
338 self.claim_id,
339 &[RuntimeActorMaterializationClaimPhase::ActorCreating],
340 ) {
341 if self.transactional {
342 state.phase = self.previous_phase;
343 } else {
344 state.current = None;
345 state.phase = RuntimeActorMaterializationClaimPhase::Vacant;
346 Arc::clone(&state.changed).notify_waiters();
347 }
348 }
349 }
350}
351
352fn validated_session_runtime_bindings_authority(
353 bindings: &meerkat_core::SessionRuntimeBindings,
354) -> Result<&SessionRuntimeBindingsAuthority, RuntimeActorMaterializationError> {
355 let authority = bindings
356 .__runtime_authority()
357 .downcast_ref::<SessionRuntimeBindingsAuthority>()
358 .ok_or_else(|| {
359 RuntimeActorMaterializationError::InvalidAuthority(
360 "session runtime bindings lack MeerkatMachine authority".to_string(),
361 )
362 })?;
363 if bindings.session_id() != &authority.session_id || bindings.epoch_id() != &authority.epoch_id
364 {
365 return Err(RuntimeActorMaterializationError::InvalidAuthority(
366 "session runtime binding identity does not match its machine authority".into(),
367 ));
368 }
369 Ok(authority)
370}
371
372fn validate_materialization_registration_authority(
373 session_id: &meerkat_core::SessionId,
374 epoch_id: &meerkat_core::RuntimeEpochId,
375 teardown_gate: &Arc<handles::HandleTeardownGate>,
376 generated_authority: &meerkat_machine::dsl::MeerkatMachineAuthority,
377 phase_policy: RuntimeActorMaterializationPhasePolicy,
378) -> Result<(), RuntimeActorMaterializationError> {
379 let state = generated_authority.state();
380 let expected_session_id = meerkat_machine::dsl::SessionId::from_domain(session_id);
381 let expected_epoch_id = meerkat_machine::dsl::RuntimeEpochId::from_domain(epoch_id);
382 let runtime_phase =
383 meerkat_machine::dsl_authority::runtime_phase_from_authority(generated_authority);
384 if !teardown_gate.is_open()
385 || state.session_id.as_ref() != Some(&expected_session_id)
386 || state.registration_phase == meerkat_machine::dsl::RegistrationPhase::Draining
387 || matches!(
388 runtime_phase,
389 crate::runtime_state::RuntimeState::Stopped
390 | crate::runtime_state::RuntimeState::Destroyed
391 )
392 || match phase_policy {
393 RuntimeActorMaterializationPhasePolicy::RejectRetired => {
394 runtime_phase == crate::runtime_state::RuntimeState::Retired
395 }
396 RuntimeActorMaterializationPhasePolicy::RequireArchivedRevivalBoundary => !matches!(
397 runtime_phase,
398 crate::runtime_state::RuntimeState::Retired
399 | crate::runtime_state::RuntimeState::Idle
400 ),
401 }
402 || state
403 .active_runtime_epoch_id
404 .as_ref()
405 .is_some_and(|epoch_id| epoch_id != &expected_epoch_id)
406 {
407 return Err(RuntimeActorMaterializationError::RegistrationClosed);
408 }
409 Ok(())
410}
411
412pub fn begin_session_runtime_actor_materialization(
415 bindings: &meerkat_core::SessionRuntimeBindings,
416) -> Result<RuntimeActorMaterializationPermit, RuntimeActorMaterializationError> {
417 begin_session_runtime_actor_materialization_with_phase_policy(
418 bindings,
419 RuntimeActorMaterializationPhasePolicy::RejectRetired,
420 None,
421 )
422}
423
424pub async fn begin_session_runtime_actor_materialization_for_archived_resume(
432 bindings: &meerkat_core::SessionRuntimeBindings,
433 authorization: crate::meerkat_machine::ArchivedSessionActorMaterializationAuthorization,
434) -> Result<RuntimeActorMaterializationPermit, RuntimeActorMaterializationError> {
435 authorization.begin(bindings).await
436}
437
438fn begin_session_runtime_actor_materialization_with_phase_policy(
439 bindings: &meerkat_core::SessionRuntimeBindings,
440 phase_policy: RuntimeActorMaterializationPhasePolicy,
441 mutation_guard: Option<crate::tokio::sync::OwnedMutexGuard<()>>,
442) -> Result<RuntimeActorMaterializationPermit, RuntimeActorMaterializationError> {
443 let authority = validated_session_runtime_bindings_authority(bindings)?;
444 let generated_authority = authority
445 .dsl_authority
446 .lock()
447 .unwrap_or_else(std::sync::PoisonError::into_inner);
448 validate_materialization_registration_authority(
449 &authority.session_id,
450 &authority.epoch_id,
451 &authority.teardown_gate,
452 &generated_authority,
453 phase_policy,
454 )?;
455 let (claim_id, previous_phase, transactional) = {
456 let mut state = authority
457 .materialization_claim_state
458 .lock()
459 .unwrap_or_else(std::sync::PoisonError::into_inner);
460 if let Some(claim_id) = authority.materialization_claim_id {
461 if !state.exact_claim_is(
462 claim_id,
463 &[
464 RuntimeActorMaterializationClaimPhase::Prepared,
465 RuntimeActorMaterializationClaimPhase::Staged,
466 ],
467 ) {
468 return Err(RuntimeActorMaterializationError::RegistrationClosed);
469 }
470 let previous = state.phase;
471 state.phase = RuntimeActorMaterializationClaimPhase::ActorCreating;
472 (claim_id, previous, true)
473 } else if authority.legacy_actor_materialization_generation
474 == Some(state.legacy_capability_generation)
475 && state.current.is_none()
476 && state.phase == RuntimeActorMaterializationClaimPhase::Vacant
477 {
478 let claim_id = uuid::Uuid::new_v4();
479 state.current = Some(claim_id);
480 state.phase = RuntimeActorMaterializationClaimPhase::ActorCreating;
481 (
482 claim_id,
483 RuntimeActorMaterializationClaimPhase::Vacant,
484 false,
485 )
486 } else {
487 return Err(RuntimeActorMaterializationError::RegistrationClosed);
488 }
489 };
490 drop(generated_authority);
491 Ok(RuntimeActorMaterializationPermit {
492 claim_id,
493 claim_state: Arc::clone(&authority.materialization_claim_state),
494 session_id: authority.session_id.clone(),
495 epoch_id: authority.epoch_id.clone(),
496 dsl_authority: Arc::clone(&authority.dsl_authority),
497 teardown_gate: Arc::clone(&authority.teardown_gate),
498 previous_phase,
499 transactional,
500 phase_policy,
501 _mutation_guard: mutation_guard,
502 committed: false,
503 })
504}
505
506pub use accept::{AcceptOutcome, RejectReason};
508pub use coalescing::{
509 AggregateDescriptor, CoalescingResult, SupersessionScope, check_supersession,
510 create_aggregate_input, is_coalescing_eligible,
511};
512pub use completion::{
513 CompletionCleanupObservation, CompletionHandle, CompletionOutcome, CompletionWaitError,
514};
515pub use delivery_inbox::{
516 RuntimeDeliveryError, RuntimeDeliveryId, RuntimeDeliveryInbox, RuntimeDeliveryKind,
517 RuntimeDeliveryReceipt, RuntimeDeliveryRecord, RuntimeDeliverySubmission,
518};
519pub use driver::{EphemeralRuntimeDriver, PersistentRuntimeDriver, PostAdmissionSignal};
520pub use handles::{
521 HandleDslAuthority, RuntimeAuthLeaseHandle, RuntimeCommsDrainHandle,
522 RuntimeExternalToolSurfaceHandle, RuntimeInteractionStreamHandle,
523 RuntimeMcpServerLifecycleHandle, RuntimeModelRoutingHandle, RuntimePeerCommsHandle,
524 RuntimePeerInteractionHandle, RuntimeSessionAdmissionHandle, RuntimeSessionContextHandle,
525 RuntimeTurnStateHandle,
526};
527pub use identifiers::{
528 CausationId, ConversationId, CorrelationId, EventCodeId, IdempotencyKey, InputKind, KindId,
529 LogicalRuntimeId, PolicyVersion, ProjectionRuleId, RuntimeEventId, SchemaId, SupersessionKey,
530};
531pub use ingress_types::{ContentShape, RequestId, ReservationKey};
532pub use input::{
533 ContinuationInput, ContinuationKind, ExternalEventInput, FlowStepInput, Input, InputDurability,
534 InputHeader, InputOrigin, InputVisibility, OperationInput, PeerConvention, PeerInput,
535 PromptInput, ResponseProgressPhase, ResponseTerminalStatus, peer_response_terminal_input,
536 response_terminal_status_from_wire,
537};
538pub use input_ledger::InputLedger;
539pub use input_scope::InputScope;
540pub use input_state::{
541 InputAbandonReason, InputLifecycleState, InputState, InputStateEvent, InputStateHistoryEntry,
542 InputTerminalOutcome, PolicySnapshot, ReconstructionSource,
543};
544pub use meerkat_core::types::HandlingMode;
545pub use meerkat_machine::{
546 ArchivedSessionActorMaterializationAuthorization,
547 CommittedRuntimeExecutorAttachmentPublicationLease, CommsDrainMode, CommsDrainPhase,
548 DrainExitReason, EnsureRuntimeExecutorAttachment, LocalSessionMaterializationMode,
549 MachineServiceTurnCommitLease, MachineServiceTurnIdentity, MachineSessionArchiveLease,
550 MachineSessionControlAuthority, MeerkatConsumerSurface, MeerkatMachine, PeerIngressOwner,
551 PendingRuntimeExecutorAttachment, PreparedArchivedResumeCommitLease,
552 PreparedAttachedSessionActorRecovery, PreparedRuntimeExecutorAttachmentRetirement,
553 PreparedSessionMaterialization, PromotedArchivedResumeCommitLease, RuntimeBindingsError,
554 RuntimeCleanupTaskSpawner, RuntimeExecutorAttachmentRetirementCompletion,
555 RuntimeExecutorAttachmentWitness, RuntimeLifecycleFacts, RuntimeLoopQueueAdmissionPlan,
556 RuntimeSessionLifecycleObservation, RuntimeSessionRegistrationOutcome,
557 RuntimeSessionRegistrationWitness, StandaloneSessionRuntimeAuthorities,
558 classify_runtime_lifecycle_state, classify_runtime_loop_queue_admission,
559 standalone_session_runtime_authorities, standalone_tool_visibility_owner,
560};
561pub use meerkat_machine_types::{
562 HydratedSessionLlmState, ImageOperationRoutingRequest, ImageOperationRoutingResult,
563 ModelRoutingApprovalDisposition, ModelRoutingRealtimePolicy, ResolvedSessionLlmReconfigure,
564 SessionLlmCapabilitySurface, SessionLlmCapabilitySurfaceStatus, SessionLlmReconfigureHost,
565 SessionLlmReconfigureReport, SessionLlmReconfigureRequest, SessionToolVisibilityDelta,
566};
567#[doc(hidden)]
568pub use meerkat_machine_types::{
569 MeerkatAdmittedInputSnapshot, MeerkatArchiveSnapshot, MeerkatBindingSnapshot,
570 MeerkatCompletionWaiterSnapshot, MeerkatCompletionWaitersSnapshot, MeerkatControlSnapshot,
571 MeerkatCursorSnapshot, MeerkatDrainSnapshot, MeerkatDriverKind, MeerkatInputsSnapshot,
572 MeerkatMachineCatalogInput, MeerkatMachineCommandClassification,
573 MeerkatMachineCommandClassificationRecord, MeerkatMachineCommandVariant,
574 MeerkatMachineFieldlessRuntimeInternalInput, MeerkatMachineRuntimeInternalClassificationRecord,
575 MeerkatMachineRuntimeInternalInput, MeerkatMachineRuntimeInternalReason,
576 MeerkatMachineShellMechanicReason, MeerkatMachineSpineSnapshot, MeerkatOpsSnapshot,
577 OffDrainResponder, SupervisorBridgeCommandAdmissionRoute,
578 SupervisorBridgeCommandClassificationRecord, SupervisorBridgeCommandKind,
579 SupervisorBridgeCommandRealization, canonical_meerkat_machine_command_classifications,
580 canonical_meerkat_machine_command_input_variant_manifest,
581 canonical_meerkat_machine_command_manifest,
582 canonical_meerkat_machine_runtime_internal_classifications,
583 canonical_meerkat_machine_runtime_internal_fieldless_input_variant_manifest,
584 canonical_meerkat_machine_runtime_internal_input_variant_manifest,
585 canonical_meerkat_machine_runtime_internal_manifest,
586 canonical_supervisor_bridge_command_classifications,
587};
588pub use ops_lifecycle::{
589 OpsLifecycleConfig, OpsLifecyclePersistenceRequest, PersistedOpsSnapshot,
590 RuntimeOpsLifecycleRegistry,
591};
592
593#[cfg(all(not(target_arch = "wasm32"), any(test, feature = "test-support")))]
594#[doc(hidden)]
595pub fn test_peer_comms_handle() -> Arc<dyn meerkat_core::handles::PeerCommsHandle> {
596 test_peer_comms_handle_with_silent(std::iter::empty::<String>())
597}
598
599#[cfg(all(not(target_arch = "wasm32"), any(test, feature = "test-support")))]
600#[doc(hidden)]
601#[allow(clippy::expect_used)]
602pub fn test_peer_comms_handle_with_silent<I, S>(
603 silent_intents: I,
604) -> Arc<dyn meerkat_core::handles::PeerCommsHandle>
605where
606 I: IntoIterator<Item = S>,
607 S: Into<String>,
608{
609 let silent_intents = silent_intents
610 .into_iter()
611 .map(Into::into)
612 .collect::<Vec<_>>();
613 std::thread::spawn(move || {
614 let runtime = tokio::runtime::Builder::new_current_thread()
615 .enable_all()
616 .build()
617 .expect("test peer-comms runtime should build");
618 runtime.block_on(async move {
619 let machine = MeerkatMachine::ephemeral();
620 let session_id = meerkat_core::SessionId::new();
621 let bindings = machine
622 .prepare_bindings(session_id.clone())
623 .await
624 .expect("generated MeerkatMachine should prepare test peer-comms bindings");
625 if !silent_intents.is_empty() {
626 machine
627 .set_session_silent_intents(&session_id, silent_intents)
628 .await
629 .expect("set silent intents");
630 }
631 Arc::clone(bindings.peer_comms())
632 })
633 })
634 .join()
635 .expect("test peer-comms authority thread should finish")
636}
637
638#[cfg(all(not(target_arch = "wasm32"), any(test, feature = "test-support")))]
639#[doc(hidden)]
640#[allow(clippy::expect_used)]
641pub fn test_peer_input_candidate_from_interaction(
642 interaction: meerkat_core::interaction::InboxInteraction,
643 peer_id: meerkat_core::comms::PeerId,
644) -> meerkat_core::interaction::PeerInputCandidate {
645 use meerkat_core::interaction::{
646 InteractionContent, InteractionId, PeerIngressEnvelopeFacts, PeerIngressEnvelopeKind,
647 PeerIngressFact, PeerIngressIdentity,
648 };
649
650 let handle = test_peer_comms_handle();
651 let facts = PeerIngressEnvelopeFacts {
652 item_id: interaction.id.to_string(),
653 from_peer: interaction.from.clone(),
654 from_peer_id: peer_id,
655 kind: match &interaction.content {
656 InteractionContent::Message { body, .. }
657 | InteractionContent::IncarnationFencedMessage { body, .. } => {
658 PeerIngressEnvelopeKind::Message { body: body.clone() }
659 }
660 InteractionContent::Request { intent, params, .. } => {
661 PeerIngressEnvelopeKind::Request {
662 intent: intent.clone(),
663 params: params.clone(),
664 }
665 }
666 InteractionContent::Response {
667 in_reply_to,
668 status,
669 result,
670 ..
671 } => PeerIngressEnvelopeKind::Response {
672 in_reply_to: in_reply_to.to_string(),
673 status: *status,
674 result: result.clone(),
675 },
676 },
677 };
678 let admission = handle
679 .classify_external_envelope(facts)
680 .expect("generated peer-comms authority should classify test interaction");
681 let canonical_from_peer_id = admission
684 .from_peer_id
685 .expect("generated envelope classification should echo the canonical sender peer id");
686 let classification = admission.classification;
687 let convention = match &interaction.content {
688 InteractionContent::Message { .. }
689 | InteractionContent::IncarnationFencedMessage { .. } => {
690 meerkat_core::PeerIngressConvention::Message
691 }
692 InteractionContent::Request { intent, .. } => {
693 if let Some(kind) = classification.lifecycle_kind {
694 let peer = admission
695 .lifecycle_peer
696 .clone()
697 .expect("generated lifecycle classification should include a peer subject");
698 meerkat_core::PeerIngressConvention::Lifecycle { kind, peer }
699 } else {
700 let request_id = admission
701 .request_id
702 .clone()
703 .expect("generated request classification should include request id");
704 meerkat_core::PeerIngressConvention::Request {
705 request_id,
706 intent: intent.clone(),
707 }
708 }
709 }
710 InteractionContent::Response { status, .. } => {
711 let in_reply_to = admission
712 .request_id
713 .as_deref()
714 .and_then(|id| uuid::Uuid::parse_str(id).ok())
715 .map(InteractionId)
716 .expect("generated response classification should include in-reply-to id");
717 meerkat_core::PeerIngressConvention::Response {
718 in_reply_to,
719 status: *status,
720 }
721 }
722 };
723 let ingress = PeerIngressFact::peer(
724 interaction.id,
725 classification.class,
726 classification.kind,
727 Some(classification.auth),
728 PeerIngressIdentity::new(canonical_from_peer_id, interaction.from.clone(), convention),
729 );
730 let mut candidate = meerkat_core::interaction::PeerInputCandidate::new(
731 interaction,
732 ingress,
733 admission.lifecycle_peer,
734 );
735 candidate.response_terminality = classification.response_terminality;
736 candidate
737}
738
739pub fn runtime_stamped_prompt_turn_metadata(
746 metadata: Option<RuntimeStampedTurnMetadata>,
747) -> RuntimeStampedTurnMetadata {
748 let input = Input::Prompt(PromptInput::from_content_input(
749 meerkat_core::ContentInput::Text(String::new()),
750 metadata,
751 ));
752 let semantics = runtime_prompt_semantics_from_machine(&input);
753 runtime_loop::for_input(&input, semantics)
754}
755
756#[allow(clippy::expect_used)]
757fn runtime_prompt_semantics_from_machine(input: &Input) -> ingress_types::RuntimeInputSemantics {
758 let mut authority = meerkat_machine::dsl_authority::new_initialized_authority(
759 "generated runtime prompt machine authority must initialize",
760 );
761 let transition = meerkat_machine::dsl::MeerkatMachineMutator::apply(
762 &mut authority,
763 meerkat_machine::dsl::MeerkatMachineInput::ResolveAdmissionPlan {
764 input_id: input.id().to_string(),
765 input_kind: meerkat_machine::dsl::AdmissionInputKind::from(input.kind()),
766 requested_lane: input
767 .handling_mode()
768 .map(meerkat_machine::dsl::InputLane::from),
769 continuation_kind: meerkat_machine::dsl::AdmissionContinuationKind::from(
770 input.continuation_kind(),
771 ),
772 silent_intent_match: false,
773 existing_superseded_input_id: None,
774 runtime_running: false,
775 active_turn_boundary_available: false,
776 without_wake: false,
777 },
778 )
779 .expect("generated admission authority must accept runtime prompt metadata");
780
781 transition
782 .into_effects()
783 .into_iter()
784 .find_map(|effect| match effect {
785 meerkat_machine::dsl::MeerkatMachineEffect::AdmissionResolved {
786 runtime_boundary,
787 runtime_execution_kind,
788 runtime_peer_response_terminal_apply_intent,
789 live_interrupt_required,
790 ..
791 } => Some(ingress_types::RuntimeInputSemantics {
792 boundary: runtime_boundary.into(),
793 execution_kind: runtime_execution_kind.into(),
794 execution_handling_mode: None,
795 peer_response_terminal_apply_intent: runtime_peer_response_terminal_apply_intent
796 .map(Into::into),
797 live_interrupt_required,
798 }),
799 _ => None,
800 })
801 .expect("generated admission authority must emit prompt runtime semantics")
802}
803
804#[cfg(test)]
805mod runtime_prompt_metadata_tests {
806 #[test]
807 fn runtime_stamped_prompt_turn_metadata_uses_generated_prompt_semantics() {
808 let metadata = super::runtime_stamped_prompt_turn_metadata(None);
809 assert_eq!(
810 metadata.execution_kind,
811 Some(meerkat_core::lifecycle::RuntimeExecutionKind::ContentTurn)
812 );
813 assert!(metadata.peer_response_terminal_apply_intent.is_none());
814 }
815}
816
817#[doc(hidden)]
818pub mod machine_schema_exports {
819 pub fn meerkat_machine_schema() -> meerkat_machine_schema::MachineSchema {
820 meerkat_machine_schema::catalog::dsl::meerkat_machine_schema_metadata()
821 .attach_to(crate::meerkat_machine::dsl::MeerkatMachineState::schema())
822 }
823
824 pub fn auth_machine_schema() -> meerkat_machine_schema::MachineSchema {
825 meerkat_machine_schema::catalog::dsl::auth_machine_schema_metadata()
826 .attach_to(crate::auth_machine::dsl::AuthMachineState::schema())
827 }
828}
829pub use interrupt_public_result::{
830 UserInterruptObservation, UserInterruptPublicResult, resolve_user_interrupt_public_result,
831};
832pub use peer_handling_mode::{PeerHandlingModeError, validate_peer_handling_mode};
833pub use policy::{
834 ApplyMode, ConsumePoint, DrainPolicy, PolicyDecision, QueueMode, RoutingDisposition, WakeMode,
835};
836pub use policy_table::{DefaultPolicyTable, generated_default_policy_version};
837pub use runtime_event::{
838 InputLifecycleEvent, RunLifecycleEvent, RuntimeEvent, RuntimeEventEnvelope,
839 RuntimeProjectionEvent, RuntimeStateChangeEvent, RuntimeTopologyEvent,
840};
841pub use runtime_state::{RuntimeState, RuntimeStateTransitionError};
842pub use service_ext::SessionServiceRuntimeExt;
843#[cfg(feature = "sqlite-store")]
844pub use store::SqliteRuntimeStore;
845pub use store::{
846 InMemoryRuntimeStore, InputStateRow, RuntimeDeliveryAuthorityCasOutcome,
847 RuntimeDeliveryAuthorityRecord, RuntimeDeliveryStoreRecord, RuntimeStore, RuntimeStoreError,
848 RuntimeStoreWriteFence, RuntimeStoreWriteFenceOutcome, SessionDelta,
849};
850pub use traits::{
851 DestroyReport, RecoveryReport, RecycleReport, ResetReport, RetireReport, RuntimeControlPlane,
852 RuntimeControlPlaneError, RuntimeDriver, RuntimeDriverError,
853};