mirror of
https://github.com/openai/codex.git
synced 2026-11-10 21:00:47 +00:00
Preserve display instructions in answer moderation (#60172)
## Why Recovered answer history needs presentation instructions alongside the moderation flag so clients can apply the intended display behavior. ## What changed - Add optional `display` metadata with an `action` and optional `blockType`, `cyberTrustedAccess`, and `checkTrustedContacts` fields. - Carry display metadata through final answers, legacy events, thread history reconstruction, and legacy rollout migration. - Expose the metadata in the app-server protocol and update generated JSON schemas, TypeScript types, and Python SDK models. Missing display fields remain compatible with existing stored moderation data; the app-server emits absent optional values as `null`. ## Testing Extend the final-answer moderation test to cover display metadata in answer items and legacy events. Add serialization coverage for missing display data, nullable fields, and preservation of an explicit `false` value. GitOrigin-RevId: b798a2ecc53c2a94c7659ef3d9663b3143b70a1a
This commit is contained in:
@@ -151,9 +151,30 @@ pub struct AsyncUserInputQuestion {
|
||||
pub options: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, TS, JsonSchema)]
|
||||
/// A presentation instruction for Chat to apply to this answer when recovering history.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, TS, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct AgentMessageDisplay {
|
||||
/// Unknown actions must be left for the producing client to handle.
|
||||
pub action: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub block_type: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub cyber_trusted_access: Option<bool>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub check_trusted_contacts: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, TS, JsonSchema)]
|
||||
pub struct AgentMessageModeration {
|
||||
pub moderated: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub display: Option<AgentMessageDisplay>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, TS, JsonSchema)]
|
||||
|
||||
@@ -139,13 +139,14 @@ impl AgentMessageItem {
|
||||
questions: self.questions.clone(),
|
||||
})
|
||||
};
|
||||
if let Some(decision) = self.moderation {
|
||||
if let Some(decision) = &self.moderation {
|
||||
// The canonical answer has one ID even when the model supplied multiple text parts.
|
||||
return vec![event(
|
||||
texts.collect(),
|
||||
Some(crate::protocol::TargetedAnswerModeration {
|
||||
item_id: self.id.clone(),
|
||||
moderated: decision.moderated,
|
||||
display: decision.display.clone(),
|
||||
}),
|
||||
)];
|
||||
}
|
||||
|
||||
@@ -2400,6 +2400,9 @@ pub struct ModelVerificationEvent {
|
||||
pub struct TargetedAnswerModeration {
|
||||
pub item_id: String,
|
||||
pub moderated: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub display: Option<crate::items::AgentMessageDisplay>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)]
|
||||
|
||||
Reference in New Issue
Block a user