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