2025-08-22 17:12:10 +01:00
|
|
|
use crate::config_types::Verbosity as VerbosityConfig;
|
2025-05-08 21:46:06 -07:00
|
|
|
use crate::error::Result;
|
2025-08-04 23:50:03 -07:00
|
|
|
use crate::model_family::ModelFamily;
|
2025-08-06 01:13:31 -07:00
|
|
|
use crate::models::ContentItem;
|
2025-05-08 21:46:06 -07:00
|
|
|
use crate::models::ResponseItem;
|
2025-08-05 19:27:52 -07:00
|
|
|
use crate::openai_tools::OpenAiTool;
|
feat: show number of tokens remaining in UI (#1388)
When using the OpenAI Responses API, we now record the `usage` field for
a `"response.completed"` event, which includes metrics about the number
of tokens consumed. We also introduce `openai_model_info.rs`, which
includes current data about the most common OpenAI models available via
the API (specifically `context_window` and `max_output_tokens`). If
Codex does not recognize the model, you can set `model_context_window`
and `model_max_output_tokens` explicitly in `config.toml`.
When then introduce a new event type to `protocol.rs`, `TokenCount`,
which includes the `TokenUsage` for the most recent turn.
Finally, we update the TUI to record the running sum of tokens used so
the percentage of available context window remaining can be reported via
the placeholder text for the composer:

We could certainly get much fancier with this (such as reporting the
estimated cost of the conversation), but for now, we are just trying to
achieve feature parity with the TypeScript CLI.
Though arguably this improves upon the TypeScript CLI, as the TypeScript
CLI uses heuristics to estimate the number of tokens used rather than
using the `usage` information directly:
https://github.com/openai/codex/blob/296996d74e345b1b05d8c3451a06ace21c5ada96/codex-cli/src/utils/approximate-tokens-used.ts#L3-L16
Fixes https://github.com/openai/codex/issues/1242
2025-06-25 23:31:11 -07:00
|
|
|
use crate::protocol::TokenUsage;
|
fix: provide tolerance for apply_patch tool (#993)
As explained in detail in the doc comment for `ParseMode::Lenient`, we
have observed that GPT-4.1 does not always generate a valid invocation
of `apply_patch`. Fortunately, the error is predictable, so we introduce
some new logic to the `codex-apply-patch` crate to recover from this
error.
Because we would like to avoid this becoming a de facto standard (as it
would be incompatible if `apply_patch` were provided as an actual
executable, unless we also introduced the lenient behavior in the
executable, as well), we require passing `ParseMode::Lenient` to
`parse_patch_text()` to make it clear that the caller is opting into
supporting this special case.
Note the analogous change to the TypeScript CLI was
https://github.com/openai/codex/pull/930. In addition to changing the
accepted input to `apply_patch`, it also introduced additional
instructions for the model, which we include in this PR.
Note that `apply-patch` does not depend on either `regex` or
`regex-lite`, so some of the checks are slightly more verbose to avoid
introducing this dependency.
That said, this PR does not leverage the existing
`extract_heredoc_body_from_apply_patch_command()`, which depends on
`tree-sitter` and `tree-sitter-bash`:
https://github.com/openai/codex/blob/5a5aa899143f9b9ef606692c401b010368b15bdb/codex-rs/apply-patch/src/lib.rs#L191-L246
though perhaps it should.
2025-06-03 09:06:38 -07:00
|
|
|
use codex_apply_patch::APPLY_PATCH_TOOL_INSTRUCTIONS;
|
2025-08-18 11:50:17 -07:00
|
|
|
use codex_protocol::config_types::ReasoningEffort as ReasoningEffortConfig;
|
|
|
|
|
use codex_protocol::config_types::ReasoningSummary as ReasoningSummaryConfig;
|
2025-05-08 21:46:06 -07:00
|
|
|
use futures::Stream;
|
|
|
|
|
use serde::Serialize;
|
2025-05-12 17:24:44 -07:00
|
|
|
use std::borrow::Cow;
|
2025-05-08 21:46:06 -07:00
|
|
|
use std::pin::Pin;
|
|
|
|
|
use std::task::Context;
|
|
|
|
|
use std::task::Poll;
|
|
|
|
|
use tokio::sync::mpsc;
|
|
|
|
|
|
2025-05-12 17:24:44 -07:00
|
|
|
/// The `instructions` field in the payload sent to a model should always start
|
|
|
|
|
/// with this content.
|
|
|
|
|
const BASE_INSTRUCTIONS: &str = include_str!("../prompt.md");
|
|
|
|
|
|
2025-08-04 18:55:57 -07:00
|
|
|
/// wraps user instructions message in a tag for the model to parse more easily.
|
|
|
|
|
const USER_INSTRUCTIONS_START: &str = "<user_instructions>\n\n";
|
|
|
|
|
const USER_INSTRUCTIONS_END: &str = "\n\n</user_instructions>";
|
|
|
|
|
|
2025-08-14 14:51:13 -04:00
|
|
|
/// API request payload for a single model turn
|
2025-05-08 21:46:06 -07:00
|
|
|
#[derive(Default, Debug, Clone)]
|
|
|
|
|
pub struct Prompt {
|
|
|
|
|
/// Conversation context input items.
|
|
|
|
|
pub input: Vec<ResponseItem>,
|
2025-08-14 14:51:13 -04:00
|
|
|
|
2025-05-08 21:46:06 -07:00
|
|
|
/// Whether to store response on server side (disable_response_storage = !store).
|
|
|
|
|
pub store: bool,
|
|
|
|
|
|
2025-08-05 19:27:52 -07:00
|
|
|
/// Tools available to the model, including additional tools sourced from
|
|
|
|
|
/// external MCP servers.
|
|
|
|
|
pub tools: Vec<OpenAiTool>,
|
2025-07-22 09:42:22 -07:00
|
|
|
|
|
|
|
|
/// Optional override for the built-in BASE_INSTRUCTIONS.
|
|
|
|
|
pub base_instructions_override: Option<String>,
|
2025-05-08 21:46:06 -07:00
|
|
|
}
|
|
|
|
|
|
2025-05-12 17:24:44 -07:00
|
|
|
impl Prompt {
|
2025-08-04 23:50:03 -07:00
|
|
|
pub(crate) fn get_full_instructions(&self, model: &ModelFamily) -> Cow<'_, str> {
|
2025-07-22 09:42:22 -07:00
|
|
|
let base = self
|
|
|
|
|
.base_instructions_override
|
|
|
|
|
.as_deref()
|
|
|
|
|
.unwrap_or(BASE_INSTRUCTIONS);
|
|
|
|
|
let mut sections: Vec<&str> = vec![base];
|
2025-08-21 20:07:41 -07:00
|
|
|
|
|
|
|
|
// When there are no custom instructions, add apply_patch if either:
|
|
|
|
|
// - the model needs special instructions, or
|
|
|
|
|
// - there is no apply_patch tool present
|
|
|
|
|
let is_apply_patch_tool_present = self
|
|
|
|
|
.tools
|
|
|
|
|
.iter()
|
|
|
|
|
.any(|t| matches!(t, OpenAiTool::Function(f) if f.name == "apply_patch"));
|
|
|
|
|
if self.base_instructions_override.is_none()
|
|
|
|
|
&& (model.needs_special_apply_patch_instructions || !is_apply_patch_tool_present)
|
|
|
|
|
{
|
2025-06-03 09:40:19 -07:00
|
|
|
sections.push(APPLY_PATCH_TOOL_INSTRUCTIONS);
|
|
|
|
|
}
|
|
|
|
|
Cow::Owned(sections.join("\n"))
|
2025-05-12 17:24:44 -07:00
|
|
|
}
|
2025-08-04 18:55:57 -07:00
|
|
|
|
2025-08-14 14:51:13 -04:00
|
|
|
pub(crate) fn get_formatted_input(&self) -> Vec<ResponseItem> {
|
|
|
|
|
self.input.clone()
|
2025-08-06 01:13:31 -07:00
|
|
|
}
|
|
|
|
|
|
2025-08-14 14:51:13 -04:00
|
|
|
/// Creates a formatted user instructions message from a string
|
|
|
|
|
pub(crate) fn format_user_instructions_message(ui: &str) -> ResponseItem {
|
|
|
|
|
ResponseItem::Message {
|
|
|
|
|
id: None,
|
|
|
|
|
role: "user".to_string(),
|
|
|
|
|
content: vec![ContentItem::InputText {
|
|
|
|
|
text: format!("{USER_INSTRUCTIONS_START}{ui}{USER_INSTRUCTIONS_END}"),
|
|
|
|
|
}],
|
2025-08-06 01:13:31 -07:00
|
|
|
}
|
|
|
|
|
}
|
2025-05-12 17:24:44 -07:00
|
|
|
}
|
|
|
|
|
|
2025-05-08 21:46:06 -07:00
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub enum ResponseEvent {
|
2025-06-26 14:40:42 -04:00
|
|
|
Created,
|
2025-05-08 21:46:06 -07:00
|
|
|
OutputItemDone(ResponseItem),
|
feat: show number of tokens remaining in UI (#1388)
When using the OpenAI Responses API, we now record the `usage` field for
a `"response.completed"` event, which includes metrics about the number
of tokens consumed. We also introduce `openai_model_info.rs`, which
includes current data about the most common OpenAI models available via
the API (specifically `context_window` and `max_output_tokens`). If
Codex does not recognize the model, you can set `model_context_window`
and `model_max_output_tokens` explicitly in `config.toml`.
When then introduce a new event type to `protocol.rs`, `TokenCount`,
which includes the `TokenUsage` for the most recent turn.
Finally, we update the TUI to record the running sum of tokens used so
the percentage of available context window remaining can be reported via
the placeholder text for the composer:

We could certainly get much fancier with this (such as reporting the
estimated cost of the conversation), but for now, we are just trying to
achieve feature parity with the TypeScript CLI.
Though arguably this improves upon the TypeScript CLI, as the TypeScript
CLI uses heuristics to estimate the number of tokens used rather than
using the `usage` information directly:
https://github.com/openai/codex/blob/296996d74e345b1b05d8c3451a06ace21c5ada96/codex-cli/src/utils/approximate-tokens-used.ts#L3-L16
Fixes https://github.com/openai/codex/issues/1242
2025-06-25 23:31:11 -07:00
|
|
|
Completed {
|
|
|
|
|
response_id: String,
|
|
|
|
|
token_usage: Option<TokenUsage>,
|
|
|
|
|
},
|
2025-07-16 15:11:18 -07:00
|
|
|
OutputTextDelta(String),
|
|
|
|
|
ReasoningSummaryDelta(String),
|
2025-08-05 01:56:13 -07:00
|
|
|
ReasoningContentDelta(String),
|
2025-08-12 17:37:28 -07:00
|
|
|
ReasoningSummaryPartAdded,
|
2025-05-08 21:46:06 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
|
pub(crate) struct Reasoning {
|
2025-08-18 11:50:17 -07:00
|
|
|
pub(crate) effort: ReasoningEffortConfig,
|
|
|
|
|
pub(crate) summary: ReasoningSummaryConfig,
|
feat: make reasoning effort/summaries configurable (#1199)
Previous to this PR, we always set `reasoning` when making a request
using the Responses API:
https://github.com/openai/codex/blob/d7245cbbc9d8ff5446da45e5951761103492476d/codex-rs/core/src/client.rs#L108-L111
Though if you tried to use the Rust CLI with `--model gpt-4.1`, this
would fail with:
```shell
"Unsupported parameter: 'reasoning.effort' is not supported with this model."
```
We take a cue from the TypeScript CLI, which does a check on the model
name:
https://github.com/openai/codex/blob/d7245cbbc9d8ff5446da45e5951761103492476d/codex-cli/src/utils/agent/agent-loop.ts#L786-L789
This PR does a similar check, though also adds support for the following
config options:
```
model_reasoning_effort = "low" | "medium" | "high" | "none"
model_reasoning_summary = "auto" | "concise" | "detailed" | "none"
```
This way, if you have a model whose name happens to start with `"o"` (or
`"codex"`?), you can set these to `"none"` to explicitly disable
reasoning, if necessary. (That said, it seems unlikely anyone would use
the Responses API with non-OpenAI models, but we provide an escape
hatch, anyway.)
This PR also updates both the TUI and `codex exec` to show `reasoning
effort` and `reasoning summaries` in the header.
2025-06-02 16:01:34 -07:00
|
|
|
}
|
|
|
|
|
|
2025-08-22 17:12:10 +01:00
|
|
|
/// Controls under the `text` field in the Responses API for GPT-5.
|
|
|
|
|
#[derive(Debug, Serialize, Default, Clone, Copy)]
|
|
|
|
|
pub(crate) struct TextControls {
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub(crate) verbosity: Option<OpenAiVerbosity>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize, Default, Clone, Copy)]
|
|
|
|
|
#[serde(rename_all = "lowercase")]
|
|
|
|
|
pub(crate) enum OpenAiVerbosity {
|
|
|
|
|
Low,
|
|
|
|
|
#[default]
|
|
|
|
|
Medium,
|
|
|
|
|
High,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<VerbosityConfig> for OpenAiVerbosity {
|
|
|
|
|
fn from(v: VerbosityConfig) -> Self {
|
|
|
|
|
match v {
|
|
|
|
|
VerbosityConfig::Low => OpenAiVerbosity::Low,
|
|
|
|
|
VerbosityConfig::Medium => OpenAiVerbosity::Medium,
|
|
|
|
|
VerbosityConfig::High => OpenAiVerbosity::High,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat: make reasoning effort/summaries configurable (#1199)
Previous to this PR, we always set `reasoning` when making a request
using the Responses API:
https://github.com/openai/codex/blob/d7245cbbc9d8ff5446da45e5951761103492476d/codex-rs/core/src/client.rs#L108-L111
Though if you tried to use the Rust CLI with `--model gpt-4.1`, this
would fail with:
```shell
"Unsupported parameter: 'reasoning.effort' is not supported with this model."
```
We take a cue from the TypeScript CLI, which does a check on the model
name:
https://github.com/openai/codex/blob/d7245cbbc9d8ff5446da45e5951761103492476d/codex-cli/src/utils/agent/agent-loop.ts#L786-L789
This PR does a similar check, though also adds support for the following
config options:
```
model_reasoning_effort = "low" | "medium" | "high" | "none"
model_reasoning_summary = "auto" | "concise" | "detailed" | "none"
```
This way, if you have a model whose name happens to start with `"o"` (or
`"codex"`?), you can set these to `"none"` to explicitly disable
reasoning, if necessary. (That said, it seems unlikely anyone would use
the Responses API with non-OpenAI models, but we provide an escape
hatch, anyway.)
This PR also updates both the TUI and `codex exec` to show `reasoning
effort` and `reasoning summaries` in the header.
2025-06-02 16:01:34 -07:00
|
|
|
/// Request object that is serialized as JSON and POST'ed when using the
|
|
|
|
|
/// Responses API.
|
2025-05-08 21:46:06 -07:00
|
|
|
#[derive(Debug, Serialize)]
|
feat: make reasoning effort/summaries configurable (#1199)
Previous to this PR, we always set `reasoning` when making a request
using the Responses API:
https://github.com/openai/codex/blob/d7245cbbc9d8ff5446da45e5951761103492476d/codex-rs/core/src/client.rs#L108-L111
Though if you tried to use the Rust CLI with `--model gpt-4.1`, this
would fail with:
```shell
"Unsupported parameter: 'reasoning.effort' is not supported with this model."
```
We take a cue from the TypeScript CLI, which does a check on the model
name:
https://github.com/openai/codex/blob/d7245cbbc9d8ff5446da45e5951761103492476d/codex-cli/src/utils/agent/agent-loop.ts#L786-L789
This PR does a similar check, though also adds support for the following
config options:
```
model_reasoning_effort = "low" | "medium" | "high" | "none"
model_reasoning_summary = "auto" | "concise" | "detailed" | "none"
```
This way, if you have a model whose name happens to start with `"o"` (or
`"codex"`?), you can set these to `"none"` to explicitly disable
reasoning, if necessary. (That said, it seems unlikely anyone would use
the Responses API with non-OpenAI models, but we provide an escape
hatch, anyway.)
This PR also updates both the TUI and `codex exec` to show `reasoning
effort` and `reasoning summaries` in the header.
2025-06-02 16:01:34 -07:00
|
|
|
pub(crate) struct ResponsesApiRequest<'a> {
|
2025-05-08 21:46:06 -07:00
|
|
|
pub(crate) model: &'a str,
|
2025-05-12 17:24:44 -07:00
|
|
|
pub(crate) instructions: &'a str,
|
2025-05-08 21:46:06 -07:00
|
|
|
// TODO(mbolin): ResponseItem::Other should not be serialized. Currently,
|
|
|
|
|
// we code defensively to avoid this case, but perhaps we should use a
|
|
|
|
|
// separate enum for serialization.
|
|
|
|
|
pub(crate) input: &'a Vec<ResponseItem>,
|
|
|
|
|
pub(crate) tools: &'a [serde_json::Value],
|
|
|
|
|
pub(crate) tool_choice: &'static str,
|
|
|
|
|
pub(crate) parallel_tool_calls: bool,
|
|
|
|
|
pub(crate) reasoning: Option<Reasoning>,
|
|
|
|
|
/// true when using the Responses API.
|
|
|
|
|
pub(crate) store: bool,
|
|
|
|
|
pub(crate) stream: bool,
|
2025-07-23 10:37:45 -07:00
|
|
|
pub(crate) include: Vec<String>,
|
2025-08-11 16:37:45 -07:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub(crate) prompt_cache_key: Option<String>,
|
2025-08-22 17:12:10 +01:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub(crate) text: Option<TextControls>,
|
2025-05-08 21:46:06 -07:00
|
|
|
}
|
|
|
|
|
|
feat: make reasoning effort/summaries configurable (#1199)
Previous to this PR, we always set `reasoning` when making a request
using the Responses API:
https://github.com/openai/codex/blob/d7245cbbc9d8ff5446da45e5951761103492476d/codex-rs/core/src/client.rs#L108-L111
Though if you tried to use the Rust CLI with `--model gpt-4.1`, this
would fail with:
```shell
"Unsupported parameter: 'reasoning.effort' is not supported with this model."
```
We take a cue from the TypeScript CLI, which does a check on the model
name:
https://github.com/openai/codex/blob/d7245cbbc9d8ff5446da45e5951761103492476d/codex-cli/src/utils/agent/agent-loop.ts#L786-L789
This PR does a similar check, though also adds support for the following
config options:
```
model_reasoning_effort = "low" | "medium" | "high" | "none"
model_reasoning_summary = "auto" | "concise" | "detailed" | "none"
```
This way, if you have a model whose name happens to start with `"o"` (or
`"codex"`?), you can set these to `"none"` to explicitly disable
reasoning, if necessary. (That said, it seems unlikely anyone would use
the Responses API with non-OpenAI models, but we provide an escape
hatch, anyway.)
This PR also updates both the TUI and `codex exec` to show `reasoning
effort` and `reasoning summaries` in the header.
2025-06-02 16:01:34 -07:00
|
|
|
pub(crate) fn create_reasoning_param_for_request(
|
2025-08-04 23:50:03 -07:00
|
|
|
model_family: &ModelFamily,
|
feat: make reasoning effort/summaries configurable (#1199)
Previous to this PR, we always set `reasoning` when making a request
using the Responses API:
https://github.com/openai/codex/blob/d7245cbbc9d8ff5446da45e5951761103492476d/codex-rs/core/src/client.rs#L108-L111
Though if you tried to use the Rust CLI with `--model gpt-4.1`, this
would fail with:
```shell
"Unsupported parameter: 'reasoning.effort' is not supported with this model."
```
We take a cue from the TypeScript CLI, which does a check on the model
name:
https://github.com/openai/codex/blob/d7245cbbc9d8ff5446da45e5951761103492476d/codex-cli/src/utils/agent/agent-loop.ts#L786-L789
This PR does a similar check, though also adds support for the following
config options:
```
model_reasoning_effort = "low" | "medium" | "high" | "none"
model_reasoning_summary = "auto" | "concise" | "detailed" | "none"
```
This way, if you have a model whose name happens to start with `"o"` (or
`"codex"`?), you can set these to `"none"` to explicitly disable
reasoning, if necessary. (That said, it seems unlikely anyone would use
the Responses API with non-OpenAI models, but we provide an escape
hatch, anyway.)
This PR also updates both the TUI and `codex exec` to show `reasoning
effort` and `reasoning summaries` in the header.
2025-06-02 16:01:34 -07:00
|
|
|
effort: ReasoningEffortConfig,
|
|
|
|
|
summary: ReasoningSummaryConfig,
|
|
|
|
|
) -> Option<Reasoning> {
|
2025-08-04 23:50:03 -07:00
|
|
|
if model_family.supports_reasoning_summaries {
|
2025-08-18 11:50:17 -07:00
|
|
|
Some(Reasoning { effort, summary })
|
feat: make reasoning effort/summaries configurable (#1199)
Previous to this PR, we always set `reasoning` when making a request
using the Responses API:
https://github.com/openai/codex/blob/d7245cbbc9d8ff5446da45e5951761103492476d/codex-rs/core/src/client.rs#L108-L111
Though if you tried to use the Rust CLI with `--model gpt-4.1`, this
would fail with:
```shell
"Unsupported parameter: 'reasoning.effort' is not supported with this model."
```
We take a cue from the TypeScript CLI, which does a check on the model
name:
https://github.com/openai/codex/blob/d7245cbbc9d8ff5446da45e5951761103492476d/codex-cli/src/utils/agent/agent-loop.ts#L786-L789
This PR does a similar check, though also adds support for the following
config options:
```
model_reasoning_effort = "low" | "medium" | "high" | "none"
model_reasoning_summary = "auto" | "concise" | "detailed" | "none"
```
This way, if you have a model whose name happens to start with `"o"` (or
`"codex"`?), you can set these to `"none"` to explicitly disable
reasoning, if necessary. (That said, it seems unlikely anyone would use
the Responses API with non-OpenAI models, but we provide an escape
hatch, anyway.)
This PR also updates both the TUI and `codex exec` to show `reasoning
effort` and `reasoning summaries` in the header.
2025-06-02 16:01:34 -07:00
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-22 17:12:10 +01:00
|
|
|
pub(crate) fn create_text_param_for_request(
|
|
|
|
|
verbosity: Option<VerbosityConfig>,
|
|
|
|
|
) -> Option<TextControls> {
|
|
|
|
|
verbosity.map(|v| TextControls {
|
|
|
|
|
verbosity: Some(v.into()),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-08 21:46:06 -07:00
|
|
|
pub(crate) struct ResponseStream {
|
|
|
|
|
pub(crate) rx_event: mpsc::Receiver<Result<ResponseEvent>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Stream for ResponseStream {
|
|
|
|
|
type Item = Result<ResponseEvent>;
|
|
|
|
|
|
|
|
|
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
|
|
|
|
self.rx_event.poll_recv(cx)
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-07-30 13:56:24 -07:00
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
2025-08-04 23:50:03 -07:00
|
|
|
use crate::model_family::find_family_for_model;
|
|
|
|
|
|
2025-07-30 13:56:24 -07:00
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn get_full_instructions_no_user_content() {
|
|
|
|
|
let prompt = Prompt {
|
|
|
|
|
..Default::default()
|
|
|
|
|
};
|
|
|
|
|
let expected = format!("{BASE_INSTRUCTIONS}\n{APPLY_PATCH_TOOL_INSTRUCTIONS}");
|
2025-08-04 23:50:03 -07:00
|
|
|
let model_family = find_family_for_model("gpt-4.1").expect("known model slug");
|
|
|
|
|
let full = prompt.get_full_instructions(&model_family);
|
2025-07-30 13:56:24 -07:00
|
|
|
assert_eq!(full, expected);
|
|
|
|
|
}
|
2025-08-22 17:12:10 +01:00
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn serializes_text_verbosity_when_set() {
|
|
|
|
|
let input: Vec<ResponseItem> = vec![];
|
|
|
|
|
let tools: Vec<serde_json::Value> = vec![];
|
|
|
|
|
let req = ResponsesApiRequest {
|
|
|
|
|
model: "gpt-5",
|
|
|
|
|
instructions: "i",
|
|
|
|
|
input: &input,
|
|
|
|
|
tools: &tools,
|
|
|
|
|
tool_choice: "auto",
|
|
|
|
|
parallel_tool_calls: false,
|
|
|
|
|
reasoning: None,
|
|
|
|
|
store: true,
|
|
|
|
|
stream: true,
|
|
|
|
|
include: vec![],
|
|
|
|
|
prompt_cache_key: None,
|
|
|
|
|
text: Some(TextControls {
|
|
|
|
|
verbosity: Some(OpenAiVerbosity::Low),
|
|
|
|
|
}),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let v = serde_json::to_value(&req).expect("json");
|
|
|
|
|
assert_eq!(
|
|
|
|
|
v.get("text")
|
|
|
|
|
.and_then(|t| t.get("verbosity"))
|
|
|
|
|
.and_then(|s| s.as_str()),
|
|
|
|
|
Some("low")
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn omits_text_when_not_set() {
|
|
|
|
|
let input: Vec<ResponseItem> = vec![];
|
|
|
|
|
let tools: Vec<serde_json::Value> = vec![];
|
|
|
|
|
let req = ResponsesApiRequest {
|
|
|
|
|
model: "gpt-5",
|
|
|
|
|
instructions: "i",
|
|
|
|
|
input: &input,
|
|
|
|
|
tools: &tools,
|
|
|
|
|
tool_choice: "auto",
|
|
|
|
|
parallel_tool_calls: false,
|
|
|
|
|
reasoning: None,
|
|
|
|
|
store: true,
|
|
|
|
|
stream: true,
|
|
|
|
|
include: vec![],
|
|
|
|
|
prompt_cache_key: None,
|
|
|
|
|
text: None,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let v = serde_json::to_value(&req).expect("json");
|
|
|
|
|
assert!(v.get("text").is_none());
|
|
|
|
|
}
|
2025-07-30 13:56:24 -07:00
|
|
|
}
|