diff --git a/codex-rs/app-server-protocol/schema/json/ServerNotification.json b/codex-rs/app-server-protocol/schema/json/ServerNotification.json index 52198ba6b5..f39713d496 100644 --- a/codex-rs/app-server-protocol/schema/json/ServerNotification.json +++ b/codex-rs/app-server-protocol/schema/json/ServerNotification.json @@ -178,35 +178,100 @@ "type": "object" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageModeration": { "properties": { @@ -232,6 +297,47 @@ "AgentPath": { "type": "string" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "AppBranding": { "description": "EXPERIMENTAL - app metadata returned by app-list APIs.", "properties": { @@ -686,6 +792,50 @@ ], "type": "string" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "ByteRange": { "properties": { "end": { @@ -2414,6 +2564,13 @@ ], "type": "object" }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookCompletedNotification": { "properties": { "run": { @@ -6671,6 +6828,13 @@ ], "type": "object" }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "Turn": { "properties": { "completedAt": { diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index 0e44ea9dea..762933428e 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -7409,35 +7409,100 @@ "type": "object" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/v2/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/v2/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/v2/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/v2/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageInputContent": { "oneOf": [ @@ -7526,6 +7591,47 @@ }, "type": "object" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/v2/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "AppBranding": { "description": "EXPERIMENTAL - app metadata returned by app-list APIs.", "properties": { @@ -8584,6 +8690,50 @@ ], "type": "string" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "BrowserUseAccessApprovalLifetime": { "enum": [ "turn", @@ -14015,6 +14165,13 @@ "title": "GuardianWarningNotification", "type": "object" }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookCompletedNotification": { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { @@ -27403,6 +27560,13 @@ }, "type": "object" }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "Turn": { "properties": { "completedAt": { diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json index 89b9537f0b..d26f060332 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json @@ -524,35 +524,100 @@ "type": "object" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageInputContent": { "oneOf": [ @@ -641,6 +706,47 @@ }, "type": "object" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "AppBranding": { "description": "EXPERIMENTAL - app metadata returned by app-list APIs.", "properties": { @@ -1699,6 +1805,50 @@ ], "type": "string" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "BrowserUseAccessApprovalLifetime": { "enum": [ "turn", @@ -9907,6 +10057,13 @@ "title": "GuardianWarningNotification", "type": "object" }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookCompletedNotification": { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { @@ -25106,6 +25263,13 @@ }, "type": "object" }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "Turn": { "properties": { "completedAt": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json index 7d82adcdc2..3964c269fc 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ItemCompletedNotification.json @@ -12,35 +12,100 @@ "type": "string" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageModeration": { "properties": { @@ -63,6 +128,47 @@ ], "type": "object" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "AsyncUserInputQuestion": { "additionalProperties": false, "properties": { @@ -84,6 +190,50 @@ ], "type": "object" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "ByteRange": { "properties": { "end": { @@ -527,6 +677,13 @@ } ] }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -1817,6 +1974,13 @@ }, "type": "object" }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "UserInput": { "oneOf": [ { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json index ad9ddd5b05..861e638fd3 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ItemStartedNotification.json @@ -12,35 +12,100 @@ "type": "string" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageModeration": { "properties": { @@ -63,6 +128,47 @@ ], "type": "object" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "AsyncUserInputQuestion": { "additionalProperties": false, "properties": { @@ -84,6 +190,50 @@ ], "type": "object" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "ByteRange": { "properties": { "end": { @@ -527,6 +677,13 @@ } ] }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -1817,6 +1974,13 @@ }, "type": "object" }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "UserInput": { "oneOf": [ { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json index 6a027403d1..0cc138260a 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ReviewStartResponse.json @@ -12,35 +12,100 @@ "type": "string" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageModeration": { "properties": { @@ -63,6 +128,47 @@ ], "type": "object" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "AsyncUserInputQuestion": { "additionalProperties": false, "properties": { @@ -84,6 +190,50 @@ ], "type": "object" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "ByteRange": { "properties": { "end": { @@ -684,6 +834,13 @@ } ] }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -2029,6 +2186,13 @@ }, "type": "object" }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "Turn": { "properties": { "completedAt": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json index d0cb7ef6ad..bf0f3700cf 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json @@ -32,35 +32,100 @@ "type": "string" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageModeration": { "properties": { @@ -86,6 +151,47 @@ "AgentPath": { "type": "string" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "ApprovalsReviewer": { "description": "Configures who approval requests are routed to for review. Examples include sandbox escapes, blocked network access, MCP approval prompts, and ARC escalations. Defaults to `user`. `auto_review` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request. The legacy value `guardian_subagent` is accepted for compatibility.", "enum": [ @@ -165,6 +271,50 @@ ], "type": "object" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "ByteRange": { "properties": { "end": { @@ -788,6 +938,13 @@ }, "type": "object" }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -2769,6 +2926,13 @@ } ] }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "Turn": { "properties": { "completedAt": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadItemsListResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadItemsListResponse.json index 5ab4f7ed23..586a2aa11e 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadItemsListResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadItemsListResponse.json @@ -12,35 +12,100 @@ "type": "string" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageModeration": { "properties": { @@ -63,6 +128,47 @@ ], "type": "object" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "AsyncUserInputQuestion": { "additionalProperties": false, "properties": { @@ -84,6 +190,50 @@ ], "type": "object" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "ByteRange": { "properties": { "end": { @@ -527,6 +677,13 @@ } ] }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -1849,6 +2006,13 @@ ], "type": "object" }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "UserInput": { "oneOf": [ { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json index 3f7b745ce1..ca46c1894f 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadListResponse.json @@ -12,35 +12,100 @@ "type": "string" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageModeration": { "properties": { @@ -66,6 +131,47 @@ "AgentPath": { "type": "string" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "AsyncUserInputQuestion": { "additionalProperties": false, "properties": { @@ -87,6 +193,50 @@ ], "type": "object" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "ByteRange": { "properties": { "end": { @@ -710,6 +860,13 @@ }, "type": "object" }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -2624,6 +2781,13 @@ } ] }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "Turn": { "properties": { "completedAt": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadMetadataUpdateResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadMetadataUpdateResponse.json index b4cef43629..414dc05459 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadMetadataUpdateResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadMetadataUpdateResponse.json @@ -12,35 +12,100 @@ "type": "string" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageModeration": { "properties": { @@ -66,6 +131,47 @@ "AgentPath": { "type": "string" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "AsyncUserInputQuestion": { "additionalProperties": false, "properties": { @@ -87,6 +193,50 @@ ], "type": "object" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "ByteRange": { "properties": { "end": { @@ -710,6 +860,13 @@ }, "type": "object" }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -2560,6 +2717,13 @@ } ] }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "Turn": { "properties": { "completedAt": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json index 483f0ad846..4b2f012ba7 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadReadResponse.json @@ -12,35 +12,100 @@ "type": "string" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageModeration": { "properties": { @@ -66,6 +131,47 @@ "AgentPath": { "type": "string" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "AsyncUserInputQuestion": { "additionalProperties": false, "properties": { @@ -87,6 +193,50 @@ ], "type": "object" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "ByteRange": { "properties": { "end": { @@ -710,6 +860,13 @@ }, "type": "object" }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -2624,6 +2781,13 @@ } ] }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "Turn": { "properties": { "completedAt": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json index 4818843ecd..f0ea2047d6 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json @@ -32,35 +32,100 @@ "type": "string" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageModeration": { "properties": { @@ -86,6 +151,47 @@ "AgentPath": { "type": "string" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "ApprovalsReviewer": { "description": "Configures who approval requests are routed to for review. Examples include sandbox escapes, blocked network access, MCP approval prompts, and ARC escalations. Defaults to `user`. `auto_review` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request. The legacy value `guardian_subagent` is accepted for compatibility.", "enum": [ @@ -165,6 +271,50 @@ ], "type": "object" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "ByteRange": { "properties": { "end": { @@ -804,6 +954,13 @@ }, "type": "object" }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -2821,6 +2978,13 @@ } ] }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "Turn": { "properties": { "completedAt": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadRevertResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadRevertResponse.json index b39cff7aac..58ebb693b9 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadRevertResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadRevertResponse.json @@ -12,35 +12,100 @@ "type": "string" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageModeration": { "properties": { @@ -66,6 +131,47 @@ "AgentPath": { "type": "string" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "AsyncUserInputQuestion": { "additionalProperties": false, "properties": { @@ -87,6 +193,50 @@ ], "type": "object" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "ByteRange": { "properties": { "end": { @@ -710,6 +860,13 @@ }, "type": "object" }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -2560,6 +2717,13 @@ } ] }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "Turn": { "properties": { "completedAt": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json index d0b7314bac..119aa09d6b 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json @@ -32,35 +32,100 @@ "type": "string" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageModeration": { "properties": { @@ -86,6 +151,47 @@ "AgentPath": { "type": "string" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "ApprovalsReviewer": { "description": "Configures who approval requests are routed to for review. Examples include sandbox escapes, blocked network access, MCP approval prompts, and ARC escalations. Defaults to `user`. `auto_review` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request. The legacy value `guardian_subagent` is accepted for compatibility.", "enum": [ @@ -165,6 +271,50 @@ ], "type": "object" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "ByteRange": { "properties": { "end": { @@ -788,6 +938,13 @@ }, "type": "object" }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -2769,6 +2926,13 @@ } ] }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "Turn": { "properties": { "completedAt": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json index c3e1ed1ba6..d4c524913a 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartedNotification.json @@ -12,35 +12,100 @@ "type": "string" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageModeration": { "properties": { @@ -66,6 +131,47 @@ "AgentPath": { "type": "string" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "AsyncUserInputQuestion": { "additionalProperties": false, "properties": { @@ -87,6 +193,50 @@ ], "type": "object" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "ByteRange": { "properties": { "end": { @@ -710,6 +860,13 @@ }, "type": "object" }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -2560,6 +2717,13 @@ } ] }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "Turn": { "properties": { "completedAt": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadTurnsListResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadTurnsListResponse.json index eb02b3a2fd..384722f1e7 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadTurnsListResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadTurnsListResponse.json @@ -12,35 +12,100 @@ "type": "string" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageModeration": { "properties": { @@ -63,6 +128,47 @@ ], "type": "object" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "AsyncUserInputQuestion": { "additionalProperties": false, "properties": { @@ -84,6 +190,50 @@ ], "type": "object" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "ByteRange": { "properties": { "end": { @@ -684,6 +834,13 @@ } ] }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -2029,6 +2186,13 @@ }, "type": "object" }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "Turn": { "properties": { "completedAt": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json index 5b8cdb419b..0ee1eda4a7 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadUnarchiveResponse.json @@ -12,35 +12,100 @@ "type": "string" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageModeration": { "properties": { @@ -66,6 +131,47 @@ "AgentPath": { "type": "string" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "AsyncUserInputQuestion": { "additionalProperties": false, "properties": { @@ -87,6 +193,50 @@ ], "type": "object" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "ByteRange": { "properties": { "end": { @@ -710,6 +860,13 @@ }, "type": "object" }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -2560,6 +2717,13 @@ } ] }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "Turn": { "properties": { "completedAt": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json index 5d900b0140..64552f14c0 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnCompletedNotification.json @@ -12,35 +12,100 @@ "type": "string" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageModeration": { "properties": { @@ -63,6 +128,47 @@ ], "type": "object" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "AsyncUserInputQuestion": { "additionalProperties": false, "properties": { @@ -84,6 +190,50 @@ ], "type": "object" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "ByteRange": { "properties": { "end": { @@ -684,6 +834,13 @@ } ] }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -2029,6 +2186,13 @@ }, "type": "object" }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "Turn": { "properties": { "completedAt": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json b/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json index c6561a7f6d..74c05749c0 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnStartResponse.json @@ -12,35 +12,100 @@ "type": "string" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageModeration": { "properties": { @@ -63,6 +128,47 @@ ], "type": "object" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "AsyncUserInputQuestion": { "additionalProperties": false, "properties": { @@ -84,6 +190,50 @@ ], "type": "object" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "ByteRange": { "properties": { "end": { @@ -684,6 +834,13 @@ } ] }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -2029,6 +2186,13 @@ }, "type": "object" }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "Turn": { "properties": { "completedAt": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json b/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json index 1f9a38a30a..e424f8d17b 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnStartedNotification.json @@ -12,35 +12,100 @@ "type": "string" }, "AgentMessageDisplay": { - "description": "A presentation instruction for Chat to apply to this answer when recovering history.", - "properties": { - "action": { - "description": "Unknown actions must be left for the producing client to handle.", - "type": "string" + "description": "How Chat should present a recovered answer.", + "oneOf": [ + { + "properties": { + "annotation": { + "anyOf": [ + { + "$ref": "#/definitions/AnswerAnnotation" + }, + { + "type": "null" + } + ] + }, + "mode": { + "enum": [ + "show" + ], + "type": "string" + }, + "trustedContacts": { + "$ref": "#/definitions/TrustedContacts" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "trustedContacts", + "version" + ], + "type": "object" }, - "blockType": { - "type": [ - "string", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "hide" + ], + "type": "string" + }, + "replacement": { + "$ref": "#/definitions/AnswerReplacement" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "replacement", + "version" + ], + "type": "object" }, - "checkTrustedContacts": { - "type": [ - "boolean", - "null" - ] - }, - "cyberTrustedAccess": { - "type": [ - "boolean", - "null" - ] + { + "properties": { + "mode": { + "enum": [ + "block" + ], + "type": "string" + }, + "reason": { + "$ref": "#/definitions/BlockReason" + }, + "version": { + "enum": [ + 1 + ], + "format": "uint8", + "minimum": 0.0, + "type": "integer" + } + }, + "required": [ + "mode", + "reason", + "version" + ], + "type": "object" } - }, - "required": [ - "action" - ], - "type": "object" + ] }, "AgentMessageModeration": { "properties": { @@ -63,6 +128,47 @@ ], "type": "object" }, + "AnswerAnnotation": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingHelpline" + ], + "type": "string" + }, + "subject": { + "$ref": "#/definitions/HelplineSubject" + } + }, + "required": [ + "kind", + "subject" + ], + "type": "object" + } + ] + }, + "AnswerReplacement": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "wellbeingPromptHelpline" + ], + "type": "string" + } + }, + "required": [ + "kind" + ], + "title": "WellbeingPromptHelplineAnswerReplacement", + "type": "object" + } + ] + }, "AsyncUserInputQuestion": { "additionalProperties": false, "properties": { @@ -84,6 +190,50 @@ ], "type": "object" }, + "BlockReason": { + "oneOf": [ + { + "properties": { + "kind": { + "enum": [ + "protection" + ], + "type": "string" + }, + "protectionType": { + "description": "Identifies the same moderation row that Chat writes on the live path.", + "type": "string" + } + }, + "required": [ + "kind", + "protectionType" + ], + "type": "object" + }, + { + "properties": { + "kind": { + "enum": [ + "cyber" + ], + "type": "string" + }, + "trustedAccess": { + "type": [ + "boolean", + "null" + ] + } + }, + "required": [ + "kind" + ], + "title": "KindBlockReason", + "type": "object" + } + ] + }, "ByteRange": { "properties": { "end": { @@ -684,6 +834,13 @@ } ] }, + "HelplineSubject": { + "enum": [ + "answer", + "prompt" + ], + "type": "string" + }, "HookPromptFragment": { "properties": { "hookRunId": { @@ -2029,6 +2186,13 @@ }, "type": "object" }, + "TrustedContacts": { + "enum": [ + "check", + "skip" + ], + "type": "string" + }, "Turn": { "properties": { "completedAt": { diff --git a/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-experimental.json.zst b/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-experimental.json.zst index cc70847e71..c3eee33958 100644 Binary files a/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-experimental.json.zst and b/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-experimental.json.zst differ diff --git a/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-stable.json.zst b/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-stable.json.zst index 6bffcd663e..b9452c7537 100644 Binary files a/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-stable.json.zst and b/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-stable.json.zst differ diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/AgentMessageDisplay.ts b/codex-rs/app-server-protocol/schema/typescript/v2/AgentMessageDisplay.ts index 62f0051536..e0ceb847b8 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/AgentMessageDisplay.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/AgentMessageDisplay.ts @@ -1,12 +1,12 @@ // 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 { AnswerAnnotation } from "./AnswerAnnotation"; +import type { AnswerReplacement } from "./AnswerReplacement"; +import type { BlockReason } from "./BlockReason"; +import type { TrustedContacts } from "./TrustedContacts"; /** - * A presentation instruction for Chat to apply to this answer when recovering history. + * How Chat should present a recovered answer. */ -export type AgentMessageDisplay = { -/** - * Unknown actions must be left for the producing client to handle. - */ -action: string, blockType: string | null, cyberTrustedAccess: boolean | null, checkTrustedContacts: boolean | null, }; +export type AgentMessageDisplay = { "mode": "show", version: 1, annotation?: AnswerAnnotation, trustedContacts: TrustedContacts, } | { "mode": "hide", version: 1, replacement: AnswerReplacement, } | { "mode": "block", version: 1, reason: BlockReason, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/AnswerAnnotation.ts b/codex-rs/app-server-protocol/schema/typescript/v2/AnswerAnnotation.ts new file mode 100644 index 0000000000..17a9dc988f --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/AnswerAnnotation.ts @@ -0,0 +1,6 @@ +// 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 { HelplineSubject } from "./HelplineSubject"; + +export type AnswerAnnotation = { "kind": "wellbeingHelpline", subject: HelplineSubject, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/AnswerReplacement.ts b/codex-rs/app-server-protocol/schema/typescript/v2/AnswerReplacement.ts new file mode 100644 index 0000000000..024981d98d --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/AnswerReplacement.ts @@ -0,0 +1,5 @@ +// 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. + +export type AnswerReplacement = { "kind": "wellbeingPromptHelpline", }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/BlockReason.ts b/codex-rs/app-server-protocol/schema/typescript/v2/BlockReason.ts new file mode 100644 index 0000000000..145fb91359 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/BlockReason.ts @@ -0,0 +1,9 @@ +// 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. + +export type BlockReason = { "kind": "protection", +/** + * Identifies the same moderation row that Chat writes on the live path. + */ +protectionType: string, } | { "kind": "cyber", trustedAccess?: boolean, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/HelplineSubject.ts b/codex-rs/app-server-protocol/schema/typescript/v2/HelplineSubject.ts new file mode 100644 index 0000000000..ec29b42b14 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/HelplineSubject.ts @@ -0,0 +1,5 @@ +// 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. + +export type HelplineSubject = "answer" | "prompt"; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/TrustedContacts.ts b/codex-rs/app-server-protocol/schema/typescript/v2/TrustedContacts.ts new file mode 100644 index 0000000000..8f7c195d33 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/TrustedContacts.ts @@ -0,0 +1,5 @@ +// 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. + +export type TrustedContacts = "check" | "skip"; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/index.ts b/codex-rs/app-server-protocol/schema/typescript/v2/index.ts index 7e6c488806..c3e0d64de9 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/index.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/index.ts @@ -26,6 +26,8 @@ export type { AgentMessageDisplay } from "./AgentMessageDisplay"; export type { AgentMessageModeration } from "./AgentMessageModeration"; export type { AllowDenyRequirement } from "./AllowDenyRequirement"; export type { AnalyticsConfig } from "./AnalyticsConfig"; +export type { AnswerAnnotation } from "./AnswerAnnotation"; +export type { AnswerReplacement } from "./AnswerReplacement"; export type { AppBranding } from "./AppBranding"; export type { AppInfo } from "./AppInfo"; export type { AppLinksConfig } from "./AppLinksConfig"; @@ -60,6 +62,7 @@ export type { AutoReviewDecisionSource } from "./AutoReviewDecisionSource"; export type { AutoReviewRequirements } from "./AutoReviewRequirements"; export type { BedrockProviderId } from "./BedrockProviderId"; export type { BedrockSettingsParams } from "./BedrockSettingsParams"; +export type { BlockReason } from "./BlockReason"; export type { BrowserUseAccessApprovalLifetime } from "./BrowserUseAccessApprovalLifetime"; export type { BrowserUseConfig } from "./BrowserUseConfig"; export type { BrowserUseExtensionRequirements } from "./BrowserUseExtensionRequirements"; @@ -237,6 +240,7 @@ export type { GuardianCommandSource } from "./GuardianCommandSource"; export type { GuardianRiskLevel } from "./GuardianRiskLevel"; export type { GuardianUserAuthorization } from "./GuardianUserAuthorization"; export type { GuardianWarningNotification } from "./GuardianWarningNotification"; +export type { HelplineSubject } from "./HelplineSubject"; export type { HookCompletedNotification } from "./HookCompletedNotification"; export type { HookErrorInfo } from "./HookErrorInfo"; export type { HookEventName } from "./HookEventName"; @@ -651,6 +655,7 @@ export type { ToolRequestUserInputParams } from "./ToolRequestUserInputParams"; export type { ToolRequestUserInputQuestion } from "./ToolRequestUserInputQuestion"; export type { ToolRequestUserInputResponse } from "./ToolRequestUserInputResponse"; export type { ToolsV2 } from "./ToolsV2"; +export type { TrustedContacts } from "./TrustedContacts"; export type { Turn } from "./Turn"; export type { TurnCompletedNotification } from "./TurnCompletedNotification"; export type { TurnDiffUpdatedNotification } from "./TurnDiffUpdatedNotification"; diff --git a/codex-rs/app-server-protocol/src/protocol/thread_history.rs b/codex-rs/app-server-protocol/src/protocol/thread_history.rs index 70e4cad1de..c64c81e11a 100644 --- a/codex-rs/app-server-protocol/src/protocol/thread_history.rs +++ b/codex-rs/app-server-protocol/src/protocol/thread_history.rs @@ -638,7 +638,7 @@ impl ThreadHistoryBuilder { .as_ref() .map(|decision| AgentMessageModeration { moderated: decision.moderated, - display: decision.display.clone().map(Into::into), + display: decision.display.clone(), }), id, text: payload.message.clone(), diff --git a/codex-rs/app-server-protocol/src/protocol/v2/item.rs b/codex-rs/app-server-protocol/src/protocol/v2/item.rs index c4cdf60e77..932212343c 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2/item.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2/item.rs @@ -28,7 +28,7 @@ use codex_protocol::approvals::GuardianAssessmentDecisionSource as CoreGuardianA use codex_protocol::approvals::GuardianCommandSource as CoreGuardianCommandSource; use codex_protocol::items::AgentMessageContent as CoreAgentMessageContent; pub use codex_protocol::items::AgentMessageDelivery; -use codex_protocol::items::AgentMessageDisplay as CoreAgentMessageDisplay; +pub use codex_protocol::items::AgentMessageDisplay; use codex_protocol::items::AgentMessageModeration as CoreAgentMessageModeration; pub use codex_protocol::items::AsyncUserInputQuestion; use codex_protocol::items::CollabAgentTool as CoreCollabAgentTool; @@ -154,6 +154,7 @@ pub enum CommandAction { #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[serde(rename_all = "camelCase")] #[ts(export_to = "v2/")] +#[serde(from = "CoreAgentMessageModeration")] pub struct AgentMessageModeration { pub moderated: bool, pub display: Option, @@ -163,30 +164,7 @@ impl From for AgentMessageModeration { fn from(value: CoreAgentMessageModeration) -> Self { Self { moderated: value.moderated, - display: value.display.map(Into::into), - } - } -} - -/// A presentation instruction for Chat to apply to this answer when recovering history. -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] -#[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, - pub block_type: Option, - pub cyber_trusted_access: Option, - pub check_trusted_contacts: Option, -} - -impl From for AgentMessageDisplay { - fn from(value: CoreAgentMessageDisplay) -> Self { - Self { - action: value.action, - block_type: value.block_type, - cyber_trusted_access: value.cyber_trusted_access, - check_trusted_contacts: value.check_trusted_contacts, + display: value.display, } } } diff --git a/codex-rs/app-server-protocol/src/protocol/v2/tests.rs b/codex-rs/app-server-protocol/src/protocol/v2/tests.rs index 4a5da61b82..4fe5360277 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2/tests.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2/tests.rs @@ -3172,30 +3172,27 @@ fn audio_references_round_trip_through_core_and_json() { } #[test] -fn answer_moderation_exposes_nullable_display_fields() { - for (stored, expected) in [ - ( - json!({"moderated": false}), - json!({"moderated": false, "display": null}), - ), - ( - json!({"moderated": true, "display": { - "action": "answerHelpline", - "checkTrustedContacts": false, - }}), - json!({"moderated": true, "display": { - "action": "answerHelpline", - "blockType": null, - "cyberTrustedAccess": null, - "checkTrustedContacts": false, - }}), - ), +fn answer_moderation_preserves_the_display_instruction() { + for display in [ + JsonValue::Null, + json!({"version":1, "mode":"show", "trustedContacts":"check", + "annotation":{"kind":"wellbeingHelpline", "subject":"prompt"}}), + json!({"version":1, "mode":"hide", "replacement":{"kind":"wellbeingPromptHelpline"}}), + json!({"version":1, "mode":"block", "reason":{"kind":"protection","protectionType":"omnimod"}}), + json!({"version":1, "mode":"block", "reason":{"kind":"cyber","trustedAccess":false}}), ] { - let core: codex_protocol::items::AgentMessageModeration = - serde_json::from_value(stored).unwrap(); + let stored = json!({"moderated": !display.is_null(), "display": display}); + let mut with_extra_fields = stored.clone(); + if let Some(object) = with_extra_fields["display"].as_object_mut() { + object.insert("additionalV1Field".into(), json!(true)); + } + let core = serde_json::from_value::( + with_extra_fields, + ) + .unwrap(); assert_eq!( serde_json::to_value(AgentMessageModeration::from(core)).unwrap(), - expected + stored ); } } @@ -3777,6 +3774,19 @@ fn core_turn_item_into_thread_item_converts_supported_variants() { ); } +#[test] +fn unsupported_answer_display_leaves_the_answer_restricted() { + for display in [ + json!({"version": 2, "mode": "show", "trustedContacts": "skip"}), + json!({"version": 1, "mode": "unknown"}), + ] { + let parsed: AgentMessageModeration = + serde_json::from_value(json!({"moderated": false, "display": display})).unwrap(); + assert!(parsed.moderated); + assert!(parsed.display.is_none()); + } +} + #[test] fn mcp_tool_call_app_context_serializes_connector_id() { let item = ThreadItemPayload::McpToolCall { diff --git a/codex-rs/core/tests/suite/model_request.rs b/codex-rs/core/tests/suite/model_request.rs index 431636d37f..fb4131d5aa 100644 --- a/codex-rs/core/tests/suite/model_request.rs +++ b/codex-rs/core/tests/suite/model_request.rs @@ -465,12 +465,16 @@ async fn final_answer_carries_its_moderation_decision() -> Result<()> { let server = responses::start_mock_server().await; let mut answer = responses::ev_assistant_message("msg-42", "Answer"); answer["item"]["phase"] = json!("final_answer"); + let display = json!({ + "version": 1, "mode": "show", "trustedContacts": "skip", + "annotation": {"kind": "wellbeingHelpline", "subject": "answer"} + }); responses::mount_sse_once( &server, responses::sse(vec![ responses::ev_response_created("resp-1"), json!({"type":"response.metadata","metadata":{"openai_chatgpt_moderation_metadata":{ - "final_answer_moderation":{"item_id":"msg-42","moderated":true,"display":{"action":"answerHelpline"}}, + "final_answer_moderation":{"item_id":"msg-42","moderated":true,"display":display}, "generation":{"private":"classifier details"} }}}), answer, @@ -496,14 +500,14 @@ async fn final_answer_carries_its_moderation_decision() -> Result<()> { let public = serde_json::to_value(&message)?; assert_eq!( public["moderation"], - json!({"moderated": true,"display":{"action":"answerHelpline"}}) + json!({"moderated": true,"display":display}) ); let [EventMsg::AgentMessage(legacy)] = &message.as_legacy_events()[..] else { panic!("expected one legacy answer"); }; assert_eq!( serde_json::to_value(&legacy.moderation)?, - json!({"item_id":"msg-42","moderated":true,"display":{"action":"answerHelpline"}}) + json!({"item_id":"msg-42","moderated":true,"display":display}) ); Ok(()) } diff --git a/codex-rs/protocol/src/items.rs b/codex-rs/protocol/src/items.rs index 03f5f18740..12d96c56e3 100644 --- a/codex-rs/protocol/src/items.rs +++ b/codex-rs/protocol/src/items.rs @@ -1,3 +1,13 @@ +mod display; + +pub use display::AgentMessageDisplay; +pub use display::AgentMessageDisplayVersion; +pub use display::AnswerAnnotation; +pub use display::AnswerReplacement; +pub use display::BlockReason; +pub use display::HelplineSubject; +pub use display::TrustedContacts; + use crate::AgentPath; use crate::ItemIdGenerator; use crate::ThreadId; @@ -151,25 +161,8 @@ pub struct AsyncUserInputQuestion { pub options: Option>, } -/// 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, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub cyber_trusted_access: Option, - #[serde(default, skip_serializing_if = "Option::is_none")] - #[ts(optional)] - pub check_trusted_contacts: Option, -} - #[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, TS, JsonSchema)] +#[serde(from = "display::StoredModeration")] pub struct AgentMessageModeration { pub moderated: bool, #[serde(default, skip_serializing_if = "Option::is_none")] diff --git a/codex-rs/protocol/src/items/display.rs b/codex-rs/protocol/src/items/display.rs new file mode 100644 index 0000000000..18a5c4bc6a --- /dev/null +++ b/codex-rs/protocol/src/items/display.rs @@ -0,0 +1,147 @@ +//! The presentation instruction attached to one moderated Chat answer. +use super::AgentMessageModeration; +use schemars::JsonSchema; +use schemars::r#gen::SchemaGenerator; +use schemars::schema::Schema; +use serde::Deserialize; +use serde::Serialize; +use serde_json::Value; +use ts_rs::TS; + +/// The only supported version of the answer display contract. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, TS)] +#[serde(try_from = "u8", into = "u8")] +#[ts(type = "1", export_to = "v2/")] +pub struct AgentMessageDisplayVersion; + +impl TryFrom for AgentMessageDisplayVersion { + type Error = &'static str; + + fn try_from(version: u8) -> Result { + match version { + 1 => Ok(Self), + _ => Err("unsupported answer display version"), + } + } +} + +impl From for u8 { + fn from(_: AgentMessageDisplayVersion) -> Self { + 1 + } +} + +impl JsonSchema for AgentMessageDisplayVersion { + fn schema_name() -> String { + "AgentMessageDisplayVersion".to_owned() + } + + fn is_referenceable() -> bool { + false + } + + fn json_schema(generator: &mut SchemaGenerator) -> Schema { + let mut schema = u8::json_schema(generator).into_object(); + schema.enum_values = Some(vec![Value::from(1)]); + Schema::Object(schema) + } +} + +/// How Chat should present a recovered answer. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TS, JsonSchema)] +#[serde(tag = "mode", rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub enum AgentMessageDisplay { + Show { + #[ts(type = "1")] + version: AgentMessageDisplayVersion, + #[serde(default, skip_serializing_if = "Option::is_none")] + #[ts(optional)] + annotation: Option, + #[serde(rename = "trustedContacts")] + trusted_contacts: TrustedContacts, + }, + Hide { + #[ts(type = "1")] + version: AgentMessageDisplayVersion, + replacement: AnswerReplacement, + }, + Block { + #[ts(type = "1")] + version: AgentMessageDisplayVersion, + reason: BlockReason, + }, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TS, JsonSchema)] +#[serde(tag = "kind", rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub enum AnswerAnnotation { + WellbeingHelpline { subject: HelplineSubject }, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TS, JsonSchema)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub enum HelplineSubject { + Answer, + Prompt, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TS, JsonSchema)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub enum TrustedContacts { + Check, + Skip, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TS, JsonSchema)] +#[serde(tag = "kind", rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub enum AnswerReplacement { + WellbeingPromptHelpline {}, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, TS, JsonSchema)] +#[serde(tag = "kind", rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub enum BlockReason { + Protection { + /// Identifies the same moderation row that Chat writes on the live path. + #[serde(rename = "protectionType")] + protection_type: String, + }, + Cyber { + #[serde( + default, + rename = "trustedAccess", + skip_serializing_if = "Option::is_none" + )] + #[ts(optional)] + trusted_access: Option, + }, +} + +/// An unreadable instruction leaves the answer restricted. +#[derive(Deserialize)] +pub(super) struct StoredModeration { + moderated: bool, + display: Option, +} + +impl From for AgentMessageModeration { + fn from(stored: StoredModeration) -> Self { + let Some(value) = stored.display else { + return Self { + moderated: stored.moderated, + display: None, + }; + }; + let display = serde_json::from_value(value).ok(); + Self { + moderated: stored.moderated || display.is_none(), + display, + } + } +} diff --git a/codex-rs/protocol/src/protocol.rs b/codex-rs/protocol/src/protocol.rs index 18c29a465c..8d4b3fe8be 100644 --- a/codex-rs/protocol/src/protocol.rs +++ b/codex-rs/protocol/src/protocol.rs @@ -2416,6 +2416,7 @@ pub struct ModelVerificationEvent { } #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)] +#[serde(from = "StoredTargetedModeration")] pub struct TargetedAnswerModeration { pub item_id: String, pub moderated: bool, @@ -2424,6 +2425,23 @@ pub struct TargetedAnswerModeration { pub display: Option, } +#[derive(Deserialize)] +struct StoredTargetedModeration { + item_id: String, + #[serde(flatten)] + decision: crate::items::AgentMessageModeration, +} + +impl From for TargetedAnswerModeration { + fn from(value: StoredTargetedModeration) -> Self { + Self { + item_id: value.item_id, + moderated: value.decision.moderated, + display: value.decision.display, + } + } +} + #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)] pub struct TurnModerationMetadataEvent { pub metadata: Value, diff --git a/sdk/python/scripts/update_sdk_artifacts.py b/sdk/python/scripts/update_sdk_artifacts.py index 9c70b8fc11..d43bb7178a 100755 --- a/sdk/python/scripts/update_sdk_artifacts.py +++ b/sdk/python/scripts/update_sdk_artifacts.py @@ -612,6 +612,30 @@ def generate_v2_all(schema_dir: Path, *, format_output: bool = True) -> None: _preserve_thread_source_enum(out_path) _preserve_open_enum(out_path, "PlanType") _normalize_generated_timestamps(out_path) + _add_answer_display_fallback(out_path) + + +def _add_answer_display_fallback(out_path: Path) -> None: + """Keep items readable and restricted when their display instruction is unsupported.""" + source = out_path.read_text() + header = "class AgentMessageModeration(BaseModel):" + if source.count(header) != 1: + raise RuntimeError("Generated SDK is missing a unique AgentMessageModeration class") + source = source.replace( + "from pydantic import ", "from pydantic import ValidationError, model_validator, ", 1 + ) + validator = """ + @model_validator(mode="before") + @classmethod + def _read_display(cls, data: Any) -> Any: + if not isinstance(data, dict) or "moderated" not in data or data.get("display") is None: + return data + try: + return {**data, "display": AgentMessageDisplay.model_validate(data["display"])} + except ValidationError: + return {**data, "moderated": True, "display": None} +""" + out_path.write_text(source.replace(header, header + "\n" + validator, 1)) def _preserve_inline_media_class_names(out_path: Path) -> None: diff --git a/sdk/python/src/openai_codex/generated/v2_all.py b/sdk/python/src/openai_codex/generated/v2_all.py index 2297db30c2..cc2a104d2f 100644 --- a/sdk/python/src/openai_codex/generated/v2_all.py +++ b/sdk/python/src/openai_codex/generated/v2_all.py @@ -2,7 +2,7 @@ # filename: codex_app_server_protocol.v2.schemas.json from __future__ import annotations -from pydantic import BaseModel, ConfigDict, Field, RootModel +from pydantic import ValidationError, model_validator, BaseModel, ConfigDict, Field, RootModel from typing import Annotated, Any, Literal from enum import Enum @@ -149,18 +149,6 @@ class AgentMessageDeltaNotification(BaseModel): turn_id: Annotated[str, Field(alias="turnId")] -class AgentMessageDisplay(BaseModel): - model_config = ConfigDict( - populate_by_name=True, - ) - action: Annotated[ - str, Field(description="Unknown actions must be left for the producing client to handle.") - ] - block_type: Annotated[str | None, Field(alias="blockType")] = None - check_trusted_contacts: Annotated[bool | None, Field(alias="checkTrustedContacts")] = None - cyber_trusted_access: Annotated[bool | None, Field(alias="cyberTrustedAccess")] = None - - class InputTextAgentMessageInputContent(BaseModel): model_config = ConfigDict( populate_by_name=True, @@ -185,14 +173,6 @@ class AgentMessageInputContent( root: InputTextAgentMessageInputContent | EncryptedContentAgentMessageInputContent -class AgentMessageModeration(BaseModel): - model_config = ConfigDict( - populate_by_name=True, - ) - display: AgentMessageDisplay | None = None - moderated: bool - - class AgentPath(RootModel[str]): root: str @@ -210,6 +190,17 @@ class AnalyticsConfig(BaseModel): enabled: bool | None = None +class WellbeingPromptHelplineAnswerReplacement(BaseModel): + model_config = ConfigDict( + populate_by_name=True, + ) + kind: Literal["wellbeingPromptHelpline"] + + +class AnswerReplacement(RootModel[WellbeingPromptHelplineAnswerReplacement]): + root: WellbeingPromptHelplineAnswerReplacement + + class AppBranding(BaseModel): model_config = ConfigDict( populate_by_name=True, @@ -470,6 +461,32 @@ class BedrockProviderId(Enum): amazon_bedrock_runtime = "amazon-bedrock-runtime" +class BlockReason1(BaseModel): + model_config = ConfigDict( + populate_by_name=True, + ) + kind: Literal["protection"] + protection_type: Annotated[ + str, + Field( + alias="protectionType", + description="Identifies the same moderation row that Chat writes on the live path.", + ), + ] + + +class KindBlockReason(BaseModel): + model_config = ConfigDict( + populate_by_name=True, + ) + kind: Literal["cyber"] + trusted_access: Annotated[bool | None, Field(alias="trustedAccess")] = None + + +class BlockReason(RootModel[BlockReason1 | KindBlockReason]): + root: BlockReason1 | KindBlockReason + + class BrowserUseAccessApprovalLifetime(Enum): turn = "turn" thread = "thread" @@ -2062,6 +2079,11 @@ class GuardianWarningNotification(BaseModel): ] +class HelplineSubject(Enum): + answer = "answer" + prompt = "prompt" + + class HookErrorInfo(BaseModel): model_config = ConfigDict( populate_by_name=True, @@ -6919,6 +6941,11 @@ class ToolExposureSurface(Enum): direct = "direct" +class TrustedContacts(Enum): + check = "check" + skip = "skip" + + class TurnDiffUpdatedNotification(BaseModel): model_config = ConfigDict( populate_by_name=True, @@ -7342,6 +7369,36 @@ class AdditionalContextEntry(BaseModel): value: str +class HideAgentMessageDisplay(BaseModel): + model_config = ConfigDict( + populate_by_name=True, + ) + mode: Annotated[Literal["hide"], Field(title="HideAgentMessageDisplayMode")] + replacement: AnswerReplacement + version: Literal[1] + + +class BlockAgentMessageDisplay(BaseModel): + model_config = ConfigDict( + populate_by_name=True, + ) + mode: Annotated[Literal["block"], Field(title="BlockAgentMessageDisplayMode")] + reason: BlockReason + version: Literal[1] + + +class AnswerAnnotation1(BaseModel): + model_config = ConfigDict( + populate_by_name=True, + ) + kind: Literal["wellbeingHelpline"] + subject: HelplineSubject + + +class AnswerAnnotation(RootModel[AnswerAnnotation1]): + root: AnswerAnnotation1 + + class AppConfig(BaseModel): model_config = ConfigDict( populate_by_name=True, @@ -10808,34 +10865,6 @@ class UserMessageThreadItem(BaseModel): type: Annotated[Literal["userMessage"], Field(title="UserMessageThreadItemType")] -class AgentMessageThreadItem(BaseModel): - model_config = ConfigDict( - populate_by_name=True, - ) - completed_at_ms: Annotated[ - int | None, - Field( - alias="completedAtMs", - description="Unix timestamp in milliseconds when the item completed, if recorded.", - ), - ] = None - delivery: AgentMessageDelivery | None = None - id: str - memory_citation: Annotated[MemoryCitation | None, Field(alias="memoryCitation")] = None - moderation: AgentMessageModeration | None = None - phase: MessagePhase | None = None - questions: list[AsyncUserInputQuestion] | None = None - started_at_ms: Annotated[ - int | None, - Field( - alias="startedAtMs", - description="Unix timestamp in milliseconds when the item started, if recorded.", - ), - ] = None - text: str - type: Annotated[Literal["agentMessage"], Field(title="AgentMessageThreadItemType")] - - class CommandExecutionThreadItem(BaseModel): model_config = ConfigDict( populate_by_name=True, @@ -11524,6 +11553,44 @@ class AccountSession(BaseModel): workspaces: list[AccountSessionWorkspace] +class ShowAgentMessageDisplay(BaseModel): + model_config = ConfigDict( + populate_by_name=True, + ) + annotation: AnswerAnnotation | None = None + mode: Annotated[Literal["show"], Field(title="ShowAgentMessageDisplayMode")] + trusted_contacts: Annotated[TrustedContacts, Field(alias="trustedContacts")] + version: Literal[1] + + +class AgentMessageDisplay( + RootModel[ShowAgentMessageDisplay | HideAgentMessageDisplay | BlockAgentMessageDisplay] +): + root: Annotated[ + ShowAgentMessageDisplay | HideAgentMessageDisplay | BlockAgentMessageDisplay, + Field(description="How Chat should present a recovered answer."), + ] + + +class AgentMessageModeration(BaseModel): + + @model_validator(mode="before") + @classmethod + def _read_display(cls, data: Any) -> Any: + if not isinstance(data, dict) or "moderated" not in data or data.get("display") is None: + return data + try: + return {**data, "display": AgentMessageDisplay.model_validate(data["display"])} + except ValidationError: + return {**data, "moderated": True, "display": None} + + model_config = ConfigDict( + populate_by_name=True, + ) + display: AgentMessageDisplay | None = None + moderated: bool + + class AppInfo(BaseModel): model_config = ConfigDict( populate_by_name=True, @@ -12517,6 +12584,34 @@ class SessionSource(RootModel[SessionSourceValue | CustomSessionSource | SubAgen root: SessionSourceValue | CustomSessionSource | SubAgentSessionSource +class AgentMessageThreadItem(BaseModel): + model_config = ConfigDict( + populate_by_name=True, + ) + completed_at_ms: Annotated[ + int | None, + Field( + alias="completedAtMs", + description="Unix timestamp in milliseconds when the item completed, if recorded.", + ), + ] = None + delivery: AgentMessageDelivery | None = None + id: str + memory_citation: Annotated[MemoryCitation | None, Field(alias="memoryCitation")] = None + moderation: AgentMessageModeration | None = None + phase: MessagePhase | None = None + questions: list[AsyncUserInputQuestion] | None = None + started_at_ms: Annotated[ + int | None, + Field( + alias="startedAtMs", + description="Unix timestamp in milliseconds when the item started, if recorded.", + ), + ] = None + text: str + type: Annotated[Literal["agentMessage"], Field(title="AgentMessageThreadItemType")] + + class FunctionCallOutputThreadItem(BaseModel): model_config = ConfigDict( populate_by_name=True, diff --git a/sdk/python/tests/test_contract_generation.py b/sdk/python/tests/test_contract_generation.py index 178f5c6a64..e53800fb6d 100644 --- a/sdk/python/tests/test_contract_generation.py +++ b/sdk/python/tests/test_contract_generation.py @@ -142,3 +142,37 @@ def test_model_provider_errors_round_trip_wire_names(payload): error = ModelProviderError.model_validate(payload) assert error.model_dump(by_alias=True) == payload + + +def test_answer_display_is_read_in_thread_history_and_notifications(): + from openai_codex.generated.v2_all import ItemCompletedNotification, ThreadItemsListResponse + + display = { + "version": 1, + "mode": "show", + "trustedContacts": "check", + "annotation": {"kind": "wellbeingHelpline", "subject": "answer"}, + } + item = { + "id": "a", + "type": "agentMessage", + "text": "answer", + "moderation": {"moderated": True, "display": {**display, "additionalV1Field": True}}, + } + history = ThreadItemsListResponse.model_validate({"data": [{"turnId": "u", "item": item}]}) + event = ItemCompletedNotification.model_validate( + {"threadId": "t", "turnId": "u", "completedAtMs": 1, "item": item} + ) + for envelope in (history.data[0].item, event.item): + assert ( + envelope.root.moderation.display.model_dump( + mode="json", by_alias=True, exclude_none=True + ) + == display + ) + item["moderation"] = {"moderated": False, "display": {"version": 2, "mode": "new"}} + moderated = ItemCompletedNotification.model_validate( + {"threadId": "t", "turnId": "u", "completedAtMs": 1, "item": item} + ).item.root.moderation + assert moderated.moderated is True + assert moderated.display is None