Commit Diff


commit - 80d01e8e19c1b9b7f13401442cd44218746a79ca
commit + c5b95489c75049dee80844b53e706be704929dfb
blob - c518f977566828fb20eba8b47b4db91a7070735b
blob + e7752d5851ce6dd49241bb19fd098610f22b89ae
--- src/cli.rs
+++ src/cli.rs
@@ -4,7 +4,7 @@ use std::time::Duration;
 
 use crate::openai::{Message, ReasoningEffort};
 use clap::{
-    arg, builder::PossibleValue, command, value_parser, ArgGroup, ArgMatches, Command, ValueEnum,
+    ArgGroup, ArgMatches, Command, ValueEnum, arg, builder::PossibleValue, command, value_parser,
 };
 use derive_builder::Builder;
 
@@ -14,7 +14,8 @@ pub struct Invocation {
     pub api_key: Option<String>,
     pub messages: Vec<Message>,
     pub model: String,
-    pub temperature: f32,
+    #[builder(default)]
+    pub temperature: Option<f32>,
     pub output_format: OutputFormat,
     pub file: String,
     pub timeout: Duration,
@@ -40,11 +41,10 @@ pub fn parse() -> Invocation {
 /// Top-level command
 fn cli() -> Command {
     command!()
-        .arg(arg!(model: -m --model <MODEL> "Sets model. See https://platform.openai.com/docs/models for model identifiers.").default_value("gpt-5"))
+        .arg(arg!(model: -m --model <MODEL> "Sets model. See https://platform.openai.com/docs/models for model identifiers.").default_value("gpt-5.5"))
         .arg(
             arg!(temperature: -t --temperature <TEMP> "Sets temperature")
-                .value_parser(value_parser!(f32))
-                .default_value("0.0"),
+                .value_parser(value_parser!(f32)),
         )
         .arg(
             arg!(timeout: -T --timeout <DURATION> "Sets timeout duration in seconds")
@@ -92,9 +92,7 @@ impl From<ArgMatches> for Invocation {
             .expect("Models is required")
             .to_string();
 
-        let temperature = *matches
-            .get_one::<f32>("temperature")
-            .expect("Temperature is required");
+        let temperature = matches.get_one::<f32>("temperature").copied();
 
         let timeout = matches
             .get_one::<u64>("timeout")
@@ -272,7 +270,8 @@ mod test {
                 Message::assistant("ROBOT"),
                 Message::user("USER2"),
             ],
-            "system message is always brought to front, followed by assistant and user messages in order");
+            "system message is always brought to front, followed by assistant and user messages in order"
+        );
 
         Ok(())
     }
blob - 385cb933f50e88ff173b340a8a8252a807509bab
blob + 076c7e1b35e95e97574dc4be3b457573adc05731
--- src/exec/chat.rs
+++ src/exec/chat.rs
@@ -1,9 +1,9 @@
 //! Implements chat subcommand
 
+use crate::Error;
 use crate::cli::{Invocation, OutputFormat};
 use crate::openai::{self, FinishReason, Message, Reasoning, Response};
 use crate::parse;
-use crate::Error;
 
 use anyhow::{Context, Result};
 use std::fs::File;
@@ -81,7 +81,7 @@ fn show_response(dest: impl Write, args: &Invocation, 
             return Err(Error::UnexpectedResponse(format!(
                 "Unexpected number of choices in response: {:?}",
                 resp
-            )))
+            )));
         }
     };
 
@@ -100,7 +100,7 @@ fn show_response(dest: impl Write, args: &Invocation, 
             return Err(Error::UnexpectedResponse(format!(
                 "Received unrecognized stop reason for choice: {:?}",
                 choice
-            )))
+            )));
         }
     }
 
