Skip to main content

cookie_agent_engine/
delegation_events.rs

1//! Durable delegation state projected from parent-session events.
2
3use std::{
4    collections::HashMap,
5    sync::{Arc, Mutex},
6};
7
8use cookie_agent_protocol::{
9    AgentRevision, AgentSnapshot, CatalogRevision, DelegateRequestPayload, DelegationReservation,
10    EventPayload, FrozenCacheStrategy, FrozenModelBinding, InvocationId, ModelRevision,
11    ModelSnapshotRevision, ProviderStateRevision, RecipeRegistryRevision, RunId, RuntimeRevision,
12    SessionId, SessionStatus, Sha256Digest, ToolCallId,
13};
14use sha2::{Digest as _, Sha256};
15use thiserror::Error;
16
17use crate::session::{SessionError, SessionStore};
18
19pub(crate) fn delegation_request_fingerprint(
20    child_agent: &AgentSnapshot,
21    selected_suffix: &[FrozenModelBinding],
22    cache_strategies: &[Option<FrozenCacheStrategy>],
23    request: &DelegateRequestPayload,
24) -> Result<Sha256Digest, ()> {
25    let payload = if cache_strategies.is_empty() {
26        serde_json::to_vec(&(
27            &child_agent.agent,
28            &request.description,
29            &request.prompt,
30            &request.title,
31            &request.resume_session_id,
32            request.inherit_context,
33            request.background,
34            &request.seeded_context,
35            child_agent,
36            selected_suffix,
37            &request.staged_skill,
38        ))
39    } else {
40        serde_json::to_vec(&(
41            &child_agent.agent,
42            &request.description,
43            &request.prompt,
44            &request.title,
45            &request.resume_session_id,
46            request.inherit_context,
47            request.background,
48            &request.seeded_context,
49            child_agent,
50            selected_suffix,
51            cache_strategies,
52            &request.staged_skill,
53        ))
54    }
55    .map_err(|_| ())?;
56    Sha256Digest::new(format!("{:x}", Sha256::digest(payload))).map_err(|_| ())
57}
58
59#[derive(Clone, Debug, Eq, PartialEq)]
60pub struct DelegationRuntimeRevisions {
61    pub manifest_revision: ModelSnapshotRevision,
62    pub runtime_revision: RuntimeRevision,
63    pub catalog_revision: CatalogRevision,
64    pub provider_state_revision: ProviderStateRevision,
65    pub model_revision: ModelRevision,
66    pub agent_revision: AgentRevision,
67    pub recipe_registry_revision: RecipeRegistryRevision,
68}
69
70#[derive(Clone, Debug, PartialEq)]
71pub struct DelegationEntry {
72    pub reservation: DelegationReservation,
73    pub child_agent: AgentSnapshot,
74    pub revisions: DelegationRuntimeRevisions,
75    pub selected_suffix: Vec<FrozenModelBinding>,
76    pub cache_strategies: Vec<Option<FrozenCacheStrategy>>,
77    pub request_fingerprint: Sha256Digest,
78    pub request: DelegateRequestPayload,
79    pub started: bool,
80    pub child_run_id: Option<RunId>,
81    pub run_attached: bool,
82    pub terminal_status: Option<SessionStatus>,
83    pub terminal_reason: Option<cookie_agent_protocol::SafeErrorMessage>,
84}
85
86#[derive(Debug, Error)]
87pub enum DelegationEventError {
88    #[error(transparent)]
89    Session(#[from] SessionError),
90    #[error("delegation event corruption for invocation {0}")]
91    Corrupt(InvocationId),
92}
93
94#[derive(Debug, Default)]
95struct DelegationState {
96    entries: HashMap<InvocationId, DelegationEntry>,
97    order: Vec<InvocationId>,
98}
99
100#[derive(Debug)]
101pub struct DelegationEventStore {
102    sessions: Arc<SessionStore>,
103    state: Mutex<DelegationState>,
104}
105
106impl DelegationEventStore {
107    /// Folds delegation records from **root logs only**. Depth-1 records live in
108    /// the parent's log, so roots are complete at startup; nested records arrive
109    /// later through [`Self::extend_from_payloads`] when their tree is loaded.
110    pub fn open(sessions: Arc<SessionStore>) -> Result<Arc<Self>, DelegationEventError> {
111        let mut state = DelegationState::default();
112        let mut parents = sessions.root_snapshots();
113        parents.sort_by_key(|session| session.meta.session_id);
114        for parent in parents {
115            for envelope in parent.log.event_snapshot().iter() {
116                if parent.log.delegation_event_tainted(envelope) {
117                    continue;
118                }
119                apply_event(
120                    &mut state,
121                    parent.meta.session_id,
122                    envelope.run_id,
123                    envelope.payload.clone(),
124                )?;
125            }
126        }
127        Ok(Arc::new(Self {
128            sessions,
129            state: Mutex::new(state),
130        }))
131    }
132
133    /// Folds delegation records harvested from child logs (ยง4.1.2), returning the
134    /// entries that changed so the engine can rebuild only what moved.
135    pub fn extend_from_payloads(
136        &self,
137        payloads: &[(
138            SessionId,
139            Option<RunId>,
140            cookie_agent_protocol::EventPayload,
141        )],
142    ) -> Result<Vec<DelegationEntry>, DelegationEventError> {
143        if payloads.is_empty() {
144            return Ok(Vec::new());
145        }
146        let mut state = self
147            .state
148            .lock()
149            .unwrap_or_else(|poisoned| poisoned.into_inner());
150        let mut touched = Vec::new();
151        for (parent_session_id, run_id, payload) in payloads {
152            let Some(invocation_id) = delegation_invocation_of(payload) else {
153                continue;
154            };
155            let before = state.entries.get(&invocation_id).cloned();
156            apply_event(&mut state, *parent_session_id, *run_id, payload.clone())?;
157            match state.entries.get(&invocation_id).cloned() {
158                Some(updated) if Some(&updated) != before.as_ref() => touched.push(updated),
159                _ => {}
160            }
161        }
162        Ok(touched)
163    }
164
165    #[allow(clippy::too_many_arguments)]
166    pub fn reserve(
167        &self,
168        invocation_id: InvocationId,
169        parent_session_id: SessionId,
170        parent_run_id: RunId,
171        parent_tool_call_id: ToolCallId,
172        child_agent: AgentSnapshot,
173        revisions: DelegationRuntimeRevisions,
174        selected_suffix: Vec<FrozenModelBinding>,
175        cache_strategies: Vec<Option<FrozenCacheStrategy>>,
176        request_fingerprint: Sha256Digest,
177        request: DelegateRequestPayload,
178    ) -> Result<DelegationEntry, DelegationEventError> {
179        let mut state = self
180            .state
181            .lock()
182            .unwrap_or_else(|poisoned| poisoned.into_inner());
183        if let Some(entry) = state.entries.get(&invocation_id) {
184            let same_request = entry.reservation.parent_session_id == parent_session_id
185                && entry.reservation.parent_run_id == parent_run_id
186                && entry.reservation.parent_tool_call_id == parent_tool_call_id
187                && entry.request_fingerprint == request_fingerprint
188                && entry.child_agent == child_agent
189                && entry.revisions == revisions
190                && entry.selected_suffix == selected_suffix
191                && entry.cache_strategies == cache_strategies
192                && entry.request == request;
193            return if same_request {
194                Ok(entry.clone())
195            } else {
196                Err(DelegationEventError::Corrupt(invocation_id))
197            };
198        }
199        if !valid_request(&request)
200            || selected_suffix.is_empty()
201            || !cache_strategies_match_bindings(&selected_suffix, &cache_strategies)
202            || selected_suffix
203                .iter()
204                .any(|binding| binding.manifest_revision != revisions.manifest_revision)
205            || child_agent
206                .validate_selected_suffix(
207                    &cookie_agent_protocol::RunSelection {
208                        agent: child_agent.agent.clone(),
209                        model: selected_suffix[0].selection.clone(),
210                        preset: None,
211                    },
212                    &selected_suffix,
213                )
214                .is_err()
215        {
216            return Err(DelegationEventError::Corrupt(invocation_id));
217        }
218        let child_session_id = request.resume_session_id.unwrap_or_else(SessionId::new_v7);
219        let reservation = DelegationReservation {
220            invocation_id,
221            parent_session_id,
222            parent_run_id,
223            parent_tool_call_id,
224            child_session_id,
225        };
226        let entry = DelegationEntry {
227            reservation: reservation.clone(),
228            child_agent: child_agent.clone(),
229            revisions: revisions.clone(),
230            selected_suffix: selected_suffix.clone(),
231            cache_strategies: cache_strategies.clone(),
232            request_fingerprint: request_fingerprint.clone(),
233            request: request.clone(),
234            started: false,
235            child_run_id: None,
236            run_attached: false,
237            terminal_status: None,
238            terminal_reason: None,
239        };
240        self.sessions.append(
241            parent_session_id,
242            Some(parent_run_id),
243            cookie_agent_protocol::EventOrigin::new("engine:delegation")
244                .expect("static event origin is valid"),
245            EventPayload::DelegationReserved {
246                reservation,
247                child_agent: Box::new(child_agent),
248                manifest_revision: revisions.manifest_revision,
249                runtime_revision: revisions.runtime_revision,
250                catalog_revision: revisions.catalog_revision,
251                provider_state_revision: revisions.provider_state_revision,
252                model_revision: revisions.model_revision,
253                agent_revision: revisions.agent_revision,
254                recipe_registry_revision: revisions.recipe_registry_revision,
255                selected_suffix,
256                cache_strategies,
257                request_fingerprint,
258                request,
259            },
260        )?;
261        state.entries.insert(invocation_id, entry.clone());
262        state.order.push(invocation_id);
263        Ok(entry)
264    }
265
266    pub fn mark_started(&self, invocation_id: InvocationId) -> Result<(), DelegationEventError> {
267        let mut state = self
268            .state
269            .lock()
270            .unwrap_or_else(|poisoned| poisoned.into_inner());
271        let Some(entry) = state.entries.get(&invocation_id) else {
272            return Err(DelegationEventError::Corrupt(invocation_id));
273        };
274        if entry.started {
275            return Ok(());
276        }
277        let reservation = entry.reservation.clone();
278        self.sessions.append(
279            reservation.parent_session_id,
280            Some(reservation.parent_run_id),
281            cookie_agent_protocol::EventOrigin::new("engine:delegation")
282                .expect("static event origin is valid"),
283            EventPayload::DelegationStarted {
284                invocation_id,
285                child_session_id: reservation.child_session_id,
286            },
287        )?;
288        state
289            .entries
290            .get_mut(&invocation_id)
291            .expect("checked entry")
292            .started = true;
293        Ok(())
294    }
295
296    pub fn mark_run_started(
297        &self,
298        invocation_id: InvocationId,
299        child_run_id: RunId,
300    ) -> Result<(), DelegationEventError> {
301        self.mark_run(invocation_id, child_run_id, false)
302    }
303
304    pub fn mark_run_attached(
305        &self,
306        invocation_id: InvocationId,
307        child_run_id: RunId,
308    ) -> Result<(), DelegationEventError> {
309        self.mark_run(invocation_id, child_run_id, true)
310    }
311
312    fn mark_run(
313        &self,
314        invocation_id: InvocationId,
315        child_run_id: RunId,
316        attached: bool,
317    ) -> Result<(), DelegationEventError> {
318        let mut state = self
319            .state
320            .lock()
321            .unwrap_or_else(|poisoned| poisoned.into_inner());
322        let Some(entry) = state.entries.get(&invocation_id) else {
323            return Err(DelegationEventError::Corrupt(invocation_id));
324        };
325        if entry.terminal_status.is_some()
326            || (attached && entry.request.resume_session_id.is_none())
327        {
328            return Err(DelegationEventError::Corrupt(invocation_id));
329        }
330        if entry.child_run_id == Some(child_run_id) && entry.run_attached == attached {
331            return Ok(());
332        }
333        if entry.child_run_id.is_some() {
334            return Err(DelegationEventError::Corrupt(invocation_id));
335        }
336        let reservation = entry.reservation.clone();
337        let payload = if attached {
338            EventPayload::DelegationRunAttached {
339                invocation_id,
340                child_run_id,
341            }
342        } else {
343            EventPayload::DelegationRunStarted {
344                invocation_id,
345                child_run_id,
346            }
347        };
348        self.sessions.append(
349            reservation.parent_session_id,
350            Some(reservation.parent_run_id),
351            cookie_agent_protocol::EventOrigin::new("engine:delegation")
352                .expect("static event origin is valid"),
353            payload,
354        )?;
355        let entry = state
356            .entries
357            .get_mut(&invocation_id)
358            .expect("checked entry");
359        entry.child_run_id = Some(child_run_id);
360        entry.run_attached = attached;
361        Ok(())
362    }
363
364    pub fn mark_finished(
365        &self,
366        invocation_id: InvocationId,
367        status: SessionStatus,
368    ) -> Result<(), DelegationEventError> {
369        self.mark_finished_with_reason(invocation_id, status, None)
370    }
371
372    pub fn mark_finished_with_reason(
373        &self,
374        invocation_id: InvocationId,
375        status: SessionStatus,
376        reason: Option<cookie_agent_protocol::SafeErrorMessage>,
377    ) -> Result<(), DelegationEventError> {
378        if !matches!(
379            status,
380            SessionStatus::Completed
381                | SessionStatus::Failed
382                | SessionStatus::Cancelled
383                | SessionStatus::Interrupted
384        ) {
385            return Err(DelegationEventError::Corrupt(invocation_id));
386        }
387        let mut state = self
388            .state
389            .lock()
390            .unwrap_or_else(|poisoned| poisoned.into_inner());
391        let Some(entry) = state.entries.get(&invocation_id) else {
392            return Err(DelegationEventError::Corrupt(invocation_id));
393        };
394        if entry.terminal_status == Some(status) {
395            return if entry.terminal_reason == reason {
396                Ok(())
397            } else {
398                Err(DelegationEventError::Corrupt(invocation_id))
399            };
400        }
401        if entry.terminal_status.is_some() {
402            return Err(DelegationEventError::Corrupt(invocation_id));
403        }
404        let reservation = entry.reservation.clone();
405        let child_run_id = entry.child_run_id;
406        self.sessions.append(
407            reservation.parent_session_id,
408            Some(reservation.parent_run_id),
409            cookie_agent_protocol::EventOrigin::new("engine:delegation")
410                .expect("static event origin is valid"),
411            EventPayload::DelegationFinished {
412                invocation_id,
413                child_session_id: reservation.child_session_id,
414                child_run_id,
415                status,
416                reason: reason.clone(),
417            },
418        )?;
419        let entry = state
420            .entries
421            .get_mut(&invocation_id)
422            .expect("checked entry");
423        entry.terminal_status = Some(status);
424        entry.terminal_reason = reason;
425        Ok(())
426    }
427
428    #[must_use]
429    pub fn get(&self, invocation_id: InvocationId) -> Option<DelegationEntry> {
430        self.state
431            .lock()
432            .unwrap_or_else(|poisoned| poisoned.into_inner())
433            .entries
434            .get(&invocation_id)
435            .cloned()
436    }
437
438    #[must_use]
439    pub fn entries(&self) -> Vec<DelegationEntry> {
440        let state = self
441            .state
442            .lock()
443            .unwrap_or_else(|poisoned| poisoned.into_inner());
444        state
445            .order
446            .iter()
447            .filter_map(|invocation_id| state.entries.get(invocation_id).cloned())
448            .collect()
449    }
450
451    pub fn reconcile_parent(
452        &self,
453        parent_session_id: SessionId,
454    ) -> Result<(), DelegationEventError> {
455        let parent = self.sessions.get(parent_session_id)?;
456        let mut rebuilt = DelegationState::default();
457        for envelope in parent.log.event_snapshot().iter() {
458            if parent.log.delegation_event_tainted(envelope) {
459                continue;
460            }
461            apply_event(
462                &mut rebuilt,
463                parent_session_id,
464                envelope.run_id,
465                envelope.payload.clone(),
466            )?;
467        }
468
469        let mut state = self
470            .state
471            .lock()
472            .unwrap_or_else(|poisoned| poisoned.into_inner());
473        state
474            .entries
475            .retain(|_, entry| entry.reservation.parent_session_id != parent_session_id);
476        let retained = state
477            .entries
478            .keys()
479            .copied()
480            .collect::<std::collections::HashSet<_>>();
481        state
482            .order
483            .retain(|invocation_id| retained.contains(invocation_id));
484        for invocation_id in rebuilt.order {
485            if let Some(entry) = rebuilt.entries.remove(&invocation_id) {
486                state.entries.insert(invocation_id, entry);
487                state.order.push(invocation_id);
488            }
489        }
490        Ok(())
491    }
492}
493
494/// The invocation a delegation payload belongs to, for cache-diff bookkeeping.
495fn delegation_invocation_of(payload: &EventPayload) -> Option<cookie_agent_protocol::InvocationId> {
496    match payload {
497        EventPayload::DelegationReserved { reservation, .. } => Some(reservation.invocation_id),
498        EventPayload::DelegationStarted { invocation_id, .. }
499        | EventPayload::DelegationRunStarted { invocation_id, .. }
500        | EventPayload::DelegationRunAttached { invocation_id, .. }
501        | EventPayload::DelegationFinished { invocation_id, .. } => Some(*invocation_id),
502        _ => None,
503    }
504}
505
506/// The delegation lifecycle payloads [`apply_event`] consumes.
507///
508/// Lazy tree loads hand child-session payloads over in log order and must offer
509/// exactly this set: a missing arm would leave an entry half-folded, and the
510/// following payload would then be rejected as corrupt.
511pub(crate) fn is_delegation_payload(payload: &EventPayload) -> bool {
512    matches!(
513        payload,
514        EventPayload::DelegationReserved { .. }
515            | EventPayload::DelegationStarted { .. }
516            | EventPayload::DelegationRunStarted { .. }
517            | EventPayload::DelegationRunAttached { .. }
518            | EventPayload::DelegationFinished { .. }
519    )
520}
521
522fn apply_event(
523    state: &mut DelegationState,
524    parent_session_id: SessionId,
525    run_id: Option<RunId>,
526    payload: EventPayload,
527) -> Result<(), DelegationEventError> {
528    match payload {
529        EventPayload::DelegationReserved {
530            reservation,
531            child_agent,
532            manifest_revision,
533            runtime_revision,
534            catalog_revision,
535            provider_state_revision,
536            model_revision,
537            agent_revision,
538            recipe_registry_revision,
539            selected_suffix,
540            cache_strategies,
541            request_fingerprint,
542            request,
543        } => {
544            let invocation_id = reservation.invocation_id;
545            let revisions = DelegationRuntimeRevisions {
546                manifest_revision,
547                runtime_revision,
548                catalog_revision,
549                provider_state_revision,
550                model_revision,
551                agent_revision,
552                recipe_registry_revision,
553            };
554            let fingerprint_valid = delegation_request_fingerprint(
555                &child_agent,
556                &selected_suffix,
557                &cache_strategies,
558                &request,
559            )
560            .is_ok_and(|computed| computed == request_fingerprint);
561            if parent_session_id != reservation.parent_session_id
562                || run_id != Some(reservation.parent_run_id)
563                || state.entries.contains_key(&invocation_id)
564                || request
565                    .resume_session_id
566                    .is_some_and(|id| id != reservation.child_session_id)
567                || !valid_request(&request)
568                || !fingerprint_valid
569                || selected_suffix.is_empty()
570                || (!cache_strategies.is_empty()
571                    && !cache_strategies_match_bindings(&selected_suffix, &cache_strategies))
572                || selected_suffix
573                    .iter()
574                    .any(|binding| binding.manifest_revision != revisions.manifest_revision)
575                || child_agent
576                    .validate_selected_suffix(
577                        &cookie_agent_protocol::RunSelection {
578                            agent: child_agent.agent.clone(),
579                            model: selected_suffix[0].selection.clone(),
580                            preset: None,
581                        },
582                        &selected_suffix,
583                    )
584                    .is_err()
585            {
586                return Err(DelegationEventError::Corrupt(invocation_id));
587            }
588            state.entries.insert(
589                invocation_id,
590                DelegationEntry {
591                    reservation,
592                    child_agent: *child_agent,
593                    revisions,
594                    selected_suffix,
595                    cache_strategies,
596                    request_fingerprint,
597                    request,
598                    started: false,
599                    child_run_id: None,
600                    run_attached: false,
601                    terminal_status: None,
602                    terminal_reason: None,
603                },
604            );
605            state.order.push(invocation_id);
606        }
607        EventPayload::DelegationStarted {
608            invocation_id,
609            child_session_id,
610        } => {
611            let Some(entry) = state.entries.get_mut(&invocation_id) else {
612                return Ok(());
613            };
614            if parent_session_id != entry.reservation.parent_session_id
615                || run_id != Some(entry.reservation.parent_run_id)
616                || child_session_id != entry.reservation.child_session_id
617                || entry.started
618            {
619                return Err(DelegationEventError::Corrupt(invocation_id));
620            }
621            entry.started = true;
622        }
623        payload @ (EventPayload::DelegationRunStarted { .. }
624        | EventPayload::DelegationRunAttached { .. }) => {
625            let (invocation_id, child_run_id, attached) = match payload {
626                EventPayload::DelegationRunStarted {
627                    invocation_id,
628                    child_run_id,
629                } => (invocation_id, child_run_id, false),
630                EventPayload::DelegationRunAttached {
631                    invocation_id,
632                    child_run_id,
633                } => (invocation_id, child_run_id, true),
634                _ => unreachable!(),
635            };
636            let Some(entry) = state.entries.get_mut(&invocation_id) else {
637                return Ok(());
638            };
639            if parent_session_id != entry.reservation.parent_session_id
640                || run_id != Some(entry.reservation.parent_run_id)
641                || entry.child_run_id.is_some()
642                || entry.terminal_status.is_some()
643                || (attached && entry.request.resume_session_id.is_none())
644            {
645                return Err(DelegationEventError::Corrupt(invocation_id));
646            }
647            entry.child_run_id = Some(child_run_id);
648            entry.run_attached = attached;
649        }
650        EventPayload::DelegationFinished {
651            invocation_id,
652            child_session_id,
653            child_run_id,
654            status,
655            reason,
656        } => {
657            let Some(entry) = state.entries.get_mut(&invocation_id) else {
658                return Ok(());
659            };
660            if parent_session_id != entry.reservation.parent_session_id
661                || run_id != Some(entry.reservation.parent_run_id)
662                || child_session_id != entry.reservation.child_session_id
663                || child_run_id != entry.child_run_id
664                || entry.terminal_status.is_some()
665                || !matches!(
666                    status,
667                    SessionStatus::Completed
668                        | SessionStatus::Failed
669                        | SessionStatus::Cancelled
670                        | SessionStatus::Interrupted
671                )
672            {
673                return Err(DelegationEventError::Corrupt(invocation_id));
674            }
675            entry.terminal_status = Some(status);
676            entry.terminal_reason = reason;
677        }
678        _ => {}
679    }
680    Ok(())
681}
682
683fn valid_request(request: &DelegateRequestPayload) -> bool {
684    if request.description.is_empty() || request.prompt.is_empty() {
685        return false;
686    }
687    if request.resume_session_id.is_some() && request.inherit_context {
688        return false;
689    }
690    if !request.inherit_context && !request.seeded_context.is_empty() {
691        return false;
692    }
693    if request.seeded_context.len() > 65_536 {
694        return false;
695    }
696    if request.staged_skill.as_ref().is_some_and(|skill| {
697        skill.provenance != cookie_agent_protocol::StagedSkillProvenance::SkillFork
698            || skill.name.is_empty()
699            || skill.rendered_body.is_empty()
700            || skill.source_path.is_empty()
701            || skill.base_dir.is_empty()
702            || skill.supporting_files.len() > 10
703            || skill.grants.len() > 256
704            || request.resume_session_id.is_some()
705    }) {
706        return false;
707    }
708    if request
709        .seeded_context
710        .iter()
711        .any(|turn| turn.text.is_empty())
712    {
713        return false;
714    }
715    request
716        .seeded_context
717        .iter()
718        .map(|turn| turn.text.len())
719        .sum::<usize>()
720        <= 65_536
721}
722
723fn cache_strategies_match_bindings(
724    bindings: &[FrozenModelBinding],
725    strategies: &[Option<FrozenCacheStrategy>],
726) -> bool {
727    bindings.len() == strategies.len()
728        && bindings.iter().zip(strategies).all(|(binding, strategy)| {
729            let Some(strategy) = strategy else {
730                return true;
731            };
732            let Some(family) = cookie_agent_models::adapters::wire_adapter_for_protocol(
733                binding.descriptor.adapter_id.as_str(),
734            ) else {
735                return false;
736            };
737            matches!(
738                (family, strategy),
739                (
740                    cookie_agent_models::adapters::OvenAdapterFamily::Anthropic
741                        | cookie_agent_models::adapters::OvenAdapterFamily::AnthropicCompatible,
742                    FrozenCacheStrategy::Anthropic { .. }
743                ) | (
744                    cookie_agent_models::adapters::OvenAdapterFamily::AwsBedrockConverse,
745                    FrozenCacheStrategy::Bedrock { .. }
746                ) | (
747                    cookie_agent_models::adapters::OvenAdapterFamily::GoogleGemini
748                        | cookie_agent_models::adapters::OvenAdapterFamily::GoogleVertexGemini,
749                    FrozenCacheStrategy::Google { .. }
750                ) | (
751                    cookie_agent_models::adapters::OvenAdapterFamily::OpenaiChat
752                        | cookie_agent_models::adapters::OvenAdapterFamily::OpenaiResponses
753                        | cookie_agent_models::adapters::OvenAdapterFamily::OpenaiCompatible
754                        | cookie_agent_models::adapters::OvenAdapterFamily::AzureOpenaiChat
755                        | cookie_agent_models::adapters::OvenAdapterFamily::AzureOpenaiResponses,
756                    FrozenCacheStrategy::OpenAi { .. }
757                )
758            )
759        })
760}