mirror of
https://github.com/openai/codex.git
synced 2026-06-03 20:02:10 +00:00
Compare commits
5 Commits
dev/carlc/
...
codemode_i
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c9ff87229c | ||
|
|
7266686103 | ||
|
|
9d98f6cf96 | ||
|
|
3f51cc1806 | ||
|
|
4fc3f11dee |
@@ -4916,23 +4916,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"TurnModerationMetadataNotification": {
|
||||
"properties": {
|
||||
"metadata": true,
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
},
|
||||
"turnId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"metadata",
|
||||
"threadId",
|
||||
"turnId"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"TurnPlanStep": {
|
||||
"properties": {
|
||||
"status": {
|
||||
@@ -6272,26 +6255,6 @@
|
||||
"title": "Model/verificationNotification",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"method": {
|
||||
"enum": [
|
||||
"turn/moderationMetadata"
|
||||
],
|
||||
"title": "Turn/moderationMetadataNotificationMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/TurnModerationMetadataNotification"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Turn/moderationMetadataNotification",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"method": {
|
||||
|
||||
@@ -4904,26 +4904,6 @@
|
||||
"title": "Model/verificationNotification",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"method": {
|
||||
"enum": [
|
||||
"turn/moderationMetadata"
|
||||
],
|
||||
"title": "Turn/moderationMetadataNotificationMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/v2/TurnModerationMetadataNotification"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Turn/moderationMetadataNotification",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"method": {
|
||||
@@ -18503,25 +18483,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"TurnModerationMetadataNotification": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
"metadata": true,
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
},
|
||||
"turnId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"metadata",
|
||||
"threadId",
|
||||
"turnId"
|
||||
],
|
||||
"title": "TurnModerationMetadataNotification",
|
||||
"type": "object"
|
||||
},
|
||||
"TurnPlanStep": {
|
||||
"properties": {
|
||||
"status": {
|
||||
|
||||
@@ -12302,26 +12302,6 @@
|
||||
"title": "Model/verificationNotification",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"method": {
|
||||
"enum": [
|
||||
"turn/moderationMetadata"
|
||||
],
|
||||
"title": "Turn/moderationMetadataNotificationMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"$ref": "#/definitions/TurnModerationMetadataNotification"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"method",
|
||||
"params"
|
||||
],
|
||||
"title": "Turn/moderationMetadataNotification",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"method": {
|
||||
@@ -16320,25 +16300,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"TurnModerationMetadataNotification": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
"metadata": true,
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
},
|
||||
"turnId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"metadata",
|
||||
"threadId",
|
||||
"turnId"
|
||||
],
|
||||
"title": "TurnModerationMetadataNotification",
|
||||
"type": "object"
|
||||
},
|
||||
"TurnPlanStep": {
|
||||
"properties": {
|
||||
"status": {
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
"metadata": true,
|
||||
"threadId": {
|
||||
"type": "string"
|
||||
},
|
||||
"turnId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"metadata",
|
||||
"threadId",
|
||||
"turnId"
|
||||
],
|
||||
"title": "TurnModerationMetadataNotification",
|
||||
"type": "object"
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,6 +0,0 @@
|
||||
// GENERATED CODE! DO NOT MODIFY BY HAND!
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { JsonValue } from "../serde_json/JsonValue";
|
||||
|
||||
export type TurnModerationMetadataNotification = { threadId: string, turnId: string, metadata: JsonValue, };
|
||||
@@ -445,7 +445,6 @@ export type { TurnError } from "./TurnError";
|
||||
export type { TurnInterruptParams } from "./TurnInterruptParams";
|
||||
export type { TurnInterruptResponse } from "./TurnInterruptResponse";
|
||||
export type { TurnItemsView } from "./TurnItemsView";
|
||||
export type { TurnModerationMetadataNotification } from "./TurnModerationMetadataNotification";
|
||||
export type { TurnPlanStep } from "./TurnPlanStep";
|
||||
export type { TurnPlanStepStatus } from "./TurnPlanStepStatus";
|
||||
export type { TurnPlanUpdatedNotification } from "./TurnPlanUpdatedNotification";
|
||||
|
||||
@@ -1537,7 +1537,6 @@ server_notification_definitions! {
|
||||
ContextCompacted => "thread/compacted" (v2::ContextCompactedNotification),
|
||||
ModelRerouted => "model/rerouted" (v2::ModelReroutedNotification),
|
||||
ModelVerification => "model/verification" (v2::ModelVerificationNotification),
|
||||
TurnModerationMetadata => "turn/moderationMetadata" (v2::TurnModerationMetadataNotification),
|
||||
Warning => "warning" (v2::WarningNotification),
|
||||
GuardianWarning => "guardianWarning" (v2::GuardianWarningNotification),
|
||||
DeprecationNotice => "deprecationNotice" (v2::DeprecationNoticeNotification),
|
||||
|
||||
@@ -8,7 +8,6 @@ use codex_protocol::protocol::ModelVerification as CoreModelVerification;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use serde_json::Value as JsonValue;
|
||||
use ts_rs::TS;
|
||||
|
||||
v2_enum_from_core!(
|
||||
@@ -153,12 +152,3 @@ pub struct ModelVerificationNotification {
|
||||
pub turn_id: String,
|
||||
pub verifications: Vec<ModelVerification>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct TurnModerationMetadataNotification {
|
||||
pub thread_id: String,
|
||||
pub turn_id: String,
|
||||
pub metadata: JsonValue,
|
||||
}
|
||||
|
||||
@@ -1242,7 +1242,6 @@ The app-server streams JSON-RPC notifications while a turn is running. Each turn
|
||||
- `turn/plan/updated` — `{ turnId, explanation?, plan }` whenever the agent shares or changes its plan; each `plan` entry is `{ step, status }` with `status` in `pending`, `inProgress`, or `completed`.
|
||||
- `model/rerouted` — `{ threadId, turnId, fromModel, toModel, reason }` when the backend reroutes a request to a different model (for example, due to high-risk cyber safety checks).
|
||||
- `model/verification` — `{ threadId, turnId, verifications }` when the backend flags additional account verification, such as `trustedAccessForCyber`.
|
||||
- `turn/moderationMetadata` — `{ threadId, turnId, metadata }` when a first-party backend supplies turn-scoped moderation metadata for client-side presentation.
|
||||
|
||||
Today both notifications carry an empty `items` array even when item events were streamed; rely on `item/*` notifications for the canonical item list until this is fixed.
|
||||
|
||||
|
||||
@@ -75,7 +75,6 @@ use codex_app_server_protocol::TurnDiffUpdatedNotification;
|
||||
use codex_app_server_protocol::TurnError;
|
||||
use codex_app_server_protocol::TurnInterruptResponse;
|
||||
use codex_app_server_protocol::TurnItemsView;
|
||||
use codex_app_server_protocol::TurnModerationMetadataNotification;
|
||||
use codex_app_server_protocol::TurnPlanStep;
|
||||
use codex_app_server_protocol::TurnPlanUpdatedNotification;
|
||||
use codex_app_server_protocol::TurnStartedNotification;
|
||||
@@ -338,16 +337,6 @@ pub(crate) async fn apply_bespoke_event_handling(
|
||||
.send_server_notification(ServerNotification::ModelVerification(notification))
|
||||
.await;
|
||||
}
|
||||
EventMsg::TurnModerationMetadata(event) => {
|
||||
let notification = TurnModerationMetadataNotification {
|
||||
thread_id: conversation_id.to_string(),
|
||||
turn_id: event_turn_id.clone(),
|
||||
metadata: event.metadata,
|
||||
};
|
||||
outgoing
|
||||
.send_server_notification(ServerNotification::TurnModerationMetadata(notification))
|
||||
.await;
|
||||
}
|
||||
EventMsg::RealtimeConversationStarted(event) => {
|
||||
let notification = ThreadRealtimeStartedNotification {
|
||||
thread_id: conversation_id.to_string(),
|
||||
|
||||
@@ -725,7 +725,6 @@ mod tests {
|
||||
use codex_app_server_protocol::RateLimitWindow;
|
||||
use codex_app_server_protocol::ServerResponse;
|
||||
use codex_app_server_protocol::ToolRequestUserInputParams;
|
||||
use codex_app_server_protocol::TurnModerationMetadataNotification;
|
||||
use codex_protocol::ThreadId;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::json;
|
||||
@@ -952,31 +951,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_turn_moderation_metadata_notification_serialization() {
|
||||
let notification =
|
||||
ServerNotification::TurnModerationMetadata(TurnModerationMetadataNotification {
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
metadata: json!({"presentation": "inline"}),
|
||||
});
|
||||
|
||||
let jsonrpc_notification = OutgoingMessage::AppServerNotification(notification);
|
||||
assert_eq!(
|
||||
json!({
|
||||
"method": "turn/moderationMetadata",
|
||||
"params": {
|
||||
"threadId": "thread-1",
|
||||
"turnId": "turn-1",
|
||||
"metadata": {"presentation": "inline"},
|
||||
},
|
||||
}),
|
||||
serde_json::to_value(jsonrpc_notification)
|
||||
.expect("ensure the notification serializes correctly"),
|
||||
"ensure the notification serializes correctly"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn server_request_response_from_result_decodes_typed_response() {
|
||||
let request = ServerRequest::CommandExecutionRequestApproval {
|
||||
|
||||
@@ -30,6 +30,12 @@ use wiremock::matchers::path;
|
||||
|
||||
const RESULT: &str = "cG5n";
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum ImagegenTestMode {
|
||||
Direct,
|
||||
CodeModeOnly,
|
||||
}
|
||||
|
||||
// macOS and Windows Bazel CI can spend tens of seconds starting app-server
|
||||
// subprocesses or processing test RPCs under load.
|
||||
#[cfg(any(target_os = "macos", windows))]
|
||||
@@ -69,7 +75,7 @@ async fn standalone_image_generation_persists_image_and_returns_it_to_model() ->
|
||||
.await;
|
||||
|
||||
let codex_home = TempDir::new()?;
|
||||
create_config_toml(codex_home.path(), &server.uri())?;
|
||||
create_config_toml(codex_home.path(), &server.uri(), ImagegenTestMode::Direct)?;
|
||||
write_chatgpt_auth(
|
||||
codex_home.path(),
|
||||
ChatGptAuthFixture::new("access-chatgpt"),
|
||||
@@ -79,34 +85,7 @@ async fn standalone_image_generation_persists_image_and_returns_it_to_model() ->
|
||||
let mut mcp =
|
||||
TestAppServer::new_with_env(codex_home.path(), &[("OPENAI_API_KEY", None)]).await?;
|
||||
timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??;
|
||||
|
||||
let thread_req = mcp
|
||||
.send_thread_start_request(ThreadStartParams::default())
|
||||
.await?;
|
||||
let thread_resp: JSONRPCResponse = timeout(
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
mcp.read_stream_until_response_message(RequestId::Integer(thread_req)),
|
||||
)
|
||||
.await??;
|
||||
let ThreadStartResponse { thread, .. } = to_response::<ThreadStartResponse>(thread_resp)?;
|
||||
|
||||
let turn_req = mcp
|
||||
.send_turn_start_request(TurnStartParams {
|
||||
thread_id: thread.id,
|
||||
client_user_message_id: None,
|
||||
input: vec![V2UserInput::Text {
|
||||
text: "Generate an image".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
let turn_resp: JSONRPCResponse = timeout(
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
mcp.read_stream_until_response_message(RequestId::Integer(turn_req)),
|
||||
)
|
||||
.await??;
|
||||
let _turn: TurnStartResponse = to_response::<TurnStartResponse>(turn_resp)?;
|
||||
start_image_generation_turn(&mut mcp).await?;
|
||||
|
||||
let completed = timeout(
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
@@ -157,6 +136,110 @@ async fn standalone_image_generation_persists_image_and_returns_it_to_model() ->
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg_attr(windows, ignore = "covered by Linux and macOS CI")]
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn standalone_image_generation_is_callable_from_code_mode_only() -> Result<()> {
|
||||
let call_id = "code-mode-image-run-1";
|
||||
let server = responses::start_mock_server().await;
|
||||
mount_image_response(&server).await;
|
||||
|
||||
let response_mock = responses::mount_sse_sequence(
|
||||
&server,
|
||||
vec![
|
||||
responses::sse(vec![
|
||||
responses::ev_response_created("resp-1"),
|
||||
responses::ev_custom_tool_call(
|
||||
call_id,
|
||||
"exec",
|
||||
r#"
|
||||
const result = await tools.image_gen__imagegen({
|
||||
action: "generate",
|
||||
prompt: "paint a blue whale",
|
||||
});
|
||||
image(result);
|
||||
"#,
|
||||
),
|
||||
responses::ev_completed("resp-1"),
|
||||
]),
|
||||
responses::sse(vec![
|
||||
responses::ev_assistant_message("msg-1", "Done"),
|
||||
responses::ev_completed("resp-2"),
|
||||
]),
|
||||
],
|
||||
)
|
||||
.await;
|
||||
|
||||
let codex_home = TempDir::new()?;
|
||||
create_config_toml(
|
||||
codex_home.path(),
|
||||
&server.uri(),
|
||||
ImagegenTestMode::CodeModeOnly,
|
||||
)?;
|
||||
write_chatgpt_auth(
|
||||
codex_home.path(),
|
||||
ChatGptAuthFixture::new("access-chatgpt"),
|
||||
AuthCredentialsStoreMode::File,
|
||||
)?;
|
||||
|
||||
let mut mcp =
|
||||
TestAppServer::new_with_env(codex_home.path(), &[("OPENAI_API_KEY", None)]).await?;
|
||||
timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??;
|
||||
start_image_generation_turn(&mut mcp).await?;
|
||||
timeout(
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
mcp.read_stream_until_notification_message("turn/completed"),
|
||||
)
|
||||
.await??;
|
||||
|
||||
let requests = response_mock.requests();
|
||||
assert_eq!(requests.len(), 2);
|
||||
assert!(requests[0].body_contains_text("image_gen__imagegen"));
|
||||
let output = requests[1].custom_tool_call_output(call_id);
|
||||
assert_eq!(
|
||||
output["output"][1],
|
||||
json!({
|
||||
"type": "input_image",
|
||||
"image_url": format!("data:image/png;base64,{RESULT}"),
|
||||
"detail": "high",
|
||||
})
|
||||
);
|
||||
assert_eq!(output["output"].as_array().map(Vec::len), Some(2));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn start_image_generation_turn(mcp: &mut TestAppServer) -> Result<()> {
|
||||
let thread_req = mcp
|
||||
.send_thread_start_request(ThreadStartParams::default())
|
||||
.await?;
|
||||
let thread_resp: JSONRPCResponse = timeout(
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
mcp.read_stream_until_response_message(RequestId::Integer(thread_req)),
|
||||
)
|
||||
.await??;
|
||||
let ThreadStartResponse { thread, .. } = to_response::<ThreadStartResponse>(thread_resp)?;
|
||||
|
||||
let turn_req = mcp
|
||||
.send_turn_start_request(TurnStartParams {
|
||||
thread_id: thread.id,
|
||||
client_user_message_id: None,
|
||||
input: vec![V2UserInput::Text {
|
||||
text: "Generate an image".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
..Default::default()
|
||||
})
|
||||
.await?;
|
||||
let turn_resp: JSONRPCResponse = timeout(
|
||||
DEFAULT_READ_TIMEOUT,
|
||||
mcp.read_stream_until_response_message(RequestId::Integer(turn_req)),
|
||||
)
|
||||
.await??;
|
||||
let _turn: TurnStartResponse = to_response::<TurnStartResponse>(turn_resp)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn wait_for_image_generation_completed(
|
||||
mcp: &mut TestAppServer,
|
||||
) -> Result<ItemCompletedNotification> {
|
||||
@@ -187,7 +270,15 @@ async fn mount_image_response(server: &MockServer) {
|
||||
.await;
|
||||
}
|
||||
|
||||
fn create_config_toml(codex_home: &Path, server_uri: &str) -> std::io::Result<()> {
|
||||
fn create_config_toml(
|
||||
codex_home: &Path,
|
||||
server_uri: &str,
|
||||
mode: ImagegenTestMode,
|
||||
) -> std::io::Result<()> {
|
||||
let code_mode_only = match mode {
|
||||
ImagegenTestMode::Direct => "",
|
||||
ImagegenTestMode::CodeModeOnly => "code_mode_only = true",
|
||||
};
|
||||
std::fs::write(
|
||||
codex_home.join("config.toml"),
|
||||
format!(
|
||||
@@ -200,6 +291,7 @@ chatgpt_base_url = "{server_uri}"
|
||||
|
||||
[features]
|
||||
imagegenext = true
|
||||
{code_mode_only}
|
||||
|
||||
[model_providers.openai-custom]
|
||||
name = "OpenAI"
|
||||
@@ -17,7 +17,7 @@ mod experimental_feature_list;
|
||||
mod external_agent_config;
|
||||
mod fs;
|
||||
mod hooks_list;
|
||||
mod image_generation;
|
||||
mod imagegen_extension;
|
||||
mod initialize;
|
||||
mod marketplace_add;
|
||||
mod marketplace_remove;
|
||||
|
||||
@@ -6,7 +6,6 @@ use codex_protocol::openai_models::ReasoningEffort as ReasoningEffortConfig;
|
||||
use codex_protocol::protocol::ModelVerification;
|
||||
use codex_protocol::protocol::RateLimitSnapshot;
|
||||
use codex_protocol::protocol::TokenUsage;
|
||||
use codex_protocol::protocol::TurnModerationMetadataEvent;
|
||||
use codex_protocol::protocol::W3cTraceContext;
|
||||
use futures::Stream;
|
||||
use serde::Deserialize;
|
||||
@@ -79,8 +78,6 @@ pub enum ResponseEvent {
|
||||
ServerModel(String),
|
||||
/// Emitted when the server recommends additional account verification.
|
||||
ModelVerifications(Vec<ModelVerification>),
|
||||
/// Emitted when the server includes moderation metadata for first-party turn presentation.
|
||||
TurnModerationMetadata(TurnModerationMetadataEvent),
|
||||
/// Emitted when `X-Reasoning-Included: true` is present on the response,
|
||||
/// meaning the server already accounted for past reasoning tokens and the
|
||||
/// client should not re-estimate them.
|
||||
|
||||
@@ -718,7 +718,6 @@ async fn run_websocket_response_stream(
|
||||
}
|
||||
};
|
||||
let model_verifications = event.model_verifications();
|
||||
let turn_moderation_metadata = event.turn_moderation_metadata();
|
||||
if event.kind() == "codex.rate_limits" {
|
||||
if let Some(snapshot) = parse_rate_limit_event(&text) {
|
||||
let _ = tx_event.send(Ok(ResponseEvent::RateLimits(snapshot))).await;
|
||||
@@ -743,16 +742,6 @@ async fn run_websocket_response_stream(
|
||||
"response event consumer dropped".to_string(),
|
||||
));
|
||||
}
|
||||
if let Some(metadata) = turn_moderation_metadata
|
||||
&& tx_event
|
||||
.send(Ok(ResponseEvent::TurnModerationMetadata(metadata)))
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
return Err(ApiError::Stream(
|
||||
"response event consumer dropped".to_string(),
|
||||
));
|
||||
}
|
||||
match process_responses_event(event) {
|
||||
Ok(Some(event)) => {
|
||||
let is_completed = matches!(event, ResponseEvent::Completed { .. });
|
||||
|
||||
@@ -8,7 +8,6 @@ use codex_client::StreamResponse;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::protocol::ModelVerification;
|
||||
use codex_protocol::protocol::TokenUsage;
|
||||
use codex_protocol::protocol::TurnModerationMetadataEvent;
|
||||
use eventsource_stream::Eventsource;
|
||||
use futures::StreamExt;
|
||||
use serde::Deserialize;
|
||||
@@ -194,18 +193,6 @@ impl ResponsesStreamEvent {
|
||||
.and_then(|metadata| metadata.get("openai_verification_recommendation"))
|
||||
.and_then(model_verifications_from_json_value)
|
||||
}
|
||||
|
||||
pub(crate) fn turn_moderation_metadata(&self) -> Option<TurnModerationMetadataEvent> {
|
||||
if self.kind() != "response.metadata" {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.metadata
|
||||
.as_ref()
|
||||
.and_then(|metadata| metadata.get("openai_chatgpt_moderation_metadata"))
|
||||
.cloned()
|
||||
.map(|metadata| TurnModerationMetadataEvent { metadata })
|
||||
}
|
||||
}
|
||||
|
||||
fn header_openai_model_value_from_json(value: &Value) -> Option<String> {
|
||||
@@ -457,7 +444,6 @@ pub async fn process_sse(
|
||||
}
|
||||
};
|
||||
let model_verifications = event.model_verifications();
|
||||
let turn_moderation_metadata = event.turn_moderation_metadata();
|
||||
|
||||
if let Some(model) = event.response_model()
|
||||
&& last_server_model.as_deref() != Some(model.as_str())
|
||||
@@ -479,14 +465,6 @@ pub async fn process_sse(
|
||||
{
|
||||
return;
|
||||
}
|
||||
if let Some(metadata) = turn_moderation_metadata
|
||||
&& tx_event
|
||||
.send(Ok(ResponseEvent::TurnModerationMetadata(metadata)))
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
match process_responses_event(event) {
|
||||
Ok(Some(event)) => {
|
||||
@@ -1237,41 +1215,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn process_sse_emits_turn_moderation_metadata_field() {
|
||||
let events = run_sse(vec![
|
||||
json!({
|
||||
"type": "response.metadata",
|
||||
"metadata": {
|
||||
"openai_chatgpt_moderation_metadata": {
|
||||
"presentation": "inline"
|
||||
}
|
||||
}
|
||||
}),
|
||||
json!({
|
||||
"type": "response.completed",
|
||||
"response": {
|
||||
"id": "resp-1"
|
||||
}
|
||||
}),
|
||||
])
|
||||
.await;
|
||||
|
||||
assert_matches!(
|
||||
&events[0],
|
||||
ResponseEvent::TurnModerationMetadata(result)
|
||||
if result.metadata == json!({"presentation": "inline"})
|
||||
);
|
||||
assert_matches!(
|
||||
&events[1],
|
||||
ResponseEvent::Completed {
|
||||
response_id,
|
||||
token_usage: None,
|
||||
end_turn: None,
|
||||
} if response_id == "resp-1"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn responses_stream_event_response_model_reads_top_level_headers() {
|
||||
let ev: ResponsesStreamEvent = serde_json::from_value(json!({
|
||||
|
||||
@@ -20,6 +20,7 @@ use codex_protocol::protocol::EventMsg;
|
||||
use codex_protocol::protocol::InitialHistory;
|
||||
use codex_protocol::protocol::Op;
|
||||
use codex_protocol::protocol::RolloutItem;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
use codex_protocol::protocol::SessionSource;
|
||||
use codex_protocol::protocol::SubAgentSource;
|
||||
use codex_protocol::protocol::TokenUsage;
|
||||
@@ -718,7 +719,9 @@ async fn run_review_on_session(
|
||||
.total_token_usage()
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
// The legacy SandboxPolicy should match the PermissionProfile.
|
||||
let guardian_permission_profile = PermissionProfile::read_only();
|
||||
let legacy_sandbox_policy = SandboxPolicy::new_read_only_policy();
|
||||
|
||||
let submit_result = run_before_review_deadline(
|
||||
deadline,
|
||||
@@ -733,7 +736,7 @@ async fn run_review_on_session(
|
||||
#[allow(deprecated)]
|
||||
cwd: Some(params.parent_turn.cwd.to_path_buf()),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: None,
|
||||
sandbox_policy: Some(legacy_sandbox_policy),
|
||||
permission_profile: Some(guardian_permission_profile),
|
||||
summary: Some(params.reasoning_summary),
|
||||
personality: params.personality,
|
||||
|
||||
@@ -359,7 +359,6 @@ use codex_protocol::protocol::ThreadMemoryMode;
|
||||
use codex_protocol::protocol::TokenCountEvent;
|
||||
use codex_protocol::protocol::TokenUsage;
|
||||
use codex_protocol::protocol::TokenUsageInfo;
|
||||
use codex_protocol::protocol::TurnModerationMetadataEvent;
|
||||
use codex_protocol::protocol::WarningEvent;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use codex_tools::ToolEnvironmentMode;
|
||||
@@ -2629,15 +2628,6 @@ impl Session {
|
||||
.await;
|
||||
}
|
||||
|
||||
pub(crate) async fn emit_turn_moderation_metadata(
|
||||
self: &Arc<Self>,
|
||||
turn_context: &Arc<TurnContext>,
|
||||
metadata: TurnModerationMetadataEvent,
|
||||
) {
|
||||
self.send_event(turn_context, EventMsg::TurnModerationMetadata(metadata))
|
||||
.await;
|
||||
}
|
||||
|
||||
pub(crate) async fn replace_history(
|
||||
&self,
|
||||
items: Vec<ResponseItem>,
|
||||
|
||||
@@ -1322,7 +1322,6 @@ pub(super) fn realtime_text_for_event(msg: &EventMsg) -> Option<String> {
|
||||
| EventMsg::RealtimeConversationClosed(_)
|
||||
| EventMsg::ModelReroute(_)
|
||||
| EventMsg::ModelVerification(_)
|
||||
| EventMsg::TurnModerationMetadata(_)
|
||||
| EventMsg::ContextCompacted(_)
|
||||
| EventMsg::ThreadRolledBack(_)
|
||||
| EventMsg::TurnStarted(_)
|
||||
@@ -1988,10 +1987,6 @@ async fn try_run_sampling_request(
|
||||
.await;
|
||||
}
|
||||
}
|
||||
ResponseEvent::TurnModerationMetadata(metadata) => {
|
||||
sess.emit_turn_moderation_metadata(&turn_context, metadata)
|
||||
.await;
|
||||
}
|
||||
ResponseEvent::ServerReasoningIncluded(included) => {
|
||||
sess.set_server_reasoning_included(included).await;
|
||||
}
|
||||
|
||||
@@ -147,7 +147,6 @@ fn response_event_records_turn_ttft(event: &ResponseEvent) -> bool {
|
||||
ResponseEvent::Created
|
||||
| ResponseEvent::ServerModel(_)
|
||||
| ResponseEvent::ModelVerifications(_)
|
||||
| ResponseEvent::TurnModerationMetadata(_)
|
||||
| ResponseEvent::ServerReasoningIncluded(_)
|
||||
| ResponseEvent::ToolCallInputDelta { .. }
|
||||
| ResponseEvent::Completed { .. }
|
||||
|
||||
@@ -77,9 +77,9 @@ impl ToolExecutor<ToolCall> for ImageGenerationTool {
|
||||
imagegen_tool_spec()
|
||||
}
|
||||
|
||||
/// Keeps this model-facing tool out of the nested code-mode tool surface.
|
||||
/// Exposes image generation directly and through the nested code-mode tool surface.
|
||||
fn exposure(&self) -> ToolExposure {
|
||||
ToolExposure::DirectModelOnly
|
||||
ToolExposure::Direct
|
||||
}
|
||||
|
||||
/// Executes the selected image operation and returns the completed image result.
|
||||
|
||||
@@ -266,8 +266,7 @@ async fn run_codex_tool_session_inner(
|
||||
}
|
||||
EventMsg::Warning(_)
|
||||
| EventMsg::GuardianWarning(_)
|
||||
| EventMsg::ModelVerification(_)
|
||||
| EventMsg::TurnModerationMetadata(_) => {
|
||||
| EventMsg::ModelVerification(_) => {
|
||||
continue;
|
||||
}
|
||||
EventMsg::GuardianAssessment(_) => {
|
||||
|
||||
@@ -1177,7 +1177,6 @@ impl SessionTelemetry {
|
||||
}
|
||||
ResponseEvent::ServerModel(_) => "server_model".into(),
|
||||
ResponseEvent::ModelVerifications(_) => "model_verifications".into(),
|
||||
ResponseEvent::TurnModerationMetadata(_) => "turn_moderation_metadata".into(),
|
||||
ResponseEvent::ServerReasoningIncluded(_) => "server_reasoning_included".into(),
|
||||
ResponseEvent::RateLimits(_) => "rate_limits".into(),
|
||||
ResponseEvent::ModelsEtag(_) => "models_etag".into(),
|
||||
|
||||
@@ -1186,9 +1186,6 @@ pub enum EventMsg {
|
||||
/// Backend recommends additional account verification for this turn.
|
||||
ModelVerification(ModelVerificationEvent),
|
||||
|
||||
/// Backend moderation metadata intended for first-party turn presentation.
|
||||
TurnModerationMetadata(TurnModerationMetadataEvent),
|
||||
|
||||
/// Conversation history was compacted (either automatically or manually).
|
||||
ContextCompacted(ContextCompactedEvent),
|
||||
|
||||
@@ -1853,11 +1850,6 @@ pub struct ModelVerificationEvent {
|
||||
pub verifications: Vec<ModelVerification>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)]
|
||||
pub struct TurnModerationMetadataEvent {
|
||||
pub metadata: Value,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
|
||||
pub struct ContextCompactedEvent;
|
||||
|
||||
|
||||
@@ -224,7 +224,6 @@ pub(crate) fn tool_runtime_trace_event(event: &EventMsg) -> Option<ToolRuntimeTr
|
||||
| EventMsg::RealtimeConversationSdp(_)
|
||||
| EventMsg::ModelReroute(_)
|
||||
| EventMsg::ModelVerification(_)
|
||||
| EventMsg::TurnModerationMetadata(_)
|
||||
| EventMsg::ContextCompacted(_)
|
||||
| EventMsg::ThreadRolledBack(_)
|
||||
| EventMsg::ThreadGoalUpdated(_)
|
||||
@@ -298,7 +297,6 @@ pub(crate) fn wrapped_protocol_event_type(event: &EventMsg) -> Option<&'static s
|
||||
| EventMsg::RealtimeConversationSdp(_)
|
||||
| EventMsg::ModelReroute(_)
|
||||
| EventMsg::ModelVerification(_)
|
||||
| EventMsg::TurnModerationMetadata(_)
|
||||
| EventMsg::ContextCompacted(_)
|
||||
| EventMsg::ThreadSettingsApplied(_)
|
||||
| EventMsg::TokenCount(_)
|
||||
|
||||
@@ -115,7 +115,6 @@ pub fn should_persist_event_msg(ev: &EventMsg) -> bool {
|
||||
| EventMsg::RealtimeConversationClosed(_)
|
||||
| EventMsg::ModelReroute(_)
|
||||
| EventMsg::ModelVerification(_)
|
||||
| EventMsg::TurnModerationMetadata(_)
|
||||
| EventMsg::AgentReasoningSectionBreak(_)
|
||||
| EventMsg::RawResponseItem(_)
|
||||
| EventMsg::SessionConfigured(_)
|
||||
|
||||
@@ -118,9 +118,6 @@ pub(super) fn server_notification_thread_target(
|
||||
ServerNotification::ModelVerification(notification) => {
|
||||
Some(notification.thread_id.as_str())
|
||||
}
|
||||
ServerNotification::TurnModerationMetadata(notification) => {
|
||||
Some(notification.thread_id.as_str())
|
||||
}
|
||||
ServerNotification::ThreadRealtimeStarted(notification) => {
|
||||
Some(notification.thread_id.as_str())
|
||||
}
|
||||
|
||||
@@ -233,7 +233,6 @@ impl ChatWidget {
|
||||
| ServerNotification::RemoteControlStatusChanged(_)
|
||||
| ServerNotification::ExternalAgentConfigImportCompleted(_)
|
||||
| ServerNotification::FsChanged(_)
|
||||
| ServerNotification::TurnModerationMetadata(_)
|
||||
| ServerNotification::FuzzyFileSearchSessionUpdated(_)
|
||||
| ServerNotification::FuzzyFileSearchSessionCompleted(_)
|
||||
| ServerNotification::ThreadRealtimeTranscriptDelta(_)
|
||||
|
||||
Reference in New Issue
Block a user