Skip to main content

meerkat_runtime/handles/
model_routing.rs

1//! Runtime impl of [`meerkat_core::handles::ModelRoutingHandle`].
2
3use std::sync::Arc;
4
5use meerkat_core::handles::{DslTransitionError, ModelRoutingHandle};
6use meerkat_core::lifecycle::run_primitive::ModelId;
7use meerkat_core::model_profile::ModelProfile;
8use meerkat_core::{SessionLlmIdentity, ToolFilter};
9
10use super::HandleDslAuthority;
11use crate::meerkat_machine::dsl as mm_dsl;
12
13fn capability_surface_from_profile(profile: &ModelProfile) -> mm_dsl::SessionLlmCapabilitySurface {
14    mm_dsl::SessionLlmCapabilitySurface {
15        supports_temperature: profile.supports_temperature,
16        supports_thinking: profile.supports_thinking,
17        supports_reasoning: profile.supports_reasoning,
18        inline_video: profile.inline_video,
19        vision: profile.vision,
20        image_input: profile.image_input,
21        image_tool_results: profile.image_tool_results,
22        supports_web_search: profile.supports_web_search,
23        image_generation: profile.image_generation,
24        realtime: profile.realtime,
25        call_timeout_secs: profile.call_timeout_secs,
26    }
27}
28
29/// Runtime-backed [`ModelRoutingHandle`] impl.
30#[derive(Debug)]
31pub struct RuntimeModelRoutingHandle {
32    dsl: Arc<HandleDslAuthority>,
33}
34
35impl RuntimeModelRoutingHandle {
36    /// Construct a handle backed by the session's shared DSL authority.
37    pub fn new(dsl: Arc<HandleDslAuthority>) -> Self {
38        Self { dsl }
39    }
40
41    /// Construct a handle backed by an ephemeral DSL authority.
42    pub fn ephemeral() -> Self {
43        Self::new(Arc::new(HandleDslAuthority::ephemeral()))
44    }
45}
46
47impl ModelRoutingHandle for RuntimeModelRoutingHandle {
48    fn set_baseline(
49        &self,
50        baseline_model: ModelId,
51        realtime_capable: bool,
52    ) -> Result<(), DslTransitionError> {
53        // intra-machine: no route; dispatcher not applicable (handle targets the meerkat DSL directly, not a CompositionDispatcher seam)
54        self.dsl.apply_input(
55            mm_dsl::MeerkatMachineInput::SetModelRoutingBaseline {
56                baseline_model: baseline_model.to_string(),
57                realtime_capable,
58            },
59            "ModelRoutingHandle::set_baseline",
60        )
61    }
62
63    fn hydrate_llm_capability_surface(
64        &self,
65        identity: &SessionLlmIdentity,
66        profile: Option<&ModelProfile>,
67        capability_base_filter: &ToolFilter,
68    ) -> Result<(), DslTransitionError> {
69        let (current_capability_surface, current_capability_surface_status) = match profile {
70            Some(profile) => (
71                Some(capability_surface_from_profile(profile)),
72                mm_dsl::SessionLlmCapabilitySurfaceStatus::Resolved,
73            ),
74            None => (None, mm_dsl::SessionLlmCapabilitySurfaceStatus::Unresolved),
75        };
76        // intra-machine: no route; dispatcher not applicable (handle targets the meerkat DSL directly, not a CompositionDispatcher seam)
77        self.dsl.apply_input(
78            mm_dsl::MeerkatMachineInput::HydrateSessionLlmState {
79                current_identity: mm_dsl::SessionLlmIdentity::from_domain(identity),
80                current_capability_surface,
81                current_capability_surface_status,
82                current_capability_base_filter: mm_dsl::ToolFilter::from_domain(
83                    capability_base_filter,
84                ),
85            },
86            "ModelRoutingHandle::hydrate_llm_capability_surface",
87        )
88    }
89}