88
99#![ allow( clippy:: unwrap_used, clippy:: expect_used) ]
1010
11- use std:: collections:: HashSet ;
11+ use std:: { collections:: HashSet , sync :: Arc } ;
1212
1313use {
1414 futures:: StreamExt ,
15- moltis_agents:: model:: { ChatMessage , LlmProvider , StreamEvent , ToolCall } ,
15+ moltis_agents:: model:: { ChatMessage , LlmProvider , ReasoningEffort , StreamEvent , ToolCall } ,
1616 moltis_providers:: openai:: OpenAiProvider ,
1717 secrecy:: { ExposeSecret , Secret } ,
1818} ;
1919
2020const OPENAI_BASE_URL : & str = "https://api.openai.com/v1" ;
2121const TEST_MODEL : & str = "gpt-5-mini" ;
22+ const LUNA_MODEL : & str = "gpt-5.6-luna" ;
2223
2324/// Known OpenAI models we catalog. Keep in sync with `DEFAULT_OPENAI_MODELS`
24- /// in `crates/providers/src/openai.rs`.
25- const KNOWN_MODELS : & [ & str ] = & [ "gpt-5.2" , "gpt-5.2-chat-latest" , "gpt-5-mini" ] ;
25+ /// in `crates/providers/src/openai/catalog.rs`.
26+ const KNOWN_MODELS : & [ & str ] = & [
27+ "gpt-5.6-sol" ,
28+ "gpt-5.6-terra" ,
29+ LUNA_MODEL ,
30+ "gpt-5.2" ,
31+ "gpt-5.2-chat-latest" ,
32+ TEST_MODEL ,
33+ ] ;
2634
2735fn api_key ( ) -> Secret < String > {
2836 let key =
@@ -34,6 +42,12 @@ fn make_provider(model: &str) -> OpenAiProvider {
3442 OpenAiProvider :: new ( api_key ( ) , model. to_string ( ) , OPENAI_BASE_URL . to_string ( ) )
3543}
3644
45+ fn make_provider_with_reasoning ( model : & str , effort : ReasoningEffort ) -> Arc < dyn LlmProvider > {
46+ Arc :: new ( make_provider ( model) )
47+ . with_reasoning_effort ( effort)
48+ . expect ( "OpenAI provider should support reasoning_effort" )
49+ }
50+
3751fn weather_tool ( ) -> serde_json:: Value {
3852 serde_json:: json!( {
3953 "name" : "get_weather" ,
@@ -170,6 +184,37 @@ async fn tool_call_round_trip_streaming() {
170184 assert_eq ! ( tool_name, "get_weather" ) ;
171185}
172186
187+ #[ tokio:: test]
188+ #[ ignore]
189+ async fn luna_reasoning_tool_call_uses_responses_api ( ) {
190+ let p = make_provider_with_reasoning ( LUNA_MODEL , ReasoningEffort :: High ) ;
191+ let messages = vec ! [ ChatMessage :: user(
192+ "What's the weather in Paris? Use the get_weather tool." ,
193+ ) ] ;
194+
195+ let mut stream = p. stream_with_tools ( messages, vec ! [ weather_tool( ) ] ) ;
196+ let mut saw_tool_start = false ;
197+ let mut saw_done = false ;
198+
199+ while let Some ( event) = stream. next ( ) . await {
200+ match event {
201+ StreamEvent :: ToolCallStart { name, .. } => {
202+ assert_eq ! ( name, "get_weather" ) ;
203+ saw_tool_start = true ;
204+ } ,
205+ StreamEvent :: Done ( _) => {
206+ saw_done = true ;
207+ break ;
208+ } ,
209+ StreamEvent :: Error ( err) => panic ! ( "stream error: {err}" ) ,
210+ _ => { } ,
211+ }
212+ }
213+
214+ assert ! ( saw_done, "Luna reasoning tool stream must emit Done" ) ;
215+ assert ! ( saw_tool_start, "Luna should call get_weather" ) ;
216+ }
217+
173218#[ tokio:: test]
174219#[ ignore]
175220async fn multi_turn_tool_use ( ) {
@@ -261,6 +306,7 @@ async fn catalog_models_are_live() {
261306 eprintln ! ( "==================================\n " ) ;
262307
263308 assert ! ( alive. contains( & TEST_MODEL ) , "{TEST_MODEL} should be live" ) ;
309+ assert ! ( alive. contains( & LUNA_MODEL ) , "{LUNA_MODEL} should be live" ) ;
264310}
265311
266312#[ tokio:: test]
0 commit comments