,
/// Details of the permission being requested
pub permission_request: PermissionRequest,
/// Derived user-facing permission prompt details for UI consumers
@@ -8622,6 +8664,144 @@ pub enum PermissionRequestMemoryAction {
Unknown,
}
+/// Stage that produced this attribution.
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub enum PermissionApprovalEvaluationEvaluationStage {
+ /// The attribution stage is unknown.
+ #[serde(rename = "unknown")]
+ UnknownValue,
+ /// The request resolved before assisted-approval evaluation.
+ #[serde(rename = "not_reached")]
+ NotReached,
+ /// A runtime gate skipped the judge.
+ #[serde(rename = "pre_judge")]
+ PreJudge,
+ /// The judge interface produced the evaluation.
+ #[serde(rename = "judge")]
+ Judge,
+ /// A cached recommendation or another request's outcome was reused.
+ #[serde(rename = "reuse")]
+ Reuse,
+ /// Unknown variant for forward compatibility.
+ #[default]
+ #[serde(other)]
+ Unknown,
+}
+
+/// Status of the local judge interface, not proof of a model network call.
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub enum PermissionApprovalEvaluationJudgeStatus {
+ /// No authoritative attribution is available.
+ #[serde(rename = "unknown")]
+ UnknownValue,
+ /// This evaluation did not invoke the judge interface.
+ #[serde(rename = "not_called")]
+ NotCalled,
+ /// The judge interface returned a usable verdict.
+ #[serde(rename = "completed")]
+ Completed,
+ /// The judge interface returned an error.
+ #[serde(rename = "failed")]
+ Failed,
+ /// This evaluation reused a cached recommendation.
+ #[serde(rename = "cached")]
+ Cached,
+ /// This request inherited another decision without local judge attribution.
+ #[serde(rename = "inherited")]
+ Inherited,
+ /// Unknown variant for forward compatibility.
+ #[default]
+ #[serde(other)]
+ Unknown,
+}
+
+/// Machine-readable runtime gate reason, never a command, path or human rationale.
+#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub enum PermissionApprovalEvaluationReasonCode {
+ /// Attribution is missing or outside the supported vocabulary.
+ #[serde(rename = "unknown")]
+ UnknownValue,
+ /// The request resolved before assisted-approval evaluation.
+ #[serde(rename = "not-reached")]
+ NotReached,
+ /// Assisted approval was inactive for this request.
+ #[serde(rename = "inactive")]
+ Inactive,
+ /// The judge was skipped because authorization extraction could not safely establish a complete recent history.
+ #[serde(rename = "authorization-history-incomplete")]
+ AuthorizationHistoryIncomplete,
+ /// Managed policy required a human decision.
+ #[serde(rename = "managed-approval-required")]
+ ManagedApprovalRequired,
+ /// The request asked to bypass sandbox restrictions.
+ #[serde(rename = "sandbox-bypass")]
+ SandboxBypass,
+ /// An action field exceeded the judge input limit.
+ #[serde(rename = "action-too-long")]
+ ActionTooLong,
+ /// The script path was not authorized for inspection.
+ #[serde(rename = "path-not-authorized")]
+ PathNotAuthorized,
+ /// The script working directory was invalid.
+ #[serde(rename = "invalid-working-directory")]
+ InvalidWorkingDirectory,
+ /// The script snapshot could not be read.
+ #[serde(rename = "unreadable")]
+ Unreadable,
+ /// The script path was not a regular file.
+ #[serde(rename = "not-regular-file")]
+ NotRegularFile,
+ /// The script snapshot exceeded the size limit.
+ #[serde(rename = "too-large")]
+ TooLarge,
+ /// The script snapshot was not UTF-8.
+ #[serde(rename = "non-utf8")]
+ NonUtf8,
+ /// The script interpreter could not be inspected.
+ #[serde(rename = "interpreter-unavailable")]
+ InterpreterUnavailable,
+ /// The interpreter snapshot exceeded the size limit.
+ #[serde(rename = "interpreter-too-large")]
+ InterpreterTooLarge,
+ /// The shell environment could not be reviewed.
+ #[serde(rename = "shell-environment-unreviewable")]
+ ShellEnvironmentUnreviewable,
+ /// A script path could not be represented for review.
+ #[serde(rename = "unrepresentable-path")]
+ UnrepresentablePath,
+ /// An interpreter wrapped a script that could not be reviewed.
+ #[serde(rename = "interpreter-wrapped-script")]
+ InterpreterWrappedScript,
+ /// The script invocation could not be reviewed.
+ #[serde(rename = "unreviewable-script-invocation")]
+ UnreviewableScriptInvocation,
+ /// The script argument binding could not be reviewed.
+ #[serde(rename = "argument-binding-unreviewable")]
+ ArgumentBindingUnreviewable,
+ /// The script review metadata was malformed.
+ #[serde(rename = "malformed-script-action-review")]
+ MalformedScriptActionReview,
+ /// The script snapshot manifest was malformed.
+ #[serde(rename = "malformed-script-action-manifest")]
+ MalformedScriptActionManifest,
+ /// Script review was unavailable.
+ #[serde(rename = "unavailable")]
+ Unavailable,
+ /// The judge interface returned a usable verdict.
+ #[serde(rename = "judge-verdict")]
+ JudgeVerdict,
+ /// The judge interface returned an error.
+ #[serde(rename = "judge-error")]
+ JudgeError,
+ /// The request inherited an outcome from another decision.
+ #[serde(rename = "inherited")]
+ Inherited,
+ /// Unknown variant for forward compatibility.
+ #[default]
+ #[serde(other)]
+ Unknown,
+}
+
/// Why the assisted-approval judge produced no usable recommendation. Present only alongside an `error` recommendation, where the human-readable reason is a fixed string and therefore cannot distinguish these cases. Intended to make a judge failure reportable by a consumer that has no access to the host's logs.
///
///
diff --git a/rust/tests/session_events_test.rs b/rust/tests/session_events_test.rs
index 437be9861f..3a7765cd13 100644
--- a/rust/tests/session_events_test.rs
+++ b/rust/tests/session_events_test.rs
@@ -2,7 +2,58 @@
#![allow(clippy::unwrap_used)]
-use github_copilot_sdk::session_events::UserMessageData;
+use github_copilot_sdk::session_events::{
+ PermissionApprovalEvaluation, PermissionApprovalEvaluationEvaluationStage,
+ PermissionApprovalEvaluationJudgeStatus, PermissionApprovalEvaluationReasonCode,
+ UserMessageData,
+};
+
+#[test]
+fn approval_evaluation_preserves_protocol_unknown_values() {
+ let wire = serde_json::json!({
+ "evaluationStage": "unknown",
+ "judgeStatus": "unknown",
+ "reasonCode": "unknown"
+ });
+ let data: PermissionApprovalEvaluation = serde_json::from_value(wire.clone()).unwrap();
+
+ assert_eq!(
+ data.evaluation_stage,
+ PermissionApprovalEvaluationEvaluationStage::UnknownValue
+ );
+ assert_eq!(
+ data.judge_status,
+ PermissionApprovalEvaluationJudgeStatus::UnknownValue
+ );
+ assert_eq!(
+ data.reason_code,
+ PermissionApprovalEvaluationReasonCode::UnknownValue
+ );
+ assert_eq!(serde_json::to_value(data).unwrap(), wire);
+}
+
+#[test]
+fn approval_evaluation_accepts_future_values_without_confusing_them_with_protocol_unknown() {
+ let data: PermissionApprovalEvaluation = serde_json::from_value(serde_json::json!({
+ "evaluationStage": "future-stage",
+ "judgeStatus": "future-status",
+ "reasonCode": "future-reason"
+ }))
+ .unwrap();
+
+ assert_eq!(
+ data.evaluation_stage,
+ PermissionApprovalEvaluationEvaluationStage::Unknown
+ );
+ assert_eq!(
+ data.judge_status,
+ PermissionApprovalEvaluationJudgeStatus::Unknown
+ );
+ assert_eq!(
+ data.reason_code,
+ PermissionApprovalEvaluationReasonCode::Unknown
+ );
+}
#[test]
fn user_message_id_uses_camel_case_wire_name() {
diff --git a/scripts/codegen/rust.ts b/scripts/codegen/rust.ts
index 714988cb05..c439273d50 100644
--- a/scripts/codegen/rust.ts
+++ b/scripts/codegen/rust.ts
@@ -85,12 +85,6 @@ const STRING_NEWTYPE_OVERRIDES: Record = {
requestId: "RequestId",
};
-const STRING_ENUM_VARIANT_OVERRIDES: Record> = {
- CatalogTrustEligibility: {
- unknown: "UnknownValue",
- },
-};
-
// ── Naming helpers ──────────────────────────────────────────────────────────
function toPascalCase(s: string): string {
@@ -1055,12 +1049,14 @@ function emitRustStringEnum(
const usedVariantNames = new Set();
const reservedVariantNames = new Set(["Unknown"]);
for (const value of values) {
+ // Keep the protocol's explicit "unknown" distinct from the serde fallback,
+ // including anonymous enums whose names depend on their containing type.
const variantName = uniqueRustPascalIdentifier(
value,
usedVariantNames,
"Value",
reservedVariantNames,
- STRING_ENUM_VARIANT_OVERRIDES[enumName]?.[value],
+ value === "unknown" ? "UnknownValue" : undefined,
);
pushRustDoc(lines, enumValueDescriptions?.[value], " ");
if (variantName !== value) {