From 997650a196d6941bdfcc62d69b82180402403f8e Mon Sep 17 00:00:00 2001 From: justschen Date: Mon, 13 Jul 2026 16:37:36 -0700 Subject: [PATCH 1/6] chat: add judge confirmation rationale Expose model-judge explanations on pending tool confirmations and propagate them through every generated SDK and reducer. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- clients/go/ahp/reducers.go | 27 ++++++++++--------- clients/go/ahptypes/actions.generated.go | 2 ++ clients/go/ahptypes/state.generated.go | 15 +++++++++++ .../microsoft/agenthostprotocol/Reducers.kt | 1 + .../generated/Actions.generated.kt | 4 +++ .../generated/State.generated.kt | 19 +++++++++++++ clients/rust/crates/ahp-types/src/actions.rs | 6 ++++- clients/rust/crates/ahp-types/src/state.rs | 18 +++++++++++++ clients/rust/crates/ahp/src/reducers.rs | 1 + .../Generated/Actions.generated.swift | 5 ++++ .../Generated/State.generated.swift | 23 ++++++++++++++++ .../Sources/AgentHostProtocol/Reducers.swift | 1 + ...20260713-tool-call-judge-confirmation.json | 4 +++ schema/actions.schema.json | 24 +++++++++++++++++ schema/commands.schema.json | 24 +++++++++++++++++ schema/errors.schema.json | 24 +++++++++++++++++ schema/notifications.schema.json | 20 ++++++++++++++ schema/state.schema.json | 20 ++++++++++++++ scripts/generate-go.ts | 4 ++- scripts/generate-kotlin.ts | 6 +++-- scripts/generate-rust.ts | 6 +++-- scripts/generate-swift.ts | 6 +++-- types/channels-chat/actions.ts | 3 +++ types/channels-chat/reducer.ts | 1 + types/channels-chat/state.ts | 21 +++++++++++++++ types/index.ts | 2 ++ ...ing-tool-back-to-pending-confirmation.json | 1 + ...confirmation-sets-input-needed-status.json | 1 + ...olcallready-with-confirmation-options.json | 8 ++++++ .../220-toolcall-actions-update-meta.json | 1 + 30 files changed, 277 insertions(+), 21 deletions(-) create mode 100644 docs/.changes/20260713-tool-call-judge-confirmation.json diff --git a/clients/go/ahp/reducers.go b/clients/go/ahp/reducers.go index 4c9cdb18..d547f55c 100644 --- a/clients/go/ahp/reducers.go +++ b/clients/go/ahp/reducers.go @@ -1009,19 +1009,20 @@ func applyToolCallReady(state *ahptypes.ChatState, a *ahptypes.ChatToolCallReady }} } return ahptypes.ToolCallState{Value: &ahptypes.ToolCallPendingConfirmationState{ - Status: ahptypes.ToolCallStatusPendingConfirmation, - ToolCallId: common.id, - ToolName: common.name, - DisplayName: common.displayName, - Intention: common.intention, - Contributor: common.contributor, - Meta: common.meta, - InvocationMessage: a.InvocationMessage, - ToolInput: a.ToolInput, - ConfirmationTitle: a.ConfirmationTitle, - Edits: a.Edits, - Editable: a.Editable, - Options: a.Options, + Status: ahptypes.ToolCallStatusPendingConfirmation, + ToolCallId: common.id, + ToolName: common.name, + DisplayName: common.displayName, + Intention: common.intention, + Contributor: common.contributor, + Meta: common.meta, + InvocationMessage: a.InvocationMessage, + ToolInput: a.ToolInput, + ConfirmationTitle: a.ConfirmationTitle, + ConfirmationReason: a.ConfirmationReason, + Edits: a.Edits, + Editable: a.Editable, + Options: a.Options, }} } return tc diff --git a/clients/go/ahptypes/actions.generated.go b/clients/go/ahptypes/actions.generated.go index 18de3b4f..2e2c79a6 100644 --- a/clients/go/ahptypes/actions.generated.go +++ b/clients/go/ahptypes/actions.generated.go @@ -350,6 +350,8 @@ type ChatToolCallReadyAction struct { ToolInput *string `json:"toolInput,omitempty"` // Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) ConfirmationTitle *StringOrMarkdown `json:"confirmationTitle,omitempty"` + // Why the tool requires user confirmation. + ConfirmationReason *ToolCallJudgeConfirmationReason `json:"confirmationReason,omitempty"` // File edits that this tool call will perform, for preview before confirmation Edits *json.RawMessage `json:"edits,omitempty"` // Whether the agent host allows the client to edit the tool's input parameters before confirming diff --git a/clients/go/ahptypes/state.generated.go b/clients/go/ahptypes/state.generated.go index 462087f3..49213cda 100644 --- a/clients/go/ahptypes/state.generated.go +++ b/clients/go/ahptypes/state.generated.go @@ -237,6 +237,13 @@ const ( ToolCallConfirmationReasonSetting ToolCallConfirmationReason = "setting" ) +// Identifies a model judge as the source of a confirmation requirement. +type ToolCallJudgeConfirmationReasonKind string + +const ( + ToolCallJudgeConfirmationReasonKindJudge ToolCallJudgeConfirmationReasonKind = "judge" +) + // Why a tool call was cancelled. type ToolCallCancellationReason string @@ -1702,6 +1709,12 @@ type ToolCallResult struct { Error *json.RawMessage `json:"error,omitempty"` } +// A model judge's explanation for requiring user confirmation. +type ToolCallJudgeConfirmationReason struct { + Kind ToolCallJudgeConfirmationReasonKind `json:"kind"` + Reason string `json:"reason"` +} + // A confirmation option that the server offers for a tool call awaiting // approval. Allows richer choices beyond simple approve/deny — for example, // "Approve in this Session" or "Deny with reason." @@ -1771,6 +1784,8 @@ type ToolCallPendingConfirmationState struct { Status ToolCallStatus `json:"status"` // Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) ConfirmationTitle *StringOrMarkdown `json:"confirmationTitle,omitempty"` + // Why the tool requires user confirmation. + ConfirmationReason *ToolCallJudgeConfirmationReason `json:"confirmationReason,omitempty"` // File edits that this tool call will perform, for preview before confirmation Edits *json.RawMessage `json:"edits,omitempty"` // Whether the agent host allows the client to edit the tool's input parameters before confirming diff --git a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt index 712a688e..cb52c367 100644 --- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt +++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt @@ -892,6 +892,7 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when toolInput = a.toolInput, status = ToolCallStatus.PENDING_CONFIRMATION, confirmationTitle = a.confirmationTitle, + confirmationReason = a.confirmationReason, edits = a.edits, editable = a.editable, options = a.options, diff --git a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Actions.generated.kt b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Actions.generated.kt index 4a9517c4..d0b64697 100644 --- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Actions.generated.kt +++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Actions.generated.kt @@ -471,6 +471,10 @@ data class ChatToolCallReadyAction( * Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) */ val confirmationTitle: StringOrMarkdown? = null, + /** + * Why the tool requires user confirmation. + */ + val confirmationReason: ToolCallJudgeConfirmationReason? = null, /** * File edits that this tool call will perform, for preview before confirmation */ diff --git a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt index 9a008418..16511304 100644 --- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt +++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt @@ -433,6 +433,15 @@ enum class ToolCallConfirmationReason { SETTING } +/** + * Identifies a model judge as the source of a confirmation requirement. + */ +@Serializable +enum class ToolCallJudgeConfirmationReasonKind { + @SerialName("judge") + JUDGE +} + /** * Why a tool call was cancelled. */ @@ -2446,6 +2455,10 @@ data class ToolCallPendingConfirmationState( * Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) */ val confirmationTitle: StringOrMarkdown? = null, + /** + * Why the tool requires user confirmation. + */ + val confirmationReason: ToolCallJudgeConfirmationReason? = null, /** * File edits that this tool call will perform, for preview before confirmation */ @@ -2726,6 +2739,12 @@ data class ToolCallCancelledState( val selectedOption: ConfirmationOption? = null ) +@Serializable +data class ToolCallJudgeConfirmationReason( + val kind: ToolCallJudgeConfirmationReasonKind, + val reason: String +) + @Serializable data class ConfirmationOption( /** diff --git a/clients/rust/crates/ahp-types/src/actions.rs b/clients/rust/crates/ahp-types/src/actions.rs index c76109d8..7f1e1592 100644 --- a/clients/rust/crates/ahp-types/src/actions.rs +++ b/clients/rust/crates/ahp-types/src/actions.rs @@ -19,7 +19,8 @@ use crate::state::{ ConfirmationOption, Customization, ErrorInfo, McpServerState, Message, ModelSelection, PendingMessageKind, ResponsePart, SessionActiveClient, SessionInputRequest, TerminalClaim, TerminalInfo, TextRange, ToolCallCancellationReason, ToolCallConfirmationReason, - ToolCallContributor, ToolCallResult, ToolDefinition, ToolResultContent, Turn, UsageInfo, + ToolCallContributor, ToolCallJudgeConfirmationReason, ToolCallResult, ToolDefinition, + ToolResultContent, Turn, UsageInfo, }; // ─── ActionType ────────────────────────────────────────────────────── @@ -476,6 +477,9 @@ pub struct ChatToolCallReadyAction { /// Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) #[serde(default, skip_serializing_if = "Option::is_none")] pub confirmation_title: Option, + /// Why the tool requires user confirmation. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub confirmation_reason: Option, /// File edits that this tool call will perform, for preview before confirmation #[serde(default, skip_serializing_if = "Option::is_none")] pub edits: Option, diff --git a/clients/rust/crates/ahp-types/src/state.rs b/clients/rust/crates/ahp-types/src/state.rs index 3c857eb6..52cf67b7 100644 --- a/clients/rust/crates/ahp-types/src/state.rs +++ b/clients/rust/crates/ahp-types/src/state.rs @@ -342,6 +342,13 @@ pub enum ToolCallConfirmationReason { Setting, } +/// Identifies a model judge as the source of a confirmation requirement. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum ToolCallJudgeConfirmationReasonKind { + #[serde(rename = "judge")] + Judge, +} + /// Why a tool call was cancelled. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum ToolCallCancellationReason { @@ -2127,6 +2134,14 @@ pub struct ToolCallResult { pub error: Option, } +/// A model judge's explanation for requiring user confirmation. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ToolCallJudgeConfirmationReason { + pub kind: ToolCallJudgeConfirmationReasonKind, + pub reason: String, +} + /// A confirmation option that the server offers for a tool call awaiting /// approval. Allows richer choices beyond simple approve/deny — for example, /// "Approve in this Session" or "Deny with reason." @@ -2211,6 +2226,9 @@ pub struct ToolCallPendingConfirmationState { /// Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) #[serde(default, skip_serializing_if = "Option::is_none")] pub confirmation_title: Option, + /// Why the tool requires user confirmation. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub confirmation_reason: Option, /// File edits that this tool call will perform, for preview before confirmation #[serde(default, skip_serializing_if = "Option::is_none")] pub edits: Option, diff --git a/clients/rust/crates/ahp/src/reducers.rs b/clients/rust/crates/ahp/src/reducers.rs index ba975d70..d3568eff 100644 --- a/clients/rust/crates/ahp/src/reducers.rs +++ b/clients/rust/crates/ahp/src/reducers.rs @@ -1184,6 +1184,7 @@ fn apply_tool_call_ready(state: &mut ChatState, a: &ChatToolCallReadyAction) -> invocation_message: a.invocation_message.clone(), tool_input: a.tool_input.clone(), confirmation_title: a.confirmation_title.clone(), + confirmation_reason: a.confirmation_reason.clone(), edits: a.edits.clone(), editable: a.editable, options: a.options.clone(), diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift index 76473df3..2e9e9681 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift @@ -480,6 +480,8 @@ public struct ChatToolCallReadyAction: Codable, Sendable { public var toolInput: String? /// Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) public var confirmationTitle: StringOrMarkdown? + /// Why the tool requires user confirmation. + public var confirmationReason: ToolCallJudgeConfirmationReason? /// File edits that this tool call will perform, for preview before confirmation public var edits: AnyCodable? /// Whether the agent host allows the client to edit the tool's input parameters before confirming @@ -500,6 +502,7 @@ public struct ChatToolCallReadyAction: Codable, Sendable { case invocationMessage case toolInput case confirmationTitle + case confirmationReason case edits case editable case confirmed @@ -514,6 +517,7 @@ public struct ChatToolCallReadyAction: Codable, Sendable { invocationMessage: StringOrMarkdown, toolInput: String? = nil, confirmationTitle: StringOrMarkdown? = nil, + confirmationReason: ToolCallJudgeConfirmationReason? = nil, edits: AnyCodable? = nil, editable: Bool? = nil, confirmed: ToolCallConfirmationReason? = nil, @@ -526,6 +530,7 @@ public struct ChatToolCallReadyAction: Codable, Sendable { self.invocationMessage = invocationMessage self.toolInput = toolInput self.confirmationTitle = confirmationTitle + self.confirmationReason = confirmationReason self.edits = edits self.editable = editable self.confirmed = confirmed diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift index 6af2ddf1..6dde8cbf 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift @@ -225,6 +225,11 @@ public enum ToolCallConfirmationReason: String, Codable, Sendable { case setting = "setting" } +/// Identifies a model judge as the source of a confirmation requirement. +public enum ToolCallJudgeConfirmationReasonKind: String, Codable, Sendable { + case judge = "judge" +} + /// Why a tool call was cancelled. public enum ToolCallCancellationReason: String, Codable, Sendable { case denied = "denied" @@ -2462,6 +2467,8 @@ public struct ToolCallPendingConfirmationState: Codable, Sendable { public var status: ToolCallStatus /// Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) public var confirmationTitle: StringOrMarkdown? + /// Why the tool requires user confirmation. + public var confirmationReason: ToolCallJudgeConfirmationReason? /// File edits that this tool call will perform, for preview before confirmation public var edits: AnyCodable? /// Whether the agent host allows the client to edit the tool's input parameters before confirming @@ -2483,6 +2490,7 @@ public struct ToolCallPendingConfirmationState: Codable, Sendable { case toolInput case status case confirmationTitle + case confirmationReason case edits case editable case options @@ -2499,6 +2507,7 @@ public struct ToolCallPendingConfirmationState: Codable, Sendable { toolInput: String? = nil, status: ToolCallStatus, confirmationTitle: StringOrMarkdown? = nil, + confirmationReason: ToolCallJudgeConfirmationReason? = nil, edits: AnyCodable? = nil, editable: Bool? = nil, options: [ConfirmationOption]? = nil @@ -2513,6 +2522,7 @@ public struct ToolCallPendingConfirmationState: Codable, Sendable { self.toolInput = toolInput self.status = status self.confirmationTitle = confirmationTitle + self.confirmationReason = confirmationReason self.edits = edits self.editable = editable self.options = options @@ -2867,6 +2877,19 @@ public struct ToolCallCancelledState: Codable, Sendable { } } +public struct ToolCallJudgeConfirmationReason: Codable, Sendable { + public var kind: ToolCallJudgeConfirmationReasonKind + public var reason: String + + public init( + kind: ToolCallJudgeConfirmationReasonKind, + reason: String + ) { + self.kind = kind + self.reason = reason + } +} + public struct ConfirmationOption: Codable, Sendable { /// Unique identifier for the option, returned in the confirmed action public var id: String diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift index 58c67fc3..0674e04f 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift @@ -219,6 +219,7 @@ public func chatReducer(state: ChatState, action: StateAction) -> ChatState { toolInput: a.toolInput, status: .pendingConfirmation, confirmationTitle: a.confirmationTitle, + confirmationReason: a.confirmationReason, edits: a.edits, editable: a.editable, options: a.options diff --git a/docs/.changes/20260713-tool-call-judge-confirmation.json b/docs/.changes/20260713-tool-call-judge-confirmation.json new file mode 100644 index 00000000..dcd4ddd9 --- /dev/null +++ b/docs/.changes/20260713-tool-call-judge-confirmation.json @@ -0,0 +1,4 @@ +{ + "type": "added", + "message": "`judge` tool-call confirmation reasons with a model-provided explanation for pending confirmations." +} diff --git a/schema/actions.schema.json b/schema/actions.schema.json index bb4a1a28..bd4daa49 100644 --- a/schema/actions.schema.json +++ b/schema/actions.schema.json @@ -846,6 +846,10 @@ "$ref": "#/$defs/StringOrMarkdown", "description": "Short title for the confirmation prompt (e.g. `\"Run in terminal\"`, `\"Write file\"`)" }, + "confirmationReason": { + "$ref": "#/$defs/ToolCallJudgeConfirmationReason", + "description": "Why the tool requires user confirmation." + }, "edits": { "type": "object", "properties": { @@ -5266,6 +5270,22 @@ "content" ] }, + "ToolCallJudgeConfirmationReason": { + "type": "object", + "description": "A model judge's explanation for requiring user confirmation.", + "properties": { + "kind": { + "const": "judge" + }, + "reason": { + "type": "string" + } + }, + "required": [ + "kind", + "reason" + ] + }, "ConfirmationOption": { "type": "object", "description": "A confirmation option that the server offers for a tool call awaiting\napproval. Allows richer choices beyond simple approve/deny — for example,\n\"Approve in this Session\" or \"Deny with reason.\"", @@ -5515,6 +5535,10 @@ "$ref": "#/$defs/StringOrMarkdown", "description": "Short title for the confirmation prompt (e.g. `\"Run in terminal\"`, `\"Write file\"`)" }, + "confirmationReason": { + "$ref": "#/$defs/ToolCallJudgeConfirmationReason", + "description": "Why the tool requires user confirmation." + }, "edits": { "type": "object", "properties": { diff --git a/schema/commands.schema.json b/schema/commands.schema.json index 2379858d..5554ab73 100644 --- a/schema/commands.schema.json +++ b/schema/commands.schema.json @@ -4534,6 +4534,22 @@ "content" ] }, + "ToolCallJudgeConfirmationReason": { + "type": "object", + "description": "A model judge's explanation for requiring user confirmation.", + "properties": { + "kind": { + "const": "judge" + }, + "reason": { + "type": "string" + } + }, + "required": [ + "kind", + "reason" + ] + }, "ConfirmationOption": { "type": "object", "description": "A confirmation option that the server offers for a tool call awaiting\napproval. Allows richer choices beyond simple approve/deny — for example,\n\"Approve in this Session\" or \"Deny with reason.\"", @@ -4783,6 +4799,10 @@ "$ref": "#/$defs/StringOrMarkdown", "description": "Short title for the confirmation prompt (e.g. `\"Run in terminal\"`, `\"Write file\"`)" }, + "confirmationReason": { + "$ref": "#/$defs/ToolCallJudgeConfirmationReason", + "description": "Why the tool requires user confirmation." + }, "edits": { "type": "object", "properties": { @@ -6707,6 +6727,10 @@ "$ref": "#/$defs/StringOrMarkdown", "description": "Short title for the confirmation prompt (e.g. `\"Run in terminal\"`, `\"Write file\"`)" }, + "confirmationReason": { + "$ref": "#/$defs/ToolCallJudgeConfirmationReason", + "description": "Why the tool requires user confirmation." + }, "edits": { "type": "object", "properties": { diff --git a/schema/errors.schema.json b/schema/errors.schema.json index e5d2b1ef..9f904f03 100644 --- a/schema/errors.schema.json +++ b/schema/errors.schema.json @@ -3325,6 +3325,22 @@ "content" ] }, + "ToolCallJudgeConfirmationReason": { + "type": "object", + "description": "A model judge's explanation for requiring user confirmation.", + "properties": { + "kind": { + "const": "judge" + }, + "reason": { + "type": "string" + } + }, + "required": [ + "kind", + "reason" + ] + }, "ConfirmationOption": { "type": "object", "description": "A confirmation option that the server offers for a tool call awaiting\napproval. Allows richer choices beyond simple approve/deny — for example,\n\"Approve in this Session\" or \"Deny with reason.\"", @@ -3574,6 +3590,10 @@ "$ref": "#/$defs/StringOrMarkdown", "description": "Short title for the confirmation prompt (e.g. `\"Run in terminal\"`, `\"Write file\"`)" }, + "confirmationReason": { + "$ref": "#/$defs/ToolCallJudgeConfirmationReason", + "description": "Why the tool requires user confirmation." + }, "edits": { "type": "object", "properties": { @@ -7618,6 +7638,10 @@ "$ref": "#/$defs/StringOrMarkdown", "description": "Short title for the confirmation prompt (e.g. `\"Run in terminal\"`, `\"Write file\"`)" }, + "confirmationReason": { + "$ref": "#/$defs/ToolCallJudgeConfirmationReason", + "description": "Why the tool requires user confirmation." + }, "edits": { "type": "object", "properties": { diff --git a/schema/notifications.schema.json b/schema/notifications.schema.json index 85e21832..8a68f6de 100644 --- a/schema/notifications.schema.json +++ b/schema/notifications.schema.json @@ -3485,6 +3485,22 @@ "content" ] }, + "ToolCallJudgeConfirmationReason": { + "type": "object", + "description": "A model judge's explanation for requiring user confirmation.", + "properties": { + "kind": { + "const": "judge" + }, + "reason": { + "type": "string" + } + }, + "required": [ + "kind", + "reason" + ] + }, "ConfirmationOption": { "type": "object", "description": "A confirmation option that the server offers for a tool call awaiting\napproval. Allows richer choices beyond simple approve/deny — for example,\n\"Approve in this Session\" or \"Deny with reason.\"", @@ -3734,6 +3750,10 @@ "$ref": "#/$defs/StringOrMarkdown", "description": "Short title for the confirmation prompt (e.g. `\"Run in terminal\"`, `\"Write file\"`)" }, + "confirmationReason": { + "$ref": "#/$defs/ToolCallJudgeConfirmationReason", + "description": "Why the tool requires user confirmation." + }, "edits": { "type": "object", "properties": { diff --git a/schema/state.schema.json b/schema/state.schema.json index 5017391e..69b73494 100644 --- a/schema/state.schema.json +++ b/schema/state.schema.json @@ -3236,6 +3236,22 @@ "content" ] }, + "ToolCallJudgeConfirmationReason": { + "type": "object", + "description": "A model judge's explanation for requiring user confirmation.", + "properties": { + "kind": { + "const": "judge" + }, + "reason": { + "type": "string" + } + }, + "required": [ + "kind", + "reason" + ] + }, "ConfirmationOption": { "type": "object", "description": "A confirmation option that the server offers for a tool call awaiting\napproval. Allows richer choices beyond simple approve/deny — for example,\n\"Approve in this Session\" or \"Deny with reason.\"", @@ -3485,6 +3501,10 @@ "$ref": "#/$defs/StringOrMarkdown", "description": "Short title for the confirmation prompt (e.g. `\"Run in terminal\"`, `\"Write file\"`)" }, + "confirmationReason": { + "$ref": "#/$defs/ToolCallJudgeConfirmationReason", + "description": "Why the tool requires user confirmation." + }, "edits": { "type": "object", "properties": { diff --git a/scripts/generate-go.ts b/scripts/generate-go.ts index 19176699..71327c10 100644 --- a/scripts/generate-go.ts +++ b/scripts/generate-go.ts @@ -644,7 +644,8 @@ const STATE_ENUMS = [ 'ChatOriginKind', 'ChatInteractivity', 'PendingMessageKind', 'ChatInputAnswerState', 'ChatInputAnswerValueKind', 'ChatInputQuestionKind', 'ChatInputResponseKind', 'SessionInputRequestKind', 'TurnState', 'MessageKind', 'MessageAttachmentKind', 'ResponsePartKind', 'ToolCallStatus', - 'ToolCallConfirmationReason', 'ToolCallCancellationReason', + 'ToolCallConfirmationReason', 'ToolCallJudgeConfirmationReasonKind', + 'ToolCallCancellationReason', 'ConfirmationOptionKind', 'ToolCallContributorKind', 'ToolResultContentType', 'CustomizationType', 'CustomizationLoadStatus', 'TerminalClaimKind', 'McpServerStatus', 'McpAuthRequiredReason', @@ -711,6 +712,7 @@ const STATE_STRUCTS: { name: string; omitDiscriminants?: boolean; goName?: strin { name: 'SystemNotificationResponsePart' }, { name: 'InputRequestResponsePart' }, { name: 'ToolCallResult' }, + { name: 'ToolCallJudgeConfirmationReason' }, { name: 'ConfirmationOption' }, { name: 'ToolCallStreamingState' }, { name: 'ToolCallPendingConfirmationState' }, diff --git a/scripts/generate-kotlin.ts b/scripts/generate-kotlin.ts index 9ab6b405..3edcac22 100644 --- a/scripts/generate-kotlin.ts +++ b/scripts/generate-kotlin.ts @@ -791,7 +791,8 @@ const STATE_ENUMS = [ 'ChatOriginKind', 'ChatInteractivity', 'ChatInputAnswerState', 'ChatInputAnswerValueKind', 'ChatInputQuestionKind', 'ChatInputResponseKind', 'SessionInputRequestKind', 'TurnState', 'MessageKind', 'MessageAttachmentKind', 'ResponsePartKind', 'ToolCallStatus', - 'ToolCallConfirmationReason', 'ToolCallCancellationReason', 'ConfirmationOptionKind', + 'ToolCallConfirmationReason', 'ToolCallJudgeConfirmationReasonKind', + 'ToolCallCancellationReason', 'ConfirmationOptionKind', 'ToolCallContributorKind', 'ToolResultContentType', 'CustomizationType', 'CustomizationLoadStatus', 'TerminalClaimKind', 'McpServerStatus', 'McpAuthRequiredReason', @@ -825,7 +826,8 @@ const STATE_STRUCTS = [ 'ToolCallResult', 'ToolCallStreamingState', 'ToolCallPendingConfirmationState', 'ToolCallRunningState', 'ToolCallPendingResultConfirmationState', 'ToolCallCompletedState', - 'ToolCallCancelledState', 'ConfirmationOption', 'ToolDefinition', 'ToolAnnotations', + 'ToolCallCancelledState', 'ToolCallJudgeConfirmationReason', 'ConfirmationOption', + 'ToolDefinition', 'ToolAnnotations', 'ToolResultTextContent', 'ToolResultEmbeddedResourceContent', 'ToolResultResourceContent', 'ToolResultFileEditContent', 'ToolResultTerminalContent', 'ToolResultTerminalCompleteContent', diff --git a/scripts/generate-rust.ts b/scripts/generate-rust.ts index d29e56f1..c69e95b9 100644 --- a/scripts/generate-rust.ts +++ b/scripts/generate-rust.ts @@ -654,7 +654,8 @@ const STATE_ENUMS = [ 'ChatOriginKind', 'ChatInteractivity', 'ChatInputAnswerState', 'ChatInputAnswerValueKind', 'ChatInputQuestionKind', 'ChatInputResponseKind', 'SessionInputRequestKind', 'TurnState', 'MessageKind', 'MessageAttachmentKind', 'ResponsePartKind', 'ToolCallStatus', - 'ToolCallConfirmationReason', 'ToolCallCancellationReason', + 'ToolCallConfirmationReason', 'ToolCallJudgeConfirmationReasonKind', + 'ToolCallCancellationReason', 'ConfirmationOptionKind', 'ToolCallContributorKind', 'ToolResultContentType', 'CustomizationType', 'CustomizationLoadStatus', 'TerminalClaimKind', 'McpServerStatus', 'McpAuthRequiredReason', @@ -742,6 +743,7 @@ const STATE_STRUCTS: { name: string; omitDiscriminants?: boolean; rustName?: str { name: 'SystemNotificationResponsePart', omitDiscriminants: true }, { name: 'InputRequestResponsePart', omitDiscriminants: true }, { name: 'ToolCallResult' }, + { name: 'ToolCallJudgeConfirmationReason' }, { name: 'ConfirmationOption' }, { name: 'ToolCallStreamingState', omitDiscriminants: true }, { name: 'ToolCallPendingConfirmationState', omitDiscriminants: true }, @@ -1274,7 +1276,7 @@ pub struct ${scope}ToolCallConfirmedAction { function generateActionsFile(project: Project): string { const lines: string[] = [GENERATED_HEADER]; lines.push('#[allow(unused_imports)]'); - lines.push('use crate::state::{AgentInfo, AgentSelection, Annotation, AnnotationEntry, ChatInputAnswer, ChatInputRequest, ChatInputResponseKind, ChatInteractivity, ChatOrigin, ConfirmationOption, Customization, ErrorInfo, McpServerState, ModelSelection, ResponsePart, SessionActiveClient, SessionInputRequest, TerminalClaim, TerminalInfo, TextRange, ToolCallContributor, ToolCallResult, ToolCallConfirmationReason, ToolCallCancellationReason, ToolDefinition, ToolResultContent, UsageInfo, Message, PendingMessageKind, Turn, ChangesetStatus, ChangesetFile, ChangesetOperation, ChangesetOperationStatus, Changeset, ChatSummary};'); + lines.push('use crate::state::{AgentInfo, AgentSelection, Annotation, AnnotationEntry, ChatInputAnswer, ChatInputRequest, ChatInputResponseKind, ChatInteractivity, ChatOrigin, ConfirmationOption, Customization, ErrorInfo, McpServerState, ModelSelection, ResponsePart, SessionActiveClient, SessionInputRequest, TerminalClaim, TerminalInfo, TextRange, ToolCallContributor, ToolCallResult, ToolCallJudgeConfirmationReason, ToolCallConfirmationReason, ToolCallCancellationReason, ToolDefinition, ToolResultContent, UsageInfo, Message, PendingMessageKind, Turn, ChangesetStatus, ChangesetFile, ChangesetOperation, ChangesetOperationStatus, Changeset, ChatSummary};'); lines.push(''); // ActionType enum diff --git a/scripts/generate-swift.ts b/scripts/generate-swift.ts index d168d1e8..64b50103 100644 --- a/scripts/generate-swift.ts +++ b/scripts/generate-swift.ts @@ -541,7 +541,8 @@ const STATE_ENUMS = [ 'ChatOriginKind', 'ChatInteractivity', 'ChatInputAnswerState', 'ChatInputAnswerValueKind', 'ChatInputQuestionKind', 'ChatInputResponseKind', 'SessionInputRequestKind', 'TurnState', 'MessageKind', 'MessageAttachmentKind', 'ResponsePartKind', 'ToolCallStatus', - 'ToolCallConfirmationReason', 'ToolCallCancellationReason', 'ConfirmationOptionKind', + 'ToolCallConfirmationReason', 'ToolCallJudgeConfirmationReasonKind', + 'ToolCallCancellationReason', 'ConfirmationOptionKind', 'ToolCallContributorKind', 'ToolResultContentType', 'CustomizationType', 'CustomizationLoadStatus', 'TerminalClaimKind', 'McpServerStatus', 'McpAuthRequiredReason', @@ -575,7 +576,8 @@ const STATE_STRUCTS = [ 'ToolCallResult', 'ToolCallStreamingState', 'ToolCallPendingConfirmationState', 'ToolCallRunningState', 'ToolCallPendingResultConfirmationState', 'ToolCallCompletedState', - 'ToolCallCancelledState', 'ConfirmationOption', 'ToolDefinition', 'ToolAnnotations', + 'ToolCallCancelledState', 'ToolCallJudgeConfirmationReason', 'ConfirmationOption', + 'ToolDefinition', 'ToolAnnotations', 'ToolResultTextContent', 'ToolResultEmbeddedResourceContent', 'ToolResultResourceContent', 'ToolResultFileEditContent', 'ToolResultTerminalContent', 'ToolResultTerminalCompleteContent', diff --git a/types/channels-chat/actions.ts b/types/channels-chat/actions.ts index c1f5e663..478d6f98 100644 --- a/types/channels-chat/actions.ts +++ b/types/channels-chat/actions.ts @@ -16,6 +16,7 @@ import type { ChatInputResponseKind, ConfirmationOption, ToolCallContributor, + ToolCallJudgeConfirmationReason, Turn, } from './state.js'; import { @@ -203,6 +204,8 @@ export interface ChatToolCallReadyAction extends ToolCallActionBase { toolInput?: string; /** Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) */ confirmationTitle?: StringOrMarkdown; + /** Why the tool requires user confirmation. */ + confirmationReason?: ToolCallJudgeConfirmationReason; /** File edits that this tool call will perform, for preview before confirmation */ edits?: { items: FileEdit[] }; /** Whether the agent host allows the client to edit the tool's input parameters before confirming */ diff --git a/types/channels-chat/reducer.ts b/types/channels-chat/reducer.ts index 1da23f9a..bdca013a 100644 --- a/types/channels-chat/reducer.ts +++ b/types/channels-chat/reducer.ts @@ -401,6 +401,7 @@ export function chatReducer(state: ChatState, action: ChatAction, log?: (msg: st invocationMessage: action.invocationMessage, toolInput: action.toolInput, confirmationTitle: action.confirmationTitle, + confirmationReason: action.confirmationReason, edits: action.edits, editable: action.editable, ...(action.options ? { options: action.options } : {}), diff --git a/types/channels-chat/state.ts b/types/channels-chat/state.ts index 9dff723f..7b746061 100644 --- a/types/channels-chat/state.ts +++ b/types/channels-chat/state.ts @@ -934,6 +934,25 @@ export const enum ToolCallConfirmationReason { Setting = 'setting', } +/** + * Identifies a model judge as the source of a confirmation requirement. + * + * @category Tool Call Types + */ +export const enum ToolCallJudgeConfirmationReasonKind { + Judge = 'judge', +} + +/** + * A model judge's explanation for requiring user confirmation. + * + * @category Tool Call Types + */ +export interface ToolCallJudgeConfirmationReason { + kind: ToolCallJudgeConfirmationReasonKind.Judge; + reason: string; +} + /** * Why a tool call was cancelled. * @@ -1100,6 +1119,8 @@ export interface ToolCallPendingConfirmationState extends ToolCallBase, ToolCall status: ToolCallStatus.PendingConfirmation; /** Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) */ confirmationTitle?: StringOrMarkdown; + /** Why the tool requires user confirmation. */ + confirmationReason?: ToolCallJudgeConfirmationReason; /** File edits that this tool call will perform, for preview before confirmation */ edits?: { items: FileEdit[] }; /** Whether the agent host allows the client to edit the tool's input parameters before confirming */ diff --git a/types/index.ts b/types/index.ts index bc57f091..9d4ee9e2 100644 --- a/types/index.ts +++ b/types/index.ts @@ -54,6 +54,7 @@ export type { ToolCallCancelledState, ToolCallState, ToolCallConfirmationState, + ToolCallJudgeConfirmationReason, ConfirmationOption, ToolDefinition, ToolAnnotations, @@ -125,6 +126,7 @@ export { ResponsePartKind, ToolCallStatus, ToolCallConfirmationReason, + ToolCallJudgeConfirmationReasonKind, ToolCallCancellationReason, ConfirmationOptionKind, ToolResultContentType, diff --git a/types/test-cases/reducers/026-toolcallready-transitions-running-tool-back-to-pending-confirmation.json b/types/test-cases/reducers/026-toolcallready-transitions-running-tool-back-to-pending-confirmation.json index 94f7f058..b97e0353 100644 --- a/types/test-cases/reducers/026-toolcallready-transitions-running-tool-back-to-pending-confirmation.json +++ b/types/test-cases/reducers/026-toolcallready-transitions-running-tool-back-to-pending-confirmation.json @@ -74,6 +74,7 @@ "invocationMessage": "Run: rm -rf /tmp/test", "toolInput": null, "confirmationTitle": null, + "confirmationReason": null, "edits": null, "editable": null } diff --git a/types/test-cases/reducers/111-toolcall-pending-confirmation-sets-input-needed-status.json b/types/test-cases/reducers/111-toolcall-pending-confirmation-sets-input-needed-status.json index fbf03a73..c63b6455 100644 --- a/types/test-cases/reducers/111-toolcall-pending-confirmation-sets-input-needed-status.json +++ b/types/test-cases/reducers/111-toolcall-pending-confirmation-sets-input-needed-status.json @@ -61,6 +61,7 @@ "invocationMessage": "Run: rm -rf /tmp/test", "toolInput": "rm -rf /tmp/test", "confirmationTitle": null, + "confirmationReason": null, "edits": null, "editable": null } diff --git a/types/test-cases/reducers/127-toolcallready-with-confirmation-options.json b/types/test-cases/reducers/127-toolcallready-with-confirmation-options.json index 0822e2fc..098d89ba 100644 --- a/types/test-cases/reducers/127-toolcallready-with-confirmation-options.json +++ b/types/test-cases/reducers/127-toolcallready-with-confirmation-options.json @@ -33,6 +33,10 @@ "turnId": "turn-1", "toolCallId": "tc-1", "invocationMessage": "Run: echo hello", + "confirmationReason": { + "kind": "judge", + "reason": "The command can modify the workspace." + }, "options": [ { "id": "approve-once", @@ -86,6 +90,10 @@ "invocationMessage": "Run: echo hello", "toolInput": null, "confirmationTitle": null, + "confirmationReason": { + "kind": "judge", + "reason": "The command can modify the workspace." + }, "edits": null, "editable": null, "options": [ diff --git a/types/test-cases/reducers/220-toolcall-actions-update-meta.json b/types/test-cases/reducers/220-toolcall-actions-update-meta.json index 2eebdd14..c2243229 100644 --- a/types/test-cases/reducers/220-toolcall-actions-update-meta.json +++ b/types/test-cases/reducers/220-toolcall-actions-update-meta.json @@ -273,6 +273,7 @@ "invocationMessage": "Needs approval", "toolInput": null, "confirmationTitle": null, + "confirmationReason": null, "edits": null, "editable": null } From d5bf842c7ba0d6c7e168c5caa476248d54a83a91 Mon Sep 17 00:00:00 2001 From: justschen Date: Mon, 13 Jul 2026 18:34:42 -0700 Subject: [PATCH 2/6] chat: allow markdown in judge rationale Use StringOrMarkdown for the user-visible judge explanation so clients can render it consistently with other confirmation text. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- clients/go/ahptypes/state.generated.go | 2 +- .../microsoft/agenthostprotocol/generated/State.generated.kt | 2 +- clients/rust/crates/ahp-types/src/state.rs | 2 +- .../Sources/AgentHostProtocol/Generated/State.generated.swift | 4 ++-- schema/actions.schema.json | 2 +- schema/commands.schema.json | 2 +- schema/errors.schema.json | 2 +- schema/notifications.schema.json | 2 +- schema/state.schema.json | 2 +- types/channels-chat/state.ts | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/clients/go/ahptypes/state.generated.go b/clients/go/ahptypes/state.generated.go index 49213cda..d8ba40f5 100644 --- a/clients/go/ahptypes/state.generated.go +++ b/clients/go/ahptypes/state.generated.go @@ -1712,7 +1712,7 @@ type ToolCallResult struct { // A model judge's explanation for requiring user confirmation. type ToolCallJudgeConfirmationReason struct { Kind ToolCallJudgeConfirmationReasonKind `json:"kind"` - Reason string `json:"reason"` + Reason StringOrMarkdown `json:"reason"` } // A confirmation option that the server offers for a tool call awaiting diff --git a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt index 16511304..f032a350 100644 --- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt +++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt @@ -2742,7 +2742,7 @@ data class ToolCallCancelledState( @Serializable data class ToolCallJudgeConfirmationReason( val kind: ToolCallJudgeConfirmationReasonKind, - val reason: String + val reason: StringOrMarkdown ) @Serializable diff --git a/clients/rust/crates/ahp-types/src/state.rs b/clients/rust/crates/ahp-types/src/state.rs index 52cf67b7..1a9630f7 100644 --- a/clients/rust/crates/ahp-types/src/state.rs +++ b/clients/rust/crates/ahp-types/src/state.rs @@ -2139,7 +2139,7 @@ pub struct ToolCallResult { #[serde(rename_all = "camelCase")] pub struct ToolCallJudgeConfirmationReason { pub kind: ToolCallJudgeConfirmationReasonKind, - pub reason: String, + pub reason: StringOrMarkdown, } /// A confirmation option that the server offers for a tool call awaiting diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift index 6dde8cbf..e242bf94 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift @@ -2879,11 +2879,11 @@ public struct ToolCallCancelledState: Codable, Sendable { public struct ToolCallJudgeConfirmationReason: Codable, Sendable { public var kind: ToolCallJudgeConfirmationReasonKind - public var reason: String + public var reason: StringOrMarkdown public init( kind: ToolCallJudgeConfirmationReasonKind, - reason: String + reason: StringOrMarkdown ) { self.kind = kind self.reason = reason diff --git a/schema/actions.schema.json b/schema/actions.schema.json index bd4daa49..928e4b0f 100644 --- a/schema/actions.schema.json +++ b/schema/actions.schema.json @@ -5278,7 +5278,7 @@ "const": "judge" }, "reason": { - "type": "string" + "$ref": "#/$defs/StringOrMarkdown" } }, "required": [ diff --git a/schema/commands.schema.json b/schema/commands.schema.json index 5554ab73..47d46624 100644 --- a/schema/commands.schema.json +++ b/schema/commands.schema.json @@ -4542,7 +4542,7 @@ "const": "judge" }, "reason": { - "type": "string" + "$ref": "#/$defs/StringOrMarkdown" } }, "required": [ diff --git a/schema/errors.schema.json b/schema/errors.schema.json index 9f904f03..2641b40c 100644 --- a/schema/errors.schema.json +++ b/schema/errors.schema.json @@ -3333,7 +3333,7 @@ "const": "judge" }, "reason": { - "type": "string" + "$ref": "#/$defs/StringOrMarkdown" } }, "required": [ diff --git a/schema/notifications.schema.json b/schema/notifications.schema.json index 8a68f6de..1f8ea437 100644 --- a/schema/notifications.schema.json +++ b/schema/notifications.schema.json @@ -3493,7 +3493,7 @@ "const": "judge" }, "reason": { - "type": "string" + "$ref": "#/$defs/StringOrMarkdown" } }, "required": [ diff --git a/schema/state.schema.json b/schema/state.schema.json index 69b73494..5497cfd1 100644 --- a/schema/state.schema.json +++ b/schema/state.schema.json @@ -3244,7 +3244,7 @@ "const": "judge" }, "reason": { - "type": "string" + "$ref": "#/$defs/StringOrMarkdown" } }, "required": [ diff --git a/types/channels-chat/state.ts b/types/channels-chat/state.ts index 7b746061..4cd9cce9 100644 --- a/types/channels-chat/state.ts +++ b/types/channels-chat/state.ts @@ -950,7 +950,7 @@ export const enum ToolCallJudgeConfirmationReasonKind { */ export interface ToolCallJudgeConfirmationReason { kind: ToolCallJudgeConfirmationReasonKind.Judge; - reason: string; + reason: StringOrMarkdown; } /** From 70749f3eb6f96ec1c7bc87aecb26bfcec67cebf6 Mon Sep 17 00:00:00 2001 From: justschen Date: Tue, 14 Jul 2026 10:33:55 -0700 Subject: [PATCH 3/6] chat: make judge confirmation asynchronous Model judge rationale as loading and complete states, include the normalized safety score, and preserve confirmation context when the async result updates a pending tool call. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- clients/go/ahp/reducers.go | 33 ++++- clients/go/ahptypes/state.generated.go | 85 ++++++++++++- .../microsoft/agenthostprotocol/Reducers.kt | 19 ++- .../generated/State.generated.kt | 75 ++++++++++- clients/rust/crates/ahp-types/src/state.rs | 36 +++++- clients/rust/crates/ahp/src/reducers.rs | 20 ++- .../Generated/State.generated.swift | 63 ++++++++- .../Sources/AgentHostProtocol/Reducers.swift | 20 ++- ...20260713-tool-call-judge-confirmation.json | 2 +- schema/actions.schema.json | 61 ++++++++- schema/commands.schema.json | 61 ++++++++- schema/errors.schema.json | 61 ++++++++- schema/notifications.schema.json | 61 ++++++++- schema/state.schema.json | 61 ++++++++- scripts/generate-go.ts | 18 ++- scripts/generate-kotlin.ts | 17 ++- scripts/generate-rust.ts | 18 ++- scripts/generate-swift.ts | 17 ++- types/channels-chat/reducer.ts | 20 ++- types/channels-chat/state.ts | 38 +++++- types/index.ts | 3 + ...ates-pending-confirmation-tool-calls.json} | 9 +- ...olcallready-with-confirmation-options.json | 8 +- ...lcallready-updates-async-judge-reason.json | 83 ++++++++++++ ...allready-completes-async-judge-reason.json | 120 ++++++++++++++++++ ...callready-ignores-finished-tool-calls.json | 106 ++++++++++++++++ 26 files changed, 1041 insertions(+), 74 deletions(-) rename types/test-cases/reducers/{029-toolcallready-ignores-non-streaming-non-running-tool-calls.json => 029-toolcallready-updates-pending-confirmation-tool-calls.json} (87%) create mode 100644 types/test-cases/reducers/241-toolcallready-updates-async-judge-reason.json create mode 100644 types/test-cases/reducers/242-toolcallready-completes-async-judge-reason.json create mode 100644 types/test-cases/reducers/243-toolcallready-ignores-finished-tool-calls.json diff --git a/clients/go/ahp/reducers.go b/clients/go/ahp/reducers.go index d547f55c..ac6b4148 100644 --- a/clients/go/ahp/reducers.go +++ b/clients/go/ahp/reducers.go @@ -992,8 +992,14 @@ func applyToolCallReady(state *ahptypes.ChatState, a *ahptypes.ChatToolCallReady if a.Meta != nil { common.meta = a.Meta } + var pending *ahptypes.ToolCallPendingConfirmationState + if value, ok := tc.Value.(*ahptypes.ToolCallPendingConfirmationState); ok { + pending = value + } switch tc.Value.(type) { - case *ahptypes.ToolCallStreamingState, *ahptypes.ToolCallRunningState: + case *ahptypes.ToolCallStreamingState, + *ahptypes.ToolCallRunningState, + *ahptypes.ToolCallPendingConfirmationState: if a.Confirmed != nil { return ahptypes.ToolCallState{Value: &ahptypes.ToolCallRunningState{ Status: ahptypes.ToolCallStatusRunning, @@ -1008,7 +1014,7 @@ func applyToolCallReady(state *ahptypes.ChatState, a *ahptypes.ChatToolCallReady Confirmed: *a.Confirmed, }} } - return ahptypes.ToolCallState{Value: &ahptypes.ToolCallPendingConfirmationState{ + next := &ahptypes.ToolCallPendingConfirmationState{ Status: ahptypes.ToolCallStatusPendingConfirmation, ToolCallId: common.id, ToolName: common.name, @@ -1023,7 +1029,28 @@ func applyToolCallReady(state *ahptypes.ChatState, a *ahptypes.ChatToolCallReady Edits: a.Edits, Editable: a.Editable, Options: a.Options, - }} + } + if pending != nil { + if next.ToolInput == nil { + next.ToolInput = pending.ToolInput + } + if next.ConfirmationTitle == nil { + next.ConfirmationTitle = pending.ConfirmationTitle + } + if next.ConfirmationReason == nil { + next.ConfirmationReason = pending.ConfirmationReason + } + if next.Edits == nil { + next.Edits = pending.Edits + } + if next.Editable == nil { + next.Editable = pending.Editable + } + if next.Options == nil { + next.Options = pending.Options + } + } + return ahptypes.ToolCallState{Value: next} } return tc }) diff --git a/clients/go/ahptypes/state.generated.go b/clients/go/ahptypes/state.generated.go index d8ba40f5..aee09d2e 100644 --- a/clients/go/ahptypes/state.generated.go +++ b/clients/go/ahptypes/state.generated.go @@ -244,6 +244,14 @@ const ( ToolCallJudgeConfirmationReasonKindJudge ToolCallJudgeConfirmationReasonKind = "judge" ) +// Lifecycle status of an asynchronous model-judge confirmation decision. +type ToolCallJudgeConfirmationReasonStatus string + +const ( + ToolCallJudgeConfirmationReasonStatusLoading ToolCallJudgeConfirmationReasonStatus = "loading" + ToolCallJudgeConfirmationReasonStatusComplete ToolCallJudgeConfirmationReasonStatus = "complete" +) + // Why a tool call was cancelled. type ToolCallCancellationReason string @@ -1709,10 +1717,19 @@ type ToolCallResult struct { Error *json.RawMessage `json:"error,omitempty"` } -// A model judge's explanation for requiring user confirmation. -type ToolCallJudgeConfirmationReason struct { - Kind ToolCallJudgeConfirmationReasonKind `json:"kind"` - Reason StringOrMarkdown `json:"reason"` +// The model judge is still evaluating the tool call. +type ToolCallJudgeConfirmationReasonLoadingState struct { + Kind ToolCallJudgeConfirmationReasonKind `json:"kind"` + Status ToolCallJudgeConfirmationReasonStatus `json:"status"` +} + +// The model judge has completed its evaluation. +type ToolCallJudgeConfirmationReasonCompleteState struct { + Kind ToolCallJudgeConfirmationReasonKind `json:"kind"` + Status ToolCallJudgeConfirmationReasonStatus `json:"status"` + Reason StringOrMarkdown `json:"reason"` + // The judge's normalized safety score, where `0` is unsafe and `1` is safe. + Safety float64 `json:"safety"` } // A confirmation option that the server offers for a tool call awaiting @@ -4368,6 +4385,66 @@ func (u ToolCallContributor) MarshalJSON() ([]byte, error) { return json.Marshal(u.Value) } +// ToolCallJudgeConfirmationReason is an asynchronous model-judge confirmation rationale. +type ToolCallJudgeConfirmationReason struct { + Value isToolCallJudgeConfirmationReason +} + +// isToolCallJudgeConfirmationReason is the marker interface implemented by every +// concrete variant of ToolCallJudgeConfirmationReason. +type isToolCallJudgeConfirmationReason interface{ isToolCallJudgeConfirmationReason() } + +func (*ToolCallJudgeConfirmationReasonLoadingState) isToolCallJudgeConfirmationReason() {} +func (*ToolCallJudgeConfirmationReasonCompleteState) isToolCallJudgeConfirmationReason() {} + +// ToolCallJudgeConfirmationReasonUnknown carries an unrecognized ToolCallJudgeConfirmationReason variant — typically a discriminator value introduced by a newer protocol version. The original JSON object is preserved verbatim so that re-encoding round-trips faithfully. +type ToolCallJudgeConfirmationReasonUnknown struct { + Raw json.RawMessage +} + +func (*ToolCallJudgeConfirmationReasonUnknown) isToolCallJudgeConfirmationReason() {} + +// UnmarshalJSON decodes the variant indicated by the "status" discriminator. +func (u *ToolCallJudgeConfirmationReason) UnmarshalJSON(data []byte) error { + disc, _, err := readDiscriminator(data, "status") + if err != nil { + return err + } + switch disc { + case "loading": + var value ToolCallJudgeConfirmationReasonLoadingState + if err := json.Unmarshal(data, &value); err != nil { + return err + } + u.Value = &value + case "complete": + var value ToolCallJudgeConfirmationReasonCompleteState + if err := json.Unmarshal(data, &value); err != nil { + return err + } + u.Value = &value + default: + raw := make(json.RawMessage, len(data)) + copy(raw, data) + u.Value = &ToolCallJudgeConfirmationReasonUnknown{Raw: raw} + } + return nil +} + +// MarshalJSON encodes the active variant back to JSON. +func (u ToolCallJudgeConfirmationReason) MarshalJSON() ([]byte, error) { + if unk, ok := u.Value.(*ToolCallJudgeConfirmationReasonUnknown); ok { + if len(unk.Raw) == 0 { + return []byte("null"), nil + } + return unk.Raw, nil + } + if u.Value == nil { + return []byte("null"), nil + } + return json.Marshal(u.Value) +} + // SessionInputRequest is one outstanding piece of input a session is blocked on, aggregated across all chats. type SessionInputRequest struct { Value isSessionInputRequest diff --git a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt index cb52c367..365eb459 100644 --- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt +++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt @@ -860,10 +860,15 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when val a = action.value refreshChatSummaryStatus( updateToolCallInParts(state, a.turnId, a.toolCallId) { tc -> - if (tc !is ToolCallStateStreaming && tc !is ToolCallStateRunning) { + if ( + tc !is ToolCallStateStreaming + && tc !is ToolCallStateRunning + && tc !is ToolCallStatePendingConfirmation + ) { tc } else { val base = toolCallBase(tc).withMeta(a.meta) + val pending = (tc as? ToolCallStatePendingConfirmation)?.value if (a.confirmed != null) { ToolCallStateRunning( ToolCallRunningState( @@ -889,13 +894,13 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when contributor = base.contributor, meta = base.meta, invocationMessage = a.invocationMessage, - toolInput = a.toolInput, + toolInput = a.toolInput ?: pending?.toolInput, status = ToolCallStatus.PENDING_CONFIRMATION, - confirmationTitle = a.confirmationTitle, - confirmationReason = a.confirmationReason, - edits = a.edits, - editable = a.editable, - options = a.options, + confirmationTitle = a.confirmationTitle ?: pending?.confirmationTitle, + confirmationReason = a.confirmationReason ?: pending?.confirmationReason, + edits = a.edits ?: pending?.edits, + editable = a.editable ?: pending?.editable, + options = a.options ?: pending?.options, ), ) } diff --git a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt index f032a350..097f91de 100644 --- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt +++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt @@ -442,6 +442,17 @@ enum class ToolCallJudgeConfirmationReasonKind { JUDGE } +/** + * Lifecycle status of an asynchronous model-judge confirmation decision. + */ +@Serializable +enum class ToolCallJudgeConfirmationReasonStatus { + @SerialName("loading") + LOADING, + @SerialName("complete") + COMPLETE +} + /** * Why a tool call was cancelled. */ @@ -2740,9 +2751,20 @@ data class ToolCallCancelledState( ) @Serializable -data class ToolCallJudgeConfirmationReason( +data class ToolCallJudgeConfirmationReasonLoadingState( + val kind: ToolCallJudgeConfirmationReasonKind, + val status: ToolCallJudgeConfirmationReasonStatus +) + +@Serializable +data class ToolCallJudgeConfirmationReasonCompleteState( val kind: ToolCallJudgeConfirmationReasonKind, - val reason: StringOrMarkdown + val status: ToolCallJudgeConfirmationReasonStatus, + val reason: StringOrMarkdown, + /** + * The judge's normalized safety score, where `0` is unsafe and `1` is safe. + */ + val safety: Double ) @Serializable @@ -5182,6 +5204,55 @@ internal object ToolCallContributorSerializer : KSerializer } } +@Serializable(with = ToolCallJudgeConfirmationReasonSerializer::class) +sealed interface ToolCallJudgeConfirmationReason + +@JvmInline +value class ToolCallJudgeConfirmationReasonLoading(val value: ToolCallJudgeConfirmationReasonLoadingState) : ToolCallJudgeConfirmationReason +@JvmInline +value class ToolCallJudgeConfirmationReasonComplete(val value: ToolCallJudgeConfirmationReasonCompleteState) : ToolCallJudgeConfirmationReason +/** + * Forward-compat catch-all for unknown ToolCallJudgeConfirmationReason discriminators. + * + * Older clients may receive newer wire variants they don't recognise; capturing + * the raw `JsonObject` lets such payloads round-trip through the client unchanged. + * Reducers handle this variant conservatively on a per-union basis (typically + * as a no-op, but see `Reducers.kt` for the exact treatment). + */ +@JvmInline +value class ToolCallJudgeConfirmationReasonUnknown(val raw: JsonObject) : ToolCallJudgeConfirmationReason + +internal object ToolCallJudgeConfirmationReasonSerializer : KSerializer { + override val descriptor: SerialDescriptor = + buildClassSerialDescriptor("ToolCallJudgeConfirmationReason") + + override fun deserialize(decoder: Decoder): ToolCallJudgeConfirmationReason { + val input = decoder as? JsonDecoder + ?: error("ToolCallJudgeConfirmationReason can only be deserialized from JSON") + val element = input.decodeJsonElement() + val obj = element as? JsonObject + ?: error("Expected JsonObject for ToolCallJudgeConfirmationReason") + val discriminant = (obj["status"] as? JsonPrimitive)?.content + ?: return ToolCallJudgeConfirmationReasonUnknown(obj) + return when (discriminant) { + "loading" -> ToolCallJudgeConfirmationReasonLoading(input.json.decodeFromJsonElement(ToolCallJudgeConfirmationReasonLoadingState.serializer(), element)) + "complete" -> ToolCallJudgeConfirmationReasonComplete(input.json.decodeFromJsonElement(ToolCallJudgeConfirmationReasonCompleteState.serializer(), element)) + else -> ToolCallJudgeConfirmationReasonUnknown(obj) + } + } + + override fun serialize(encoder: Encoder, value: ToolCallJudgeConfirmationReason) { + val output = encoder as? JsonEncoder + ?: error("ToolCallJudgeConfirmationReason can only be serialized to JSON") + val element: JsonElement = when (value) { + is ToolCallJudgeConfirmationReasonLoading -> output.json.encodeToJsonElement(ToolCallJudgeConfirmationReasonLoadingState.serializer(), value.value) + is ToolCallJudgeConfirmationReasonComplete -> output.json.encodeToJsonElement(ToolCallJudgeConfirmationReasonCompleteState.serializer(), value.value) + is ToolCallJudgeConfirmationReasonUnknown -> value.raw + } + output.encodeJsonElement(element) + } +} + @Serializable(with = SessionInputRequestSerializer::class) sealed interface SessionInputRequest diff --git a/clients/rust/crates/ahp-types/src/state.rs b/clients/rust/crates/ahp-types/src/state.rs index 1a9630f7..14a24762 100644 --- a/clients/rust/crates/ahp-types/src/state.rs +++ b/clients/rust/crates/ahp-types/src/state.rs @@ -349,6 +349,15 @@ pub enum ToolCallJudgeConfirmationReasonKind { Judge, } +/// Lifecycle status of an asynchronous model-judge confirmation decision. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum ToolCallJudgeConfirmationReasonStatus { + #[serde(rename = "loading")] + Loading, + #[serde(rename = "complete")] + Complete, +} + /// Why a tool call was cancelled. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum ToolCallCancellationReason { @@ -2134,12 +2143,21 @@ pub struct ToolCallResult { pub error: Option, } -/// A model judge's explanation for requiring user confirmation. +/// The model judge is still evaluating the tool call. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ToolCallJudgeConfirmationReasonLoadingState { + pub kind: ToolCallJudgeConfirmationReasonKind, +} + +/// The model judge has completed its evaluation. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct ToolCallJudgeConfirmationReason { +pub struct ToolCallJudgeConfirmationReasonCompleteState { pub kind: ToolCallJudgeConfirmationReasonKind, pub reason: StringOrMarkdown, + /// The judge's normalized safety score, where `0` is unsafe and `1` is safe. + pub safety: f64, } /// A confirmation option that the server offers for a tool call awaiting @@ -4221,6 +4239,20 @@ pub enum ToolCallContributor { Unknown(serde_json::Value), } +/// Asynchronous model-judge confirmation rationale. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(tag = "status")] +pub enum ToolCallJudgeConfirmationReason { + #[serde(rename = "loading")] + Loading(ToolCallJudgeConfirmationReasonLoadingState), + #[serde(rename = "complete")] + Complete(ToolCallJudgeConfirmationReasonCompleteState), + /// Unknown or future variant — preserved as raw JSON for round-trip fidelity. + /// Reducers treat this as a no-op. + #[serde(untagged)] + Unknown(serde_json::Value), +} + /// One outstanding piece of input a session is blocked on, aggregated across all chats. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(tag = "kind")] diff --git a/clients/rust/crates/ahp/src/reducers.rs b/clients/rust/crates/ahp/src/reducers.rs index d3568eff..a641079b 100644 --- a/clients/rust/crates/ahp/src/reducers.rs +++ b/clients/rust/crates/ahp/src/reducers.rs @@ -1157,8 +1157,14 @@ fn apply_tool_call_ready(state: &mut ChatState, a: &ChatToolCallReadyAction) -> update_tool_call(state, &a.turn_id, &a.tool_call_id, |tc| { let base = tool_call_meta(&tc); let meta = a.meta.clone().or(base.meta); + let pending = match &tc { + ToolCallState::PendingConfirmation(value) => Some(value.clone()), + _ => None, + }; match tc { - ToolCallState::Streaming(_) | ToolCallState::Running(_) => { + ToolCallState::Streaming(_) + | ToolCallState::Running(_) + | ToolCallState::PendingConfirmation(_) => { if let Some(confirmed) = a.confirmed { ToolCallState::Running(ToolCallRunningState { tool_call_id: base.tool_call_id, @@ -1182,12 +1188,12 @@ fn apply_tool_call_ready(state: &mut ChatState, a: &ChatToolCallReadyAction) -> contributor: base.contributor, meta, invocation_message: a.invocation_message.clone(), - tool_input: a.tool_input.clone(), - confirmation_title: a.confirmation_title.clone(), - confirmation_reason: a.confirmation_reason.clone(), - edits: a.edits.clone(), - editable: a.editable, - options: a.options.clone(), + tool_input: a.tool_input.clone().or_else(|| pending.as_ref().and_then(|p| p.tool_input.clone())), + confirmation_title: a.confirmation_title.clone().or_else(|| pending.as_ref().and_then(|p| p.confirmation_title.clone())), + confirmation_reason: a.confirmation_reason.clone().or_else(|| pending.as_ref().and_then(|p| p.confirmation_reason.clone())), + edits: a.edits.clone().or_else(|| pending.as_ref().and_then(|p| p.edits.clone())), + editable: a.editable.or_else(|| pending.as_ref().and_then(|p| p.editable)), + options: a.options.clone().or_else(|| pending.as_ref().and_then(|p| p.options.clone())), }) } } diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift index e242bf94..35ca03ff 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift @@ -230,6 +230,12 @@ public enum ToolCallJudgeConfirmationReasonKind: String, Codable, Sendable { case judge = "judge" } +/// Lifecycle status of an asynchronous model-judge confirmation decision. +public enum ToolCallJudgeConfirmationReasonStatus: String, Codable, Sendable { + case loading = "loading" + case complete = "complete" +} + /// Why a tool call was cancelled. public enum ToolCallCancellationReason: String, Codable, Sendable { case denied = "denied" @@ -2877,16 +2883,36 @@ public struct ToolCallCancelledState: Codable, Sendable { } } -public struct ToolCallJudgeConfirmationReason: Codable, Sendable { +public struct ToolCallJudgeConfirmationReasonLoadingState: Codable, Sendable { public var kind: ToolCallJudgeConfirmationReasonKind + public var status: ToolCallJudgeConfirmationReasonStatus + + public init( + kind: ToolCallJudgeConfirmationReasonKind, + status: ToolCallJudgeConfirmationReasonStatus + ) { + self.kind = kind + self.status = status + } +} + +public struct ToolCallJudgeConfirmationReasonCompleteState: Codable, Sendable { + public var kind: ToolCallJudgeConfirmationReasonKind + public var status: ToolCallJudgeConfirmationReasonStatus public var reason: StringOrMarkdown + /// The judge's normalized safety score, where `0` is unsafe and `1` is safe. + public var safety: Double public init( kind: ToolCallJudgeConfirmationReasonKind, - reason: StringOrMarkdown + status: ToolCallJudgeConfirmationReasonStatus, + reason: StringOrMarkdown, + safety: Double ) { self.kind = kind + self.status = status self.reason = reason + self.safety = safety } } @@ -5488,6 +5514,39 @@ public enum ToolCallContributor: Codable, Sendable { } } +public enum ToolCallJudgeConfirmationReason: Codable, Sendable { + case loading(ToolCallJudgeConfirmationReasonLoadingState) + case complete(ToolCallJudgeConfirmationReasonCompleteState) + /// Unknown or future discriminant; the raw payload is preserved + /// and re-encoded verbatim for forward-compatibility. + case unknown(AnyCodable) + + private enum DiscriminantKey: String, CodingKey { + case discriminant = "status" + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: DiscriminantKey.self) + let discriminant = try container.decode(String.self, forKey: .discriminant) + switch discriminant { + case "loading": + self = .loading(try ToolCallJudgeConfirmationReasonLoadingState(from: decoder)) + case "complete": + self = .complete(try ToolCallJudgeConfirmationReasonCompleteState(from: decoder)) + default: + self = .unknown(try AnyCodable(from: decoder)) + } + } + + public func encode(to encoder: Encoder) throws { + switch self { + case .loading(let value): try value.encode(to: encoder) + case .complete(let value): try value.encode(to: encoder) + case .unknown(let value): try value.encode(to: encoder) + } + } +} + public enum SessionInputRequest: Codable, Sendable { case chatInput(SessionChatInputRequest) case toolConfirmation(SessionToolConfirmationRequest) diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift index 0674e04f..dce9caaa 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift @@ -189,11 +189,17 @@ public func chatReducer(state: ChatState, action: StateAction) -> ChatState { case .chatToolCallReady(let a): return refreshChatSummaryStatus(updateToolCall(state: state, turnId: a.turnId, toolCallId: a.toolCallId) { tc in switch tc { - case .streaming, .running: break + case .streaming, .running, .pendingConfirmation: break default: return tc } let base = tc.baseFields let meta = a.meta ?? base.meta + let pending: ToolCallPendingConfirmationState? + if case .pendingConfirmation(let value) = tc { + pending = value + } else { + pending = nil + } if let confirmed = a.confirmed { return .running(ToolCallRunningState( toolCallId: base.toolCallId, @@ -216,13 +222,13 @@ public func chatReducer(state: ChatState, action: StateAction) -> ChatState { contributor: base.contributor, meta: meta, invocationMessage: a.invocationMessage, - toolInput: a.toolInput, + toolInput: a.toolInput ?? pending?.toolInput, status: .pendingConfirmation, - confirmationTitle: a.confirmationTitle, - confirmationReason: a.confirmationReason, - edits: a.edits, - editable: a.editable, - options: a.options + confirmationTitle: a.confirmationTitle ?? pending?.confirmationTitle, + confirmationReason: a.confirmationReason ?? pending?.confirmationReason, + edits: a.edits ?? pending?.edits, + editable: a.editable ?? pending?.editable, + options: a.options ?? pending?.options )) }) diff --git a/docs/.changes/20260713-tool-call-judge-confirmation.json b/docs/.changes/20260713-tool-call-judge-confirmation.json index dcd4ddd9..dcb9feaf 100644 --- a/docs/.changes/20260713-tool-call-judge-confirmation.json +++ b/docs/.changes/20260713-tool-call-judge-confirmation.json @@ -1,4 +1,4 @@ { "type": "added", - "message": "`judge` tool-call confirmation reasons with a model-provided explanation for pending confirmations." + "message": "Asynchronous `judge` tool-call confirmation reasons with a model-provided explanation and normalized safety score." } diff --git a/schema/actions.schema.json b/schema/actions.schema.json index 928e4b0f..cb01cfb2 100644 --- a/schema/actions.schema.json +++ b/schema/actions.schema.json @@ -5270,20 +5270,56 @@ "content" ] }, - "ToolCallJudgeConfirmationReason": { + "ToolCallJudgeConfirmationReasonBase": { + "type": "object", + "properties": { + "kind": { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + } + }, + "required": [ + "kind" + ] + }, + "ToolCallJudgeConfirmationReasonLoadingState": { + "type": "object", + "description": "The model judge is still evaluating the tool call.", + "properties": { + "kind": { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + }, + "status": { + "const": "loading" + } + }, + "required": [ + "kind", + "status" + ] + }, + "ToolCallJudgeConfirmationReasonCompleteState": { "type": "object", - "description": "A model judge's explanation for requiring user confirmation.", + "description": "The model judge has completed its evaluation.", "properties": { "kind": { - "const": "judge" + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + }, + "status": { + "const": "complete" }, "reason": { "$ref": "#/$defs/StringOrMarkdown" + }, + "safety": { + "type": "number", + "description": "The judge's normalized safety score, where `0` is unsafe and `1` is safe." } }, "required": [ "kind", - "reason" + "status", + "reason", + "safety" ] }, "ConfirmationOption": { @@ -6912,6 +6948,16 @@ } ] }, + "ToolCallJudgeConfirmationReason": { + "oneOf": [ + { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonLoadingState" + }, + { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonCompleteState" + } + ] + }, "ToolCallContributor": { "oneOf": [ { @@ -7365,6 +7411,13 @@ "type": "string", "description": "Discriminant for {@link MessageOrigin} — identifies who produced a message." }, + "ToolCallJudgeConfirmationReasonKind": { + "enum": [ + "judge" + ], + "type": "string", + "description": "Identifies a model judge as the source of a confirmation requirement." + }, "ConfirmationOptionKind": { "enum": [ "approve", diff --git a/schema/commands.schema.json b/schema/commands.schema.json index 47d46624..3124f34a 100644 --- a/schema/commands.schema.json +++ b/schema/commands.schema.json @@ -4534,20 +4534,56 @@ "content" ] }, - "ToolCallJudgeConfirmationReason": { + "ToolCallJudgeConfirmationReasonBase": { + "type": "object", + "properties": { + "kind": { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + } + }, + "required": [ + "kind" + ] + }, + "ToolCallJudgeConfirmationReasonLoadingState": { + "type": "object", + "description": "The model judge is still evaluating the tool call.", + "properties": { + "kind": { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + }, + "status": { + "const": "loading" + } + }, + "required": [ + "kind", + "status" + ] + }, + "ToolCallJudgeConfirmationReasonCompleteState": { "type": "object", - "description": "A model judge's explanation for requiring user confirmation.", + "description": "The model judge has completed its evaluation.", "properties": { "kind": { - "const": "judge" + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + }, + "status": { + "const": "complete" }, "reason": { "$ref": "#/$defs/StringOrMarkdown" + }, + "safety": { + "type": "number", + "description": "The judge's normalized safety score, where `0` is unsafe and `1` is safe." } }, "required": [ "kind", - "reason" + "status", + "reason", + "safety" ] }, "ConfirmationOption": { @@ -8565,6 +8601,13 @@ "type": "string", "description": "How a client completed an input request." }, + "ToolCallJudgeConfirmationReasonKind": { + "enum": [ + "judge" + ], + "type": "string", + "description": "Identifies a model judge as the source of a confirmation requirement." + }, "ConfirmationOptionKind": { "enum": [ "approve", @@ -8609,6 +8652,16 @@ ], "description": "Content block in a tool result.\n\nMirrors the content blocks in MCP `CallToolResult.content`, plus\n`ToolResultResourceContent` for lazy-loading large results,\n`ToolResultFileEditContent` for file edit diffs,\n`ToolResultTerminalContent` for live terminal output,\n`ToolResultTerminalCompleteContent` for terminal-style completion metadata, and\n`ToolResultSubagentContent` for tool-spawned worker chats (AHP extensions)." }, + "ToolCallJudgeConfirmationReason": { + "oneOf": [ + { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonLoadingState" + }, + { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonCompleteState" + } + ] + }, "ToolCallConfirmationReason": { "enum": [ "not-needed", diff --git a/schema/errors.schema.json b/schema/errors.schema.json index 2641b40c..4db39723 100644 --- a/schema/errors.schema.json +++ b/schema/errors.schema.json @@ -3325,20 +3325,56 @@ "content" ] }, - "ToolCallJudgeConfirmationReason": { + "ToolCallJudgeConfirmationReasonBase": { + "type": "object", + "properties": { + "kind": { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + } + }, + "required": [ + "kind" + ] + }, + "ToolCallJudgeConfirmationReasonLoadingState": { + "type": "object", + "description": "The model judge is still evaluating the tool call.", + "properties": { + "kind": { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + }, + "status": { + "const": "loading" + } + }, + "required": [ + "kind", + "status" + ] + }, + "ToolCallJudgeConfirmationReasonCompleteState": { "type": "object", - "description": "A model judge's explanation for requiring user confirmation.", + "description": "The model judge has completed its evaluation.", "properties": { "kind": { - "const": "judge" + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + }, + "status": { + "const": "complete" }, "reason": { "$ref": "#/$defs/StringOrMarkdown" + }, + "safety": { + "type": "number", + "description": "The judge's normalized safety score, where `0` is unsafe and `1` is safe." } }, "required": [ "kind", - "reason" + "status", + "reason", + "safety" ] }, "ConfirmationOption": { @@ -6379,6 +6415,13 @@ ], "description": "A string that may optionally be rendered as Markdown.\n\n- A plain `string` is rendered as-is (no Markdown processing).\n- An object with `{ markdown: string }` is rendered with Markdown formatting." }, + "ToolCallJudgeConfirmationReasonKind": { + "enum": [ + "judge" + ], + "type": "string", + "description": "Identifies a model judge as the source of a confirmation requirement." + }, "ConfirmationOptionKind": { "enum": [ "approve", @@ -6423,6 +6466,16 @@ ], "description": "Content block in a tool result.\n\nMirrors the content blocks in MCP `CallToolResult.content`, plus\n`ToolResultResourceContent` for lazy-loading large results,\n`ToolResultFileEditContent` for file edit diffs,\n`ToolResultTerminalContent` for live terminal output,\n`ToolResultTerminalCompleteContent` for terminal-style completion metadata, and\n`ToolResultSubagentContent` for tool-spawned worker chats (AHP extensions)." }, + "ToolCallJudgeConfirmationReason": { + "oneOf": [ + { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonLoadingState" + }, + { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonCompleteState" + } + ] + }, "ToolCallConfirmationReason": { "enum": [ "not-needed", diff --git a/schema/notifications.schema.json b/schema/notifications.schema.json index 1f8ea437..2a929c8a 100644 --- a/schema/notifications.schema.json +++ b/schema/notifications.schema.json @@ -3485,20 +3485,56 @@ "content" ] }, - "ToolCallJudgeConfirmationReason": { + "ToolCallJudgeConfirmationReasonBase": { + "type": "object", + "properties": { + "kind": { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + } + }, + "required": [ + "kind" + ] + }, + "ToolCallJudgeConfirmationReasonLoadingState": { + "type": "object", + "description": "The model judge is still evaluating the tool call.", + "properties": { + "kind": { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + }, + "status": { + "const": "loading" + } + }, + "required": [ + "kind", + "status" + ] + }, + "ToolCallJudgeConfirmationReasonCompleteState": { "type": "object", - "description": "A model judge's explanation for requiring user confirmation.", + "description": "The model judge has completed its evaluation.", "properties": { "kind": { - "const": "judge" + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + }, + "status": { + "const": "complete" }, "reason": { "$ref": "#/$defs/StringOrMarkdown" + }, + "safety": { + "type": "number", + "description": "The judge's normalized safety score, where `0` is unsafe and `1` is safe." } }, "required": [ "kind", - "reason" + "status", + "reason", + "safety" ] }, "ConfirmationOption": { @@ -5249,6 +5285,13 @@ ], "description": "A string that may optionally be rendered as Markdown.\n\n- A plain `string` is rendered as-is (no Markdown processing).\n- An object with `{ markdown: string }` is rendered with Markdown formatting." }, + "ToolCallJudgeConfirmationReasonKind": { + "enum": [ + "judge" + ], + "type": "string", + "description": "Identifies a model judge as the source of a confirmation requirement." + }, "ConfirmationOptionKind": { "enum": [ "approve", @@ -5293,6 +5336,16 @@ ], "description": "Content block in a tool result.\n\nMirrors the content blocks in MCP `CallToolResult.content`, plus\n`ToolResultResourceContent` for lazy-loading large results,\n`ToolResultFileEditContent` for file edit diffs,\n`ToolResultTerminalContent` for live terminal output,\n`ToolResultTerminalCompleteContent` for terminal-style completion metadata, and\n`ToolResultSubagentContent` for tool-spawned worker chats (AHP extensions)." }, + "ToolCallJudgeConfirmationReason": { + "oneOf": [ + { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonLoadingState" + }, + { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonCompleteState" + } + ] + }, "ToolCallConfirmationReason": { "enum": [ "not-needed", diff --git a/schema/state.schema.json b/schema/state.schema.json index 5497cfd1..becb1f7a 100644 --- a/schema/state.schema.json +++ b/schema/state.schema.json @@ -3236,20 +3236,56 @@ "content" ] }, - "ToolCallJudgeConfirmationReason": { + "ToolCallJudgeConfirmationReasonBase": { + "type": "object", + "properties": { + "kind": { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + } + }, + "required": [ + "kind" + ] + }, + "ToolCallJudgeConfirmationReasonLoadingState": { + "type": "object", + "description": "The model judge is still evaluating the tool call.", + "properties": { + "kind": { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + }, + "status": { + "const": "loading" + } + }, + "required": [ + "kind", + "status" + ] + }, + "ToolCallJudgeConfirmationReasonCompleteState": { "type": "object", - "description": "A model judge's explanation for requiring user confirmation.", + "description": "The model judge has completed its evaluation.", "properties": { "kind": { - "const": "judge" + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + }, + "status": { + "const": "complete" }, "reason": { "$ref": "#/$defs/StringOrMarkdown" + }, + "safety": { + "type": "number", + "description": "The judge's normalized safety score, where `0` is unsafe and `1` is safe." } }, "required": [ "kind", - "reason" + "status", + "reason", + "safety" ] }, "ConfirmationOption": { @@ -4878,6 +4914,16 @@ } ] }, + "ToolCallJudgeConfirmationReason": { + "oneOf": [ + { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonLoadingState" + }, + { + "$ref": "#/$defs/ToolCallJudgeConfirmationReasonCompleteState" + } + ] + }, "ToolCallContributor": { "oneOf": [ { @@ -5050,6 +5096,13 @@ "type": "string", "description": "How a client completed an input request." }, + "ToolCallJudgeConfirmationReasonKind": { + "enum": [ + "judge" + ], + "type": "string", + "description": "Identifies a model judge as the source of a confirmation requirement." + }, "ConfirmationOptionKind": { "enum": [ "approve", diff --git a/scripts/generate-go.ts b/scripts/generate-go.ts index 71327c10..8ed0d6f6 100644 --- a/scripts/generate-go.ts +++ b/scripts/generate-go.ts @@ -645,6 +645,7 @@ const STATE_ENUMS = [ 'ChatInputResponseKind', 'SessionInputRequestKind', 'TurnState', 'MessageKind', 'MessageAttachmentKind', 'ResponsePartKind', 'ToolCallStatus', 'ToolCallConfirmationReason', 'ToolCallJudgeConfirmationReasonKind', + 'ToolCallJudgeConfirmationReasonStatus', 'ToolCallCancellationReason', 'ConfirmationOptionKind', 'ToolCallContributorKind', 'ToolResultContentType', 'CustomizationType', 'CustomizationLoadStatus', 'TerminalClaimKind', @@ -712,7 +713,8 @@ const STATE_STRUCTS: { name: string; omitDiscriminants?: boolean; goName?: strin { name: 'SystemNotificationResponsePart' }, { name: 'InputRequestResponsePart' }, { name: 'ToolCallResult' }, - { name: 'ToolCallJudgeConfirmationReason' }, + { name: 'ToolCallJudgeConfirmationReasonLoadingState' }, + { name: 'ToolCallJudgeConfirmationReasonCompleteState' }, { name: 'ConfirmationOption' }, { name: 'ToolCallStreamingState' }, { name: 'ToolCallPendingConfirmationState' }, @@ -973,6 +975,17 @@ const TOOL_CALL_CONTRIBUTOR_UNION: UnionConfig = { unknown: true, }; +const TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION: UnionConfig = { + name: 'ToolCallJudgeConfirmationReason', + discriminantField: 'status', + doc: 'ToolCallJudgeConfirmationReason is an asynchronous model-judge confirmation rationale.', + variants: [ + { variantName: 'Loading', innerType: 'ToolCallJudgeConfirmationReasonLoadingState', wireValue: 'loading' }, + { variantName: 'Complete', innerType: 'ToolCallJudgeConfirmationReasonCompleteState', wireValue: 'complete' }, + ], + unknown: true, +}; + const SESSION_INPUT_REQUEST_UNION: UnionConfig = { name: 'SessionInputRequest', discriminantField: 'kind', @@ -1229,6 +1242,8 @@ function generateStateFile(project: Project): string { lines.push(''); lines.push(generateDiscriminatedUnion(TOOL_CALL_CONTRIBUTOR_UNION)); lines.push(''); + lines.push(generateDiscriminatedUnion(TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION)); + lines.push(''); lines.push(generateDiscriminatedUnion(SESSION_INPUT_REQUEST_UNION)); lines.push(''); lines.push(generateChatOriginGo()); @@ -1933,6 +1948,7 @@ function checkExhaustiveness(project: Project): void { 'CustomizationLoadState', 'McpServerState', 'ToolCallContributor', + 'ToolCallJudgeConfirmationReason', 'SessionInputRequest', 'ToolCallConfirmationState', 'ReconnectResult', diff --git a/scripts/generate-kotlin.ts b/scripts/generate-kotlin.ts index 3edcac22..47517f1a 100644 --- a/scripts/generate-kotlin.ts +++ b/scripts/generate-kotlin.ts @@ -792,6 +792,7 @@ const STATE_ENUMS = [ 'ChatInputResponseKind', 'SessionInputRequestKind', 'TurnState', 'MessageKind', 'MessageAttachmentKind', 'ResponsePartKind', 'ToolCallStatus', 'ToolCallConfirmationReason', 'ToolCallJudgeConfirmationReasonKind', + 'ToolCallJudgeConfirmationReasonStatus', 'ToolCallCancellationReason', 'ConfirmationOptionKind', 'ToolCallContributorKind', 'ToolResultContentType', 'CustomizationType', 'CustomizationLoadStatus', 'TerminalClaimKind', @@ -826,7 +827,8 @@ const STATE_STRUCTS = [ 'ToolCallResult', 'ToolCallStreamingState', 'ToolCallPendingConfirmationState', 'ToolCallRunningState', 'ToolCallPendingResultConfirmationState', 'ToolCallCompletedState', - 'ToolCallCancelledState', 'ToolCallJudgeConfirmationReason', 'ConfirmationOption', + 'ToolCallCancelledState', 'ToolCallJudgeConfirmationReasonLoadingState', + 'ToolCallJudgeConfirmationReasonCompleteState', 'ConfirmationOption', 'ToolDefinition', 'ToolAnnotations', 'ToolResultTextContent', 'ToolResultEmbeddedResourceContent', 'ToolResultResourceContent', 'ToolResultFileEditContent', @@ -1077,6 +1079,16 @@ const TOOL_CALL_CONTRIBUTOR_UNION: UnionConfig = { unknown: true, }; +const TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION: UnionConfig = { + name: 'ToolCallJudgeConfirmationReason', + discriminantField: 'status', + variants: [ + { caseName: 'Loading', structName: 'ToolCallJudgeConfirmationReasonLoadingState', discriminantValue: 'loading' }, + { caseName: 'Complete', structName: 'ToolCallJudgeConfirmationReasonCompleteState', discriminantValue: 'complete' }, + ], + unknown: true, +}; + const SESSION_INPUT_REQUEST_UNION: UnionConfig = { name: 'SessionInputRequest', discriminantField: 'kind', @@ -1155,6 +1167,8 @@ function generateStateFile(project: Project): string { lines.push(''); lines.push(generateDiscriminatedUnion(TOOL_CALL_CONTRIBUTOR_UNION)); lines.push(''); + lines.push(generateDiscriminatedUnion(TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION)); + lines.push(''); lines.push(generateDiscriminatedUnion(SESSION_INPUT_REQUEST_UNION)); lines.push(''); lines.push(generateToolResultContentUnion()); @@ -1920,6 +1934,7 @@ function checkExhaustiveness(project: Project): void { 'ChildCustomization', // CHILD_CUSTOMIZATION_UNION discriminated union 'McpServerState', // MCP_SERVER_STATUS_UNION discriminated union 'ToolCallContributor', // TOOL_CALL_CONTRIBUTOR_UNION discriminated union + 'ToolCallJudgeConfirmationReason', // TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION discriminated union 'SessionInputRequest', // SESSION_INPUT_REQUEST_UNION discriminated union 'ToolCallConfirmationState', // TOOL_CALL_CONFIRMATION_STATE_UNION discriminated union 'ChildCustomizationType', // TS subset alias of CustomizationType; consumers reuse CustomizationType diff --git a/scripts/generate-rust.ts b/scripts/generate-rust.ts index c69e95b9..7071a0a3 100644 --- a/scripts/generate-rust.ts +++ b/scripts/generate-rust.ts @@ -655,6 +655,7 @@ const STATE_ENUMS = [ 'ChatInputResponseKind', 'SessionInputRequestKind', 'TurnState', 'MessageKind', 'MessageAttachmentKind', 'ResponsePartKind', 'ToolCallStatus', 'ToolCallConfirmationReason', 'ToolCallJudgeConfirmationReasonKind', + 'ToolCallJudgeConfirmationReasonStatus', 'ToolCallCancellationReason', 'ConfirmationOptionKind', 'ToolCallContributorKind', 'ToolResultContentType', 'CustomizationType', 'CustomizationLoadStatus', 'TerminalClaimKind', @@ -743,7 +744,8 @@ const STATE_STRUCTS: { name: string; omitDiscriminants?: boolean; rustName?: str { name: 'SystemNotificationResponsePart', omitDiscriminants: true }, { name: 'InputRequestResponsePart', omitDiscriminants: true }, { name: 'ToolCallResult' }, - { name: 'ToolCallJudgeConfirmationReason' }, + { name: 'ToolCallJudgeConfirmationReasonLoadingState', omitDiscriminants: true }, + { name: 'ToolCallJudgeConfirmationReasonCompleteState', omitDiscriminants: true }, { name: 'ConfirmationOption' }, { name: 'ToolCallStreamingState', omitDiscriminants: true }, { name: 'ToolCallPendingConfirmationState', omitDiscriminants: true }, @@ -1009,6 +1011,17 @@ const TOOL_CALL_CONTRIBUTOR_UNION: UnionConfig = { unknown: true, }; +const TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION: UnionConfig = { + name: 'ToolCallJudgeConfirmationReason', + discriminantField: 'status', + doc: 'Asynchronous model-judge confirmation rationale.', + variants: [ + { variantName: 'Loading', innerType: 'ToolCallJudgeConfirmationReasonLoadingState', wireValue: 'loading' }, + { variantName: 'Complete', innerType: 'ToolCallJudgeConfirmationReasonCompleteState', wireValue: 'complete' }, + ], + unknown: true, +}; + const SESSION_INPUT_REQUEST_UNION: UnionConfig = { name: 'SessionInputRequest', discriminantField: 'kind', @@ -1141,6 +1154,8 @@ function generateStateFile(project: Project): string { lines.push(''); lines.push(generateDiscriminatedUnion(TOOL_CALL_CONTRIBUTOR_UNION)); lines.push(''); + lines.push(generateDiscriminatedUnion(TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION)); + lines.push(''); lines.push(generateDiscriminatedUnion(SESSION_INPUT_REQUEST_UNION)); lines.push(''); lines.push(generateSnapshotState()); @@ -1841,6 +1856,7 @@ function checkExhaustiveness(project: Project): void { 'CustomizationLoadState', // CUSTOMIZATION_LOAD_STATE_UNION discriminated union 'McpServerState', // MCP_SERVER_STATUS_UNION discriminated union 'ToolCallContributor', // TOOL_CALL_CONTRIBUTOR_UNION discriminated union + 'ToolCallJudgeConfirmationReason', // TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION discriminated union 'SessionInputRequest', // SESSION_INPUT_REQUEST_UNION discriminated union 'ToolCallConfirmationState', // TOOL_CALL_CONFIRMATION_STATE_UNION discriminated union 'ReconnectResult', diff --git a/scripts/generate-swift.ts b/scripts/generate-swift.ts index 64b50103..e2f7e9a5 100644 --- a/scripts/generate-swift.ts +++ b/scripts/generate-swift.ts @@ -542,6 +542,7 @@ const STATE_ENUMS = [ 'ChatInputResponseKind', 'SessionInputRequestKind', 'TurnState', 'MessageKind', 'MessageAttachmentKind', 'ResponsePartKind', 'ToolCallStatus', 'ToolCallConfirmationReason', 'ToolCallJudgeConfirmationReasonKind', + 'ToolCallJudgeConfirmationReasonStatus', 'ToolCallCancellationReason', 'ConfirmationOptionKind', 'ToolCallContributorKind', 'ToolResultContentType', 'CustomizationType', 'CustomizationLoadStatus', 'TerminalClaimKind', @@ -576,7 +577,8 @@ const STATE_STRUCTS = [ 'ToolCallResult', 'ToolCallStreamingState', 'ToolCallPendingConfirmationState', 'ToolCallRunningState', 'ToolCallPendingResultConfirmationState', 'ToolCallCompletedState', - 'ToolCallCancelledState', 'ToolCallJudgeConfirmationReason', 'ConfirmationOption', + 'ToolCallCancelledState', 'ToolCallJudgeConfirmationReasonLoadingState', + 'ToolCallJudgeConfirmationReasonCompleteState', 'ConfirmationOption', 'ToolDefinition', 'ToolAnnotations', 'ToolResultTextContent', 'ToolResultEmbeddedResourceContent', 'ToolResultResourceContent', 'ToolResultFileEditContent', @@ -787,6 +789,16 @@ const TOOL_CALL_CONTRIBUTOR_UNION: UnionConfig = { ], }; +const TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION: UnionConfig = { + name: 'ToolCallJudgeConfirmationReason', + discriminantField: 'status', + allowUnknown: true, + variants: [ + { caseName: 'loading', structName: 'ToolCallJudgeConfirmationReasonLoadingState', discriminantValue: 'loading' }, + { caseName: 'complete', structName: 'ToolCallJudgeConfirmationReasonCompleteState', discriminantValue: 'complete' }, + ], +}; + const SESSION_INPUT_REQUEST_UNION: UnionConfig = { name: 'SessionInputRequest', discriminantField: 'kind', @@ -1063,6 +1075,8 @@ function generateStateFile(project: Project): string { lines.push(''); lines.push(generateDiscriminatedUnion(TOOL_CALL_CONTRIBUTOR_UNION)); lines.push(''); + lines.push(generateDiscriminatedUnion(TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION)); + lines.push(''); lines.push(generateDiscriminatedUnion(SESSION_INPUT_REQUEST_UNION)); lines.push(''); lines.push(generateToolResultContentUnion()); @@ -1942,6 +1956,7 @@ function checkExhaustiveness(project: Project): void { 'CustomizationLoadState', // CUSTOMIZATION_LOAD_STATE_UNION discriminated union 'McpServerState', // MCP_SERVER_STATUS_UNION discriminated union 'ToolCallContributor', // TOOL_CALL_CONTRIBUTOR_UNION discriminated union + 'ToolCallJudgeConfirmationReason', // TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION discriminated union 'SessionInputRequest', // SESSION_INPUT_REQUEST_UNION discriminated union 'ToolCallConfirmationState', // TOOL_CALL_CONFIRMATION_STATE_UNION discriminated union 'AuthRequiredErrorData', // emitted by generateErrorsFile() diff --git a/types/channels-chat/reducer.ts b/types/channels-chat/reducer.ts index bdca013a..26e4f22b 100644 --- a/types/channels-chat/reducer.ts +++ b/types/channels-chat/reducer.ts @@ -382,7 +382,11 @@ export function chatReducer(state: ChatState, action: ChatAction, log?: (msg: st case ActionType.ChatToolCallReady: return refreshSummaryStatus(updateToolCallInParts(state, action.turnId, action.toolCallId, tc => { - if (tc.status !== ToolCallStatus.Streaming && tc.status !== ToolCallStatus.Running) { + if ( + tc.status !== ToolCallStatus.Streaming + && tc.status !== ToolCallStatus.Running + && tc.status !== ToolCallStatus.PendingConfirmation + ) { return tc; } const base = tcBaseWithMeta(tc, action._meta); @@ -395,16 +399,18 @@ export function chatReducer(state: ChatState, action: ChatAction, log?: (msg: st confirmed: action.confirmed, }; } + const pending = tc.status === ToolCallStatus.PendingConfirmation ? tc : undefined; + const options = action.options ?? pending?.options; return { status: ToolCallStatus.PendingConfirmation, ...base, invocationMessage: action.invocationMessage, - toolInput: action.toolInput, - confirmationTitle: action.confirmationTitle, - confirmationReason: action.confirmationReason, - edits: action.edits, - editable: action.editable, - ...(action.options ? { options: action.options } : {}), + toolInput: action.toolInput ?? pending?.toolInput, + confirmationTitle: action.confirmationTitle ?? pending?.confirmationTitle, + confirmationReason: action.confirmationReason ?? pending?.confirmationReason, + edits: action.edits ?? pending?.edits, + editable: action.editable ?? pending?.editable, + ...(options ? { options } : {}), }; })); diff --git a/types/channels-chat/state.ts b/types/channels-chat/state.ts index 4cd9cce9..3a7658ac 100644 --- a/types/channels-chat/state.ts +++ b/types/channels-chat/state.ts @@ -944,15 +944,47 @@ export const enum ToolCallJudgeConfirmationReasonKind { } /** - * A model judge's explanation for requiring user confirmation. + * Lifecycle status of an asynchronous model-judge confirmation decision. * * @category Tool Call Types */ -export interface ToolCallJudgeConfirmationReason { - kind: ToolCallJudgeConfirmationReasonKind.Judge; +export const enum ToolCallJudgeConfirmationReasonStatus { + Loading = 'loading', + Complete = 'complete', +} + +interface ToolCallJudgeConfirmationReasonBase { + kind: ToolCallJudgeConfirmationReasonKind; +} + +/** + * The model judge is still evaluating the tool call. + * + * @category Tool Call Types + */ +export interface ToolCallJudgeConfirmationReasonLoadingState extends ToolCallJudgeConfirmationReasonBase { + status: ToolCallJudgeConfirmationReasonStatus.Loading; +} + +/** + * The model judge has completed its evaluation. + * + * @category Tool Call Types + */ +export interface ToolCallJudgeConfirmationReasonCompleteState extends ToolCallJudgeConfirmationReasonBase { + status: ToolCallJudgeConfirmationReasonStatus.Complete; reason: StringOrMarkdown; + /** + * The judge's normalized safety score, where `0` is unsafe and `1` is safe. + * @format float + */ + safety: number; } +export type ToolCallJudgeConfirmationReason = + | ToolCallJudgeConfirmationReasonLoadingState + | ToolCallJudgeConfirmationReasonCompleteState; + /** * Why a tool call was cancelled. * diff --git a/types/index.ts b/types/index.ts index 9d4ee9e2..39108c31 100644 --- a/types/index.ts +++ b/types/index.ts @@ -54,6 +54,8 @@ export type { ToolCallCancelledState, ToolCallState, ToolCallConfirmationState, + ToolCallJudgeConfirmationReasonLoadingState, + ToolCallJudgeConfirmationReasonCompleteState, ToolCallJudgeConfirmationReason, ConfirmationOption, ToolDefinition, @@ -127,6 +129,7 @@ export { ToolCallStatus, ToolCallConfirmationReason, ToolCallJudgeConfirmationReasonKind, + ToolCallJudgeConfirmationReasonStatus, ToolCallCancellationReason, ConfirmationOptionKind, ToolResultContentType, diff --git a/types/test-cases/reducers/029-toolcallready-ignores-non-streaming-non-running-tool-calls.json b/types/test-cases/reducers/029-toolcallready-updates-pending-confirmation-tool-calls.json similarity index 87% rename from types/test-cases/reducers/029-toolcallready-ignores-non-streaming-non-running-tool-calls.json rename to types/test-cases/reducers/029-toolcallready-updates-pending-confirmation-tool-calls.json index d7e4acd6..bc4f2cc6 100644 --- a/types/test-cases/reducers/029-toolcallready-ignores-non-streaming-non-running-tool-calls.json +++ b/types/test-cases/reducers/029-toolcallready-updates-pending-confirmation-tool-calls.json @@ -1,5 +1,5 @@ { - "description": "toolCallReady ignores non-streaming/non-running tool calls", + "description": "toolCallReady updates pending-confirmation tool calls", "reducer": "chat", "initial": { "turns": [], @@ -66,9 +66,12 @@ "intention": null, "contributor": null, "_meta": null, - "invocationMessage": "Run", + "invocationMessage": "Run again", "toolInput": null, - "confirmationTitle": null + "confirmationTitle": null, + "confirmationReason": null, + "edits": null, + "editable": null } } ], diff --git a/types/test-cases/reducers/127-toolcallready-with-confirmation-options.json b/types/test-cases/reducers/127-toolcallready-with-confirmation-options.json index 098d89ba..fe94c1cd 100644 --- a/types/test-cases/reducers/127-toolcallready-with-confirmation-options.json +++ b/types/test-cases/reducers/127-toolcallready-with-confirmation-options.json @@ -35,7 +35,9 @@ "invocationMessage": "Run: echo hello", "confirmationReason": { "kind": "judge", - "reason": "The command can modify the workspace." + "status": "complete", + "reason": "The command can modify the workspace.", + "safety": 0.25 }, "options": [ { @@ -92,7 +94,9 @@ "confirmationTitle": null, "confirmationReason": { "kind": "judge", - "reason": "The command can modify the workspace." + "status": "complete", + "reason": "The command can modify the workspace.", + "safety": 0.25 }, "edits": null, "editable": null, diff --git a/types/test-cases/reducers/241-toolcallready-updates-async-judge-reason.json b/types/test-cases/reducers/241-toolcallready-updates-async-judge-reason.json new file mode 100644 index 00000000..85277255 --- /dev/null +++ b/types/test-cases/reducers/241-toolcallready-updates-async-judge-reason.json @@ -0,0 +1,83 @@ +{ + "description": "toolCallReady stores an asynchronous judge loading state", + "reducer": "chat", + "initial": { + "turns": [], + "activeTurn": { + "id": "turn-1", + "startedAt": "1970-01-01T00:00:01.000Z", + "message": { + "text": "Hello", + "origin": { + "kind": "user" + } + }, + "responseParts": [], + "usage": null + }, + "resource": "copilot:/test-session", + "title": "Test Session", + "status": 8, + "modifiedAt": "1970-01-01T00:00:02.000Z" + }, + "actions": [ + { + "type": "chat/toolCallStart", + "turnId": "turn-1", + "toolCallId": "tc-1", + "toolName": "bash", + "displayName": "Run Command" + }, + { + "type": "chat/toolCallReady", + "turnId": "turn-1", + "toolCallId": "tc-1", + "invocationMessage": "Checking command safety", + "confirmationReason": { + "kind": "judge", + "status": "loading" + } + } + ], + "expected": { + "turns": [], + "activeTurn": { + "id": "turn-1", + "startedAt": "1970-01-01T00:00:01.000Z", + "message": { + "text": "Hello", + "origin": { + "kind": "user" + } + }, + "responseParts": [ + { + "kind": "toolCall", + "toolCall": { + "status": "pending-confirmation", + "toolCallId": "tc-1", + "toolName": "bash", + "displayName": "Run Command", + "intention": null, + "contributor": null, + "_meta": null, + "invocationMessage": "Checking command safety", + "toolInput": null, + "confirmationTitle": null, + "confirmationReason": { + "kind": "judge", + "status": "loading" + }, + "edits": null, + "editable": null + } + } + ], + "usage": null + }, + "resource": "copilot:/test-session", + "title": "Test Session", + "status": 24, + "modifiedAt": "1970-01-01T00:00:02.000Z" + } +} diff --git a/types/test-cases/reducers/242-toolcallready-completes-async-judge-reason.json b/types/test-cases/reducers/242-toolcallready-completes-async-judge-reason.json new file mode 100644 index 00000000..064f2907 --- /dev/null +++ b/types/test-cases/reducers/242-toolcallready-completes-async-judge-reason.json @@ -0,0 +1,120 @@ +{ + "description": "toolCallReady completes an asynchronous judge reason without clearing confirmation context", + "reducer": "chat", + "initial": { + "turns": [], + "activeTurn": { + "id": "turn-1", + "startedAt": "1970-01-01T00:00:01.000Z", + "message": { + "text": "Hello", + "origin": { + "kind": "user" + } + }, + "responseParts": [ + { + "kind": "toolCall", + "toolCall": { + "status": "pending-confirmation", + "toolCallId": "tc-1", + "toolName": "bash", + "displayName": "Run Command", + "intention": null, + "contributor": null, + "_meta": null, + "invocationMessage": "Checking command safety", + "toolInput": "rm -rf /tmp/test", + "confirmationTitle": "Run in terminal", + "confirmationReason": { + "kind": "judge", + "status": "loading" + }, + "edits": { + "items": [] + }, + "editable": true, + "options": [ + { + "id": "approve", + "label": "Approve", + "kind": "approve" + } + ] + } + } + ], + "usage": null + }, + "resource": "copilot:/test-session", + "title": "Test Session", + "status": 24, + "modifiedAt": "1970-01-01T00:00:02.000Z" + }, + "actions": [ + { + "type": "chat/toolCallReady", + "turnId": "turn-1", + "toolCallId": "tc-1", + "invocationMessage": "Run: rm -rf /tmp/test", + "confirmationReason": { + "kind": "judge", + "status": "complete", + "reason": "The command deletes files.", + "safety": 0.0 + } + } + ], + "expected": { + "turns": [], + "activeTurn": { + "id": "turn-1", + "startedAt": "1970-01-01T00:00:01.000Z", + "message": { + "text": "Hello", + "origin": { + "kind": "user" + } + }, + "responseParts": [ + { + "kind": "toolCall", + "toolCall": { + "status": "pending-confirmation", + "toolCallId": "tc-1", + "toolName": "bash", + "displayName": "Run Command", + "intention": null, + "contributor": null, + "_meta": null, + "invocationMessage": "Run: rm -rf /tmp/test", + "toolInput": "rm -rf /tmp/test", + "confirmationTitle": "Run in terminal", + "confirmationReason": { + "kind": "judge", + "status": "complete", + "reason": "The command deletes files.", + "safety": 0.0 + }, + "edits": { + "items": [] + }, + "editable": true, + "options": [ + { + "id": "approve", + "label": "Approve", + "kind": "approve" + } + ] + } + } + ], + "usage": null + }, + "resource": "copilot:/test-session", + "title": "Test Session", + "status": 24, + "modifiedAt": "1970-01-01T00:00:02.000Z" + } +} diff --git a/types/test-cases/reducers/243-toolcallready-ignores-finished-tool-calls.json b/types/test-cases/reducers/243-toolcallready-ignores-finished-tool-calls.json new file mode 100644 index 00000000..026a8b53 --- /dev/null +++ b/types/test-cases/reducers/243-toolcallready-ignores-finished-tool-calls.json @@ -0,0 +1,106 @@ +{ + "description": "toolCallReady ignores completed and cancelled tool calls", + "reducer": "chat", + "initial": { + "turns": [], + "activeTurn": { + "id": "turn-1", + "startedAt": "1970-01-01T00:00:01.000Z", + "message": { + "text": "Hello", + "origin": { + "kind": "user" + } + }, + "responseParts": [ + { + "kind": "toolCall", + "toolCall": { + "status": "completed", + "toolCallId": "tc-completed", + "toolName": "bash", + "displayName": "Run Command", + "invocationMessage": "Run", + "confirmed": "user-action", + "success": true, + "pastTenseMessage": "Ran command" + } + }, + { + "kind": "toolCall", + "toolCall": { + "status": "cancelled", + "toolCallId": "tc-cancelled", + "toolName": "write_file", + "displayName": "Write File", + "invocationMessage": "Write file", + "reason": "denied" + } + } + ], + "usage": null + }, + "resource": "copilot:/test-session", + "title": "Test Session", + "status": 8, + "modifiedAt": "1970-01-01T00:00:02.000Z" + }, + "actions": [ + { + "type": "chat/toolCallReady", + "turnId": "turn-1", + "toolCallId": "tc-completed", + "invocationMessage": "Late completed update" + }, + { + "type": "chat/toolCallReady", + "turnId": "turn-1", + "toolCallId": "tc-cancelled", + "invocationMessage": "Late cancelled update" + } + ], + "expected": { + "turns": [], + "activeTurn": { + "id": "turn-1", + "startedAt": "1970-01-01T00:00:01.000Z", + "message": { + "text": "Hello", + "origin": { + "kind": "user" + } + }, + "responseParts": [ + { + "kind": "toolCall", + "toolCall": { + "status": "completed", + "toolCallId": "tc-completed", + "toolName": "bash", + "displayName": "Run Command", + "invocationMessage": "Run", + "confirmed": "user-action", + "success": true, + "pastTenseMessage": "Ran command" + } + }, + { + "kind": "toolCall", + "toolCall": { + "status": "cancelled", + "toolCallId": "tc-cancelled", + "toolName": "write_file", + "displayName": "Write File", + "invocationMessage": "Write file", + "reason": "denied" + } + } + ], + "usage": null + }, + "resource": "copilot:/test-session", + "title": "Test Session", + "status": 8, + "modifiedAt": "1970-01-01T00:00:02.000Z" + } +} From acf1d6cbd03659bbadb104d94651a0e68af4e85c Mon Sep 17 00:00:00 2001 From: justschen Date: Tue, 14 Jul 2026 10:43:17 -0700 Subject: [PATCH 4/6] rust: format async judge reducer Apply cargo fmt to the pending-confirmation preservation logic. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- clients/rust/crates/ahp/src/reducers.rs | 27 +++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/clients/rust/crates/ahp/src/reducers.rs b/clients/rust/crates/ahp/src/reducers.rs index a641079b..5f8dd5e5 100644 --- a/clients/rust/crates/ahp/src/reducers.rs +++ b/clients/rust/crates/ahp/src/reducers.rs @@ -1188,12 +1188,27 @@ fn apply_tool_call_ready(state: &mut ChatState, a: &ChatToolCallReadyAction) -> contributor: base.contributor, meta, invocation_message: a.invocation_message.clone(), - tool_input: a.tool_input.clone().or_else(|| pending.as_ref().and_then(|p| p.tool_input.clone())), - confirmation_title: a.confirmation_title.clone().or_else(|| pending.as_ref().and_then(|p| p.confirmation_title.clone())), - confirmation_reason: a.confirmation_reason.clone().or_else(|| pending.as_ref().and_then(|p| p.confirmation_reason.clone())), - edits: a.edits.clone().or_else(|| pending.as_ref().and_then(|p| p.edits.clone())), - editable: a.editable.or_else(|| pending.as_ref().and_then(|p| p.editable)), - options: a.options.clone().or_else(|| pending.as_ref().and_then(|p| p.options.clone())), + tool_input: a + .tool_input + .clone() + .or_else(|| pending.as_ref().and_then(|p| p.tool_input.clone())), + confirmation_title: a.confirmation_title.clone().or_else(|| { + pending.as_ref().and_then(|p| p.confirmation_title.clone()) + }), + confirmation_reason: a.confirmation_reason.clone().or_else(|| { + pending.as_ref().and_then(|p| p.confirmation_reason.clone()) + }), + edits: a + .edits + .clone() + .or_else(|| pending.as_ref().and_then(|p| p.edits.clone())), + editable: a + .editable + .or_else(|| pending.as_ref().and_then(|p| p.editable)), + options: a + .options + .clone() + .or_else(|| pending.as_ref().and_then(|p| p.options.clone())), }) } } From 6bd177745ae9622b8a5197af334de8c4a36b7f95 Mon Sep 17 00:00:00 2001 From: justschen Date: Tue, 14 Jul 2026 12:04:26 -0700 Subject: [PATCH 5/6] chat: rename confirmation reason to risk assessment Use riskAssessment and ToolCallRiskAssessment across the protocol, generated SDKs, reducers, schemas, and fixtures. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- clients/go/ahp/reducers.go | 6 +- clients/go/ahptypes/actions.generated.go | 4 +- clients/go/ahptypes/state.generated.go | 62 +++++++++---------- .../microsoft/agenthostprotocol/Reducers.kt | 2 +- .../generated/Actions.generated.kt | 4 +- .../generated/State.generated.kt | 60 +++++++++--------- clients/rust/crates/ahp-types/src/actions.rs | 8 +-- clients/rust/crates/ahp-types/src/state.rs | 22 +++---- clients/rust/crates/ahp/src/reducers.rs | 7 ++- .../Generated/Actions.generated.swift | 10 +-- .../Generated/State.generated.swift | 44 ++++++------- .../Sources/AgentHostProtocol/Reducers.swift | 2 +- ...20260713-tool-call-judge-confirmation.json | 4 -- .../20260713-tool-call-risk-assessment.json | 4 ++ schema/actions.schema.json | 32 +++++----- schema/commands.schema.json | 32 +++++----- schema/errors.schema.json | 32 +++++----- schema/notifications.schema.json | 26 ++++---- schema/state.schema.json | 26 ++++---- scripts/generate-go.ts | 22 +++---- scripts/generate-kotlin.ts | 20 +++--- scripts/generate-rust.ts | 22 +++---- scripts/generate-swift.ts | 20 +++--- types/channels-chat/actions.ts | 6 +- types/channels-chat/reducer.ts | 2 +- types/channels-chat/state.ts | 26 ++++---- types/index.ts | 10 +-- ...ing-tool-back-to-pending-confirmation.json | 2 +- ...dates-pending-confirmation-tool-calls.json | 2 +- ...confirmation-sets-input-needed-status.json | 2 +- ...olcallready-with-confirmation-options.json | 4 +- .../220-toolcall-actions-update-meta.json | 2 +- ...ready-stores-loading-risk-assessment.json} | 6 +- ...lcallready-completes-risk-assessment.json} | 8 +-- 34 files changed, 271 insertions(+), 270 deletions(-) delete mode 100644 docs/.changes/20260713-tool-call-judge-confirmation.json create mode 100644 docs/.changes/20260713-tool-call-risk-assessment.json rename types/test-cases/reducers/{241-toolcallready-updates-async-judge-reason.json => 241-toolcallready-stores-loading-risk-assessment.json} (92%) rename types/test-cases/reducers/{242-toolcallready-completes-async-judge-reason.json => 242-toolcallready-completes-risk-assessment.json} (93%) diff --git a/clients/go/ahp/reducers.go b/clients/go/ahp/reducers.go index ac6b4148..5532ce4d 100644 --- a/clients/go/ahp/reducers.go +++ b/clients/go/ahp/reducers.go @@ -1025,7 +1025,7 @@ func applyToolCallReady(state *ahptypes.ChatState, a *ahptypes.ChatToolCallReady InvocationMessage: a.InvocationMessage, ToolInput: a.ToolInput, ConfirmationTitle: a.ConfirmationTitle, - ConfirmationReason: a.ConfirmationReason, + RiskAssessment: a.RiskAssessment, Edits: a.Edits, Editable: a.Editable, Options: a.Options, @@ -1037,8 +1037,8 @@ func applyToolCallReady(state *ahptypes.ChatState, a *ahptypes.ChatToolCallReady if next.ConfirmationTitle == nil { next.ConfirmationTitle = pending.ConfirmationTitle } - if next.ConfirmationReason == nil { - next.ConfirmationReason = pending.ConfirmationReason + if next.RiskAssessment == nil { + next.RiskAssessment = pending.RiskAssessment } if next.Edits == nil { next.Edits = pending.Edits diff --git a/clients/go/ahptypes/actions.generated.go b/clients/go/ahptypes/actions.generated.go index 2e2c79a6..0e291a7f 100644 --- a/clients/go/ahptypes/actions.generated.go +++ b/clients/go/ahptypes/actions.generated.go @@ -350,8 +350,8 @@ type ChatToolCallReadyAction struct { ToolInput *string `json:"toolInput,omitempty"` // Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) ConfirmationTitle *StringOrMarkdown `json:"confirmationTitle,omitempty"` - // Why the tool requires user confirmation. - ConfirmationReason *ToolCallJudgeConfirmationReason `json:"confirmationReason,omitempty"` + // Risk assessment that informed the confirmation requirement. + RiskAssessment *ToolCallRiskAssessment `json:"riskAssessment,omitempty"` // File edits that this tool call will perform, for preview before confirmation Edits *json.RawMessage `json:"edits,omitempty"` // Whether the agent host allows the client to edit the tool's input parameters before confirming diff --git a/clients/go/ahptypes/state.generated.go b/clients/go/ahptypes/state.generated.go index aee09d2e..1f2ba3c3 100644 --- a/clients/go/ahptypes/state.generated.go +++ b/clients/go/ahptypes/state.generated.go @@ -238,18 +238,18 @@ const ( ) // Identifies a model judge as the source of a confirmation requirement. -type ToolCallJudgeConfirmationReasonKind string +type ToolCallRiskAssessmentKind string const ( - ToolCallJudgeConfirmationReasonKindJudge ToolCallJudgeConfirmationReasonKind = "judge" + ToolCallRiskAssessmentKindJudge ToolCallRiskAssessmentKind = "judge" ) // Lifecycle status of an asynchronous model-judge confirmation decision. -type ToolCallJudgeConfirmationReasonStatus string +type ToolCallRiskAssessmentStatus string const ( - ToolCallJudgeConfirmationReasonStatusLoading ToolCallJudgeConfirmationReasonStatus = "loading" - ToolCallJudgeConfirmationReasonStatusComplete ToolCallJudgeConfirmationReasonStatus = "complete" + ToolCallRiskAssessmentStatusLoading ToolCallRiskAssessmentStatus = "loading" + ToolCallRiskAssessmentStatusComplete ToolCallRiskAssessmentStatus = "complete" ) // Why a tool call was cancelled. @@ -1718,16 +1718,16 @@ type ToolCallResult struct { } // The model judge is still evaluating the tool call. -type ToolCallJudgeConfirmationReasonLoadingState struct { - Kind ToolCallJudgeConfirmationReasonKind `json:"kind"` - Status ToolCallJudgeConfirmationReasonStatus `json:"status"` +type ToolCallRiskAssessmentLoadingState struct { + Kind ToolCallRiskAssessmentKind `json:"kind"` + Status ToolCallRiskAssessmentStatus `json:"status"` } // The model judge has completed its evaluation. -type ToolCallJudgeConfirmationReasonCompleteState struct { - Kind ToolCallJudgeConfirmationReasonKind `json:"kind"` - Status ToolCallJudgeConfirmationReasonStatus `json:"status"` - Reason StringOrMarkdown `json:"reason"` +type ToolCallRiskAssessmentCompleteState struct { + Kind ToolCallRiskAssessmentKind `json:"kind"` + Status ToolCallRiskAssessmentStatus `json:"status"` + Reason StringOrMarkdown `json:"reason"` // The judge's normalized safety score, where `0` is unsafe and `1` is safe. Safety float64 `json:"safety"` } @@ -1801,8 +1801,8 @@ type ToolCallPendingConfirmationState struct { Status ToolCallStatus `json:"status"` // Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) ConfirmationTitle *StringOrMarkdown `json:"confirmationTitle,omitempty"` - // Why the tool requires user confirmation. - ConfirmationReason *ToolCallJudgeConfirmationReason `json:"confirmationReason,omitempty"` + // Risk assessment that informed the confirmation requirement. + RiskAssessment *ToolCallRiskAssessment `json:"riskAssessment,omitempty"` // File edits that this tool call will perform, for preview before confirmation Edits *json.RawMessage `json:"edits,omitempty"` // Whether the agent host allows the client to edit the tool's input parameters before confirming @@ -4385,40 +4385,40 @@ func (u ToolCallContributor) MarshalJSON() ([]byte, error) { return json.Marshal(u.Value) } -// ToolCallJudgeConfirmationReason is an asynchronous model-judge confirmation rationale. -type ToolCallJudgeConfirmationReason struct { - Value isToolCallJudgeConfirmationReason +// ToolCallRiskAssessment is an asynchronous model-judge risk assessment. +type ToolCallRiskAssessment struct { + Value isToolCallRiskAssessment } -// isToolCallJudgeConfirmationReason is the marker interface implemented by every -// concrete variant of ToolCallJudgeConfirmationReason. -type isToolCallJudgeConfirmationReason interface{ isToolCallJudgeConfirmationReason() } +// isToolCallRiskAssessment is the marker interface implemented by every +// concrete variant of ToolCallRiskAssessment. +type isToolCallRiskAssessment interface{ isToolCallRiskAssessment() } -func (*ToolCallJudgeConfirmationReasonLoadingState) isToolCallJudgeConfirmationReason() {} -func (*ToolCallJudgeConfirmationReasonCompleteState) isToolCallJudgeConfirmationReason() {} +func (*ToolCallRiskAssessmentLoadingState) isToolCallRiskAssessment() {} +func (*ToolCallRiskAssessmentCompleteState) isToolCallRiskAssessment() {} -// ToolCallJudgeConfirmationReasonUnknown carries an unrecognized ToolCallJudgeConfirmationReason variant — typically a discriminator value introduced by a newer protocol version. The original JSON object is preserved verbatim so that re-encoding round-trips faithfully. -type ToolCallJudgeConfirmationReasonUnknown struct { +// ToolCallRiskAssessmentUnknown carries an unrecognized ToolCallRiskAssessment variant — typically a discriminator value introduced by a newer protocol version. The original JSON object is preserved verbatim so that re-encoding round-trips faithfully. +type ToolCallRiskAssessmentUnknown struct { Raw json.RawMessage } -func (*ToolCallJudgeConfirmationReasonUnknown) isToolCallJudgeConfirmationReason() {} +func (*ToolCallRiskAssessmentUnknown) isToolCallRiskAssessment() {} // UnmarshalJSON decodes the variant indicated by the "status" discriminator. -func (u *ToolCallJudgeConfirmationReason) UnmarshalJSON(data []byte) error { +func (u *ToolCallRiskAssessment) UnmarshalJSON(data []byte) error { disc, _, err := readDiscriminator(data, "status") if err != nil { return err } switch disc { case "loading": - var value ToolCallJudgeConfirmationReasonLoadingState + var value ToolCallRiskAssessmentLoadingState if err := json.Unmarshal(data, &value); err != nil { return err } u.Value = &value case "complete": - var value ToolCallJudgeConfirmationReasonCompleteState + var value ToolCallRiskAssessmentCompleteState if err := json.Unmarshal(data, &value); err != nil { return err } @@ -4426,14 +4426,14 @@ func (u *ToolCallJudgeConfirmationReason) UnmarshalJSON(data []byte) error { default: raw := make(json.RawMessage, len(data)) copy(raw, data) - u.Value = &ToolCallJudgeConfirmationReasonUnknown{Raw: raw} + u.Value = &ToolCallRiskAssessmentUnknown{Raw: raw} } return nil } // MarshalJSON encodes the active variant back to JSON. -func (u ToolCallJudgeConfirmationReason) MarshalJSON() ([]byte, error) { - if unk, ok := u.Value.(*ToolCallJudgeConfirmationReasonUnknown); ok { +func (u ToolCallRiskAssessment) MarshalJSON() ([]byte, error) { + if unk, ok := u.Value.(*ToolCallRiskAssessmentUnknown); ok { if len(unk.Raw) == 0 { return []byte("null"), nil } diff --git a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt index 365eb459..52dca063 100644 --- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt +++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt @@ -897,7 +897,7 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when toolInput = a.toolInput ?: pending?.toolInput, status = ToolCallStatus.PENDING_CONFIRMATION, confirmationTitle = a.confirmationTitle ?: pending?.confirmationTitle, - confirmationReason = a.confirmationReason ?: pending?.confirmationReason, + riskAssessment = a.riskAssessment ?: pending?.riskAssessment, edits = a.edits ?: pending?.edits, editable = a.editable ?: pending?.editable, options = a.options ?: pending?.options, diff --git a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Actions.generated.kt b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Actions.generated.kt index d0b64697..6df05eba 100644 --- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Actions.generated.kt +++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/Actions.generated.kt @@ -472,9 +472,9 @@ data class ChatToolCallReadyAction( */ val confirmationTitle: StringOrMarkdown? = null, /** - * Why the tool requires user confirmation. + * Risk assessment that informed the confirmation requirement. */ - val confirmationReason: ToolCallJudgeConfirmationReason? = null, + val riskAssessment: ToolCallRiskAssessment? = null, /** * File edits that this tool call will perform, for preview before confirmation */ diff --git a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt index 097f91de..2b330b4b 100644 --- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt +++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/generated/State.generated.kt @@ -437,7 +437,7 @@ enum class ToolCallConfirmationReason { * Identifies a model judge as the source of a confirmation requirement. */ @Serializable -enum class ToolCallJudgeConfirmationReasonKind { +enum class ToolCallRiskAssessmentKind { @SerialName("judge") JUDGE } @@ -446,7 +446,7 @@ enum class ToolCallJudgeConfirmationReasonKind { * Lifecycle status of an asynchronous model-judge confirmation decision. */ @Serializable -enum class ToolCallJudgeConfirmationReasonStatus { +enum class ToolCallRiskAssessmentStatus { @SerialName("loading") LOADING, @SerialName("complete") @@ -2467,9 +2467,9 @@ data class ToolCallPendingConfirmationState( */ val confirmationTitle: StringOrMarkdown? = null, /** - * Why the tool requires user confirmation. + * Risk assessment that informed the confirmation requirement. */ - val confirmationReason: ToolCallJudgeConfirmationReason? = null, + val riskAssessment: ToolCallRiskAssessment? = null, /** * File edits that this tool call will perform, for preview before confirmation */ @@ -2751,15 +2751,15 @@ data class ToolCallCancelledState( ) @Serializable -data class ToolCallJudgeConfirmationReasonLoadingState( - val kind: ToolCallJudgeConfirmationReasonKind, - val status: ToolCallJudgeConfirmationReasonStatus +data class ToolCallRiskAssessmentLoadingState( + val kind: ToolCallRiskAssessmentKind, + val status: ToolCallRiskAssessmentStatus ) @Serializable -data class ToolCallJudgeConfirmationReasonCompleteState( - val kind: ToolCallJudgeConfirmationReasonKind, - val status: ToolCallJudgeConfirmationReasonStatus, +data class ToolCallRiskAssessmentCompleteState( + val kind: ToolCallRiskAssessmentKind, + val status: ToolCallRiskAssessmentStatus, val reason: StringOrMarkdown, /** * The judge's normalized safety score, where `0` is unsafe and `1` is safe. @@ -5204,15 +5204,15 @@ internal object ToolCallContributorSerializer : KSerializer } } -@Serializable(with = ToolCallJudgeConfirmationReasonSerializer::class) -sealed interface ToolCallJudgeConfirmationReason +@Serializable(with = ToolCallRiskAssessmentSerializer::class) +sealed interface ToolCallRiskAssessment @JvmInline -value class ToolCallJudgeConfirmationReasonLoading(val value: ToolCallJudgeConfirmationReasonLoadingState) : ToolCallJudgeConfirmationReason +value class ToolCallRiskAssessmentLoading(val value: ToolCallRiskAssessmentLoadingState) : ToolCallRiskAssessment @JvmInline -value class ToolCallJudgeConfirmationReasonComplete(val value: ToolCallJudgeConfirmationReasonCompleteState) : ToolCallJudgeConfirmationReason +value class ToolCallRiskAssessmentComplete(val value: ToolCallRiskAssessmentCompleteState) : ToolCallRiskAssessment /** - * Forward-compat catch-all for unknown ToolCallJudgeConfirmationReason discriminators. + * Forward-compat catch-all for unknown ToolCallRiskAssessment discriminators. * * Older clients may receive newer wire variants they don't recognise; capturing * the raw `JsonObject` lets such payloads round-trip through the client unchanged. @@ -5220,34 +5220,34 @@ value class ToolCallJudgeConfirmationReasonComplete(val value: ToolCallJudgeConf * as a no-op, but see `Reducers.kt` for the exact treatment). */ @JvmInline -value class ToolCallJudgeConfirmationReasonUnknown(val raw: JsonObject) : ToolCallJudgeConfirmationReason +value class ToolCallRiskAssessmentUnknown(val raw: JsonObject) : ToolCallRiskAssessment -internal object ToolCallJudgeConfirmationReasonSerializer : KSerializer { +internal object ToolCallRiskAssessmentSerializer : KSerializer { override val descriptor: SerialDescriptor = - buildClassSerialDescriptor("ToolCallJudgeConfirmationReason") + buildClassSerialDescriptor("ToolCallRiskAssessment") - override fun deserialize(decoder: Decoder): ToolCallJudgeConfirmationReason { + override fun deserialize(decoder: Decoder): ToolCallRiskAssessment { val input = decoder as? JsonDecoder - ?: error("ToolCallJudgeConfirmationReason can only be deserialized from JSON") + ?: error("ToolCallRiskAssessment can only be deserialized from JSON") val element = input.decodeJsonElement() val obj = element as? JsonObject - ?: error("Expected JsonObject for ToolCallJudgeConfirmationReason") + ?: error("Expected JsonObject for ToolCallRiskAssessment") val discriminant = (obj["status"] as? JsonPrimitive)?.content - ?: return ToolCallJudgeConfirmationReasonUnknown(obj) + ?: return ToolCallRiskAssessmentUnknown(obj) return when (discriminant) { - "loading" -> ToolCallJudgeConfirmationReasonLoading(input.json.decodeFromJsonElement(ToolCallJudgeConfirmationReasonLoadingState.serializer(), element)) - "complete" -> ToolCallJudgeConfirmationReasonComplete(input.json.decodeFromJsonElement(ToolCallJudgeConfirmationReasonCompleteState.serializer(), element)) - else -> ToolCallJudgeConfirmationReasonUnknown(obj) + "loading" -> ToolCallRiskAssessmentLoading(input.json.decodeFromJsonElement(ToolCallRiskAssessmentLoadingState.serializer(), element)) + "complete" -> ToolCallRiskAssessmentComplete(input.json.decodeFromJsonElement(ToolCallRiskAssessmentCompleteState.serializer(), element)) + else -> ToolCallRiskAssessmentUnknown(obj) } } - override fun serialize(encoder: Encoder, value: ToolCallJudgeConfirmationReason) { + override fun serialize(encoder: Encoder, value: ToolCallRiskAssessment) { val output = encoder as? JsonEncoder - ?: error("ToolCallJudgeConfirmationReason can only be serialized to JSON") + ?: error("ToolCallRiskAssessment can only be serialized to JSON") val element: JsonElement = when (value) { - is ToolCallJudgeConfirmationReasonLoading -> output.json.encodeToJsonElement(ToolCallJudgeConfirmationReasonLoadingState.serializer(), value.value) - is ToolCallJudgeConfirmationReasonComplete -> output.json.encodeToJsonElement(ToolCallJudgeConfirmationReasonCompleteState.serializer(), value.value) - is ToolCallJudgeConfirmationReasonUnknown -> value.raw + is ToolCallRiskAssessmentLoading -> output.json.encodeToJsonElement(ToolCallRiskAssessmentLoadingState.serializer(), value.value) + is ToolCallRiskAssessmentComplete -> output.json.encodeToJsonElement(ToolCallRiskAssessmentCompleteState.serializer(), value.value) + is ToolCallRiskAssessmentUnknown -> value.raw } output.encodeJsonElement(element) } diff --git a/clients/rust/crates/ahp-types/src/actions.rs b/clients/rust/crates/ahp-types/src/actions.rs index 7f1e1592..17570b98 100644 --- a/clients/rust/crates/ahp-types/src/actions.rs +++ b/clients/rust/crates/ahp-types/src/actions.rs @@ -19,8 +19,8 @@ use crate::state::{ ConfirmationOption, Customization, ErrorInfo, McpServerState, Message, ModelSelection, PendingMessageKind, ResponsePart, SessionActiveClient, SessionInputRequest, TerminalClaim, TerminalInfo, TextRange, ToolCallCancellationReason, ToolCallConfirmationReason, - ToolCallContributor, ToolCallJudgeConfirmationReason, ToolCallResult, ToolDefinition, - ToolResultContent, Turn, UsageInfo, + ToolCallContributor, ToolCallResult, ToolCallRiskAssessment, ToolDefinition, ToolResultContent, + Turn, UsageInfo, }; // ─── ActionType ────────────────────────────────────────────────────── @@ -477,9 +477,9 @@ pub struct ChatToolCallReadyAction { /// Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) #[serde(default, skip_serializing_if = "Option::is_none")] pub confirmation_title: Option, - /// Why the tool requires user confirmation. + /// Risk assessment that informed the confirmation requirement. #[serde(default, skip_serializing_if = "Option::is_none")] - pub confirmation_reason: Option, + pub risk_assessment: Option, /// File edits that this tool call will perform, for preview before confirmation #[serde(default, skip_serializing_if = "Option::is_none")] pub edits: Option, diff --git a/clients/rust/crates/ahp-types/src/state.rs b/clients/rust/crates/ahp-types/src/state.rs index 14a24762..311bb072 100644 --- a/clients/rust/crates/ahp-types/src/state.rs +++ b/clients/rust/crates/ahp-types/src/state.rs @@ -344,14 +344,14 @@ pub enum ToolCallConfirmationReason { /// Identifies a model judge as the source of a confirmation requirement. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub enum ToolCallJudgeConfirmationReasonKind { +pub enum ToolCallRiskAssessmentKind { #[serde(rename = "judge")] Judge, } /// Lifecycle status of an asynchronous model-judge confirmation decision. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub enum ToolCallJudgeConfirmationReasonStatus { +pub enum ToolCallRiskAssessmentStatus { #[serde(rename = "loading")] Loading, #[serde(rename = "complete")] @@ -2146,15 +2146,15 @@ pub struct ToolCallResult { /// The model judge is still evaluating the tool call. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct ToolCallJudgeConfirmationReasonLoadingState { - pub kind: ToolCallJudgeConfirmationReasonKind, +pub struct ToolCallRiskAssessmentLoadingState { + pub kind: ToolCallRiskAssessmentKind, } /// The model judge has completed its evaluation. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct ToolCallJudgeConfirmationReasonCompleteState { - pub kind: ToolCallJudgeConfirmationReasonKind, +pub struct ToolCallRiskAssessmentCompleteState { + pub kind: ToolCallRiskAssessmentKind, pub reason: StringOrMarkdown, /// The judge's normalized safety score, where `0` is unsafe and `1` is safe. pub safety: f64, @@ -2244,9 +2244,9 @@ pub struct ToolCallPendingConfirmationState { /// Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) #[serde(default, skip_serializing_if = "Option::is_none")] pub confirmation_title: Option, - /// Why the tool requires user confirmation. + /// Risk assessment that informed the confirmation requirement. #[serde(default, skip_serializing_if = "Option::is_none")] - pub confirmation_reason: Option, + pub risk_assessment: Option, /// File edits that this tool call will perform, for preview before confirmation #[serde(default, skip_serializing_if = "Option::is_none")] pub edits: Option, @@ -4242,11 +4242,11 @@ pub enum ToolCallContributor { /// Asynchronous model-judge confirmation rationale. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(tag = "status")] -pub enum ToolCallJudgeConfirmationReason { +pub enum ToolCallRiskAssessment { #[serde(rename = "loading")] - Loading(ToolCallJudgeConfirmationReasonLoadingState), + Loading(ToolCallRiskAssessmentLoadingState), #[serde(rename = "complete")] - Complete(ToolCallJudgeConfirmationReasonCompleteState), + Complete(ToolCallRiskAssessmentCompleteState), /// Unknown or future variant — preserved as raw JSON for round-trip fidelity. /// Reducers treat this as a no-op. #[serde(untagged)] diff --git a/clients/rust/crates/ahp/src/reducers.rs b/clients/rust/crates/ahp/src/reducers.rs index 5f8dd5e5..0dbce2f5 100644 --- a/clients/rust/crates/ahp/src/reducers.rs +++ b/clients/rust/crates/ahp/src/reducers.rs @@ -1195,9 +1195,10 @@ fn apply_tool_call_ready(state: &mut ChatState, a: &ChatToolCallReadyAction) -> confirmation_title: a.confirmation_title.clone().or_else(|| { pending.as_ref().and_then(|p| p.confirmation_title.clone()) }), - confirmation_reason: a.confirmation_reason.clone().or_else(|| { - pending.as_ref().and_then(|p| p.confirmation_reason.clone()) - }), + risk_assessment: a + .risk_assessment + .clone() + .or_else(|| pending.as_ref().and_then(|p| p.risk_assessment.clone())), edits: a .edits .clone() diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift index 2e9e9681..6d5d0e6d 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift @@ -480,8 +480,8 @@ public struct ChatToolCallReadyAction: Codable, Sendable { public var toolInput: String? /// Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) public var confirmationTitle: StringOrMarkdown? - /// Why the tool requires user confirmation. - public var confirmationReason: ToolCallJudgeConfirmationReason? + /// Risk assessment that informed the confirmation requirement. + public var riskAssessment: ToolCallRiskAssessment? /// File edits that this tool call will perform, for preview before confirmation public var edits: AnyCodable? /// Whether the agent host allows the client to edit the tool's input parameters before confirming @@ -502,7 +502,7 @@ public struct ChatToolCallReadyAction: Codable, Sendable { case invocationMessage case toolInput case confirmationTitle - case confirmationReason + case riskAssessment case edits case editable case confirmed @@ -517,7 +517,7 @@ public struct ChatToolCallReadyAction: Codable, Sendable { invocationMessage: StringOrMarkdown, toolInput: String? = nil, confirmationTitle: StringOrMarkdown? = nil, - confirmationReason: ToolCallJudgeConfirmationReason? = nil, + riskAssessment: ToolCallRiskAssessment? = nil, edits: AnyCodable? = nil, editable: Bool? = nil, confirmed: ToolCallConfirmationReason? = nil, @@ -530,7 +530,7 @@ public struct ChatToolCallReadyAction: Codable, Sendable { self.invocationMessage = invocationMessage self.toolInput = toolInput self.confirmationTitle = confirmationTitle - self.confirmationReason = confirmationReason + self.riskAssessment = riskAssessment self.edits = edits self.editable = editable self.confirmed = confirmed diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift index 35ca03ff..43684476 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift @@ -226,12 +226,12 @@ public enum ToolCallConfirmationReason: String, Codable, Sendable { } /// Identifies a model judge as the source of a confirmation requirement. -public enum ToolCallJudgeConfirmationReasonKind: String, Codable, Sendable { +public enum ToolCallRiskAssessmentKind: String, Codable, Sendable { case judge = "judge" } /// Lifecycle status of an asynchronous model-judge confirmation decision. -public enum ToolCallJudgeConfirmationReasonStatus: String, Codable, Sendable { +public enum ToolCallRiskAssessmentStatus: String, Codable, Sendable { case loading = "loading" case complete = "complete" } @@ -2473,8 +2473,8 @@ public struct ToolCallPendingConfirmationState: Codable, Sendable { public var status: ToolCallStatus /// Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) public var confirmationTitle: StringOrMarkdown? - /// Why the tool requires user confirmation. - public var confirmationReason: ToolCallJudgeConfirmationReason? + /// Risk assessment that informed the confirmation requirement. + public var riskAssessment: ToolCallRiskAssessment? /// File edits that this tool call will perform, for preview before confirmation public var edits: AnyCodable? /// Whether the agent host allows the client to edit the tool's input parameters before confirming @@ -2496,7 +2496,7 @@ public struct ToolCallPendingConfirmationState: Codable, Sendable { case toolInput case status case confirmationTitle - case confirmationReason + case riskAssessment case edits case editable case options @@ -2513,7 +2513,7 @@ public struct ToolCallPendingConfirmationState: Codable, Sendable { toolInput: String? = nil, status: ToolCallStatus, confirmationTitle: StringOrMarkdown? = nil, - confirmationReason: ToolCallJudgeConfirmationReason? = nil, + riskAssessment: ToolCallRiskAssessment? = nil, edits: AnyCodable? = nil, editable: Bool? = nil, options: [ConfirmationOption]? = nil @@ -2528,7 +2528,7 @@ public struct ToolCallPendingConfirmationState: Codable, Sendable { self.toolInput = toolInput self.status = status self.confirmationTitle = confirmationTitle - self.confirmationReason = confirmationReason + self.riskAssessment = riskAssessment self.edits = edits self.editable = editable self.options = options @@ -2883,29 +2883,29 @@ public struct ToolCallCancelledState: Codable, Sendable { } } -public struct ToolCallJudgeConfirmationReasonLoadingState: Codable, Sendable { - public var kind: ToolCallJudgeConfirmationReasonKind - public var status: ToolCallJudgeConfirmationReasonStatus +public struct ToolCallRiskAssessmentLoadingState: Codable, Sendable { + public var kind: ToolCallRiskAssessmentKind + public var status: ToolCallRiskAssessmentStatus public init( - kind: ToolCallJudgeConfirmationReasonKind, - status: ToolCallJudgeConfirmationReasonStatus + kind: ToolCallRiskAssessmentKind, + status: ToolCallRiskAssessmentStatus ) { self.kind = kind self.status = status } } -public struct ToolCallJudgeConfirmationReasonCompleteState: Codable, Sendable { - public var kind: ToolCallJudgeConfirmationReasonKind - public var status: ToolCallJudgeConfirmationReasonStatus +public struct ToolCallRiskAssessmentCompleteState: Codable, Sendable { + public var kind: ToolCallRiskAssessmentKind + public var status: ToolCallRiskAssessmentStatus public var reason: StringOrMarkdown /// The judge's normalized safety score, where `0` is unsafe and `1` is safe. public var safety: Double public init( - kind: ToolCallJudgeConfirmationReasonKind, - status: ToolCallJudgeConfirmationReasonStatus, + kind: ToolCallRiskAssessmentKind, + status: ToolCallRiskAssessmentStatus, reason: StringOrMarkdown, safety: Double ) { @@ -5514,9 +5514,9 @@ public enum ToolCallContributor: Codable, Sendable { } } -public enum ToolCallJudgeConfirmationReason: Codable, Sendable { - case loading(ToolCallJudgeConfirmationReasonLoadingState) - case complete(ToolCallJudgeConfirmationReasonCompleteState) +public enum ToolCallRiskAssessment: Codable, Sendable { + case loading(ToolCallRiskAssessmentLoadingState) + case complete(ToolCallRiskAssessmentCompleteState) /// Unknown or future discriminant; the raw payload is preserved /// and re-encoded verbatim for forward-compatibility. case unknown(AnyCodable) @@ -5530,9 +5530,9 @@ public enum ToolCallJudgeConfirmationReason: Codable, Sendable { let discriminant = try container.decode(String.self, forKey: .discriminant) switch discriminant { case "loading": - self = .loading(try ToolCallJudgeConfirmationReasonLoadingState(from: decoder)) + self = .loading(try ToolCallRiskAssessmentLoadingState(from: decoder)) case "complete": - self = .complete(try ToolCallJudgeConfirmationReasonCompleteState(from: decoder)) + self = .complete(try ToolCallRiskAssessmentCompleteState(from: decoder)) default: self = .unknown(try AnyCodable(from: decoder)) } diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift index dce9caaa..e3df3979 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift @@ -225,7 +225,7 @@ public func chatReducer(state: ChatState, action: StateAction) -> ChatState { toolInput: a.toolInput ?? pending?.toolInput, status: .pendingConfirmation, confirmationTitle: a.confirmationTitle ?? pending?.confirmationTitle, - confirmationReason: a.confirmationReason ?? pending?.confirmationReason, + riskAssessment: a.riskAssessment ?? pending?.riskAssessment, edits: a.edits ?? pending?.edits, editable: a.editable ?? pending?.editable, options: a.options ?? pending?.options diff --git a/docs/.changes/20260713-tool-call-judge-confirmation.json b/docs/.changes/20260713-tool-call-judge-confirmation.json deleted file mode 100644 index dcb9feaf..00000000 --- a/docs/.changes/20260713-tool-call-judge-confirmation.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "added", - "message": "Asynchronous `judge` tool-call confirmation reasons with a model-provided explanation and normalized safety score." -} diff --git a/docs/.changes/20260713-tool-call-risk-assessment.json b/docs/.changes/20260713-tool-call-risk-assessment.json new file mode 100644 index 00000000..fafdbc5c --- /dev/null +++ b/docs/.changes/20260713-tool-call-risk-assessment.json @@ -0,0 +1,4 @@ +{ + "type": "added", + "message": "Asynchronous tool-call risk assessments with a model-provided explanation and normalized safety score." +} diff --git a/schema/actions.schema.json b/schema/actions.schema.json index cb01cfb2..db0fb3e1 100644 --- a/schema/actions.schema.json +++ b/schema/actions.schema.json @@ -846,9 +846,9 @@ "$ref": "#/$defs/StringOrMarkdown", "description": "Short title for the confirmation prompt (e.g. `\"Run in terminal\"`, `\"Write file\"`)" }, - "confirmationReason": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReason", - "description": "Why the tool requires user confirmation." + "riskAssessment": { + "$ref": "#/$defs/ToolCallRiskAssessment", + "description": "Risk assessment that informed the confirmation requirement." }, "edits": { "type": "object", @@ -5270,23 +5270,23 @@ "content" ] }, - "ToolCallJudgeConfirmationReasonBase": { + "ToolCallRiskAssessmentBase": { "type": "object", "properties": { "kind": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + "$ref": "#/$defs/ToolCallRiskAssessmentKind" } }, "required": [ "kind" ] }, - "ToolCallJudgeConfirmationReasonLoadingState": { + "ToolCallRiskAssessmentLoadingState": { "type": "object", "description": "The model judge is still evaluating the tool call.", "properties": { "kind": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + "$ref": "#/$defs/ToolCallRiskAssessmentKind" }, "status": { "const": "loading" @@ -5297,12 +5297,12 @@ "status" ] }, - "ToolCallJudgeConfirmationReasonCompleteState": { + "ToolCallRiskAssessmentCompleteState": { "type": "object", "description": "The model judge has completed its evaluation.", "properties": { "kind": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + "$ref": "#/$defs/ToolCallRiskAssessmentKind" }, "status": { "const": "complete" @@ -5571,9 +5571,9 @@ "$ref": "#/$defs/StringOrMarkdown", "description": "Short title for the confirmation prompt (e.g. `\"Run in terminal\"`, `\"Write file\"`)" }, - "confirmationReason": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReason", - "description": "Why the tool requires user confirmation." + "riskAssessment": { + "$ref": "#/$defs/ToolCallRiskAssessment", + "description": "Risk assessment that informed the confirmation requirement." }, "edits": { "type": "object", @@ -6948,13 +6948,13 @@ } ] }, - "ToolCallJudgeConfirmationReason": { + "ToolCallRiskAssessment": { "oneOf": [ { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonLoadingState" + "$ref": "#/$defs/ToolCallRiskAssessmentLoadingState" }, { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonCompleteState" + "$ref": "#/$defs/ToolCallRiskAssessmentCompleteState" } ] }, @@ -7411,7 +7411,7 @@ "type": "string", "description": "Discriminant for {@link MessageOrigin} — identifies who produced a message." }, - "ToolCallJudgeConfirmationReasonKind": { + "ToolCallRiskAssessmentKind": { "enum": [ "judge" ], diff --git a/schema/commands.schema.json b/schema/commands.schema.json index 3124f34a..6c56861e 100644 --- a/schema/commands.schema.json +++ b/schema/commands.schema.json @@ -4534,23 +4534,23 @@ "content" ] }, - "ToolCallJudgeConfirmationReasonBase": { + "ToolCallRiskAssessmentBase": { "type": "object", "properties": { "kind": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + "$ref": "#/$defs/ToolCallRiskAssessmentKind" } }, "required": [ "kind" ] }, - "ToolCallJudgeConfirmationReasonLoadingState": { + "ToolCallRiskAssessmentLoadingState": { "type": "object", "description": "The model judge is still evaluating the tool call.", "properties": { "kind": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + "$ref": "#/$defs/ToolCallRiskAssessmentKind" }, "status": { "const": "loading" @@ -4561,12 +4561,12 @@ "status" ] }, - "ToolCallJudgeConfirmationReasonCompleteState": { + "ToolCallRiskAssessmentCompleteState": { "type": "object", "description": "The model judge has completed its evaluation.", "properties": { "kind": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + "$ref": "#/$defs/ToolCallRiskAssessmentKind" }, "status": { "const": "complete" @@ -4835,9 +4835,9 @@ "$ref": "#/$defs/StringOrMarkdown", "description": "Short title for the confirmation prompt (e.g. `\"Run in terminal\"`, `\"Write file\"`)" }, - "confirmationReason": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReason", - "description": "Why the tool requires user confirmation." + "riskAssessment": { + "$ref": "#/$defs/ToolCallRiskAssessment", + "description": "Risk assessment that informed the confirmation requirement." }, "edits": { "type": "object", @@ -6763,9 +6763,9 @@ "$ref": "#/$defs/StringOrMarkdown", "description": "Short title for the confirmation prompt (e.g. `\"Run in terminal\"`, `\"Write file\"`)" }, - "confirmationReason": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReason", - "description": "Why the tool requires user confirmation." + "riskAssessment": { + "$ref": "#/$defs/ToolCallRiskAssessment", + "description": "Risk assessment that informed the confirmation requirement." }, "edits": { "type": "object", @@ -8601,7 +8601,7 @@ "type": "string", "description": "How a client completed an input request." }, - "ToolCallJudgeConfirmationReasonKind": { + "ToolCallRiskAssessmentKind": { "enum": [ "judge" ], @@ -8652,13 +8652,13 @@ ], "description": "Content block in a tool result.\n\nMirrors the content blocks in MCP `CallToolResult.content`, plus\n`ToolResultResourceContent` for lazy-loading large results,\n`ToolResultFileEditContent` for file edit diffs,\n`ToolResultTerminalContent` for live terminal output,\n`ToolResultTerminalCompleteContent` for terminal-style completion metadata, and\n`ToolResultSubagentContent` for tool-spawned worker chats (AHP extensions)." }, - "ToolCallJudgeConfirmationReason": { + "ToolCallRiskAssessment": { "oneOf": [ { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonLoadingState" + "$ref": "#/$defs/ToolCallRiskAssessmentLoadingState" }, { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonCompleteState" + "$ref": "#/$defs/ToolCallRiskAssessmentCompleteState" } ] }, diff --git a/schema/errors.schema.json b/schema/errors.schema.json index 4db39723..3202dff0 100644 --- a/schema/errors.schema.json +++ b/schema/errors.schema.json @@ -3325,23 +3325,23 @@ "content" ] }, - "ToolCallJudgeConfirmationReasonBase": { + "ToolCallRiskAssessmentBase": { "type": "object", "properties": { "kind": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + "$ref": "#/$defs/ToolCallRiskAssessmentKind" } }, "required": [ "kind" ] }, - "ToolCallJudgeConfirmationReasonLoadingState": { + "ToolCallRiskAssessmentLoadingState": { "type": "object", "description": "The model judge is still evaluating the tool call.", "properties": { "kind": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + "$ref": "#/$defs/ToolCallRiskAssessmentKind" }, "status": { "const": "loading" @@ -3352,12 +3352,12 @@ "status" ] }, - "ToolCallJudgeConfirmationReasonCompleteState": { + "ToolCallRiskAssessmentCompleteState": { "type": "object", "description": "The model judge has completed its evaluation.", "properties": { "kind": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + "$ref": "#/$defs/ToolCallRiskAssessmentKind" }, "status": { "const": "complete" @@ -3626,9 +3626,9 @@ "$ref": "#/$defs/StringOrMarkdown", "description": "Short title for the confirmation prompt (e.g. `\"Run in terminal\"`, `\"Write file\"`)" }, - "confirmationReason": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReason", - "description": "Why the tool requires user confirmation." + "riskAssessment": { + "$ref": "#/$defs/ToolCallRiskAssessment", + "description": "Risk assessment that informed the confirmation requirement." }, "edits": { "type": "object", @@ -6415,7 +6415,7 @@ ], "description": "A string that may optionally be rendered as Markdown.\n\n- A plain `string` is rendered as-is (no Markdown processing).\n- An object with `{ markdown: string }` is rendered with Markdown formatting." }, - "ToolCallJudgeConfirmationReasonKind": { + "ToolCallRiskAssessmentKind": { "enum": [ "judge" ], @@ -6466,13 +6466,13 @@ ], "description": "Content block in a tool result.\n\nMirrors the content blocks in MCP `CallToolResult.content`, plus\n`ToolResultResourceContent` for lazy-loading large results,\n`ToolResultFileEditContent` for file edit diffs,\n`ToolResultTerminalContent` for live terminal output,\n`ToolResultTerminalCompleteContent` for terminal-style completion metadata, and\n`ToolResultSubagentContent` for tool-spawned worker chats (AHP extensions)." }, - "ToolCallJudgeConfirmationReason": { + "ToolCallRiskAssessment": { "oneOf": [ { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonLoadingState" + "$ref": "#/$defs/ToolCallRiskAssessmentLoadingState" }, { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonCompleteState" + "$ref": "#/$defs/ToolCallRiskAssessmentCompleteState" } ] }, @@ -7691,9 +7691,9 @@ "$ref": "#/$defs/StringOrMarkdown", "description": "Short title for the confirmation prompt (e.g. `\"Run in terminal\"`, `\"Write file\"`)" }, - "confirmationReason": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReason", - "description": "Why the tool requires user confirmation." + "riskAssessment": { + "$ref": "#/$defs/ToolCallRiskAssessment", + "description": "Risk assessment that informed the confirmation requirement." }, "edits": { "type": "object", diff --git a/schema/notifications.schema.json b/schema/notifications.schema.json index 2a929c8a..894e41e5 100644 --- a/schema/notifications.schema.json +++ b/schema/notifications.schema.json @@ -3485,23 +3485,23 @@ "content" ] }, - "ToolCallJudgeConfirmationReasonBase": { + "ToolCallRiskAssessmentBase": { "type": "object", "properties": { "kind": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + "$ref": "#/$defs/ToolCallRiskAssessmentKind" } }, "required": [ "kind" ] }, - "ToolCallJudgeConfirmationReasonLoadingState": { + "ToolCallRiskAssessmentLoadingState": { "type": "object", "description": "The model judge is still evaluating the tool call.", "properties": { "kind": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + "$ref": "#/$defs/ToolCallRiskAssessmentKind" }, "status": { "const": "loading" @@ -3512,12 +3512,12 @@ "status" ] }, - "ToolCallJudgeConfirmationReasonCompleteState": { + "ToolCallRiskAssessmentCompleteState": { "type": "object", "description": "The model judge has completed its evaluation.", "properties": { "kind": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + "$ref": "#/$defs/ToolCallRiskAssessmentKind" }, "status": { "const": "complete" @@ -3786,9 +3786,9 @@ "$ref": "#/$defs/StringOrMarkdown", "description": "Short title for the confirmation prompt (e.g. `\"Run in terminal\"`, `\"Write file\"`)" }, - "confirmationReason": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReason", - "description": "Why the tool requires user confirmation." + "riskAssessment": { + "$ref": "#/$defs/ToolCallRiskAssessment", + "description": "Risk assessment that informed the confirmation requirement." }, "edits": { "type": "object", @@ -5285,7 +5285,7 @@ ], "description": "A string that may optionally be rendered as Markdown.\n\n- A plain `string` is rendered as-is (no Markdown processing).\n- An object with `{ markdown: string }` is rendered with Markdown formatting." }, - "ToolCallJudgeConfirmationReasonKind": { + "ToolCallRiskAssessmentKind": { "enum": [ "judge" ], @@ -5336,13 +5336,13 @@ ], "description": "Content block in a tool result.\n\nMirrors the content blocks in MCP `CallToolResult.content`, plus\n`ToolResultResourceContent` for lazy-loading large results,\n`ToolResultFileEditContent` for file edit diffs,\n`ToolResultTerminalContent` for live terminal output,\n`ToolResultTerminalCompleteContent` for terminal-style completion metadata, and\n`ToolResultSubagentContent` for tool-spawned worker chats (AHP extensions)." }, - "ToolCallJudgeConfirmationReason": { + "ToolCallRiskAssessment": { "oneOf": [ { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonLoadingState" + "$ref": "#/$defs/ToolCallRiskAssessmentLoadingState" }, { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonCompleteState" + "$ref": "#/$defs/ToolCallRiskAssessmentCompleteState" } ] }, diff --git a/schema/state.schema.json b/schema/state.schema.json index becb1f7a..0f4c947f 100644 --- a/schema/state.schema.json +++ b/schema/state.schema.json @@ -3236,23 +3236,23 @@ "content" ] }, - "ToolCallJudgeConfirmationReasonBase": { + "ToolCallRiskAssessmentBase": { "type": "object", "properties": { "kind": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + "$ref": "#/$defs/ToolCallRiskAssessmentKind" } }, "required": [ "kind" ] }, - "ToolCallJudgeConfirmationReasonLoadingState": { + "ToolCallRiskAssessmentLoadingState": { "type": "object", "description": "The model judge is still evaluating the tool call.", "properties": { "kind": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + "$ref": "#/$defs/ToolCallRiskAssessmentKind" }, "status": { "const": "loading" @@ -3263,12 +3263,12 @@ "status" ] }, - "ToolCallJudgeConfirmationReasonCompleteState": { + "ToolCallRiskAssessmentCompleteState": { "type": "object", "description": "The model judge has completed its evaluation.", "properties": { "kind": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonKind" + "$ref": "#/$defs/ToolCallRiskAssessmentKind" }, "status": { "const": "complete" @@ -3537,9 +3537,9 @@ "$ref": "#/$defs/StringOrMarkdown", "description": "Short title for the confirmation prompt (e.g. `\"Run in terminal\"`, `\"Write file\"`)" }, - "confirmationReason": { - "$ref": "#/$defs/ToolCallJudgeConfirmationReason", - "description": "Why the tool requires user confirmation." + "riskAssessment": { + "$ref": "#/$defs/ToolCallRiskAssessment", + "description": "Risk assessment that informed the confirmation requirement." }, "edits": { "type": "object", @@ -4914,13 +4914,13 @@ } ] }, - "ToolCallJudgeConfirmationReason": { + "ToolCallRiskAssessment": { "oneOf": [ { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonLoadingState" + "$ref": "#/$defs/ToolCallRiskAssessmentLoadingState" }, { - "$ref": "#/$defs/ToolCallJudgeConfirmationReasonCompleteState" + "$ref": "#/$defs/ToolCallRiskAssessmentCompleteState" } ] }, @@ -5096,7 +5096,7 @@ "type": "string", "description": "How a client completed an input request." }, - "ToolCallJudgeConfirmationReasonKind": { + "ToolCallRiskAssessmentKind": { "enum": [ "judge" ], diff --git a/scripts/generate-go.ts b/scripts/generate-go.ts index 8ed0d6f6..112bb9e3 100644 --- a/scripts/generate-go.ts +++ b/scripts/generate-go.ts @@ -644,8 +644,8 @@ const STATE_ENUMS = [ 'ChatOriginKind', 'ChatInteractivity', 'PendingMessageKind', 'ChatInputAnswerState', 'ChatInputAnswerValueKind', 'ChatInputQuestionKind', 'ChatInputResponseKind', 'SessionInputRequestKind', 'TurnState', 'MessageKind', 'MessageAttachmentKind', 'ResponsePartKind', 'ToolCallStatus', - 'ToolCallConfirmationReason', 'ToolCallJudgeConfirmationReasonKind', - 'ToolCallJudgeConfirmationReasonStatus', + 'ToolCallConfirmationReason', 'ToolCallRiskAssessmentKind', + 'ToolCallRiskAssessmentStatus', 'ToolCallCancellationReason', 'ConfirmationOptionKind', 'ToolCallContributorKind', 'ToolResultContentType', 'CustomizationType', 'CustomizationLoadStatus', 'TerminalClaimKind', @@ -713,8 +713,8 @@ const STATE_STRUCTS: { name: string; omitDiscriminants?: boolean; goName?: strin { name: 'SystemNotificationResponsePart' }, { name: 'InputRequestResponsePart' }, { name: 'ToolCallResult' }, - { name: 'ToolCallJudgeConfirmationReasonLoadingState' }, - { name: 'ToolCallJudgeConfirmationReasonCompleteState' }, + { name: 'ToolCallRiskAssessmentLoadingState' }, + { name: 'ToolCallRiskAssessmentCompleteState' }, { name: 'ConfirmationOption' }, { name: 'ToolCallStreamingState' }, { name: 'ToolCallPendingConfirmationState' }, @@ -975,13 +975,13 @@ const TOOL_CALL_CONTRIBUTOR_UNION: UnionConfig = { unknown: true, }; -const TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION: UnionConfig = { - name: 'ToolCallJudgeConfirmationReason', +const TOOL_CALL_RISK_ASSESSMENT_UNION: UnionConfig = { + name: 'ToolCallRiskAssessment', discriminantField: 'status', - doc: 'ToolCallJudgeConfirmationReason is an asynchronous model-judge confirmation rationale.', + doc: 'ToolCallRiskAssessment is an asynchronous model-judge risk assessment.', variants: [ - { variantName: 'Loading', innerType: 'ToolCallJudgeConfirmationReasonLoadingState', wireValue: 'loading' }, - { variantName: 'Complete', innerType: 'ToolCallJudgeConfirmationReasonCompleteState', wireValue: 'complete' }, + { variantName: 'Loading', innerType: 'ToolCallRiskAssessmentLoadingState', wireValue: 'loading' }, + { variantName: 'Complete', innerType: 'ToolCallRiskAssessmentCompleteState', wireValue: 'complete' }, ], unknown: true, }; @@ -1242,7 +1242,7 @@ function generateStateFile(project: Project): string { lines.push(''); lines.push(generateDiscriminatedUnion(TOOL_CALL_CONTRIBUTOR_UNION)); lines.push(''); - lines.push(generateDiscriminatedUnion(TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION)); + lines.push(generateDiscriminatedUnion(TOOL_CALL_RISK_ASSESSMENT_UNION)); lines.push(''); lines.push(generateDiscriminatedUnion(SESSION_INPUT_REQUEST_UNION)); lines.push(''); @@ -1948,7 +1948,7 @@ function checkExhaustiveness(project: Project): void { 'CustomizationLoadState', 'McpServerState', 'ToolCallContributor', - 'ToolCallJudgeConfirmationReason', + 'ToolCallRiskAssessment', 'SessionInputRequest', 'ToolCallConfirmationState', 'ReconnectResult', diff --git a/scripts/generate-kotlin.ts b/scripts/generate-kotlin.ts index 47517f1a..ad429635 100644 --- a/scripts/generate-kotlin.ts +++ b/scripts/generate-kotlin.ts @@ -791,8 +791,8 @@ const STATE_ENUMS = [ 'ChatOriginKind', 'ChatInteractivity', 'ChatInputAnswerState', 'ChatInputAnswerValueKind', 'ChatInputQuestionKind', 'ChatInputResponseKind', 'SessionInputRequestKind', 'TurnState', 'MessageKind', 'MessageAttachmentKind', 'ResponsePartKind', 'ToolCallStatus', - 'ToolCallConfirmationReason', 'ToolCallJudgeConfirmationReasonKind', - 'ToolCallJudgeConfirmationReasonStatus', + 'ToolCallConfirmationReason', 'ToolCallRiskAssessmentKind', + 'ToolCallRiskAssessmentStatus', 'ToolCallCancellationReason', 'ConfirmationOptionKind', 'ToolCallContributorKind', 'ToolResultContentType', 'CustomizationType', 'CustomizationLoadStatus', 'TerminalClaimKind', @@ -827,8 +827,8 @@ const STATE_STRUCTS = [ 'ToolCallResult', 'ToolCallStreamingState', 'ToolCallPendingConfirmationState', 'ToolCallRunningState', 'ToolCallPendingResultConfirmationState', 'ToolCallCompletedState', - 'ToolCallCancelledState', 'ToolCallJudgeConfirmationReasonLoadingState', - 'ToolCallJudgeConfirmationReasonCompleteState', 'ConfirmationOption', + 'ToolCallCancelledState', 'ToolCallRiskAssessmentLoadingState', + 'ToolCallRiskAssessmentCompleteState', 'ConfirmationOption', 'ToolDefinition', 'ToolAnnotations', 'ToolResultTextContent', 'ToolResultEmbeddedResourceContent', 'ToolResultResourceContent', 'ToolResultFileEditContent', @@ -1079,12 +1079,12 @@ const TOOL_CALL_CONTRIBUTOR_UNION: UnionConfig = { unknown: true, }; -const TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION: UnionConfig = { - name: 'ToolCallJudgeConfirmationReason', +const TOOL_CALL_RISK_ASSESSMENT_UNION: UnionConfig = { + name: 'ToolCallRiskAssessment', discriminantField: 'status', variants: [ - { caseName: 'Loading', structName: 'ToolCallJudgeConfirmationReasonLoadingState', discriminantValue: 'loading' }, - { caseName: 'Complete', structName: 'ToolCallJudgeConfirmationReasonCompleteState', discriminantValue: 'complete' }, + { caseName: 'Loading', structName: 'ToolCallRiskAssessmentLoadingState', discriminantValue: 'loading' }, + { caseName: 'Complete', structName: 'ToolCallRiskAssessmentCompleteState', discriminantValue: 'complete' }, ], unknown: true, }; @@ -1167,7 +1167,7 @@ function generateStateFile(project: Project): string { lines.push(''); lines.push(generateDiscriminatedUnion(TOOL_CALL_CONTRIBUTOR_UNION)); lines.push(''); - lines.push(generateDiscriminatedUnion(TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION)); + lines.push(generateDiscriminatedUnion(TOOL_CALL_RISK_ASSESSMENT_UNION)); lines.push(''); lines.push(generateDiscriminatedUnion(SESSION_INPUT_REQUEST_UNION)); lines.push(''); @@ -1934,7 +1934,7 @@ function checkExhaustiveness(project: Project): void { 'ChildCustomization', // CHILD_CUSTOMIZATION_UNION discriminated union 'McpServerState', // MCP_SERVER_STATUS_UNION discriminated union 'ToolCallContributor', // TOOL_CALL_CONTRIBUTOR_UNION discriminated union - 'ToolCallJudgeConfirmationReason', // TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION discriminated union + 'ToolCallRiskAssessment', // TOOL_CALL_RISK_ASSESSMENT_UNION discriminated union 'SessionInputRequest', // SESSION_INPUT_REQUEST_UNION discriminated union 'ToolCallConfirmationState', // TOOL_CALL_CONFIRMATION_STATE_UNION discriminated union 'ChildCustomizationType', // TS subset alias of CustomizationType; consumers reuse CustomizationType diff --git a/scripts/generate-rust.ts b/scripts/generate-rust.ts index 7071a0a3..06c2097e 100644 --- a/scripts/generate-rust.ts +++ b/scripts/generate-rust.ts @@ -654,8 +654,8 @@ const STATE_ENUMS = [ 'ChatOriginKind', 'ChatInteractivity', 'ChatInputAnswerState', 'ChatInputAnswerValueKind', 'ChatInputQuestionKind', 'ChatInputResponseKind', 'SessionInputRequestKind', 'TurnState', 'MessageKind', 'MessageAttachmentKind', 'ResponsePartKind', 'ToolCallStatus', - 'ToolCallConfirmationReason', 'ToolCallJudgeConfirmationReasonKind', - 'ToolCallJudgeConfirmationReasonStatus', + 'ToolCallConfirmationReason', 'ToolCallRiskAssessmentKind', + 'ToolCallRiskAssessmentStatus', 'ToolCallCancellationReason', 'ConfirmationOptionKind', 'ToolCallContributorKind', 'ToolResultContentType', 'CustomizationType', 'CustomizationLoadStatus', 'TerminalClaimKind', @@ -744,8 +744,8 @@ const STATE_STRUCTS: { name: string; omitDiscriminants?: boolean; rustName?: str { name: 'SystemNotificationResponsePart', omitDiscriminants: true }, { name: 'InputRequestResponsePart', omitDiscriminants: true }, { name: 'ToolCallResult' }, - { name: 'ToolCallJudgeConfirmationReasonLoadingState', omitDiscriminants: true }, - { name: 'ToolCallJudgeConfirmationReasonCompleteState', omitDiscriminants: true }, + { name: 'ToolCallRiskAssessmentLoadingState', omitDiscriminants: true }, + { name: 'ToolCallRiskAssessmentCompleteState', omitDiscriminants: true }, { name: 'ConfirmationOption' }, { name: 'ToolCallStreamingState', omitDiscriminants: true }, { name: 'ToolCallPendingConfirmationState', omitDiscriminants: true }, @@ -1011,13 +1011,13 @@ const TOOL_CALL_CONTRIBUTOR_UNION: UnionConfig = { unknown: true, }; -const TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION: UnionConfig = { - name: 'ToolCallJudgeConfirmationReason', +const TOOL_CALL_RISK_ASSESSMENT_UNION: UnionConfig = { + name: 'ToolCallRiskAssessment', discriminantField: 'status', doc: 'Asynchronous model-judge confirmation rationale.', variants: [ - { variantName: 'Loading', innerType: 'ToolCallJudgeConfirmationReasonLoadingState', wireValue: 'loading' }, - { variantName: 'Complete', innerType: 'ToolCallJudgeConfirmationReasonCompleteState', wireValue: 'complete' }, + { variantName: 'Loading', innerType: 'ToolCallRiskAssessmentLoadingState', wireValue: 'loading' }, + { variantName: 'Complete', innerType: 'ToolCallRiskAssessmentCompleteState', wireValue: 'complete' }, ], unknown: true, }; @@ -1154,7 +1154,7 @@ function generateStateFile(project: Project): string { lines.push(''); lines.push(generateDiscriminatedUnion(TOOL_CALL_CONTRIBUTOR_UNION)); lines.push(''); - lines.push(generateDiscriminatedUnion(TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION)); + lines.push(generateDiscriminatedUnion(TOOL_CALL_RISK_ASSESSMENT_UNION)); lines.push(''); lines.push(generateDiscriminatedUnion(SESSION_INPUT_REQUEST_UNION)); lines.push(''); @@ -1291,7 +1291,7 @@ pub struct ${scope}ToolCallConfirmedAction { function generateActionsFile(project: Project): string { const lines: string[] = [GENERATED_HEADER]; lines.push('#[allow(unused_imports)]'); - lines.push('use crate::state::{AgentInfo, AgentSelection, Annotation, AnnotationEntry, ChatInputAnswer, ChatInputRequest, ChatInputResponseKind, ChatInteractivity, ChatOrigin, ConfirmationOption, Customization, ErrorInfo, McpServerState, ModelSelection, ResponsePart, SessionActiveClient, SessionInputRequest, TerminalClaim, TerminalInfo, TextRange, ToolCallContributor, ToolCallResult, ToolCallJudgeConfirmationReason, ToolCallConfirmationReason, ToolCallCancellationReason, ToolDefinition, ToolResultContent, UsageInfo, Message, PendingMessageKind, Turn, ChangesetStatus, ChangesetFile, ChangesetOperation, ChangesetOperationStatus, Changeset, ChatSummary};'); + lines.push('use crate::state::{AgentInfo, AgentSelection, Annotation, AnnotationEntry, ChatInputAnswer, ChatInputRequest, ChatInputResponseKind, ChatInteractivity, ChatOrigin, ConfirmationOption, Customization, ErrorInfo, McpServerState, ModelSelection, ResponsePart, SessionActiveClient, SessionInputRequest, TerminalClaim, TerminalInfo, TextRange, ToolCallContributor, ToolCallResult, ToolCallRiskAssessment, ToolCallConfirmationReason, ToolCallCancellationReason, ToolDefinition, ToolResultContent, UsageInfo, Message, PendingMessageKind, Turn, ChangesetStatus, ChangesetFile, ChangesetOperation, ChangesetOperationStatus, Changeset, ChatSummary};'); lines.push(''); // ActionType enum @@ -1856,7 +1856,7 @@ function checkExhaustiveness(project: Project): void { 'CustomizationLoadState', // CUSTOMIZATION_LOAD_STATE_UNION discriminated union 'McpServerState', // MCP_SERVER_STATUS_UNION discriminated union 'ToolCallContributor', // TOOL_CALL_CONTRIBUTOR_UNION discriminated union - 'ToolCallJudgeConfirmationReason', // TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION discriminated union + 'ToolCallRiskAssessment', // TOOL_CALL_RISK_ASSESSMENT_UNION discriminated union 'SessionInputRequest', // SESSION_INPUT_REQUEST_UNION discriminated union 'ToolCallConfirmationState', // TOOL_CALL_CONFIRMATION_STATE_UNION discriminated union 'ReconnectResult', diff --git a/scripts/generate-swift.ts b/scripts/generate-swift.ts index e2f7e9a5..ac706d28 100644 --- a/scripts/generate-swift.ts +++ b/scripts/generate-swift.ts @@ -541,8 +541,8 @@ const STATE_ENUMS = [ 'ChatOriginKind', 'ChatInteractivity', 'ChatInputAnswerState', 'ChatInputAnswerValueKind', 'ChatInputQuestionKind', 'ChatInputResponseKind', 'SessionInputRequestKind', 'TurnState', 'MessageKind', 'MessageAttachmentKind', 'ResponsePartKind', 'ToolCallStatus', - 'ToolCallConfirmationReason', 'ToolCallJudgeConfirmationReasonKind', - 'ToolCallJudgeConfirmationReasonStatus', + 'ToolCallConfirmationReason', 'ToolCallRiskAssessmentKind', + 'ToolCallRiskAssessmentStatus', 'ToolCallCancellationReason', 'ConfirmationOptionKind', 'ToolCallContributorKind', 'ToolResultContentType', 'CustomizationType', 'CustomizationLoadStatus', 'TerminalClaimKind', @@ -577,8 +577,8 @@ const STATE_STRUCTS = [ 'ToolCallResult', 'ToolCallStreamingState', 'ToolCallPendingConfirmationState', 'ToolCallRunningState', 'ToolCallPendingResultConfirmationState', 'ToolCallCompletedState', - 'ToolCallCancelledState', 'ToolCallJudgeConfirmationReasonLoadingState', - 'ToolCallJudgeConfirmationReasonCompleteState', 'ConfirmationOption', + 'ToolCallCancelledState', 'ToolCallRiskAssessmentLoadingState', + 'ToolCallRiskAssessmentCompleteState', 'ConfirmationOption', 'ToolDefinition', 'ToolAnnotations', 'ToolResultTextContent', 'ToolResultEmbeddedResourceContent', 'ToolResultResourceContent', 'ToolResultFileEditContent', @@ -789,13 +789,13 @@ const TOOL_CALL_CONTRIBUTOR_UNION: UnionConfig = { ], }; -const TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION: UnionConfig = { - name: 'ToolCallJudgeConfirmationReason', +const TOOL_CALL_RISK_ASSESSMENT_UNION: UnionConfig = { + name: 'ToolCallRiskAssessment', discriminantField: 'status', allowUnknown: true, variants: [ - { caseName: 'loading', structName: 'ToolCallJudgeConfirmationReasonLoadingState', discriminantValue: 'loading' }, - { caseName: 'complete', structName: 'ToolCallJudgeConfirmationReasonCompleteState', discriminantValue: 'complete' }, + { caseName: 'loading', structName: 'ToolCallRiskAssessmentLoadingState', discriminantValue: 'loading' }, + { caseName: 'complete', structName: 'ToolCallRiskAssessmentCompleteState', discriminantValue: 'complete' }, ], }; @@ -1075,7 +1075,7 @@ function generateStateFile(project: Project): string { lines.push(''); lines.push(generateDiscriminatedUnion(TOOL_CALL_CONTRIBUTOR_UNION)); lines.push(''); - lines.push(generateDiscriminatedUnion(TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION)); + lines.push(generateDiscriminatedUnion(TOOL_CALL_RISK_ASSESSMENT_UNION)); lines.push(''); lines.push(generateDiscriminatedUnion(SESSION_INPUT_REQUEST_UNION)); lines.push(''); @@ -1956,7 +1956,7 @@ function checkExhaustiveness(project: Project): void { 'CustomizationLoadState', // CUSTOMIZATION_LOAD_STATE_UNION discriminated union 'McpServerState', // MCP_SERVER_STATUS_UNION discriminated union 'ToolCallContributor', // TOOL_CALL_CONTRIBUTOR_UNION discriminated union - 'ToolCallJudgeConfirmationReason', // TOOL_CALL_JUDGE_CONFIRMATION_REASON_UNION discriminated union + 'ToolCallRiskAssessment', // TOOL_CALL_RISK_ASSESSMENT_UNION discriminated union 'SessionInputRequest', // SESSION_INPUT_REQUEST_UNION discriminated union 'ToolCallConfirmationState', // TOOL_CALL_CONFIRMATION_STATE_UNION discriminated union 'AuthRequiredErrorData', // emitted by generateErrorsFile() diff --git a/types/channels-chat/actions.ts b/types/channels-chat/actions.ts index 478d6f98..463f9614 100644 --- a/types/channels-chat/actions.ts +++ b/types/channels-chat/actions.ts @@ -16,7 +16,7 @@ import type { ChatInputResponseKind, ConfirmationOption, ToolCallContributor, - ToolCallJudgeConfirmationReason, + ToolCallRiskAssessment, Turn, } from './state.js'; import { @@ -204,8 +204,8 @@ export interface ChatToolCallReadyAction extends ToolCallActionBase { toolInput?: string; /** Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) */ confirmationTitle?: StringOrMarkdown; - /** Why the tool requires user confirmation. */ - confirmationReason?: ToolCallJudgeConfirmationReason; + /** Risk assessment that informed the confirmation requirement. */ + riskAssessment?: ToolCallRiskAssessment; /** File edits that this tool call will perform, for preview before confirmation */ edits?: { items: FileEdit[] }; /** Whether the agent host allows the client to edit the tool's input parameters before confirming */ diff --git a/types/channels-chat/reducer.ts b/types/channels-chat/reducer.ts index 26e4f22b..7f843240 100644 --- a/types/channels-chat/reducer.ts +++ b/types/channels-chat/reducer.ts @@ -407,7 +407,7 @@ export function chatReducer(state: ChatState, action: ChatAction, log?: (msg: st invocationMessage: action.invocationMessage, toolInput: action.toolInput ?? pending?.toolInput, confirmationTitle: action.confirmationTitle ?? pending?.confirmationTitle, - confirmationReason: action.confirmationReason ?? pending?.confirmationReason, + riskAssessment: action.riskAssessment ?? pending?.riskAssessment, edits: action.edits ?? pending?.edits, editable: action.editable ?? pending?.editable, ...(options ? { options } : {}), diff --git a/types/channels-chat/state.ts b/types/channels-chat/state.ts index 3a7658ac..ddc3f681 100644 --- a/types/channels-chat/state.ts +++ b/types/channels-chat/state.ts @@ -939,7 +939,7 @@ export const enum ToolCallConfirmationReason { * * @category Tool Call Types */ -export const enum ToolCallJudgeConfirmationReasonKind { +export const enum ToolCallRiskAssessmentKind { Judge = 'judge', } @@ -948,13 +948,13 @@ export const enum ToolCallJudgeConfirmationReasonKind { * * @category Tool Call Types */ -export const enum ToolCallJudgeConfirmationReasonStatus { +export const enum ToolCallRiskAssessmentStatus { Loading = 'loading', Complete = 'complete', } -interface ToolCallJudgeConfirmationReasonBase { - kind: ToolCallJudgeConfirmationReasonKind; +interface ToolCallRiskAssessmentBase { + kind: ToolCallRiskAssessmentKind; } /** @@ -962,8 +962,8 @@ interface ToolCallJudgeConfirmationReasonBase { * * @category Tool Call Types */ -export interface ToolCallJudgeConfirmationReasonLoadingState extends ToolCallJudgeConfirmationReasonBase { - status: ToolCallJudgeConfirmationReasonStatus.Loading; +export interface ToolCallRiskAssessmentLoadingState extends ToolCallRiskAssessmentBase { + status: ToolCallRiskAssessmentStatus.Loading; } /** @@ -971,8 +971,8 @@ export interface ToolCallJudgeConfirmationReasonLoadingState extends ToolCallJud * * @category Tool Call Types */ -export interface ToolCallJudgeConfirmationReasonCompleteState extends ToolCallJudgeConfirmationReasonBase { - status: ToolCallJudgeConfirmationReasonStatus.Complete; +export interface ToolCallRiskAssessmentCompleteState extends ToolCallRiskAssessmentBase { + status: ToolCallRiskAssessmentStatus.Complete; reason: StringOrMarkdown; /** * The judge's normalized safety score, where `0` is unsafe and `1` is safe. @@ -981,9 +981,9 @@ export interface ToolCallJudgeConfirmationReasonCompleteState extends ToolCallJu safety: number; } -export type ToolCallJudgeConfirmationReason = - | ToolCallJudgeConfirmationReasonLoadingState - | ToolCallJudgeConfirmationReasonCompleteState; +export type ToolCallRiskAssessment = + | ToolCallRiskAssessmentLoadingState + | ToolCallRiskAssessmentCompleteState; /** * Why a tool call was cancelled. @@ -1151,8 +1151,8 @@ export interface ToolCallPendingConfirmationState extends ToolCallBase, ToolCall status: ToolCallStatus.PendingConfirmation; /** Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) */ confirmationTitle?: StringOrMarkdown; - /** Why the tool requires user confirmation. */ - confirmationReason?: ToolCallJudgeConfirmationReason; + /** Risk assessment that informed the confirmation requirement. */ + riskAssessment?: ToolCallRiskAssessment; /** File edits that this tool call will perform, for preview before confirmation */ edits?: { items: FileEdit[] }; /** Whether the agent host allows the client to edit the tool's input parameters before confirming */ diff --git a/types/index.ts b/types/index.ts index 39108c31..413b2eba 100644 --- a/types/index.ts +++ b/types/index.ts @@ -54,9 +54,9 @@ export type { ToolCallCancelledState, ToolCallState, ToolCallConfirmationState, - ToolCallJudgeConfirmationReasonLoadingState, - ToolCallJudgeConfirmationReasonCompleteState, - ToolCallJudgeConfirmationReason, + ToolCallRiskAssessmentLoadingState, + ToolCallRiskAssessmentCompleteState, + ToolCallRiskAssessment, ConfirmationOption, ToolDefinition, ToolAnnotations, @@ -128,8 +128,8 @@ export { ResponsePartKind, ToolCallStatus, ToolCallConfirmationReason, - ToolCallJudgeConfirmationReasonKind, - ToolCallJudgeConfirmationReasonStatus, + ToolCallRiskAssessmentKind, + ToolCallRiskAssessmentStatus, ToolCallCancellationReason, ConfirmationOptionKind, ToolResultContentType, diff --git a/types/test-cases/reducers/026-toolcallready-transitions-running-tool-back-to-pending-confirmation.json b/types/test-cases/reducers/026-toolcallready-transitions-running-tool-back-to-pending-confirmation.json index b97e0353..e4f6401e 100644 --- a/types/test-cases/reducers/026-toolcallready-transitions-running-tool-back-to-pending-confirmation.json +++ b/types/test-cases/reducers/026-toolcallready-transitions-running-tool-back-to-pending-confirmation.json @@ -74,7 +74,7 @@ "invocationMessage": "Run: rm -rf /tmp/test", "toolInput": null, "confirmationTitle": null, - "confirmationReason": null, + "riskAssessment": null, "edits": null, "editable": null } diff --git a/types/test-cases/reducers/029-toolcallready-updates-pending-confirmation-tool-calls.json b/types/test-cases/reducers/029-toolcallready-updates-pending-confirmation-tool-calls.json index bc4f2cc6..c63b3432 100644 --- a/types/test-cases/reducers/029-toolcallready-updates-pending-confirmation-tool-calls.json +++ b/types/test-cases/reducers/029-toolcallready-updates-pending-confirmation-tool-calls.json @@ -69,7 +69,7 @@ "invocationMessage": "Run again", "toolInput": null, "confirmationTitle": null, - "confirmationReason": null, + "riskAssessment": null, "edits": null, "editable": null } diff --git a/types/test-cases/reducers/111-toolcall-pending-confirmation-sets-input-needed-status.json b/types/test-cases/reducers/111-toolcall-pending-confirmation-sets-input-needed-status.json index c63b6455..f2d01c3f 100644 --- a/types/test-cases/reducers/111-toolcall-pending-confirmation-sets-input-needed-status.json +++ b/types/test-cases/reducers/111-toolcall-pending-confirmation-sets-input-needed-status.json @@ -61,7 +61,7 @@ "invocationMessage": "Run: rm -rf /tmp/test", "toolInput": "rm -rf /tmp/test", "confirmationTitle": null, - "confirmationReason": null, + "riskAssessment": null, "edits": null, "editable": null } diff --git a/types/test-cases/reducers/127-toolcallready-with-confirmation-options.json b/types/test-cases/reducers/127-toolcallready-with-confirmation-options.json index fe94c1cd..68f2cbf0 100644 --- a/types/test-cases/reducers/127-toolcallready-with-confirmation-options.json +++ b/types/test-cases/reducers/127-toolcallready-with-confirmation-options.json @@ -33,7 +33,7 @@ "turnId": "turn-1", "toolCallId": "tc-1", "invocationMessage": "Run: echo hello", - "confirmationReason": { + "riskAssessment": { "kind": "judge", "status": "complete", "reason": "The command can modify the workspace.", @@ -92,7 +92,7 @@ "invocationMessage": "Run: echo hello", "toolInput": null, "confirmationTitle": null, - "confirmationReason": { + "riskAssessment": { "kind": "judge", "status": "complete", "reason": "The command can modify the workspace.", diff --git a/types/test-cases/reducers/220-toolcall-actions-update-meta.json b/types/test-cases/reducers/220-toolcall-actions-update-meta.json index c2243229..e46ac035 100644 --- a/types/test-cases/reducers/220-toolcall-actions-update-meta.json +++ b/types/test-cases/reducers/220-toolcall-actions-update-meta.json @@ -273,7 +273,7 @@ "invocationMessage": "Needs approval", "toolInput": null, "confirmationTitle": null, - "confirmationReason": null, + "riskAssessment": null, "edits": null, "editable": null } diff --git a/types/test-cases/reducers/241-toolcallready-updates-async-judge-reason.json b/types/test-cases/reducers/241-toolcallready-stores-loading-risk-assessment.json similarity index 92% rename from types/test-cases/reducers/241-toolcallready-updates-async-judge-reason.json rename to types/test-cases/reducers/241-toolcallready-stores-loading-risk-assessment.json index 85277255..7af3f862 100644 --- a/types/test-cases/reducers/241-toolcallready-updates-async-judge-reason.json +++ b/types/test-cases/reducers/241-toolcallready-stores-loading-risk-assessment.json @@ -1,5 +1,5 @@ { - "description": "toolCallReady stores an asynchronous judge loading state", + "description": "toolCallReady stores a loading risk assessment", "reducer": "chat", "initial": { "turns": [], @@ -33,7 +33,7 @@ "turnId": "turn-1", "toolCallId": "tc-1", "invocationMessage": "Checking command safety", - "confirmationReason": { + "riskAssessment": { "kind": "judge", "status": "loading" } @@ -64,7 +64,7 @@ "invocationMessage": "Checking command safety", "toolInput": null, "confirmationTitle": null, - "confirmationReason": { + "riskAssessment": { "kind": "judge", "status": "loading" }, diff --git a/types/test-cases/reducers/242-toolcallready-completes-async-judge-reason.json b/types/test-cases/reducers/242-toolcallready-completes-risk-assessment.json similarity index 93% rename from types/test-cases/reducers/242-toolcallready-completes-async-judge-reason.json rename to types/test-cases/reducers/242-toolcallready-completes-risk-assessment.json index 064f2907..56d548d5 100644 --- a/types/test-cases/reducers/242-toolcallready-completes-async-judge-reason.json +++ b/types/test-cases/reducers/242-toolcallready-completes-risk-assessment.json @@ -1,5 +1,5 @@ { - "description": "toolCallReady completes an asynchronous judge reason without clearing confirmation context", + "description": "toolCallReady completes a risk assessment without clearing confirmation context", "reducer": "chat", "initial": { "turns": [], @@ -26,7 +26,7 @@ "invocationMessage": "Checking command safety", "toolInput": "rm -rf /tmp/test", "confirmationTitle": "Run in terminal", - "confirmationReason": { + "riskAssessment": { "kind": "judge", "status": "loading" }, @@ -57,7 +57,7 @@ "turnId": "turn-1", "toolCallId": "tc-1", "invocationMessage": "Run: rm -rf /tmp/test", - "confirmationReason": { + "riskAssessment": { "kind": "judge", "status": "complete", "reason": "The command deletes files.", @@ -90,7 +90,7 @@ "invocationMessage": "Run: rm -rf /tmp/test", "toolInput": "rm -rf /tmp/test", "confirmationTitle": "Run in terminal", - "confirmationReason": { + "riskAssessment": { "kind": "judge", "status": "complete", "reason": "The command deletes files.", From 941d213ac8bc4083b09111469f90233e38463603 Mon Sep 17 00:00:00 2001 From: justschen Date: Tue, 14 Jul 2026 12:16:13 -0700 Subject: [PATCH 6/6] go: format risk assessment reducer Apply gofmt to the pending risk-assessment update logic. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- clients/go/ahp/reducers.go | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/clients/go/ahp/reducers.go b/clients/go/ahp/reducers.go index 5532ce4d..2e111c4c 100644 --- a/clients/go/ahp/reducers.go +++ b/clients/go/ahp/reducers.go @@ -1015,20 +1015,20 @@ func applyToolCallReady(state *ahptypes.ChatState, a *ahptypes.ChatToolCallReady }} } next := &ahptypes.ToolCallPendingConfirmationState{ - Status: ahptypes.ToolCallStatusPendingConfirmation, - ToolCallId: common.id, - ToolName: common.name, - DisplayName: common.displayName, - Intention: common.intention, - Contributor: common.contributor, - Meta: common.meta, - InvocationMessage: a.InvocationMessage, - ToolInput: a.ToolInput, - ConfirmationTitle: a.ConfirmationTitle, - RiskAssessment: a.RiskAssessment, - Edits: a.Edits, - Editable: a.Editable, - Options: a.Options, + Status: ahptypes.ToolCallStatusPendingConfirmation, + ToolCallId: common.id, + ToolName: common.name, + DisplayName: common.displayName, + Intention: common.intention, + Contributor: common.contributor, + Meta: common.meta, + InvocationMessage: a.InvocationMessage, + ToolInput: a.ToolInput, + ConfirmationTitle: a.ConfirmationTitle, + RiskAssessment: a.RiskAssessment, + Edits: a.Edits, + Editable: a.Editable, + Options: a.Options, } if pending != nil { if next.ToolInput == nil {