Add Smart Approvals guardian review across core, app-server, and TUI (#13860)

## Summary
- add `approvals_reviewer = "user" | "guardian_subagent"` as the runtime
control for who reviews approval requests
- route Smart Approvals guardian review through core for command
execution, file changes, managed-network approvals, MCP approvals, and
delegated/subagent approval flows
- expose guardian review in app-server with temporary unstable
`item/autoApprovalReview/{started,completed}` notifications carrying
`targetItemId`, `review`, and `action`
- update the TUI so Smart Approvals can be enabled from `/experimental`,
aligned with the matching `/approvals` mode, and surfaced clearly while
reviews are pending or resolved

## Runtime model
This PR does not introduce a new `approval_policy`.

Instead:
- `approval_policy` still controls when approval is needed
- `approvals_reviewer` controls who reviewable approval requests are
routed to:
  - `user`
  - `guardian_subagent`

`guardian_subagent` is a carefully prompted reviewer subagent that
gathers relevant context and applies a risk-based decision framework
before approving or denying the request.

The `smart_approvals` feature flag is a rollout/UI gate. Core runtime
behavior keys off `approvals_reviewer`.

When Smart Approvals is enabled from the TUI, it also switches the
current `/approvals` settings to the matching Smart Approvals mode so
users immediately see guardian review in the active thread:
- `approval_policy = on-request`
- `approvals_reviewer = guardian_subagent`
- `sandbox_mode = workspace-write`

Users can still change `/approvals` afterward.

Config-load behavior stays intentionally narrow:
- plain `smart_approvals = true` in `config.toml` remains just the
rollout/UI gate and does not auto-set `approvals_reviewer`
- the deprecated `guardian_approval = true` alias migration does
backfill `approvals_reviewer = "guardian_subagent"` in the same scope
when that reviewer is not already configured there, so old configs
preserve their original guardian-enabled behavior

ARC remains a separate safety check. For MCP tool approvals, ARC
escalations now flow into the configured reviewer instead of always
bypassing guardian and forcing manual review.

## Config stability
The runtime reviewer override is stable, but the config-backed
app-server protocol shape is still settling.

- `thread/start`, `thread/resume`, and `turn/start` keep stable
`approvalsReviewer` overrides
- the config-backed `approvals_reviewer` exposure returned via
`config/read` (including profile-level config) is now marked
`[UNSTABLE]` / experimental in the app-server protocol until we are more
confident in that config surface

## App-server surface
This PR intentionally keeps the guardian app-server shape narrow and
temporary.

It adds generic unstable lifecycle notifications:
- `item/autoApprovalReview/started`
- `item/autoApprovalReview/completed`

with payloads of the form:
- `{ threadId, turnId, targetItemId, review, action? }`

`review` is currently:
- `{ status, riskScore?, riskLevel?, rationale? }`
- where `status` is one of `inProgress`, `approved`, `denied`, or
`aborted`

`action` carries the guardian action summary payload from core when
available. This lets clients render temporary standalone pending-review
UI, including parallel reviews, even when the underlying tool item has
not been emitted yet.

These notifications are explicitly documented as `[UNSTABLE]` and
expected to change soon.

This PR does **not** persist guardian review state onto `thread/read`
tool items. The intended follow-up is to attach guardian review state to
the reviewed tool item lifecycle instead, which would improve
consistency with manual approvals and allow thread history / reconnect
flows to replay guardian review state directly.

## TUI behavior
- `/experimental` exposes the rollout gate as `Smart Approvals`
- enabling it in the TUI enables the feature and switches the current
session to the matching Smart Approvals `/approvals` mode
- disabling it in the TUI clears the persisted `approvals_reviewer`
override when appropriate and returns the session to default manual
review when the effective reviewer changes
- `/approvals` still exposes the reviewer choice directly
- the TUI renders:
- pending guardian review state in the live status footer, including
parallel review aggregation
  - resolved approval/denial state in history

## Scope notes
This PR includes the supporting core/runtime work needed to make Smart
Approvals usable end-to-end:
- shell / unified-exec / apply_patch / managed-network / MCP guardian
review
- delegated/subagent approval routing into guardian review
- guardian review risk metadata and action summaries for app-server/TUI
- config/profile/TUI handling for `smart_approvals`, `guardian_approval`
alias migration, and `approvals_reviewer`
- a small internal cleanup of delegated approval forwarding to dedupe
fallback paths and simplify guardian-vs-parent approval waiting (no
intended behavior change)

Out of scope for this PR:
- redesigning the existing manual approval protocol shapes
- persisting guardian review state onto app-server `ThreadItem`s
- delegated MCP elicitation auto-review (the current delegated MCP
guardian shim only covers the legacy `RequestUserInput` path)

---------

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Charley Cunningham
2026-03-13 15:27:00 -07:00
committed by GitHub
co-authored by Codex
parent e3cbf913e8
commit bc24017d64
106 changed files with 5525 additions and 364 deletions
@@ -5,6 +5,14 @@
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
"type": "string"
},
"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`. `guardian_subagent` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request.",
"enum": [
"user",
"guardian_subagent"
],
"type": "string"
},
"AppsListParams": {
"description": "EXPERIMENTAL - list available apps/connectors.",
"properties": {
@@ -2508,6 +2516,17 @@
}
]
},
"approvalsReviewer": {
"anyOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "Override where approval requests are routed for review on this thread and subsequent turns."
},
"baseInstructions": {
"type": [
"string",
@@ -2788,6 +2807,17 @@
}
]
},
"approvalsReviewer": {
"anyOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "Override where approval requests are routed for review on this thread and subsequent turns."
},
"baseInstructions": {
"type": [
"string",
@@ -2939,6 +2969,17 @@
}
]
},
"approvalsReviewer": {
"anyOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "Override where approval requests are routed for review on this thread and subsequent turns."
},
"baseInstructions": {
"type": [
"string",
@@ -3078,6 +3119,17 @@
],
"description": "Override the approval policy for this turn and subsequent turns."
},
"approvalsReviewer": {
"anyOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "Override where approval requests are routed for review on this turn and subsequent turns."
},
"cwd": {
"description": "Override the working directory for this turn and subsequent turns.",
"type": [
@@ -1056,6 +1056,61 @@
},
"type": "object"
},
"GuardianApprovalReview": {
"description": "[UNSTABLE] Temporary guardian approval review payload used by `item/autoApprovalReview/*` notifications. This shape is expected to change soon.",
"properties": {
"rationale": {
"type": [
"string",
"null"
]
},
"riskLevel": {
"anyOf": [
{
"$ref": "#/definitions/GuardianRiskLevel"
},
{
"type": "null"
}
]
},
"riskScore": {
"format": "uint8",
"minimum": 0.0,
"type": [
"integer",
"null"
]
},
"status": {
"$ref": "#/definitions/GuardianApprovalReviewStatus"
}
},
"required": [
"status"
],
"type": "object"
},
"GuardianApprovalReviewStatus": {
"description": "[UNSTABLE] Lifecycle state for a guardian approval review.",
"enum": [
"inProgress",
"approved",
"denied",
"aborted"
],
"type": "string"
},
"GuardianRiskLevel": {
"description": "[UNSTABLE] Risk level assigned by guardian approval review.",
"enum": [
"low",
"medium",
"high"
],
"type": "string"
},
"HookCompletedNotification": {
"properties": {
"run": {
@@ -1253,6 +1308,56 @@
],
"type": "object"
},
"ItemGuardianApprovalReviewCompletedNotification": {
"description": "[UNSTABLE] Temporary notification payload for guardian automatic approval review. This shape is expected to change soon.\n\nTODO(ccunningham): Attach guardian review state to the reviewed tool item's lifecycle instead of sending separate standalone review notifications so the app-server API can persist and replay review state via `thread/read`.",
"properties": {
"action": true,
"review": {
"$ref": "#/definitions/GuardianApprovalReview"
},
"targetItemId": {
"type": "string"
},
"threadId": {
"type": "string"
},
"turnId": {
"type": "string"
}
},
"required": [
"review",
"targetItemId",
"threadId",
"turnId"
],
"type": "object"
},
"ItemGuardianApprovalReviewStartedNotification": {
"description": "[UNSTABLE] Temporary notification payload for guardian automatic approval review. This shape is expected to change soon.\n\nTODO(ccunningham): Attach guardian review state to the reviewed tool item's lifecycle instead of sending separate standalone review notifications so the app-server API can persist and replay review state via `thread/read`.",
"properties": {
"action": true,
"review": {
"$ref": "#/definitions/GuardianApprovalReview"
},
"targetItemId": {
"type": "string"
},
"threadId": {
"type": "string"
},
"turnId": {
"type": "string"
}
},
"required": [
"review",
"targetItemId",
"threadId",
"turnId"
],
"type": "object"
},
"ItemStartedNotification": {
"properties": {
"item": {
@@ -3706,6 +3811,46 @@
"title": "Item/startedNotification",
"type": "object"
},
{
"properties": {
"method": {
"enum": [
"item/autoApprovalReview/started"
],
"title": "Item/autoApprovalReview/startedNotificationMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/ItemGuardianApprovalReviewStartedNotification"
}
},
"required": [
"method",
"params"
],
"title": "Item/autoApprovalReview/startedNotification",
"type": "object"
},
{
"properties": {
"method": {
"enum": [
"item/autoApprovalReview/completed"
],
"title": "Item/autoApprovalReview/completedNotificationMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/ItemGuardianApprovalReviewCompletedNotification"
}
},
"required": [
"method",
"params"
],
"title": "Item/autoApprovalReview/completedNotification",
"type": "object"
},
{
"properties": {
"method": {
@@ -3787,6 +3787,46 @@
"title": "Item/startedNotification",
"type": "object"
},
{
"properties": {
"method": {
"enum": [
"item/autoApprovalReview/started"
],
"title": "Item/autoApprovalReview/startedNotificationMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/v2/ItemGuardianApprovalReviewStartedNotification"
}
},
"required": [
"method",
"params"
],
"title": "Item/autoApprovalReview/startedNotification",
"type": "object"
},
{
"properties": {
"method": {
"enum": [
"item/autoApprovalReview/completed"
],
"title": "Item/autoApprovalReview/completedNotificationMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/v2/ItemGuardianApprovalReviewCompletedNotification"
}
},
"required": [
"method",
"params"
],
"title": "Item/autoApprovalReview/completedNotification",
"type": "object"
},
{
"properties": {
"method": {
@@ -5288,6 +5328,14 @@
"AppToolsConfig": {
"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`. `guardian_subagent` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request.",
"enum": [
"user",
"guardian_subagent"
],
"type": "string"
},
"AppsConfig": {
"properties": {
"_default": {
@@ -6184,6 +6232,17 @@
}
]
},
"approvals_reviewer": {
"anyOf": [
{
"$ref": "#/definitions/v2/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "[UNSTABLE] Optional default for where approval requests are routed for review."
},
"compact_prompt": {
"type": [
"string",
@@ -7847,6 +7906,61 @@
},
"type": "object"
},
"GuardianApprovalReview": {
"description": "[UNSTABLE] Temporary guardian approval review payload used by `item/autoApprovalReview/*` notifications. This shape is expected to change soon.",
"properties": {
"rationale": {
"type": [
"string",
"null"
]
},
"riskLevel": {
"anyOf": [
{
"$ref": "#/definitions/v2/GuardianRiskLevel"
},
{
"type": "null"
}
]
},
"riskScore": {
"format": "uint8",
"minimum": 0.0,
"type": [
"integer",
"null"
]
},
"status": {
"$ref": "#/definitions/v2/GuardianApprovalReviewStatus"
}
},
"required": [
"status"
],
"type": "object"
},
"GuardianApprovalReviewStatus": {
"description": "[UNSTABLE] Lifecycle state for a guardian approval review.",
"enum": [
"inProgress",
"approved",
"denied",
"aborted"
],
"type": "string"
},
"GuardianRiskLevel": {
"description": "[UNSTABLE] Risk level assigned by guardian approval review.",
"enum": [
"low",
"medium",
"high"
],
"type": "string"
},
"HazelnutScope": {
"enum": [
"example",
@@ -8087,6 +8201,60 @@
"title": "ItemCompletedNotification",
"type": "object"
},
"ItemGuardianApprovalReviewCompletedNotification": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "[UNSTABLE] Temporary notification payload for guardian automatic approval review. This shape is expected to change soon.\n\nTODO(ccunningham): Attach guardian review state to the reviewed tool item's lifecycle instead of sending separate standalone review notifications so the app-server API can persist and replay review state via `thread/read`.",
"properties": {
"action": true,
"review": {
"$ref": "#/definitions/v2/GuardianApprovalReview"
},
"targetItemId": {
"type": "string"
},
"threadId": {
"type": "string"
},
"turnId": {
"type": "string"
}
},
"required": [
"review",
"targetItemId",
"threadId",
"turnId"
],
"title": "ItemGuardianApprovalReviewCompletedNotification",
"type": "object"
},
"ItemGuardianApprovalReviewStartedNotification": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "[UNSTABLE] Temporary notification payload for guardian automatic approval review. This shape is expected to change soon.\n\nTODO(ccunningham): Attach guardian review state to the reviewed tool item's lifecycle instead of sending separate standalone review notifications so the app-server API can persist and replay review state via `thread/read`.",
"properties": {
"action": true,
"review": {
"$ref": "#/definitions/v2/GuardianApprovalReview"
},
"targetItemId": {
"type": "string"
},
"threadId": {
"type": "string"
},
"turnId": {
"type": "string"
}
},
"required": [
"review",
"targetItemId",
"threadId",
"turnId"
],
"title": "ItemGuardianApprovalReviewStartedNotification",
"type": "object"
},
"ItemStartedNotification": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
@@ -9398,6 +9566,17 @@
}
]
},
"approvals_reviewer": {
"anyOf": [
{
"$ref": "#/definitions/v2/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "[UNSTABLE] Optional profile-level override for where approval requests are routed for review. If omitted, the enclosing config default is used."
},
"chatgpt_base_url": {
"type": [
"string",
@@ -11653,6 +11832,17 @@
}
]
},
"approvalsReviewer": {
"anyOf": [
{
"$ref": "#/definitions/v2/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "Override where approval requests are routed for review on this thread and subsequent turns."
},
"baseInstructions": {
"type": [
"string",
@@ -11737,6 +11927,14 @@
"approvalPolicy": {
"$ref": "#/definitions/v2/AskForApproval"
},
"approvalsReviewer": {
"allOf": [
{
"$ref": "#/definitions/v2/ApprovalsReviewer"
}
],
"description": "Reviewer currently used for approval requests on this thread."
},
"cwd": {
"type": "string"
},
@@ -11775,6 +11973,7 @@
},
"required": [
"approvalPolicy",
"approvalsReviewer",
"cwd",
"model",
"modelProvider",
@@ -12771,6 +12970,17 @@
}
]
},
"approvalsReviewer": {
"anyOf": [
{
"$ref": "#/definitions/v2/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "Override where approval requests are routed for review on this thread and subsequent turns."
},
"baseInstructions": {
"type": [
"string",
@@ -12862,6 +13072,14 @@
"approvalPolicy": {
"$ref": "#/definitions/v2/AskForApproval"
},
"approvalsReviewer": {
"allOf": [
{
"$ref": "#/definitions/v2/ApprovalsReviewer"
}
],
"description": "Reviewer currently used for approval requests on this thread."
},
"cwd": {
"type": "string"
},
@@ -12900,6 +13118,7 @@
},
"required": [
"approvalPolicy",
"approvalsReviewer",
"cwd",
"model",
"modelProvider",
@@ -13004,6 +13223,17 @@
}
]
},
"approvalsReviewer": {
"anyOf": [
{
"$ref": "#/definitions/v2/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "Override where approval requests are routed for review on this thread and subsequent turns."
},
"baseInstructions": {
"type": [
"string",
@@ -13100,6 +13330,14 @@
"approvalPolicy": {
"$ref": "#/definitions/v2/AskForApproval"
},
"approvalsReviewer": {
"allOf": [
{
"$ref": "#/definitions/v2/ApprovalsReviewer"
}
],
"description": "Reviewer currently used for approval requests on this thread."
},
"cwd": {
"type": "string"
},
@@ -13138,6 +13376,7 @@
},
"required": [
"approvalPolicy",
"approvalsReviewer",
"cwd",
"model",
"modelProvider",
@@ -13647,6 +13886,17 @@
],
"description": "Override the approval policy for this turn and subsequent turns."
},
"approvalsReviewer": {
"anyOf": [
{
"$ref": "#/definitions/v2/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "Override where approval requests are routed for review on this turn and subsequent turns."
},
"cwd": {
"description": "Override the working directory for this turn and subsequent turns.",
"type": [
@@ -532,6 +532,14 @@
"AppToolsConfig": {
"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`. `guardian_subagent` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request.",
"enum": [
"user",
"guardian_subagent"
],
"type": "string"
},
"AppsConfig": {
"properties": {
"_default": {
@@ -2825,6 +2833,17 @@
}
]
},
"approvals_reviewer": {
"anyOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "[UNSTABLE] Optional default for where approval requests are routed for review."
},
"compact_prompt": {
"type": [
"string",
@@ -4588,6 +4607,61 @@
},
"type": "object"
},
"GuardianApprovalReview": {
"description": "[UNSTABLE] Temporary guardian approval review payload used by `item/autoApprovalReview/*` notifications. This shape is expected to change soon.",
"properties": {
"rationale": {
"type": [
"string",
"null"
]
},
"riskLevel": {
"anyOf": [
{
"$ref": "#/definitions/GuardianRiskLevel"
},
{
"type": "null"
}
]
},
"riskScore": {
"format": "uint8",
"minimum": 0.0,
"type": [
"integer",
"null"
]
},
"status": {
"$ref": "#/definitions/GuardianApprovalReviewStatus"
}
},
"required": [
"status"
],
"type": "object"
},
"GuardianApprovalReviewStatus": {
"description": "[UNSTABLE] Lifecycle state for a guardian approval review.",
"enum": [
"inProgress",
"approved",
"denied",
"aborted"
],
"type": "string"
},
"GuardianRiskLevel": {
"description": "[UNSTABLE] Risk level assigned by guardian approval review.",
"enum": [
"low",
"medium",
"high"
],
"type": "string"
},
"HazelnutScope": {
"enum": [
"example",
@@ -4872,6 +4946,60 @@
"title": "ItemCompletedNotification",
"type": "object"
},
"ItemGuardianApprovalReviewCompletedNotification": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "[UNSTABLE] Temporary notification payload for guardian automatic approval review. This shape is expected to change soon.\n\nTODO(ccunningham): Attach guardian review state to the reviewed tool item's lifecycle instead of sending separate standalone review notifications so the app-server API can persist and replay review state via `thread/read`.",
"properties": {
"action": true,
"review": {
"$ref": "#/definitions/GuardianApprovalReview"
},
"targetItemId": {
"type": "string"
},
"threadId": {
"type": "string"
},
"turnId": {
"type": "string"
}
},
"required": [
"review",
"targetItemId",
"threadId",
"turnId"
],
"title": "ItemGuardianApprovalReviewCompletedNotification",
"type": "object"
},
"ItemGuardianApprovalReviewStartedNotification": {
"$schema": "http://json-schema.org/draft-07/schema#",
"description": "[UNSTABLE] Temporary notification payload for guardian automatic approval review. This shape is expected to change soon.\n\nTODO(ccunningham): Attach guardian review state to the reviewed tool item's lifecycle instead of sending separate standalone review notifications so the app-server API can persist and replay review state via `thread/read`.",
"properties": {
"action": true,
"review": {
"$ref": "#/definitions/GuardianApprovalReview"
},
"targetItemId": {
"type": "string"
},
"threadId": {
"type": "string"
},
"turnId": {
"type": "string"
}
},
"required": [
"review",
"targetItemId",
"threadId",
"turnId"
],
"title": "ItemGuardianApprovalReviewStartedNotification",
"type": "object"
},
"ItemStartedNotification": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
@@ -6183,6 +6311,17 @@
}
]
},
"approvals_reviewer": {
"anyOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "[UNSTABLE] Optional profile-level override for where approval requests are routed for review. If omitted, the enclosing config default is used."
},
"chatgpt_base_url": {
"type": [
"string",
@@ -7931,6 +8070,46 @@
"title": "Item/startedNotification",
"type": "object"
},
{
"properties": {
"method": {
"enum": [
"item/autoApprovalReview/started"
],
"title": "Item/autoApprovalReview/startedNotificationMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/ItemGuardianApprovalReviewStartedNotification"
}
},
"required": [
"method",
"params"
],
"title": "Item/autoApprovalReview/startedNotification",
"type": "object"
},
{
"properties": {
"method": {
"enum": [
"item/autoApprovalReview/completed"
],
"title": "Item/autoApprovalReview/completedNotificationMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/ItemGuardianApprovalReviewCompletedNotification"
}
},
"required": [
"method",
"params"
],
"title": "Item/autoApprovalReview/completedNotification",
"type": "object"
},
{
"properties": {
"method": {
@@ -9370,6 +9549,17 @@
}
]
},
"approvalsReviewer": {
"anyOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "Override where approval requests are routed for review on this thread and subsequent turns."
},
"baseInstructions": {
"type": [
"string",
@@ -9454,6 +9644,14 @@
"approvalPolicy": {
"$ref": "#/definitions/AskForApproval"
},
"approvalsReviewer": {
"allOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
}
],
"description": "Reviewer currently used for approval requests on this thread."
},
"cwd": {
"type": "string"
},
@@ -9492,6 +9690,7 @@
},
"required": [
"approvalPolicy",
"approvalsReviewer",
"cwd",
"model",
"modelProvider",
@@ -10488,6 +10687,17 @@
}
]
},
"approvalsReviewer": {
"anyOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "Override where approval requests are routed for review on this thread and subsequent turns."
},
"baseInstructions": {
"type": [
"string",
@@ -10579,6 +10789,14 @@
"approvalPolicy": {
"$ref": "#/definitions/AskForApproval"
},
"approvalsReviewer": {
"allOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
}
],
"description": "Reviewer currently used for approval requests on this thread."
},
"cwd": {
"type": "string"
},
@@ -10617,6 +10835,7 @@
},
"required": [
"approvalPolicy",
"approvalsReviewer",
"cwd",
"model",
"modelProvider",
@@ -10721,6 +10940,17 @@
}
]
},
"approvalsReviewer": {
"anyOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "Override where approval requests are routed for review on this thread and subsequent turns."
},
"baseInstructions": {
"type": [
"string",
@@ -10817,6 +11047,14 @@
"approvalPolicy": {
"$ref": "#/definitions/AskForApproval"
},
"approvalsReviewer": {
"allOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
}
],
"description": "Reviewer currently used for approval requests on this thread."
},
"cwd": {
"type": "string"
},
@@ -10855,6 +11093,7 @@
},
"required": [
"approvalPolicy",
"approvalsReviewer",
"cwd",
"model",
"modelProvider",
@@ -11364,6 +11603,17 @@
],
"description": "Override the approval policy for this turn and subsequent turns."
},
"approvalsReviewer": {
"anyOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "Override where approval requests are routed for review on this turn and subsequent turns."
},
"cwd": {
"description": "Override the working directory for this turn and subsequent turns.",
"type": [
@@ -96,6 +96,14 @@
"AppToolsConfig": {
"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`. `guardian_subagent` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request.",
"enum": [
"user",
"guardian_subagent"
],
"type": "string"
},
"AppsConfig": {
"properties": {
"_default": {
@@ -202,6 +210,17 @@
}
]
},
"approvals_reviewer": {
"anyOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "[UNSTABLE] Optional default for where approval requests are routed for review."
},
"compact_prompt": {
"type": [
"string",
@@ -578,6 +597,17 @@
}
]
},
"approvals_reviewer": {
"anyOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "[UNSTABLE] Optional profile-level override for where approval requests are routed for review. If omitted, the enclosing config default is used."
},
"chatgpt_base_url": {
"type": [
"string",
@@ -0,0 +1,84 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"GuardianApprovalReview": {
"description": "[UNSTABLE] Temporary guardian approval review payload used by `item/autoApprovalReview/*` notifications. This shape is expected to change soon.",
"properties": {
"rationale": {
"type": [
"string",
"null"
]
},
"riskLevel": {
"anyOf": [
{
"$ref": "#/definitions/GuardianRiskLevel"
},
{
"type": "null"
}
]
},
"riskScore": {
"format": "uint8",
"minimum": 0.0,
"type": [
"integer",
"null"
]
},
"status": {
"$ref": "#/definitions/GuardianApprovalReviewStatus"
}
},
"required": [
"status"
],
"type": "object"
},
"GuardianApprovalReviewStatus": {
"description": "[UNSTABLE] Lifecycle state for a guardian approval review.",
"enum": [
"inProgress",
"approved",
"denied",
"aborted"
],
"type": "string"
},
"GuardianRiskLevel": {
"description": "[UNSTABLE] Risk level assigned by guardian approval review.",
"enum": [
"low",
"medium",
"high"
],
"type": "string"
}
},
"description": "[UNSTABLE] Temporary notification payload for guardian automatic approval review. This shape is expected to change soon.\n\nTODO(ccunningham): Attach guardian review state to the reviewed tool item's lifecycle instead of sending separate standalone review notifications so the app-server API can persist and replay review state via `thread/read`.",
"properties": {
"action": true,
"review": {
"$ref": "#/definitions/GuardianApprovalReview"
},
"targetItemId": {
"type": "string"
},
"threadId": {
"type": "string"
},
"turnId": {
"type": "string"
}
},
"required": [
"review",
"targetItemId",
"threadId",
"turnId"
],
"title": "ItemGuardianApprovalReviewCompletedNotification",
"type": "object"
}
@@ -0,0 +1,84 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"GuardianApprovalReview": {
"description": "[UNSTABLE] Temporary guardian approval review payload used by `item/autoApprovalReview/*` notifications. This shape is expected to change soon.",
"properties": {
"rationale": {
"type": [
"string",
"null"
]
},
"riskLevel": {
"anyOf": [
{
"$ref": "#/definitions/GuardianRiskLevel"
},
{
"type": "null"
}
]
},
"riskScore": {
"format": "uint8",
"minimum": 0.0,
"type": [
"integer",
"null"
]
},
"status": {
"$ref": "#/definitions/GuardianApprovalReviewStatus"
}
},
"required": [
"status"
],
"type": "object"
},
"GuardianApprovalReviewStatus": {
"description": "[UNSTABLE] Lifecycle state for a guardian approval review.",
"enum": [
"inProgress",
"approved",
"denied",
"aborted"
],
"type": "string"
},
"GuardianRiskLevel": {
"description": "[UNSTABLE] Risk level assigned by guardian approval review.",
"enum": [
"low",
"medium",
"high"
],
"type": "string"
}
},
"description": "[UNSTABLE] Temporary notification payload for guardian automatic approval review. This shape is expected to change soon.\n\nTODO(ccunningham): Attach guardian review state to the reviewed tool item's lifecycle instead of sending separate standalone review notifications so the app-server API can persist and replay review state via `thread/read`.",
"properties": {
"action": true,
"review": {
"$ref": "#/definitions/GuardianApprovalReview"
},
"targetItemId": {
"type": "string"
},
"threadId": {
"type": "string"
},
"turnId": {
"type": "string"
}
},
"required": [
"review",
"targetItemId",
"threadId",
"turnId"
],
"title": "ItemGuardianApprovalReviewStartedNotification",
"type": "object"
}
@@ -1,6 +1,14 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"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`. `guardian_subagent` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request.",
"enum": [
"user",
"guardian_subagent"
],
"type": "string"
},
"AskForApproval": {
"oneOf": [
{
@@ -79,6 +87,17 @@
}
]
},
"approvalsReviewer": {
"anyOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "Override where approval requests are routed for review on this thread and subsequent turns."
},
"baseInstructions": {
"type": [
"string",
@@ -5,6 +5,14 @@
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
"type": "string"
},
"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`. `guardian_subagent` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request.",
"enum": [
"user",
"guardian_subagent"
],
"type": "string"
},
"AskForApproval": {
"oneOf": [
{
@@ -1955,6 +1963,14 @@
"approvalPolicy": {
"$ref": "#/definitions/AskForApproval"
},
"approvalsReviewer": {
"allOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
}
],
"description": "Reviewer currently used for approval requests on this thread."
},
"cwd": {
"type": "string"
},
@@ -1993,6 +2009,7 @@
},
"required": [
"approvalPolicy",
"approvalsReviewer",
"cwd",
"model",
"modelProvider",
@@ -1,6 +1,14 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"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`. `guardian_subagent` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request.",
"enum": [
"user",
"guardian_subagent"
],
"type": "string"
},
"AskForApproval": {
"oneOf": [
{
@@ -1002,6 +1010,17 @@
}
]
},
"approvalsReviewer": {
"anyOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "Override where approval requests are routed for review on this thread and subsequent turns."
},
"baseInstructions": {
"type": [
"string",
@@ -5,6 +5,14 @@
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
"type": "string"
},
"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`. `guardian_subagent` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request.",
"enum": [
"user",
"guardian_subagent"
],
"type": "string"
},
"AskForApproval": {
"oneOf": [
{
@@ -1955,6 +1963,14 @@
"approvalPolicy": {
"$ref": "#/definitions/AskForApproval"
},
"approvalsReviewer": {
"allOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
}
],
"description": "Reviewer currently used for approval requests on this thread."
},
"cwd": {
"type": "string"
},
@@ -1993,6 +2009,7 @@
},
"required": [
"approvalPolicy",
"approvalsReviewer",
"cwd",
"model",
"modelProvider",
@@ -1,6 +1,14 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"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`. `guardian_subagent` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request.",
"enum": [
"user",
"guardian_subagent"
],
"type": "string"
},
"AskForApproval": {
"oneOf": [
{
@@ -103,6 +111,17 @@
}
]
},
"approvalsReviewer": {
"anyOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "Override where approval requests are routed for review on this thread and subsequent turns."
},
"baseInstructions": {
"type": [
"string",
@@ -5,6 +5,14 @@
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
"type": "string"
},
"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`. `guardian_subagent` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request.",
"enum": [
"user",
"guardian_subagent"
],
"type": "string"
},
"AskForApproval": {
"oneOf": [
{
@@ -1955,6 +1963,14 @@
"approvalPolicy": {
"$ref": "#/definitions/AskForApproval"
},
"approvalsReviewer": {
"allOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
}
],
"description": "Reviewer currently used for approval requests on this thread."
},
"cwd": {
"type": "string"
},
@@ -1993,6 +2009,7 @@
},
"required": [
"approvalPolicy",
"approvalsReviewer",
"cwd",
"model",
"modelProvider",
@@ -5,6 +5,14 @@
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
"type": "string"
},
"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`. `guardian_subagent` uses a carefully prompted subagent to gather relevant context and apply a risk-based decision framework before approving or denying the request.",
"enum": [
"user",
"guardian_subagent"
],
"type": "string"
},
"AskForApproval": {
"oneOf": [
{
@@ -502,6 +510,17 @@
],
"description": "Override the approval policy for this turn and subsequent turns."
},
"approvalsReviewer": {
"anyOf": [
{
"$ref": "#/definitions/ApprovalsReviewer"
},
{
"type": "null"
}
],
"description": "Override where approval requests are routed for review on this turn and subsequent turns."
},
"cwd": {
"description": "Override the working directory for this turn and subsequent turns.",
"type": [
@@ -18,6 +18,8 @@ import type { FileChangeOutputDeltaNotification } from "./v2/FileChangeOutputDel
import type { HookCompletedNotification } from "./v2/HookCompletedNotification";
import type { HookStartedNotification } from "./v2/HookStartedNotification";
import type { ItemCompletedNotification } from "./v2/ItemCompletedNotification";
import type { ItemGuardianApprovalReviewCompletedNotification } from "./v2/ItemGuardianApprovalReviewCompletedNotification";
import type { ItemGuardianApprovalReviewStartedNotification } from "./v2/ItemGuardianApprovalReviewStartedNotification";
import type { ItemStartedNotification } from "./v2/ItemStartedNotification";
import type { McpServerOauthLoginCompletedNotification } from "./v2/McpServerOauthLoginCompletedNotification";
import type { McpToolCallProgressNotification } from "./v2/McpToolCallProgressNotification";
@@ -52,4 +54,4 @@ import type { WindowsWorldWritableWarningNotification } from "./v2/WindowsWorldW
/**
* Notification sent from the server to the client.
*/
export type ServerNotification = { "method": "error", "params": ErrorNotification } | { "method": "thread/started", "params": ThreadStartedNotification } | { "method": "thread/status/changed", "params": ThreadStatusChangedNotification } | { "method": "thread/archived", "params": ThreadArchivedNotification } | { "method": "thread/unarchived", "params": ThreadUnarchivedNotification } | { "method": "thread/closed", "params": ThreadClosedNotification } | { "method": "skills/changed", "params": SkillsChangedNotification } | { "method": "thread/name/updated", "params": ThreadNameUpdatedNotification } | { "method": "thread/tokenUsage/updated", "params": ThreadTokenUsageUpdatedNotification } | { "method": "turn/started", "params": TurnStartedNotification } | { "method": "hook/started", "params": HookStartedNotification } | { "method": "turn/completed", "params": TurnCompletedNotification } | { "method": "hook/completed", "params": HookCompletedNotification } | { "method": "turn/diff/updated", "params": TurnDiffUpdatedNotification } | { "method": "turn/plan/updated", "params": TurnPlanUpdatedNotification } | { "method": "item/started", "params": ItemStartedNotification } | { "method": "item/completed", "params": ItemCompletedNotification } | { "method": "rawResponseItem/completed", "params": RawResponseItemCompletedNotification } | { "method": "item/agentMessage/delta", "params": AgentMessageDeltaNotification } | { "method": "item/plan/delta", "params": PlanDeltaNotification } | { "method": "command/exec/outputDelta", "params": CommandExecOutputDeltaNotification } | { "method": "item/commandExecution/outputDelta", "params": CommandExecutionOutputDeltaNotification } | { "method": "item/commandExecution/terminalInteraction", "params": TerminalInteractionNotification } | { "method": "item/fileChange/outputDelta", "params": FileChangeOutputDeltaNotification } | { "method": "serverRequest/resolved", "params": ServerRequestResolvedNotification } | { "method": "item/mcpToolCall/progress", "params": McpToolCallProgressNotification } | { "method": "mcpServer/oauthLogin/completed", "params": McpServerOauthLoginCompletedNotification } | { "method": "account/updated", "params": AccountUpdatedNotification } | { "method": "account/rateLimits/updated", "params": AccountRateLimitsUpdatedNotification } | { "method": "app/list/updated", "params": AppListUpdatedNotification } | { "method": "item/reasoning/summaryTextDelta", "params": ReasoningSummaryTextDeltaNotification } | { "method": "item/reasoning/summaryPartAdded", "params": ReasoningSummaryPartAddedNotification } | { "method": "item/reasoning/textDelta", "params": ReasoningTextDeltaNotification } | { "method": "thread/compacted", "params": ContextCompactedNotification } | { "method": "model/rerouted", "params": ModelReroutedNotification } | { "method": "deprecationNotice", "params": DeprecationNoticeNotification } | { "method": "configWarning", "params": ConfigWarningNotification } | { "method": "fuzzyFileSearch/sessionUpdated", "params": FuzzyFileSearchSessionUpdatedNotification } | { "method": "fuzzyFileSearch/sessionCompleted", "params": FuzzyFileSearchSessionCompletedNotification } | { "method": "thread/realtime/started", "params": ThreadRealtimeStartedNotification } | { "method": "thread/realtime/itemAdded", "params": ThreadRealtimeItemAddedNotification } | { "method": "thread/realtime/outputAudio/delta", "params": ThreadRealtimeOutputAudioDeltaNotification } | { "method": "thread/realtime/error", "params": ThreadRealtimeErrorNotification } | { "method": "thread/realtime/closed", "params": ThreadRealtimeClosedNotification } | { "method": "windows/worldWritableWarning", "params": WindowsWorldWritableWarningNotification } | { "method": "windowsSandbox/setupCompleted", "params": WindowsSandboxSetupCompletedNotification } | { "method": "account/login/completed", "params": AccountLoginCompletedNotification };
export type ServerNotification = { "method": "error", "params": ErrorNotification } | { "method": "thread/started", "params": ThreadStartedNotification } | { "method": "thread/status/changed", "params": ThreadStatusChangedNotification } | { "method": "thread/archived", "params": ThreadArchivedNotification } | { "method": "thread/unarchived", "params": ThreadUnarchivedNotification } | { "method": "thread/closed", "params": ThreadClosedNotification } | { "method": "skills/changed", "params": SkillsChangedNotification } | { "method": "thread/name/updated", "params": ThreadNameUpdatedNotification } | { "method": "thread/tokenUsage/updated", "params": ThreadTokenUsageUpdatedNotification } | { "method": "turn/started", "params": TurnStartedNotification } | { "method": "hook/started", "params": HookStartedNotification } | { "method": "turn/completed", "params": TurnCompletedNotification } | { "method": "hook/completed", "params": HookCompletedNotification } | { "method": "turn/diff/updated", "params": TurnDiffUpdatedNotification } | { "method": "turn/plan/updated", "params": TurnPlanUpdatedNotification } | { "method": "item/started", "params": ItemStartedNotification } | { "method": "item/autoApprovalReview/started", "params": ItemGuardianApprovalReviewStartedNotification } | { "method": "item/autoApprovalReview/completed", "params": ItemGuardianApprovalReviewCompletedNotification } | { "method": "item/completed", "params": ItemCompletedNotification } | { "method": "rawResponseItem/completed", "params": RawResponseItemCompletedNotification } | { "method": "item/agentMessage/delta", "params": AgentMessageDeltaNotification } | { "method": "item/plan/delta", "params": PlanDeltaNotification } | { "method": "command/exec/outputDelta", "params": CommandExecOutputDeltaNotification } | { "method": "item/commandExecution/outputDelta", "params": CommandExecutionOutputDeltaNotification } | { "method": "item/commandExecution/terminalInteraction", "params": TerminalInteractionNotification } | { "method": "item/fileChange/outputDelta", "params": FileChangeOutputDeltaNotification } | { "method": "serverRequest/resolved", "params": ServerRequestResolvedNotification } | { "method": "item/mcpToolCall/progress", "params": McpToolCallProgressNotification } | { "method": "mcpServer/oauthLogin/completed", "params": McpServerOauthLoginCompletedNotification } | { "method": "account/updated", "params": AccountUpdatedNotification } | { "method": "account/rateLimits/updated", "params": AccountRateLimitsUpdatedNotification } | { "method": "app/list/updated", "params": AppListUpdatedNotification } | { "method": "item/reasoning/summaryTextDelta", "params": ReasoningSummaryTextDeltaNotification } | { "method": "item/reasoning/summaryPartAdded", "params": ReasoningSummaryPartAddedNotification } | { "method": "item/reasoning/textDelta", "params": ReasoningTextDeltaNotification } | { "method": "thread/compacted", "params": ContextCompactedNotification } | { "method": "model/rerouted", "params": ModelReroutedNotification } | { "method": "deprecationNotice", "params": DeprecationNoticeNotification } | { "method": "configWarning", "params": ConfigWarningNotification } | { "method": "fuzzyFileSearch/sessionUpdated", "params": FuzzyFileSearchSessionUpdatedNotification } | { "method": "fuzzyFileSearch/sessionCompleted", "params": FuzzyFileSearchSessionCompletedNotification } | { "method": "thread/realtime/started", "params": ThreadRealtimeStartedNotification } | { "method": "thread/realtime/itemAdded", "params": ThreadRealtimeItemAddedNotification } | { "method": "thread/realtime/outputAudio/delta", "params": ThreadRealtimeOutputAudioDeltaNotification } | { "method": "thread/realtime/error", "params": ThreadRealtimeErrorNotification } | { "method": "thread/realtime/closed", "params": ThreadRealtimeClosedNotification } | { "method": "windows/worldWritableWarning", "params": WindowsWorldWritableWarningNotification } | { "method": "windowsSandbox/setupCompleted", "params": WindowsSandboxSetupCompletedNotification } | { "method": "account/login/completed", "params": AccountLoginCompletedNotification };
@@ -0,0 +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.
/**
* 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`. `guardian_subagent` uses a carefully
* prompted subagent to gather relevant context and apply a risk-based
* decision framework before approving or denying the request.
*/
export type ApprovalsReviewer = "user" | "guardian_subagent";
@@ -9,10 +9,15 @@ import type { Verbosity } from "../Verbosity";
import type { WebSearchMode } from "../WebSearchMode";
import type { JsonValue } from "../serde_json/JsonValue";
import type { AnalyticsConfig } from "./AnalyticsConfig";
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
import type { AskForApproval } from "./AskForApproval";
import type { ProfileV2 } from "./ProfileV2";
import type { SandboxMode } from "./SandboxMode";
import type { SandboxWorkspaceWrite } from "./SandboxWorkspaceWrite";
import type { ToolsV2 } from "./ToolsV2";
export type Config = {model: string | null, review_model: string | null, model_context_window: bigint | null, model_auto_compact_token_limit: bigint | null, model_provider: string | null, approval_policy: AskForApproval | null, sandbox_mode: SandboxMode | null, sandbox_workspace_write: SandboxWorkspaceWrite | null, forced_chatgpt_workspace_id: string | null, forced_login_method: ForcedLoginMethod | null, web_search: WebSearchMode | null, tools: ToolsV2 | null, profile: string | null, profiles: { [key in string]?: ProfileV2 }, instructions: string | null, developer_instructions: string | null, compact_prompt: string | null, model_reasoning_effort: ReasoningEffort | null, model_reasoning_summary: ReasoningSummary | null, model_verbosity: Verbosity | null, service_tier: ServiceTier | null, analytics: AnalyticsConfig | null} & ({ [key in string]?: number | string | boolean | Array<JsonValue> | { [key in string]?: JsonValue } | null });
export type Config = {model: string | null, review_model: string | null, model_context_window: bigint | null, model_auto_compact_token_limit: bigint | null, model_provider: string | null, approval_policy: AskForApproval | null, /**
* [UNSTABLE] Optional default for where approval requests are routed for
* review.
*/
approvals_reviewer: ApprovalsReviewer | null, sandbox_mode: SandboxMode | null, sandbox_workspace_write: SandboxWorkspaceWrite | null, forced_chatgpt_workspace_id: string | null, forced_login_method: ForcedLoginMethod | null, web_search: WebSearchMode | null, tools: ToolsV2 | null, profile: string | null, profiles: { [key in string]?: ProfileV2 }, instructions: string | null, developer_instructions: string | null, compact_prompt: string | null, model_reasoning_effort: ReasoningEffort | null, model_reasoning_summary: ReasoningSummary | null, model_verbosity: Verbosity | null, service_tier: ServiceTier | null, analytics: AnalyticsConfig | null} & ({ [key in string]?: number | string | boolean | Array<JsonValue> | { [key in string]?: JsonValue } | null });
@@ -0,0 +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 { GuardianApprovalReviewStatus } from "./GuardianApprovalReviewStatus";
import type { GuardianRiskLevel } from "./GuardianRiskLevel";
/**
* [UNSTABLE] Temporary guardian approval review payload used by
* `item/autoApprovalReview/*` notifications. This shape is expected to change
* soon.
*/
export type GuardianApprovalReview = { status: GuardianApprovalReviewStatus, riskScore: number | null, riskLevel: GuardianRiskLevel | null, rationale: string | null, };
@@ -0,0 +1,8 @@
// 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.
/**
* [UNSTABLE] Lifecycle state for a guardian approval review.
*/
export type GuardianApprovalReviewStatus = "inProgress" | "approved" | "denied" | "aborted";
@@ -0,0 +1,8 @@
// 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.
/**
* [UNSTABLE] Risk level assigned by guardian approval review.
*/
export type GuardianRiskLevel = "low" | "medium" | "high";
@@ -0,0 +1,15 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { JsonValue } from "../serde_json/JsonValue";
import type { GuardianApprovalReview } from "./GuardianApprovalReview";
/**
* [UNSTABLE] Temporary notification payload for guardian automatic approval
* review. This shape is expected to change soon.
*
* TODO(ccunningham): Attach guardian review state to the reviewed tool item's
* lifecycle instead of sending separate standalone review notifications so the
* app-server API can persist and replay review state via `thread/read`.
*/
export type ItemGuardianApprovalReviewCompletedNotification = { threadId: string, turnId: string, targetItemId: string, review: GuardianApprovalReview, action: JsonValue | null, };
@@ -0,0 +1,15 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { JsonValue } from "../serde_json/JsonValue";
import type { GuardianApprovalReview } from "./GuardianApprovalReview";
/**
* [UNSTABLE] Temporary notification payload for guardian automatic approval
* review. This shape is expected to change soon.
*
* TODO(ccunningham): Attach guardian review state to the reviewed tool item's
* lifecycle instead of sending separate standalone review notifications so the
* app-server API can persist and replay review state via `thread/read`.
*/
export type ItemGuardianApprovalReviewStartedNotification = { threadId: string, turnId: string, targetItemId: string, review: GuardianApprovalReview, action: JsonValue | null, };
@@ -7,7 +7,13 @@ import type { ServiceTier } from "../ServiceTier";
import type { Verbosity } from "../Verbosity";
import type { WebSearchMode } from "../WebSearchMode";
import type { JsonValue } from "../serde_json/JsonValue";
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
import type { AskForApproval } from "./AskForApproval";
import type { ToolsV2 } from "./ToolsV2";
export type ProfileV2 = { model: string | null, model_provider: string | null, approval_policy: AskForApproval | null, service_tier: ServiceTier | null, model_reasoning_effort: ReasoningEffort | null, model_reasoning_summary: ReasoningSummary | null, model_verbosity: Verbosity | null, web_search: WebSearchMode | null, tools: ToolsV2 | null, chatgpt_base_url: string | null, } & ({ [key in string]?: number | string | boolean | Array<JsonValue> | { [key in string]?: JsonValue } | null });
export type ProfileV2 = {model: string | null, model_provider: string | null, approval_policy: AskForApproval | null, /**
* [UNSTABLE] Optional profile-level override for where approval requests
* are routed for review. If omitted, the enclosing config default is
* used.
*/
approvals_reviewer: ApprovalsReviewer | null, service_tier: ServiceTier | null, model_reasoning_effort: ReasoningEffort | null, model_reasoning_summary: ReasoningSummary | null, model_verbosity: Verbosity | null, web_search: WebSearchMode | null, tools: ToolsV2 | null, chatgpt_base_url: string | null} & ({ [key in string]?: number | string | boolean | Array<JsonValue> | { [key in string]?: JsonValue } | null });
@@ -3,6 +3,7 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ServiceTier } from "../ServiceTier";
import type { JsonValue } from "../serde_json/JsonValue";
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
import type { AskForApproval } from "./AskForApproval";
import type { SandboxMode } from "./SandboxMode";
@@ -22,7 +23,11 @@ export type ThreadForkParams = {threadId: string, /**
path?: string | null, /**
* Configuration overrides for the forked thread, if any.
*/
model?: string | null, modelProvider?: string | null, serviceTier?: ServiceTier | null | null, cwd?: string | null, approvalPolicy?: AskForApproval | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, baseInstructions?: string | null, developerInstructions?: string | null, ephemeral?: boolean, /**
model?: string | null, modelProvider?: string | null, serviceTier?: ServiceTier | null | null, cwd?: string | null, approvalPolicy?: AskForApproval | null, /**
* Override where approval requests are routed for review on this thread
* and subsequent turns.
*/
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, baseInstructions?: string | null, developerInstructions?: string | null, ephemeral?: boolean, /**
* If true, persist additional rollout EventMsg variants required to
* reconstruct a richer thread history on subsequent resume/fork/read.
*/
@@ -3,8 +3,13 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ReasoningEffort } from "../ReasoningEffort";
import type { ServiceTier } from "../ServiceTier";
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
import type { AskForApproval } from "./AskForApproval";
import type { SandboxPolicy } from "./SandboxPolicy";
import type { Thread } from "./Thread";
export type ThreadForkResponse = { thread: Thread, model: string, modelProvider: string, serviceTier: ServiceTier | null, cwd: string, approvalPolicy: AskForApproval, sandbox: SandboxPolicy, reasoningEffort: ReasoningEffort | null, };
export type ThreadForkResponse = { thread: Thread, model: string, modelProvider: string, serviceTier: ServiceTier | null, cwd: string, approvalPolicy: AskForApproval,
/**
* Reviewer currently used for approval requests on this thread.
*/
approvalsReviewer: ApprovalsReviewer, sandbox: SandboxPolicy, reasoningEffort: ReasoningEffort | null, };
@@ -5,6 +5,7 @@ import type { Personality } from "../Personality";
import type { ResponseItem } from "../ResponseItem";
import type { ServiceTier } from "../ServiceTier";
import type { JsonValue } from "../serde_json/JsonValue";
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
import type { AskForApproval } from "./AskForApproval";
import type { SandboxMode } from "./SandboxMode";
@@ -31,7 +32,11 @@ history?: Array<ResponseItem> | null, /**
path?: string | null, /**
* Configuration overrides for the resumed thread, if any.
*/
model?: string | null, modelProvider?: string | null, serviceTier?: ServiceTier | null | null, cwd?: string | null, approvalPolicy?: AskForApproval | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, baseInstructions?: string | null, developerInstructions?: string | null, personality?: Personality | null, /**
model?: string | null, modelProvider?: string | null, serviceTier?: ServiceTier | null | null, cwd?: string | null, approvalPolicy?: AskForApproval | null, /**
* Override where approval requests are routed for review on this thread
* and subsequent turns.
*/
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, baseInstructions?: string | null, developerInstructions?: string | null, personality?: Personality | null, /**
* If true, persist additional rollout EventMsg variants required to
* reconstruct a richer thread history on subsequent resume/fork/read.
*/
@@ -3,8 +3,13 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ReasoningEffort } from "../ReasoningEffort";
import type { ServiceTier } from "../ServiceTier";
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
import type { AskForApproval } from "./AskForApproval";
import type { SandboxPolicy } from "./SandboxPolicy";
import type { Thread } from "./Thread";
export type ThreadResumeResponse = { thread: Thread, model: string, modelProvider: string, serviceTier: ServiceTier | null, cwd: string, approvalPolicy: AskForApproval, sandbox: SandboxPolicy, reasoningEffort: ReasoningEffort | null, };
export type ThreadResumeResponse = { thread: Thread, model: string, modelProvider: string, serviceTier: ServiceTier | null, cwd: string, approvalPolicy: AskForApproval,
/**
* Reviewer currently used for approval requests on this thread.
*/
approvalsReviewer: ApprovalsReviewer, sandbox: SandboxPolicy, reasoningEffort: ReasoningEffort | null, };
@@ -4,10 +4,15 @@
import type { Personality } from "../Personality";
import type { ServiceTier } from "../ServiceTier";
import type { JsonValue } from "../serde_json/JsonValue";
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
import type { AskForApproval } from "./AskForApproval";
import type { SandboxMode } from "./SandboxMode";
export type ThreadStartParams = {model?: string | null, modelProvider?: string | null, serviceTier?: ServiceTier | null | null, cwd?: string | null, approvalPolicy?: AskForApproval | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, serviceName?: string | null, baseInstructions?: string | null, developerInstructions?: string | null, personality?: Personality | null, ephemeral?: boolean | null, /**
export type ThreadStartParams = {model?: string | null, modelProvider?: string | null, serviceTier?: ServiceTier | null | null, cwd?: string | null, approvalPolicy?: AskForApproval | null, /**
* Override where approval requests are routed for review on this thread
* and subsequent turns.
*/
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, serviceName?: string | null, baseInstructions?: string | null, developerInstructions?: string | null, personality?: Personality | null, ephemeral?: boolean | null, /**
* If true, opt into emitting raw Responses API items on the event stream.
* This is for internal use only (e.g. Codex Cloud).
*/
@@ -3,8 +3,13 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ReasoningEffort } from "../ReasoningEffort";
import type { ServiceTier } from "../ServiceTier";
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
import type { AskForApproval } from "./AskForApproval";
import type { SandboxPolicy } from "./SandboxPolicy";
import type { Thread } from "./Thread";
export type ThreadStartResponse = { thread: Thread, model: string, modelProvider: string, serviceTier: ServiceTier | null, cwd: string, approvalPolicy: AskForApproval, sandbox: SandboxPolicy, reasoningEffort: ReasoningEffort | null, };
export type ThreadStartResponse = { thread: Thread, model: string, modelProvider: string, serviceTier: ServiceTier | null, cwd: string, approvalPolicy: AskForApproval,
/**
* Reviewer currently used for approval requests on this thread.
*/
approvalsReviewer: ApprovalsReviewer, sandbox: SandboxPolicy, reasoningEffort: ReasoningEffort | null, };
@@ -7,6 +7,7 @@ import type { ReasoningEffort } from "../ReasoningEffort";
import type { ReasoningSummary } from "../ReasoningSummary";
import type { ServiceTier } from "../ServiceTier";
import type { JsonValue } from "../serde_json/JsonValue";
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
import type { AskForApproval } from "./AskForApproval";
import type { SandboxPolicy } from "./SandboxPolicy";
import type { UserInput } from "./UserInput";
@@ -18,6 +19,10 @@ cwd?: string | null, /**
* Override the approval policy for this turn and subsequent turns.
*/
approvalPolicy?: AskForApproval | null, /**
* Override where approval requests are routed for review on this turn and
* subsequent turns.
*/
approvalsReviewer?: ApprovalsReviewer | null, /**
* Override the sandbox policy for this turn and subsequent turns.
*/
sandboxPolicy?: SandboxPolicy | null, /**
@@ -19,6 +19,7 @@ export type { AppScreenshot } from "./AppScreenshot";
export type { AppSummary } from "./AppSummary";
export type { AppToolApproval } from "./AppToolApproval";
export type { AppToolsConfig } from "./AppToolsConfig";
export type { ApprovalsReviewer } from "./ApprovalsReviewer";
export type { AppsConfig } from "./AppsConfig";
export type { AppsDefaultConfig } from "./AppsDefaultConfig";
export type { AppsListParams } from "./AppsListParams";
@@ -116,6 +117,9 @@ export type { GetAccountResponse } from "./GetAccountResponse";
export type { GitInfo } from "./GitInfo";
export type { GrantedMacOsPermissions } from "./GrantedMacOsPermissions";
export type { GrantedPermissionProfile } from "./GrantedPermissionProfile";
export type { GuardianApprovalReview } from "./GuardianApprovalReview";
export type { GuardianApprovalReviewStatus } from "./GuardianApprovalReviewStatus";
export type { GuardianRiskLevel } from "./GuardianRiskLevel";
export type { HazelnutScope } from "./HazelnutScope";
export type { HookCompletedNotification } from "./HookCompletedNotification";
export type { HookEventName } from "./HookEventName";
@@ -128,6 +132,8 @@ export type { HookRunSummary } from "./HookRunSummary";
export type { HookScope } from "./HookScope";
export type { HookStartedNotification } from "./HookStartedNotification";
export type { ItemCompletedNotification } from "./ItemCompletedNotification";
export type { ItemGuardianApprovalReviewCompletedNotification } from "./ItemGuardianApprovalReviewCompletedNotification";
export type { ItemGuardianApprovalReviewStartedNotification } from "./ItemGuardianApprovalReviewStartedNotification";
export type { ItemStartedNotification } from "./ItemStartedNotification";
export type { ListMcpServerStatusParams } from "./ListMcpServerStatusParams";
export type { ListMcpServerStatusResponse } from "./ListMcpServerStatusResponse";
@@ -884,6 +884,8 @@ server_notification_definitions! {
TurnDiffUpdated => "turn/diff/updated" (v2::TurnDiffUpdatedNotification),
TurnPlanUpdated => "turn/plan/updated" (v2::TurnPlanUpdatedNotification),
ItemStarted => "item/started" (v2::ItemStartedNotification),
ItemGuardianApprovalReviewStarted => "item/autoApprovalReview/started" (v2::ItemGuardianApprovalReviewStartedNotification),
ItemGuardianApprovalReviewCompleted => "item/autoApprovalReview/completed" (v2::ItemGuardianApprovalReviewCompletedNotification),
ItemCompleted => "item/completed" (v2::ItemCompletedNotification),
/// This event is internal-only. Used by Codex Cloud.
RawResponseItemCompleted => "rawResponseItem/completed" (v2::RawResponseItemCompletedNotification),
@@ -13,6 +13,7 @@ use codex_protocol::approvals::NetworkApprovalContext as CoreNetworkApprovalCont
use codex_protocol::approvals::NetworkApprovalProtocol as CoreNetworkApprovalProtocol;
use codex_protocol::approvals::NetworkPolicyAmendment as CoreNetworkPolicyAmendment;
use codex_protocol::approvals::NetworkPolicyRuleAction as CoreNetworkPolicyRuleAction;
use codex_protocol::config_types::ApprovalsReviewer as CoreApprovalsReviewer;
use codex_protocol::config_types::CollaborationMode;
use codex_protocol::config_types::CollaborationModeMask as CoreCollaborationModeMask;
use codex_protocol::config_types::ForcedLoginMethod;
@@ -51,6 +52,7 @@ use codex_protocol::protocol::CodexErrorInfo as CoreCodexErrorInfo;
use codex_protocol::protocol::CreditsSnapshot as CoreCreditsSnapshot;
use codex_protocol::protocol::ExecCommandStatus as CoreExecCommandStatus;
use codex_protocol::protocol::GranularApprovalConfig as CoreGranularApprovalConfig;
use codex_protocol::protocol::GuardianRiskLevel as CoreGuardianRiskLevel;
use codex_protocol::protocol::HookEventName as CoreHookEventName;
use codex_protocol::protocol::HookExecutionMode as CoreHookExecutionMode;
use codex_protocol::protocol::HookHandlerType as CoreHookHandlerType;
@@ -256,6 +258,37 @@ impl From<CoreAskForApproval> for AskForApproval {
}
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "snake_case")]
#[ts(rename_all = "snake_case", export_to = "v2/")]
/// 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`. `guardian_subagent` uses a carefully
/// prompted subagent to gather relevant context and apply a risk-based
/// decision framework before approving or denying the request.
pub enum ApprovalsReviewer {
User,
GuardianSubagent,
}
impl ApprovalsReviewer {
pub fn to_core(self) -> CoreApprovalsReviewer {
match self {
ApprovalsReviewer::User => CoreApprovalsReviewer::User,
ApprovalsReviewer::GuardianSubagent => CoreApprovalsReviewer::GuardianSubagent,
}
}
}
impl From<CoreApprovalsReviewer> for ApprovalsReviewer {
fn from(value: CoreApprovalsReviewer) -> Self {
match value {
CoreApprovalsReviewer::User => ApprovalsReviewer::User,
CoreApprovalsReviewer::GuardianSubagent => ApprovalsReviewer::GuardianSubagent,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "kebab-case")]
#[ts(rename_all = "kebab-case", export_to = "v2/")]
@@ -519,6 +552,11 @@ pub struct ProfileV2 {
pub model_provider: Option<String>,
#[experimental(nested)]
pub approval_policy: Option<AskForApproval>,
/// [UNSTABLE] Optional profile-level override for where approval requests
/// are routed for review. If omitted, the enclosing config default is
/// used.
#[experimental("config/read.approvalsReviewer")]
pub approvals_reviewer: Option<ApprovalsReviewer>,
pub service_tier: Option<ServiceTier>,
pub model_reasoning_effort: Option<ReasoningEffort>,
pub model_reasoning_summary: Option<ReasoningSummary>,
@@ -618,6 +656,10 @@ pub struct Config {
pub model_provider: Option<String>,
#[experimental(nested)]
pub approval_policy: Option<AskForApproval>,
/// [UNSTABLE] Optional default for where approval requests are routed for
/// review.
#[experimental("config/read.approvalsReviewer")]
pub approvals_reviewer: Option<ApprovalsReviewer>,
pub sandbox_mode: Option<SandboxMode>,
pub sandbox_workspace_write: Option<SandboxWorkspaceWrite>,
pub forced_chatgpt_workspace_id: Option<String>,
@@ -2422,6 +2464,10 @@ pub struct ThreadStartParams {
#[experimental(nested)]
#[ts(optional = nullable)]
pub approval_policy: Option<AskForApproval>,
/// Override where approval requests are routed for review on this thread
/// and subsequent turns.
#[ts(optional = nullable)]
pub approvals_reviewer: Option<ApprovalsReviewer>,
#[ts(optional = nullable)]
pub sandbox: Option<SandboxMode>,
#[ts(optional = nullable)]
@@ -2484,6 +2530,8 @@ pub struct ThreadStartResponse {
pub cwd: PathBuf,
#[experimental(nested)]
pub approval_policy: AskForApproval,
/// Reviewer currently used for approval requests on this thread.
pub approvals_reviewer: ApprovalsReviewer,
pub sandbox: SandboxPolicy,
pub reasoning_effort: Option<ReasoningEffort>,
}
@@ -2536,6 +2584,10 @@ pub struct ThreadResumeParams {
#[experimental(nested)]
#[ts(optional = nullable)]
pub approval_policy: Option<AskForApproval>,
/// Override where approval requests are routed for review on this thread
/// and subsequent turns.
#[ts(optional = nullable)]
pub approvals_reviewer: Option<ApprovalsReviewer>,
#[ts(optional = nullable)]
pub sandbox: Option<SandboxMode>,
#[ts(optional = nullable)]
@@ -2564,6 +2616,8 @@ pub struct ThreadResumeResponse {
pub cwd: PathBuf,
#[experimental(nested)]
pub approval_policy: AskForApproval,
/// Reviewer currently used for approval requests on this thread.
pub approvals_reviewer: ApprovalsReviewer,
pub sandbox: SandboxPolicy,
pub reasoning_effort: Option<ReasoningEffort>,
}
@@ -2607,6 +2661,10 @@ pub struct ThreadForkParams {
#[experimental(nested)]
#[ts(optional = nullable)]
pub approval_policy: Option<AskForApproval>,
/// Override where approval requests are routed for review on this thread
/// and subsequent turns.
#[ts(optional = nullable)]
pub approvals_reviewer: Option<ApprovalsReviewer>,
#[ts(optional = nullable)]
pub sandbox: Option<SandboxMode>,
#[ts(optional = nullable)]
@@ -2635,6 +2693,8 @@ pub struct ThreadForkResponse {
pub cwd: PathBuf,
#[experimental(nested)]
pub approval_policy: AskForApproval,
/// Reviewer currently used for approval requests on this thread.
pub approvals_reviewer: ApprovalsReviewer,
pub sandbox: SandboxPolicy,
pub reasoning_effort: Option<ReasoningEffort>,
}
@@ -3758,6 +3818,10 @@ pub struct TurnStartParams {
#[experimental(nested)]
#[ts(optional = nullable)]
pub approval_policy: Option<AskForApproval>,
/// Override where approval requests are routed for review on this turn and
/// subsequent turns.
#[ts(optional = nullable)]
pub approvals_reviewer: Option<ApprovalsReviewer>,
/// Override the sandbox policy for this turn and subsequent turns.
#[ts(optional = nullable)]
pub sandbox_policy: Option<SandboxPolicy>,
@@ -4194,6 +4258,53 @@ impl ThreadItem {
}
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
/// [UNSTABLE] Lifecycle state for a guardian approval review.
pub enum GuardianApprovalReviewStatus {
InProgress,
Approved,
Denied,
Aborted,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "lowercase")]
#[ts(export_to = "v2/")]
/// [UNSTABLE] Risk level assigned by guardian approval review.
pub enum GuardianRiskLevel {
Low,
Medium,
High,
}
impl From<CoreGuardianRiskLevel> for GuardianRiskLevel {
fn from(value: CoreGuardianRiskLevel) -> Self {
match value {
CoreGuardianRiskLevel::Low => Self::Low,
CoreGuardianRiskLevel::Medium => Self::Medium,
CoreGuardianRiskLevel::High => Self::High,
}
}
}
/// [UNSTABLE] Temporary guardian approval review payload used by
/// `item/autoApprovalReview/*` notifications. This shape is expected to change
/// soon.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct GuardianApprovalReview {
pub status: GuardianApprovalReviewStatus,
#[serde(alias = "risk_score")]
#[ts(type = "number | null")]
pub risk_score: Option<u8>,
#[serde(alias = "risk_level")]
pub risk_level: Option<GuardianRiskLevel>,
pub rationale: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(tag = "type", rename_all = "camelCase")]
#[ts(tag = "type", rename_all = "camelCase")]
@@ -4625,6 +4736,40 @@ pub struct ItemStartedNotification {
pub turn_id: String,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
/// [UNSTABLE] Temporary notification payload for guardian automatic approval
/// review. This shape is expected to change soon.
///
/// TODO(ccunningham): Attach guardian review state to the reviewed tool item's
/// lifecycle instead of sending separate standalone review notifications so the
/// app-server API can persist and replay review state via `thread/read`.
pub struct ItemGuardianApprovalReviewStartedNotification {
pub thread_id: String,
pub turn_id: String,
pub target_item_id: String,
pub review: GuardianApprovalReview,
pub action: Option<JsonValue>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
/// [UNSTABLE] Temporary notification payload for guardian automatic approval
/// review. This shape is expected to change soon.
///
/// TODO(ccunningham): Attach guardian review state to the reviewed tool item's
/// lifecycle instead of sending separate standalone review notifications so the
/// app-server API can persist and replay review state via `thread/read`.
pub struct ItemGuardianApprovalReviewCompletedNotification {
pub thread_id: String,
pub turn_id: String,
pub target_item_id: String,
pub review: GuardianApprovalReview,
pub action: Option<JsonValue>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
@@ -6600,6 +6745,7 @@ mod tests {
request_permissions: true,
mcp_elicitations: false,
}),
approvals_reviewer: None,
service_tier: None,
model_reasoning_effort: None,
model_reasoning_summary: None,
@@ -6628,6 +6774,7 @@ mod tests {
request_permissions: false,
mcp_elicitations: true,
}),
approvals_reviewer: None,
sandbox_mode: None,
sandbox_workspace_write: None,
forced_chatgpt_workspace_id: None,
@@ -6651,6 +6798,39 @@ mod tests {
assert_eq!(reason, Some("askForApproval.granular"));
}
#[test]
fn config_approvals_reviewer_is_marked_experimental() {
let reason = crate::experimental_api::ExperimentalApi::experimental_reason(&Config {
model: None,
review_model: None,
model_context_window: None,
model_auto_compact_token_limit: None,
model_provider: None,
approval_policy: None,
approvals_reviewer: Some(ApprovalsReviewer::GuardianSubagent),
sandbox_mode: None,
sandbox_workspace_write: None,
forced_chatgpt_workspace_id: None,
forced_login_method: None,
web_search: None,
tools: None,
profile: None,
profiles: HashMap::new(),
instructions: None,
developer_instructions: None,
compact_prompt: None,
model_reasoning_effort: None,
model_reasoning_summary: None,
model_verbosity: None,
service_tier: None,
analytics: None,
apps: None,
additional: HashMap::new(),
});
assert_eq!(reason, Some("config/read.approvalsReviewer"));
}
#[test]
fn config_nested_profile_granular_approval_policy_is_marked_experimental() {
let reason = crate::experimental_api::ExperimentalApi::experimental_reason(&Config {
@@ -6660,6 +6840,7 @@ mod tests {
model_auto_compact_token_limit: None,
model_provider: None,
approval_policy: None,
approvals_reviewer: None,
sandbox_mode: None,
sandbox_workspace_write: None,
forced_chatgpt_workspace_id: None,
@@ -6679,6 +6860,7 @@ mod tests {
request_permissions: false,
mcp_elicitations: true,
}),
approvals_reviewer: None,
service_tier: None,
model_reasoning_effort: None,
model_reasoning_summary: None,
@@ -6704,6 +6886,55 @@ mod tests {
assert_eq!(reason, Some("askForApproval.granular"));
}
#[test]
fn config_nested_profile_approvals_reviewer_is_marked_experimental() {
let reason = crate::experimental_api::ExperimentalApi::experimental_reason(&Config {
model: None,
review_model: None,
model_context_window: None,
model_auto_compact_token_limit: None,
model_provider: None,
approval_policy: None,
approvals_reviewer: None,
sandbox_mode: None,
sandbox_workspace_write: None,
forced_chatgpt_workspace_id: None,
forced_login_method: None,
web_search: None,
tools: None,
profile: None,
profiles: HashMap::from([(
"default".to_string(),
ProfileV2 {
model: None,
model_provider: None,
approval_policy: None,
approvals_reviewer: Some(ApprovalsReviewer::GuardianSubagent),
service_tier: None,
model_reasoning_effort: None,
model_reasoning_summary: None,
model_verbosity: None,
web_search: None,
tools: None,
chatgpt_base_url: None,
additional: HashMap::new(),
},
)]),
instructions: None,
developer_instructions: None,
compact_prompt: None,
model_reasoning_effort: None,
model_reasoning_summary: None,
model_verbosity: None,
service_tier: None,
analytics: None,
apps: None,
additional: HashMap::new(),
});
assert_eq!(reason, Some("config/read.approvalsReviewer"));
}
#[test]
fn config_requirements_granular_allowed_approval_policy_is_marked_experimental() {
let reason =
@@ -7114,6 +7345,46 @@ mod tests {
);
}
#[test]
fn automatic_approval_review_deserializes_legacy_snake_case_risk_fields() {
let review: GuardianApprovalReview = serde_json::from_value(json!({
"status": "denied",
"risk_score": 91,
"risk_level": "high",
"rationale": "too risky"
}))
.expect("legacy snake_case automatic review should deserialize");
assert_eq!(
review,
GuardianApprovalReview {
status: GuardianApprovalReviewStatus::Denied,
risk_score: Some(91),
risk_level: Some(GuardianRiskLevel::High),
rationale: Some("too risky".to_string()),
}
);
}
#[test]
fn automatic_approval_review_deserializes_aborted_status() {
let review: GuardianApprovalReview = serde_json::from_value(json!({
"status": "aborted",
"riskScore": null,
"riskLevel": null,
"rationale": null
}))
.expect("aborted automatic review should deserialize");
assert_eq!(
review,
GuardianApprovalReview {
status: GuardianApprovalReviewStatus::Aborted,
risk_score: None,
risk_level: None,
rationale: None,
}
);
}
#[test]
fn core_turn_item_into_thread_item_converts_supported_variants() {
let user_item = TurnItem::UserMessage(UserMessageItem {
@@ -7420,6 +7691,7 @@ mod tests {
input: vec![],
cwd: None,
approval_policy: None,
approvals_reviewer: None,
sandbox_policy: None,
model: None,
service_tier: None,