@@ -196,7 +196,7 @@ mod test {
             .api_key(Some(String::default()))
             .messages(vec![])
             .model(String::default())
-            .temperature(1.0)
+            .temperature(Some(1.0))
             .output_format(OutputFormat::Plaintext)
             .timeout(Duration::from_secs(10))
             .file("-".to_string())
blob - e2497fbce7911cb9f73c40389e1cb841a474879b
blob + e0e9bedd15e252c826cee3ae5507c2a1bba259a3
--- src/openai.rs
+++ src/openai.rs
@@ -9,7 +9,7 @@ use chrono::{DateTime, Utc};
 use derive_builder::Builder;
 use reqwest::StatusCode;
 use serde::{Deserialize, Serialize};
-use serde_json::{json, Value};
+use serde_json::{Value, json};
 
 /// Convienience Client for OpenAI Responses API
 pub struct Client {
@@ -27,7 +27,8 @@ pub struct Client {
 pub struct ResponseRequest {
     model: String,
     messages: Vec<Message>,
-    temperature: f32,
+    #[builder(default)]
+    temperature: Option<f32>,
     timeout: Duration,
     #[builder(default)]
     reasoning: Option<Reasoning>,
@@ -191,7 +192,7 @@ impl Message {
         json!({
             "role": self.role.as_str(),
             "content": [{
-                "type": "text",
+                "type": "input_text",
                 "text": self.content.clone(),
             }]
         })
@@ -223,16 +224,22 @@ impl ResponseRequest {
         let mut payload = json!({
             "model": self.model,
             "input": input,
-            "temperature": self.temperature,
         });
 
+        if let Some(temperature) = self.temperature
+            && let Some(obj) = payload.as_object_mut()
+        {
+            obj.insert("temperature".to_string(), json!(temperature));
+        }
+
         if let Some(reasoning) = &self.reasoning
-            && let Some(obj) = payload.as_object_mut() {
-                obj.insert(
-                    "reasoning".to_string(),
-                    serde_json::to_value(reasoning).expect("failed to serialize reasoning"),
-                );
-            }
+            && let Some(obj) = payload.as_object_mut()
+        {
+            obj.insert(
+                "reasoning".to_string(),
+                serde_json::to_value(reasoning).expect("failed to serialize reasoning"),
+            );
+        }
 
         payload
     }
@@ -246,6 +253,7 @@ impl Response {
 
 #[derive(Debug, Deserialize)]
 struct ResponsesAPIResponse {
+    #[serde(rename = "created_at", alias = "created")]
     #[serde(with = "ts_seconds")]
     created: DateTime<Utc>,
     model: String,
@@ -419,7 +427,7 @@ mod test {
         let request = ResponseRequest::builder()
             .model("gpt-5".to_string())
             .messages(vec![Message::user("Hello")])
-            .temperature(0.0)
+            .temperature(Some(0.0))
             .timeout(Duration::from_secs(30))
             .reasoning(Some(Reasoning::from_effort(ReasoningEffort::High)))
             .build()
@@ -429,6 +437,7 @@ mod test {
 
         assert_eq!(payload["reasoning"]["effort"], "high");
         assert_eq!(payload["model"], "gpt-5");
+        assert_eq!(payload["temperature"], 0.0);
 
         Ok(())
     }
@@ -438,7 +447,6 @@ mod test {
         let request = ResponseRequest::builder()
             .model("gpt-5".to_string())
             .messages(vec![Message::user("Hello")])
-            .temperature(0.0)
             .timeout(Duration::from_secs(30))
             .build()
             .expect("request builds");
@@ -446,6 +454,7 @@ mod test {
         let payload = request.to_payload();
 
         assert!(payload.get("reasoning").is_none());
+        assert!(payload.get("temperature").is_none());
         Ok(())
     }
 
blob - 05b4e04c7c77c264b5006ba51802f1006384b482
blob + b5bfc88ba906ba1e4d7e8addfd1917c584906417
--- tests/chat.rs
+++ tests/chat.rs
@@ -35,11 +35,11 @@ fn chat_user_message_from_flag() {
         .with_header("content-type", "application/json")
         .with_header("authorization", "Bearer ABCDE")
         .match_body(mockito::Matcher::PartialJson(json!({
-            "model": "gpt-5",
+            "model": "gpt-5.5",
             "input": [{
                 "role": "user",
                 "content": [{
-                    "type": "text",
+                    "type": "input_text",
                     "text": "Hello"
                 }]
             }]
@@ -48,7 +48,7 @@ fn chat_user_message_from_flag() {
             r#"{
              "id": "resp_XXXXX",
              "created": 1688413145,
-             "model": "gpt-5",
+             "model": "gpt-5.5",
              "output": [{
                  "id": "msg_XXXXX",
                  "type": "message",
@@ -89,11 +89,11 @@ fn chat_user_message_from_stdin() {
         .with_header("content-type", "application/json")
         .with_header("authorization", "Bearer ABCDE")
         .match_body(mockito::Matcher::PartialJson(json!({
-            "model": "gpt-5",
+            "model": "gpt-5.5",
             "input": [{
                 "role": "user",
                 "content": [{
-                    "type": "text",
+                    "type": "input_text",
                     "text": "Hello"
                 }]
             }]
@@ -102,7 +102,7 @@ fn chat_user_message_from_stdin() {
             r#"{
              "id": "resp_XXXXX",
              "created": 1688413145,
-             "model": "gpt-5",
+             "model": "gpt-5.5",
              "output": [{
                  "id": "msg_XXXXX",
                  "type": "message",
@@ -143,14 +143,14 @@ fn chat_with_reasoning_effort() {
         .with_header("content-type", "application/json")
         .with_header("authorization", "Bearer ABCDE")
         .match_body(mockito::Matcher::PartialJson(json!({
-            "model": "gpt-5",
+            "model": "gpt-5.5",
             "reasoning": {
                 "effort": "medium"
             },
             "input": [{
                 "role": "user",
                 "content": [{
-                    "type": "text",
+                    "type": "input_text",
                     "text": "Hello"
                 }]
             }]
@@ -159,7 +159,7 @@ fn chat_with_reasoning_effort() {
             r#"{
              "id": "resp_XXXXX",
              "created": 1688413145,
-             "model": "gpt-5",
+             "model": "gpt-5.5",
              "output": [{
                  "id": "msg_XXXXX",
                  "type": "message",
@@ -205,41 +205,41 @@ fn chat_multiple_messages() {
         .with_header("content-type", "application/json")
         .with_header("authorization", "Bearer ABCDE")
         .match_body(mockito::Matcher::PartialJson(json!({
-            "model": "gpt-5",
+            "model": "gpt-5.5",
             "input": [{
                 "role": "system",
                 "content": [{
-                    "type": "text",
+                    "type": "input_text",
                     "text": "SYSTEM"
                 }],
             }, {
                 "role": "user",
                 "content": [{
-                    "type": "text",
+                    "type": "input_text",
                     "text": "USER_1"
                 }],
             }, {
                 "role": "assistant",
                 "content": [{
-                    "type": "text",
+                    "type": "input_text",
                     "text": "ASSI_1"
                 }],
             }, {
                 "role": "user",
                 "content": [{
-                    "type": "text",
+                    "type": "input_text",
                     "text": "USER_2"
                 }],
             }, {
                 "role": "assistant",
                 "content": [{
-                    "type": "text",
+                    "type": "input_text",
                     "text": "ASSI_2"
                 }],
             }, {
                 "role": "user",
                 "content": [{
-                    "type": "text",
+                    "type": "input_text",
                     "text": "USER_STDIN"
                 }],
             }]
@@ -248,7 +248,7 @@ fn chat_multiple_messages() {
             r#"{
              "id": "resp_XXXXX",
              "created": 1688413145,
-             "model": "gpt-5",
+             "model": "gpt-5.5",
              "output": [{
                  "id": "msg_XXXXX",
                  "type": "message",
@@ -294,11 +294,11 @@ fn chat_api_error() {
         .with_header("content-type", "application/json")
         .with_header("authorization", "Bearer ABCDE")
         .match_body(mockito::Matcher::PartialJson(json!({
-            "model": "gpt-5",
+            "model": "gpt-5.5",
             "input": [{
                 "role": "user",
                 "content": [{
-                    "type": "text",
+                    "type": "input_text",
                     "text": "USER"
                 }],
             }],
@@ -344,11 +344,11 @@ fn chat_user_message_from_file() {
         .with_header("content-type", "application/json")
         .with_header("authorization", "Bearer ABCDE")
         .match_body(mockito::Matcher::PartialJson(json!({
-            "model": "gpt-5",
+            "model": "gpt-5.5",
             "input": [{
                 "role": "user",
                 "content": [{
-                    "type": "text",
+                    "type": "input_text",
                     "text": "Hello from file"
                 }],
             }],
@@ -357,7 +357,7 @@ fn chat_user_message_from_file() {
             r#"{
              "id": "resp_XXXXX",
              "created": 1688413145,
-             "model": "gpt-5",
+             "model": "gpt-5.5",
              "output": [{
                  "id": "msg_XXXXX",
                  "type": "message",