genai/client/model_spec.rs
1use crate::{ModelIden, ModelName, ServiceTarget};
2
3/// Specifies how to identify and resolve a model for API calls.
4///
5/// `ModelSpec` provides three levels of control over model resolution:
6///
7/// - [`ModelSpec::Name`]: Just a model name string. The adapter kind is inferred
8/// from the name, and auth/endpoint are resolved via the client's configured resolvers.
9///
10/// - [`ModelSpec::Iden`]: An explicit [`ModelIden`] with adapter kind specified.
11/// Skips adapter inference but still resolves auth/endpoint via config.
12///
13/// - [`ModelSpec::Target`]: A complete [`ServiceTarget`] with endpoint, auth, and model.
14/// Used directly, only runs the service target resolver.
15///
16/// # Examples
17///
18/// ```rust
19/// use genai::adapter::AdapterKind;
20/// use genai::resolver::{AuthData, Endpoint};
21/// use genai::{ModelIden, ModelSpec, ServiceTarget};
22///
23/// // Using a string name (full inference)
24/// let spec: ModelSpec = "gpt-4".into();
25///
26/// // Using an explicit ModelIden (skip adapter inference)
27/// let spec: ModelSpec = ModelIden::new(AdapterKind::OpenAI, "gpt-4").into();
28///
29/// // Using a complete ServiceTarget (bypass all resolution)
30/// let target = ServiceTarget {
31/// endpoint: Endpoint::from_static("https://custom.api/v1/"),
32/// auth: AuthData::from_env("CUSTOM_API_KEY"),
33/// model: ModelIden::new(AdapterKind::OpenAI, "custom-model"),
34/// };
35/// let spec: ModelSpec = target.into();
36/// ```
37#[derive(Debug, Clone)]
38pub enum ModelSpec {
39 /// Model name - without or without model namespace
40 Name(ModelName),
41
42 /// Explicit [`ModelIden`] - skips adapter inference, still resolves auth/endpoint.
43 Iden(ModelIden),
44
45 /// Complete [`ServiceTarget`] - used directly, bypasses model mapping and auth resolution
46 Target(ServiceTarget),
47}
48
49// region: --- Constructors
50
51impl ModelSpec {
52 /// Creates a `ModelSpec::Name` from a string.
53 pub fn from_name(name: impl Into<ModelName>) -> Self {
54 ModelSpec::Name(name.into())
55 }
56
57 /// Creates a `ModelSpec::Name` from a static str.
58 pub fn from_static_name(name: &'static str) -> Self {
59 let name = ModelName::from_static(name);
60 ModelSpec::Name(name)
61 }
62
63 /// Creates a `ModelSpec::Iden` from a ModelIden
64 pub fn from_iden(model_iden: impl Into<ModelIden>) -> Self {
65 let model_iden = model_iden.into();
66 Self::Iden(model_iden)
67 }
68
69 /// Creates a `ModelSpec::Target` from a complete service target.
70 pub fn from_target(target: ServiceTarget) -> Self {
71 ModelSpec::Target(target)
72 }
73}
74
75// endregion: --- Constructors
76
77// region: --- From Implementations
78
79impl From<&str> for ModelSpec {
80 fn from(name: &str) -> Self {
81 ModelSpec::Name(name.into())
82 }
83}
84
85impl From<&&str> for ModelSpec {
86 fn from(name: &&str) -> Self {
87 ModelSpec::Name((*name).into())
88 }
89}
90
91impl From<String> for ModelSpec {
92 fn from(name: String) -> Self {
93 ModelSpec::Name(name.into())
94 }
95}
96
97impl From<&String> for ModelSpec {
98 fn from(name: &String) -> Self {
99 ModelSpec::Name(name.into())
100 }
101}
102
103impl From<ModelName> for ModelSpec {
104 fn from(model: ModelName) -> Self {
105 ModelSpec::Name(model)
106 }
107}
108
109impl From<&ModelName> for ModelSpec {
110 fn from(model: &ModelName) -> Self {
111 ModelSpec::Name(model.clone())
112 }
113}
114
115impl From<ModelIden> for ModelSpec {
116 fn from(model: ModelIden) -> Self {
117 ModelSpec::Iden(model)
118 }
119}
120
121impl From<&ModelIden> for ModelSpec {
122 fn from(model: &ModelIden) -> Self {
123 ModelSpec::Iden(model.clone())
124 }
125}
126
127impl From<ServiceTarget> for ModelSpec {
128 fn from(target: ServiceTarget) -> Self {
129 ModelSpec::Target(target)
130 }
131}
132
133// endregion: --- From Implementations