Skip to main content

rightkit_agent_engine_protocol/
retry_notice.rs

1//! Provider retry notices: a plain-data hook so a provider adapter can tell
2//! its caller "I am backing off and retrying" without owning any session
3//! state. The engine installs a notifier on the request metadata and turns
4//! each notice into a `providerRetrying` protocol event.
5
6use std::fmt;
7use std::sync::Arc;
8
9/// One pending provider retry.
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct RetryNotice {
12    /// Short provider label (route host).
13    pub provider: String,
14    /// Why the previous attempt failed: `rate limited`, `HTTP 503`,
15    /// `connection error`, `stream interrupted`.
16    pub reason: String,
17    /// The retry about to run (1-based).
18    pub attempt: u32,
19    /// Retries the ladder allows.
20    pub max_attempts: u32,
21    /// Backoff the adapter sleeps before the retry.
22    pub delay_ms: u64,
23}
24
25type NotifyFn = dyn Fn(RetryNotice) + Send + Sync;
26
27/// Cloneable, optional retry sink. Default is a no-op.
28#[derive(Clone, Default)]
29pub struct RetryNotifier(Option<Arc<NotifyFn>>);
30
31impl RetryNotifier {
32    pub fn new(f: impl Fn(RetryNotice) + Send + Sync + 'static) -> Self {
33        Self(Some(Arc::new(f)))
34    }
35
36    pub fn notify(&self, notice: RetryNotice) {
37        if let Some(f) = &self.0 {
38            f(notice);
39        }
40    }
41}
42
43impl fmt::Debug for RetryNotifier {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        f.write_str(if self.0.is_some() {
46            "RetryNotifier(set)"
47        } else {
48            "RetryNotifier(none)"
49        })
50    }
51}
52
53impl PartialEq for RetryNotifier {
54    fn eq(&self, other: &Self) -> bool {
55        match (&self.0, &other.0) {
56            (None, None) => true,
57            (Some(a), Some(b)) => Arc::ptr_eq(a, b),
58            _ => false,
59        }
60    }
61}
62
63impl Eq for RetryNotifier {}