tt_shared/context.rs
1//! RequestContext carries authenticated identity, trace IDs, and credentials
2//! through the request lifecycle. Adapters are stateless — every call gets a
3//! fresh context.
4
5use std::time::Duration;
6
7use uuid::Uuid;
8
9/// Subscription tier for the calling organisation, as surfaced by the cloud
10/// tier-resolution layer.
11///
12/// The tier drives cache TTL selection per spec §8.4 (24h / 7d / 30d bands).
13/// The tier is carried as `Option<CallerTier>` on `tt_auth::ApiKeyContext`
14/// (NOT on [`crate::context::RequestContext`], which has no `tier` field): when
15/// `None`, the gateway falls back to the conservative 24h default. The cloud
16/// will inject the real tier once `rv-tier-limits-enforcement` is wired; until
17/// then all requests run as if Free.
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum CallerTier {
20 /// Free tier — 24h cache TTL (spec §8.4).
21 Free,
22 /// Pro tier — 7d cache TTL (spec §8.4).
23 Pro,
24 /// Team tier — 7d cache TTL (spec §8.4, same band as Pro).
25 Team,
26 /// Scale tier — 30d cache TTL (spec §8.4).
27 Scale,
28}
29
30impl CallerTier {
31 /// Cache TTL in seconds for this tier, per spec §8.4.
32 ///
33 /// | Tier | TTL |
34 /// | ----------- | ------ |
35 /// | Free | 24h |
36 /// | Pro / Team | 7d |
37 /// | Scale | 30d |
38 #[must_use]
39 pub fn ttl_secs(self) -> u64 {
40 match self {
41 CallerTier::Free => 24 * 60 * 60,
42 CallerTier::Pro | CallerTier::Team => 7 * 24 * 60 * 60,
43 CallerTier::Scale => 30 * 24 * 60 * 60,
44 }
45 }
46}
47
48#[derive(Debug, Clone)]
49pub struct RequestContext {
50 pub trace_id: Uuid,
51 pub org_id: Uuid,
52 pub api_key_id: Uuid,
53 pub credentials: ProviderCredentials,
54 /// Free-form cost-attribution tag from `X-TokenTrimmer-Tag` header.
55 pub tag: Option<String>,
56 /// Deadline for the entire request. Adapters should respect this.
57 pub deadline: Option<Duration>,
58}
59
60#[derive(Debug, Clone)]
61pub struct ProviderCredentials {
62 pub api_key: SecretString,
63 /// Self-hosted endpoint override (used for Ollama, vLLM, LM Studio, OpenRouter, etc.).
64 pub base_url: Option<String>,
65 pub extra_headers: Vec<(String, String)>,
66}
67
68/// String wrapper whose `Debug` impl never prints the secret.
69#[derive(Clone)]
70pub struct SecretString(String);
71
72impl SecretString {
73 pub fn new(s: impl Into<String>) -> Self {
74 Self(s.into())
75 }
76
77 pub fn expose(&self) -> &str {
78 &self.0
79 }
80}
81
82impl std::fmt::Debug for SecretString {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 write!(f, "SecretString(****)")
85 }
86}