next_web_ai/chat/observation/
chat_model_observation_documentation.rs

1use next_web_core::error::BoxError;
2
3use crate::{
4    observation::{
5        observation::{Context, Observation, ObservationImpl},
6        observation_documentation::{BoxObservationConvention, ObservationDocumentation},
7        observation_registry::ObservationRegistry,
8    },
9    util::key_name::KeyName,
10};
11
12use super::{
13    conventions::ai_observation_attributes::AiObservationAttributes,
14    default_chat_model_observation_convention::DefaultChatModelObservationConvention,
15    observation_convention::ObservationConvention,
16};
17
18#[derive(Debug, PartialEq, Eq)]
19pub enum ChatModelObservationDocumentation {
20    ChatModelOperation,
21    LowCardinalityKeyNames(LowNames),
22    HighCardinalityKeyNames(HighNames),
23}
24
25impl ObservationDocumentation for ChatModelObservationDocumentation {
26    fn observation(
27        &self,
28        custom_convention: Option<BoxObservationConvention>,
29        default_convention: Option<BoxObservationConvention>,
30        context: impl Context + 'static,
31        registry: Box<dyn ObservationRegistry>,
32    ) -> Result<Box<dyn Observation>, BoxError> {
33        if self.default_convention().is_empty() {
34            return Err("No default convention provided for chat model observation".into());
35        }
36
37        let mut observation = ObservationImpl::create_not_started(
38            custom_convention,
39            default_convention,
40            context,
41            Some(registry),
42        );
43
44        if let Some(name) = self.name() {
45            observation.context().set_name(name);
46        }
47
48        if let Some(contextual_name) = self.contextual_name() {
49            observation.contextual_name(contextual_name);
50        }
51
52        Ok(observation)
53    }
54
55    fn default_convention(&self) -> &'static str {
56        std::any::type_name::<DefaultChatModelObservationConvention>()
57    }
58
59    fn low_cardinality_key_names(&self) -> Vec<KeyName> {
60        LowNames::values()
61    }
62
63    fn high_cardinality_key_names(&self) -> Vec<KeyName> {
64        HighNames::values()
65    }
66}
67
68impl ChatModelObservationDocumentation {
69    pub fn value(&self) -> &str {
70        match self {
71            ChatModelObservationDocumentation::LowCardinalityKeyNames(names) => names.value(),
72            ChatModelObservationDocumentation::HighCardinalityKeyNames(names) => names.value(),
73            _ => "",
74        }
75    }
76}
77
78#[derive(Debug, PartialEq, Eq)]
79pub enum LowNames {
80    AiOperationType,
81    AiProvider,
82    RequestModel,
83    ResponseModel,
84}
85
86#[derive(Debug, PartialEq, Eq)]
87pub enum HighNames {
88    RequestFrequencyPenalty,
89    RequestMaxTokens,
90    RequestPresencePenalty,
91    RequestStopSequences,
92    RequestTemperature,
93    RequestToolNames,
94    RequestTopK,
95    RequestTopP,
96    ResponseFinishReasons,
97    ResponseId,
98    UsageInputTokens,
99    UsageOutputTokens,
100    UsageTotalTokens,
101}
102
103impl HighNames {
104    pub fn value(&self) -> &str {
105        match self {
106            HighNames::RequestFrequencyPenalty => {
107                AiObservationAttributes::RequestFrequencyPenalty.value()
108            }
109            HighNames::RequestMaxTokens => AiObservationAttributes::RequestMaxTokens.value(),
110            HighNames::RequestPresencePenalty => {
111                AiObservationAttributes::RequestPresencePenalty.value()
112            }
113            HighNames::RequestStopSequences => {
114                AiObservationAttributes::RequestStopSequences.value()
115            }
116            HighNames::RequestTemperature => AiObservationAttributes::RequestTemperature.value(),
117            HighNames::RequestToolNames => AiObservationAttributes::RequestToolNames.value(),
118            HighNames::RequestTopK => AiObservationAttributes::RequestTopK.value(),
119            HighNames::RequestTopP => AiObservationAttributes::RequestTopP.value(),
120            HighNames::ResponseFinishReasons => {
121                AiObservationAttributes::ResponseFinishReasons.value()
122            }
123            HighNames::ResponseId => AiObservationAttributes::ResponseId.value(),
124            HighNames::UsageInputTokens => AiObservationAttributes::UsageInputTokens.value(),
125            HighNames::UsageOutputTokens => AiObservationAttributes::UsageOutputTokens.value(),
126            HighNames::UsageTotalTokens => AiObservationAttributes::UsageTotalTokens.value(),
127        }
128    }
129
130    pub fn values() -> Vec<KeyName> {
131        vec![
132            KeyName(HighNames::RequestFrequencyPenalty.value().into()),
133            KeyName(HighNames::RequestMaxTokens.value().into()),
134            KeyName(HighNames::RequestPresencePenalty.value().into()),
135            KeyName(HighNames::RequestStopSequences.value().into()),
136            KeyName(HighNames::RequestTemperature.value().into()),
137            KeyName(HighNames::RequestToolNames.value().into()),
138            KeyName(HighNames::RequestTopK.value().into()),
139            KeyName(HighNames::RequestTopP.value().into()),
140            KeyName(HighNames::ResponseFinishReasons.value().into()),
141            KeyName(HighNames::ResponseId.value().into()),
142            KeyName(HighNames::UsageInputTokens.value().into()),
143            KeyName(HighNames::UsageOutputTokens.value().into()),
144            KeyName(HighNames::UsageTotalTokens.value().into()),
145        ]
146    }
147}
148
149impl LowNames {
150    pub fn value(&self) -> &str {
151        match self {
152            LowNames::AiOperationType => AiObservationAttributes::AiOperationType.value(),
153            LowNames::AiProvider => AiObservationAttributes::AiProvider.value(),
154            LowNames::RequestModel => AiObservationAttributes::RequestModel.value(),
155            LowNames::ResponseModel => AiObservationAttributes::ResponseModel.value(),
156        }
157    }
158
159    pub fn values() -> Vec<KeyName> {
160        vec![
161            KeyName(LowNames::AiOperationType.value().into()),
162            KeyName(LowNames::AiProvider.value().into()),
163            KeyName(LowNames::RequestModel.value().into()),
164            KeyName(LowNames::ResponseModel.value().into()),
165        ]
166    }
167}