@@ -9,6 +9,7 @@ use crossterm::{
99} ;
1010use dialoguer:: Select ;
1111
12+ use crate :: auth:: AuthError ;
1213use crate :: auth:: builder_id:: {
1314 BuilderIdToken ,
1415 TokenType ,
@@ -21,18 +22,37 @@ use crate::cli::chat::{
2122use crate :: os:: Os ;
2223
2324pub struct ModelOption {
25+ /// Display name
2426 pub name : & ' static str ,
27+ /// Actual model id to send in the API
2528 pub model_id : & ' static str ,
29+ /// Size of the model's context window, in tokens
30+ pub context_window_tokens : usize ,
2631}
2732
28- pub const MODEL_OPTIONS : [ ModelOption ; 2 ] = [
33+ const MODEL_OPTIONS : [ ModelOption ; 2 ] = [
2934 ModelOption {
3035 name : "claude-4-sonnet" ,
3136 model_id : "CLAUDE_SONNET_4_20250514_V1_0" ,
37+ context_window_tokens : 200_000 ,
3238 } ,
3339 ModelOption {
3440 name : "claude-3.7-sonnet" ,
3541 model_id : "CLAUDE_3_7_SONNET_20250219_V1_0" ,
42+ context_window_tokens : 200_000 ,
43+ } ,
44+ ] ;
45+
46+ const OPENAI_MODEL_OPTIONS : [ ModelOption ; 2 ] = [
47+ ModelOption {
48+ name : "experimental-gpt-oss-120b" ,
49+ model_id : "OPENAI_GPT_OSS_120B_1_0" ,
50+ context_window_tokens : 128_000 ,
51+ } ,
52+ ModelOption {
53+ name : "experimental-gpt-oss-20b" ,
54+ model_id : "OPENAI_GPT_OSS_20B_1_0" ,
55+ context_window_tokens : 128_000 ,
3656 } ,
3757] ;
3858
@@ -41,17 +61,19 @@ pub const MODEL_OPTIONS: [ModelOption; 2] = [
4161pub struct ModelArgs ;
4262
4363impl ModelArgs {
44- pub async fn execute ( self , session : & mut ChatSession ) -> Result < ChatState , ChatError > {
45- Ok ( select_model ( session) ?. unwrap_or ( ChatState :: PromptUser {
64+ pub async fn execute ( self , os : & Os , session : & mut ChatSession ) -> Result < ChatState , ChatError > {
65+ Ok ( select_model ( os , session) . await ?. unwrap_or ( ChatState :: PromptUser {
4666 skip_printing_tools : false ,
4767 } ) )
4868 }
4969}
5070
51- pub fn select_model ( session : & mut ChatSession ) -> Result < Option < ChatState > , ChatError > {
71+ pub async fn select_model ( os : & Os , session : & mut ChatSession ) -> Result < Option < ChatState > , ChatError > {
5272 queue ! ( session. stderr, style:: Print ( "\n " ) ) ?;
5373 let active_model_id = session. conversation . model . as_deref ( ) ;
54- let labels: Vec < String > = MODEL_OPTIONS
74+ let model_options = get_model_options ( os) . await ?;
75+
76+ let labels: Vec < String > = model_options
5577 . iter ( )
5678 . map ( |opt| {
5779 if ( opt. model_id . is_empty ( ) && active_model_id. is_none ( ) ) || Some ( opt. model_id ) == active_model_id {
@@ -83,7 +105,7 @@ pub fn select_model(session: &mut ChatSession) -> Result<Option<ChatState>, Chat
83105 queue ! ( session. stderr, style:: ResetColor ) ?;
84106
85107 if let Some ( index) = selection {
86- let selected = & MODEL_OPTIONS [ index] ;
108+ let selected = & model_options [ index] ;
87109 let model_id_str = selected. model_id . to_string ( ) ;
88110 session. conversation . model = Some ( model_id_str) ;
89111
@@ -104,6 +126,8 @@ pub fn select_model(session: &mut ChatSession) -> Result<Option<ChatState>, Chat
104126 } ) )
105127}
106128
129+ /// Returns a default model id to use if none has been otherwise provided.
130+ ///
107131/// Returns Claude 3.7 for: Amazon IDC users, FRA region users
108132/// Returns Claude 4.0 for: Builder ID users, other regions
109133pub async fn default_model_id ( os : & Os ) -> & ' static str {
@@ -124,3 +148,35 @@ pub async fn default_model_id(os: &Os) -> &'static str {
124148 // Default to 4.0
125149 "CLAUDE_SONNET_4_20250514_V1_0"
126150}
151+
152+ /// Returns the available models for use.
153+ pub async fn get_model_options ( os : & Os ) -> Result < Vec < ModelOption > , ChatError > {
154+ let is_amzn_user = BuilderIdToken :: load ( & os. database )
155+ . await ?
156+ . ok_or ( AuthError :: NoToken ) ?
157+ . is_amzn_user ( ) ;
158+
159+ let mut model_options = MODEL_OPTIONS . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
160+ if is_amzn_user {
161+ for opt in OPENAI_MODEL_OPTIONS {
162+ model_options. push ( opt) ;
163+ }
164+ }
165+
166+ Ok ( model_options)
167+ }
168+
169+ /// Returns the context window length in tokens for the given model_id.
170+ pub fn context_window_tokens ( model_id : Option < & str > ) -> usize {
171+ const DEFAULT_CONTEXT_WINDOW_LENGTH : usize = 200_000 ;
172+
173+ let Some ( model_id) = model_id else {
174+ return DEFAULT_CONTEXT_WINDOW_LENGTH ;
175+ } ;
176+
177+ MODEL_OPTIONS
178+ . iter ( )
179+ . chain ( OPENAI_MODEL_OPTIONS . iter ( ) )
180+ . find ( |m| m. model_id == model_id)
181+ . map_or ( DEFAULT_CONTEXT_WINDOW_LENGTH , |m| m. context_window_tokens )
182+ }
0 commit comments