From 4ea9cc61436e5d54aebe9619d5a630c6559e91bc Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 30 Jul 2026 19:57:32 -0700 Subject: [PATCH 1/6] chat: lazy-load final tool input Replace streamed raw tool parameters with invocation-message updates and retain the final input as a resource-readable ContentRef. Keep edited input action-only and require the host to update the referenced resource before echoing confirmation. (Written by Copilot) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- clients/go/ahp/reducers.go | 81 +++++++-------- clients/go/ahptypes/actions.generated.go | 10 +- clients/go/ahptypes/state.generated.go | 58 ++++++++--- .../microsoft/agenthostprotocol/Reducers.kt | 55 +++++------ .../generated/Actions.generated.kt | 12 +-- .../generated/State.generated.kt | 60 +++++++---- .../FixtureDrivenReducerTest.kt | 1 + clients/rust/crates/ahp-types/src/actions.rs | 21 ++-- clients/rust/crates/ahp-types/src/state.rs | 59 ++++++++--- .../crates/ahp/src/multi_host_state_mirror.rs | 2 + clients/rust/crates/ahp/src/reducers.rs | 55 +++++------ .../swift/AHPApp/AHPApp/Views/ChatView.swift | 8 +- .../AHPApp/Views/ResponsePartView.swift | 34 +++---- .../Generated/Actions.generated.swift | 17 ++-- .../Generated/State.generated.swift | 73 +++++++++----- .../Sources/AgentHostProtocol/Reducers.swift | 23 ++--- .../ToolCallStateExtensions.swift | 8 ++ .../src/client/hosts/state-mirror.ts | 2 + clients/typescript/src/client/state-mirror.ts | 2 + clients/typescript/test/hosts.test.ts | 1 + .../20260730-tool-input-content-ref.json | 4 + docs/guide/actions.md | 2 +- docs/guide/customizations.md | 10 +- docs/guide/state-model.md | 11 +-- schema/actions.schema.json | 46 ++++----- schema/commands.schema.json | 46 ++++----- schema/errors.schema.json | 46 ++++----- schema/notifications.schema.json | 32 +++--- schema/state.schema.json | 32 +++--- scripts/generate-go.ts | 2 +- scripts/generate-kotlin.ts | 2 +- scripts/generate-markdown.ts | 2 + scripts/generate-rust.ts | 4 +- scripts/generate-swift.ts | 2 +- types/channels-chat/actions.ts | 19 ++-- types/channels-chat/reducer.ts | 11 ++- types/channels-chat/state.ts | 13 ++- ...-start-delta-ready-confirmed-complete.json | 9 +- ...ions-for-unknown-toolcallid-are-no-op.json | 2 +- ...olcall-contentchanged-updates-running.json | 8 +- ...lcall-contentchanged-noop-non-running.json | 8 +- ...call-contentchanged-replaces-existing.json | 8 +- ...0-toolcalldelta-wrong-turnid-is-no-op.json | 2 +- ...5-toolcalldelta-wrong-status-is-no-op.json | 10 +- ...olcallconfirmed-wrong-status-is-no-op.json | 8 +- ...oolcallcomplete-wrong-status-is-no-op.json | 8 +- ...resultconfirmed-wrong-status-is-no-op.json | 8 +- ...dturn-force-cancels-running-tool-call.json | 8 +- ...ta-targeting-toolcall-partid-is-no-op.json | 8 +- ...olcalldelta-without-invocationmessage.json | 7 +- ...confirmation-sets-input-needed-status.json | 8 +- ...th-editedtoolinput-overrides-original.json | 10 +- ...ies-mcp-contributor-through-lifecycle.json | 8 +- .../220-toolcall-actions-update-meta.json | 10 +- ...olcallready-completes-risk-assessment.json | 8 +- ...unning-authrequired-running-completed.json | 12 ++- ...hresolved-noop-when-not-auth-required.json | 8 +- ...-needed-status-and-preserves-metadata.json | 16 ++- ...serves-fields-and-clears-input-needed.json | 8 +- ...force-cancels-auth-required-tool-call.json | 8 +- ...neededset-appends-tool-authentication.json | 34 +++++-- ...edremoved-removes-tool-authentication.json | 4 +- ...plete-cancels-auth-required-tool-call.json | 12 ++- ...-successful-result-from-auth-required.json | 16 ++- ...rmation-when-cancelling-auth-required.json | 12 ++- ...ed-tool-input-survives-reconfirmation.json | 99 +++++++++++++++++++ 66 files changed, 755 insertions(+), 478 deletions(-) create mode 100644 docs/.changes/20260730-tool-input-content-ref.json create mode 100644 types/test-cases/reducers/260-edited-tool-input-survives-reconfirmation.json diff --git a/clients/go/ahp/reducers.go b/clients/go/ahp/reducers.go index 978608c97..ccd683e50 100644 --- a/clients/go/ahp/reducers.go +++ b/clients/go/ahp/reducers.go @@ -91,6 +91,7 @@ type toolCallCommon struct { name string displayName string intention *string + toolInput *ahptypes.ContentRef contributor *ahptypes.ToolCallContributor meta ahptypes.JSONObject } @@ -98,44 +99,43 @@ type toolCallCommon struct { func toolCallMeta(tc ahptypes.ToolCallState) toolCallCommon { switch v := tc.Value.(type) { case *ahptypes.ToolCallStreamingState: - return toolCallCommon{v.ToolCallId, v.ToolName, v.DisplayName, v.Intention, v.Contributor, v.Meta} + return toolCallCommon{v.ToolCallId, v.ToolName, v.DisplayName, v.Intention, nil, v.Contributor, v.Meta} case *ahptypes.ToolCallPendingConfirmationState: - return toolCallCommon{v.ToolCallId, v.ToolName, v.DisplayName, v.Intention, v.Contributor, v.Meta} + return toolCallCommon{v.ToolCallId, v.ToolName, v.DisplayName, v.Intention, v.ToolInput, v.Contributor, v.Meta} case *ahptypes.ToolCallRunningState: - return toolCallCommon{v.ToolCallId, v.ToolName, v.DisplayName, v.Intention, v.Contributor, v.Meta} + return toolCallCommon{v.ToolCallId, v.ToolName, v.DisplayName, v.Intention, v.ToolInput, v.Contributor, v.Meta} case *ahptypes.ToolCallAuthRequiredState: - return toolCallCommon{v.ToolCallId, v.ToolName, v.DisplayName, v.Intention, v.Contributor, v.Meta} + return toolCallCommon{v.ToolCallId, v.ToolName, v.DisplayName, v.Intention, v.ToolInput, v.Contributor, v.Meta} case *ahptypes.ToolCallPendingResultConfirmationState: - return toolCallCommon{v.ToolCallId, v.ToolName, v.DisplayName, v.Intention, v.Contributor, v.Meta} + return toolCallCommon{v.ToolCallId, v.ToolName, v.DisplayName, v.Intention, v.ToolInput, v.Contributor, v.Meta} case *ahptypes.ToolCallCompletedState: - return toolCallCommon{v.ToolCallId, v.ToolName, v.DisplayName, v.Intention, v.Contributor, v.Meta} + return toolCallCommon{v.ToolCallId, v.ToolName, v.DisplayName, v.Intention, v.ToolInput, v.Contributor, v.Meta} case *ahptypes.ToolCallCancelledState: - return toolCallCommon{v.ToolCallId, v.ToolName, v.DisplayName, v.Intention, v.Contributor, v.Meta} + return toolCallCommon{v.ToolCallId, v.ToolName, v.DisplayName, v.Intention, v.ToolInput, v.Contributor, v.Meta} } return toolCallCommon{} } -// toolCallInvocationAndInput pulls the optional invocationMessage and -// toolInput fields out of whichever non-terminal variant tc points to. -// Returns (StringOrMarkdown{}, nil) for variants that don't carry them. -func toolCallInvocationAndInput(tc ahptypes.ToolCallState) (ahptypes.StringOrMarkdown, *string) { +// toolCallInvocationMessage pulls the invocation message from a non-terminal +// tool-call variant. +func toolCallInvocationMessage(tc ahptypes.ToolCallState) ahptypes.StringOrMarkdown { switch v := tc.Value.(type) { case *ahptypes.ToolCallStreamingState: var im ahptypes.StringOrMarkdown if v.InvocationMessage != nil { im = *v.InvocationMessage } - return im, nil + return im case *ahptypes.ToolCallPendingConfirmationState: - return v.InvocationMessage, v.ToolInput + return v.InvocationMessage case *ahptypes.ToolCallRunningState: - return v.InvocationMessage, v.ToolInput + return v.InvocationMessage case *ahptypes.ToolCallAuthRequiredState: - return v.InvocationMessage, v.ToolInput + return v.InvocationMessage case *ahptypes.ToolCallPendingResultConfirmationState: - return v.InvocationMessage, v.ToolInput + return v.InvocationMessage } - return ahptypes.StringOrMarkdown{}, nil + return ahptypes.StringOrMarkdown{} } func toolCallID(tc ahptypes.ToolCallState) string { @@ -221,17 +221,17 @@ func endTurn(state *ahptypes.ChatState, turnID string, duration int64, turnState continue } common := toolCallMeta(tc.ToolCall) - invocation, toolInput := toolCallInvocationAndInput(tc.ToolCall) + invocation := toolCallInvocationMessage(tc.ToolCall) cancelled := &ahptypes.ToolCallCancelledState{ Status: ahptypes.ToolCallStatusCancelled, ToolCallId: common.id, ToolName: common.name, DisplayName: common.displayName, Intention: common.intention, + ToolInput: common.toolInput, Contributor: common.contributor, Meta: common.meta, InvocationMessage: invocation, - ToolInput: toolInput, Reason: ahptypes.ToolCallCancellationReasonSkipped, } parts = append(parts, ahptypes.ResponsePart{Value: &ahptypes.ToolCallResponsePart{ @@ -1026,19 +1026,10 @@ func applyToolCallDelta(state *ahptypes.ChatState, a *ahptypes.ChatToolCallDelta if !ok { return tc } - current := "" - if s.PartialInput != nil { - current = *s.PartialInput - } - joined := current + a.Content - s.PartialInput = &joined if a.Meta != nil { s.Meta = a.Meta } - if a.InvocationMessage != nil { - im := *a.InvocationMessage - s.InvocationMessage = &im - } + s.InvocationMessage = &a.InvocationMessage return tc }) } @@ -1067,6 +1058,9 @@ func applyToolCallReady(state *ahptypes.ChatState, a *ahptypes.ChatToolCallReady if a.Intention != nil { common.intention = a.Intention } + if a.ToolInput != nil { + common.toolInput = a.ToolInput + } common.contributor = refineToolCallContributor(common.contributor, a.Contributor) if a.Meta != nil { common.meta = a.Meta @@ -1086,10 +1080,10 @@ func applyToolCallReady(state *ahptypes.ChatState, a *ahptypes.ChatToolCallReady ToolName: common.name, DisplayName: common.displayName, Intention: common.intention, + ToolInput: common.toolInput, Contributor: common.contributor, Meta: common.meta, InvocationMessage: a.InvocationMessage, - ToolInput: a.ToolInput, Confirmed: *a.Confirmed, }} } @@ -1099,10 +1093,10 @@ func applyToolCallReady(state *ahptypes.ChatState, a *ahptypes.ChatToolCallReady ToolName: common.name, DisplayName: common.displayName, Intention: common.intention, + ToolInput: common.toolInput, Contributor: common.contributor, Meta: common.meta, InvocationMessage: a.InvocationMessage, - ToolInput: a.ToolInput, ConfirmationTitle: a.ConfirmationTitle, RiskAssessment: a.RiskAssessment, Edits: a.Edits, @@ -1110,9 +1104,6 @@ func applyToolCallReady(state *ahptypes.ChatState, a *ahptypes.ChatToolCallReady Options: a.Options, } if pending != nil { - if next.ToolInput == nil { - next.ToolInput = pending.ToolInput - } if next.ConfirmationTitle == nil { next.ConfirmationTitle = pending.ConfirmationTitle } @@ -1156,10 +1147,6 @@ func applyToolCallConfirmed(state *ahptypes.ChatState, a *ahptypes.ChatToolCallC } selected := resolveSelectedOption(s.Options, a.SelectedOptionId) if a.Approved { - toolInput := s.ToolInput - if a.EditedToolInput != nil { - toolInput = a.EditedToolInput - } meta := s.Meta if a.Meta != nil { meta = a.Meta @@ -1174,10 +1161,10 @@ func applyToolCallConfirmed(state *ahptypes.ChatState, a *ahptypes.ChatToolCallC ToolName: s.ToolName, DisplayName: s.DisplayName, Intention: s.Intention, + ToolInput: s.ToolInput, Contributor: s.Contributor, Meta: meta, InvocationMessage: s.InvocationMessage, - ToolInput: toolInput, Confirmed: confirmed, SelectedOption: selected, }} @@ -1196,10 +1183,10 @@ func applyToolCallConfirmed(state *ahptypes.ChatState, a *ahptypes.ChatToolCallC ToolName: s.ToolName, DisplayName: s.DisplayName, Intention: s.Intention, + ToolInput: s.ToolInput, Contributor: s.Contributor, Meta: meta, InvocationMessage: s.InvocationMessage, - ToolInput: s.ToolInput, Reason: reason, ReasonMessage: a.ReasonMessage, UserSuggestion: a.UserSuggestion, @@ -1216,7 +1203,7 @@ func applyToolCallComplete(state *ahptypes.ChatState, a *ahptypes.ChatToolCallCo } var ( invocation ahptypes.StringOrMarkdown - toolInput *string + toolInput *ahptypes.ContentRef confirmed = ahptypes.ToolCallConfirmationReasonNotNeeded selectedOption *ahptypes.ConfirmationOption preAuthContent []ahptypes.ToolResultContent @@ -1266,10 +1253,10 @@ func applyToolCallComplete(state *ahptypes.ChatState, a *ahptypes.ChatToolCallCo ToolName: common.name, DisplayName: common.displayName, Intention: common.intention, + ToolInput: toolInput, Contributor: common.contributor, Meta: common.meta, InvocationMessage: invocation, - ToolInput: toolInput, Success: a.Result.Success, PastTenseMessage: a.Result.PastTenseMessage, Content: append([]ahptypes.ToolResultContent(nil), content...), @@ -1285,10 +1272,10 @@ func applyToolCallComplete(state *ahptypes.ChatState, a *ahptypes.ChatToolCallCo ToolName: common.name, DisplayName: common.displayName, Intention: common.intention, + ToolInput: toolInput, Contributor: common.contributor, Meta: common.meta, InvocationMessage: invocation, - ToolInput: toolInput, Success: a.Result.Success, PastTenseMessage: a.Result.PastTenseMessage, Content: append([]ahptypes.ToolResultContent(nil), content...), @@ -1317,10 +1304,10 @@ func applyToolCallResultConfirmed(state *ahptypes.ChatState, a *ahptypes.ChatToo ToolName: s.ToolName, DisplayName: s.DisplayName, Intention: s.Intention, + ToolInput: s.ToolInput, Contributor: s.Contributor, Meta: meta, InvocationMessage: s.InvocationMessage, - ToolInput: s.ToolInput, Success: s.Success, PastTenseMessage: s.PastTenseMessage, Content: s.Content, @@ -1340,10 +1327,10 @@ func applyToolCallResultConfirmed(state *ahptypes.ChatState, a *ahptypes.ChatToo ToolName: s.ToolName, DisplayName: s.DisplayName, Intention: s.Intention, + ToolInput: s.ToolInput, Contributor: s.Contributor, Meta: meta, InvocationMessage: s.InvocationMessage, - ToolInput: s.ToolInput, Reason: ahptypes.ToolCallCancellationReasonResultDenied, SelectedOption: s.SelectedOption, }} @@ -1372,10 +1359,10 @@ func applyToolCallAuthRequired(state *ahptypes.ChatState, a *ahptypes.ChatToolCa ToolName: s.ToolName, DisplayName: s.DisplayName, Intention: s.Intention, + ToolInput: s.ToolInput, Contributor: s.Contributor, Meta: meta, InvocationMessage: s.InvocationMessage, - ToolInput: s.ToolInput, Confirmed: s.Confirmed, SelectedOption: s.SelectedOption, Auth: a.Auth, @@ -1400,10 +1387,10 @@ func applyToolCallAuthResolved(state *ahptypes.ChatState, a *ahptypes.ChatToolCa ToolName: s.ToolName, DisplayName: s.DisplayName, Intention: s.Intention, + ToolInput: s.ToolInput, Contributor: s.Contributor, Meta: meta, InvocationMessage: s.InvocationMessage, - ToolInput: s.ToolInput, Confirmed: s.Confirmed, SelectedOption: s.SelectedOption, Content: append([]ahptypes.ToolResultContent(nil), s.Content...), diff --git a/clients/go/ahptypes/actions.generated.go b/clients/go/ahptypes/actions.generated.go index 4071bd50a..2afdba076 100644 --- a/clients/go/ahptypes/actions.generated.go +++ b/clients/go/ahptypes/actions.generated.go @@ -318,10 +318,8 @@ type ChatToolCallDeltaAction struct { // contain escape sequences). Meta map[string]json.RawMessage `json:"_meta,omitempty"` Type ActionType `json:"type"` - // Partial parameter content to append - Content string `json:"content"` - // Updated progress message - InvocationMessage *StringOrMarkdown `json:"invocationMessage,omitempty"` + // Updated display-ready progress message + InvocationMessage StringOrMarkdown `json:"invocationMessage"` } // Tool call parameters are complete, or a running tool requires re-confirmation. @@ -358,8 +356,8 @@ type ChatToolCallReadyAction struct { Intention *string `json:"intention,omitempty"` // Message describing what the tool will do or what confirmation is needed InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Raw tool input - ToolInput *string `json:"toolInput,omitempty"` + // Reference to the final raw tool input, readable with `resourceRead` + ToolInput *ContentRef `json:"toolInput,omitempty"` // Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) ConfirmationTitle *StringOrMarkdown `json:"confirmationTitle,omitempty"` // Risk assessment that informed the confirmation requirement. diff --git a/clients/go/ahptypes/state.generated.go b/clients/go/ahptypes/state.generated.go index e0618669b..5a12260fe 100644 --- a/clients/go/ahptypes/state.generated.go +++ b/clients/go/ahptypes/state.generated.go @@ -1920,8 +1920,6 @@ type ToolCallStreamingState struct { // with the {@link contributor} to serve MCP Apps. Meta map[string]json.RawMessage `json:"_meta,omitempty"` Status ToolCallStatus `json:"status"` - // Partial parameters accumulated so far - PartialInput *string `json:"partialInput,omitempty"` // Progress message shown while parameters are streaming InvocationMessage *StringOrMarkdown `json:"invocationMessage,omitempty"` } @@ -1947,8 +1945,13 @@ type ToolCallPendingConfirmationState struct { Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Message describing what the tool will do InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Raw tool input - ToolInput *string `json:"toolInput,omitempty"` + // Reference to the final raw tool input, readable with `resourceRead`. + // + // The referenced resource is mutable until the tool call leaves + // `pending-confirmation`. When the client confirms with `editedToolInput`, + // the host MUST replace the resource contents before echoing the accepted + // confirmation action. Clients MUST NOT cache tool input across confirmation. + ToolInput *ContentRef `json:"toolInput,omitempty"` Status ToolCallStatus `json:"status"` // Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) ConfirmationTitle *StringOrMarkdown `json:"confirmationTitle,omitempty"` @@ -1985,8 +1988,13 @@ type ToolCallRunningState struct { Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Message describing what the tool will do InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Raw tool input - ToolInput *string `json:"toolInput,omitempty"` + // Reference to the final raw tool input, readable with `resourceRead`. + // + // The referenced resource is mutable until the tool call leaves + // `pending-confirmation`. When the client confirms with `editedToolInput`, + // the host MUST replace the resource contents before echoing the accepted + // confirmation action. Clients MUST NOT cache tool input across confirmation. + ToolInput *ContentRef `json:"toolInput,omitempty"` // How the tool was confirmed for execution Confirmed ToolCallConfirmationReason `json:"confirmed"` // The confirmation option the user selected, if confirmation options were provided @@ -2045,8 +2053,13 @@ type ToolCallAuthRequiredState struct { Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Message describing what the tool will do InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Raw tool input - ToolInput *string `json:"toolInput,omitempty"` + // Reference to the final raw tool input, readable with `resourceRead`. + // + // The referenced resource is mutable until the tool call leaves + // `pending-confirmation`. When the client confirms with `editedToolInput`, + // the host MUST replace the resource contents before echoing the accepted + // confirmation action. Clients MUST NOT cache tool input across confirmation. + ToolInput *ContentRef `json:"toolInput,omitempty"` // How the tool was confirmed for execution Confirmed ToolCallConfirmationReason `json:"confirmed"` // The confirmation option the user selected, if confirmation options were provided @@ -2078,8 +2091,13 @@ type ToolCallPendingResultConfirmationState struct { Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Message describing what the tool will do InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Raw tool input - ToolInput *string `json:"toolInput,omitempty"` + // Reference to the final raw tool input, readable with `resourceRead`. + // + // The referenced resource is mutable until the tool call leaves + // `pending-confirmation`. When the client confirms with `editedToolInput`, + // the host MUST replace the resource contents before echoing the accepted + // confirmation action. Clients MUST NOT cache tool input across confirmation. + ToolInput *ContentRef `json:"toolInput,omitempty"` // Whether the tool succeeded Success bool `json:"success"` // Past-tense description of what the tool did @@ -2121,8 +2139,13 @@ type ToolCallCompletedState struct { Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Message describing what the tool will do InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Raw tool input - ToolInput *string `json:"toolInput,omitempty"` + // Reference to the final raw tool input, readable with `resourceRead`. + // + // The referenced resource is mutable until the tool call leaves + // `pending-confirmation`. When the client confirms with `editedToolInput`, + // the host MUST replace the resource contents before echoing the accepted + // confirmation action. Clients MUST NOT cache tool input across confirmation. + ToolInput *ContentRef `json:"toolInput,omitempty"` // Whether the tool succeeded Success bool `json:"success"` // Past-tense description of what the tool did @@ -2164,8 +2187,13 @@ type ToolCallCancelledState struct { Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Message describing what the tool will do InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Raw tool input - ToolInput *string `json:"toolInput,omitempty"` + // Reference to the final raw tool input, readable with `resourceRead`. + // + // The referenced resource is mutable until the tool call leaves + // `pending-confirmation`. When the client confirms with `editedToolInput`, + // the host MUST replace the resource contents before echoing the accepted + // confirmation action. Clients MUST NOT cache tool input across confirmation. + ToolInput *ContentRef `json:"toolInput,omitempty"` Status ToolCallStatus `json:"status"` // Why the tool was cancelled Reason ToolCallCancellationReason `json:"reason"` @@ -4888,7 +4916,7 @@ func (o ChatOrigin) MarshalJSON() ([]byte, error) { } // SnapshotState is the state payload of a snapshot — root, session, -// chat, terminal, changeset, resource-watch, or annotations state. The active +// chat, terminal, changeset, resource-watch, annotations, or content state. The active // variant is chosen by which pointer field is non-nil; UnmarshalJSON probes // for required fields in the canonical order // (session → chat → terminal → changeset → resourceWatch → annotations → root). 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 b62d7a617..09844f447 100644 --- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt +++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt @@ -70,6 +70,7 @@ public object ResourceWatchReducer : Reducer { resourceWatchReducer(state, action) } + // ─── Timestamp Provider ───────────────────────────────────────────────────── /** @@ -165,6 +166,7 @@ private data class ToolCallBase( val toolName: String, val displayName: String, val intention: String?, + val toolInput: ContentRef?, val contributor: ToolCallContributor?, val meta: Map?, ) { @@ -188,31 +190,31 @@ private fun refineToolCallContributor( private fun toolCallBase(tc: ToolCallState): ToolCallBase = when (tc) { is ToolCallStateStreaming -> tc.value.let { - ToolCallBase(it.toolCallId, it.toolName, it.displayName, it.intention, it.contributor, it.meta) + ToolCallBase(it.toolCallId, it.toolName, it.displayName, it.intention, null, it.contributor, it.meta) } is ToolCallStatePendingConfirmation -> tc.value.let { - ToolCallBase(it.toolCallId, it.toolName, it.displayName, it.intention, it.contributor, it.meta) + ToolCallBase(it.toolCallId, it.toolName, it.displayName, it.intention, it.toolInput, it.contributor, it.meta) } is ToolCallStateRunning -> tc.value.let { - ToolCallBase(it.toolCallId, it.toolName, it.displayName, it.intention, it.contributor, it.meta) + ToolCallBase(it.toolCallId, it.toolName, it.displayName, it.intention, it.toolInput, it.contributor, it.meta) } is ToolCallStateAuthRequired -> tc.value.let { - ToolCallBase(it.toolCallId, it.toolName, it.displayName, it.intention, it.contributor, it.meta) + ToolCallBase(it.toolCallId, it.toolName, it.displayName, it.intention, it.toolInput, it.contributor, it.meta) } is ToolCallStatePendingResultConfirmation -> tc.value.let { - ToolCallBase(it.toolCallId, it.toolName, it.displayName, it.intention, it.contributor, it.meta) + ToolCallBase(it.toolCallId, it.toolName, it.displayName, it.intention, it.toolInput, it.contributor, it.meta) } is ToolCallStateCompleted -> tc.value.let { - ToolCallBase(it.toolCallId, it.toolName, it.displayName, it.intention, it.contributor, it.meta) + ToolCallBase(it.toolCallId, it.toolName, it.displayName, it.intention, it.toolInput, it.contributor, it.meta) } is ToolCallStateCancelled -> tc.value.let { - ToolCallBase(it.toolCallId, it.toolName, it.displayName, it.intention, it.contributor, it.meta) + ToolCallBase(it.toolCallId, it.toolName, it.displayName, it.intention, it.toolInput, it.contributor, it.meta) } // Forward-compat: unknown lifecycle variants have no extractable base; mirror // Rust's `ToolCallState::Unknown(_) => (String::new(), ...)`. Combined with // `toolCallIdOf` returning `""`, this guarantees an unknown tool call never // matches a real `toolCallId` in delta/lookup paths. - is ToolCallStateUnknown -> ToolCallBase("", "", "", null, null, null) + is ToolCallStateUnknown -> ToolCallBase("", "", "", null, null, null, null) } /** Resolves a selected confirmation option by ID from a pending-confirmation state. */ @@ -389,15 +391,6 @@ private fun endTurn( // invocation message — destructive, but matches Rust parity exactly. is ToolCallStateUnknown -> com.microsoft.agenthostprotocol.generated.StringOrMarkdown.Plain("") } - val toolInput: String? = when (tc) { - is ToolCallStateStreaming -> null - is ToolCallStatePendingConfirmation -> tc.value.toolInput - is ToolCallStateRunning -> tc.value.toolInput - is ToolCallStateAuthRequired -> tc.value.toolInput - is ToolCallStatePendingResultConfirmation -> tc.value.toolInput - is ToolCallStateCompleted, is ToolCallStateCancelled -> error("filtered above") - is ToolCallStateUnknown -> null - } ResponsePartToolCall( part.value.copy( toolCall = ToolCallStateCancelled( @@ -406,10 +399,10 @@ private fun endTurn( toolName = base.toolName, displayName = base.displayName, intention = base.intention, + toolInput = base.toolInput, contributor = base.contributor, meta = base.meta, invocationMessage = invocationMessage, - toolInput = toolInput, status = ToolCallStatus.CANCELLED, reason = ToolCallCancellationReason.SKIPPED, ), @@ -935,8 +928,7 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when ToolCallStateStreaming( tc.value.copy( meta = a.meta ?: tc.value.meta, - partialInput = (tc.value.partialInput ?: "") + a.content, - invocationMessage = a.invocationMessage ?: tc.value.invocationMessage, + invocationMessage = a.invocationMessage, ), ) } @@ -957,6 +949,7 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when val initialBase = toolCallBase(tc) val base = initialBase.copy( intention = a.intention ?: initialBase.intention, + toolInput = a.toolInput ?: initialBase.toolInput, contributor = refineToolCallContributor(initialBase.contributor, a.contributor), ).withMeta(a.meta) val pending = (tc as? ToolCallStatePendingConfirmation)?.value @@ -967,10 +960,10 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when toolName = base.toolName, displayName = base.displayName, intention = base.intention, + toolInput = base.toolInput, contributor = base.contributor, meta = base.meta, invocationMessage = a.invocationMessage, - toolInput = a.toolInput, status = ToolCallStatus.RUNNING, confirmed = a.confirmed, ), @@ -982,10 +975,10 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when toolName = base.toolName, displayName = base.displayName, intention = base.intention, + toolInput = base.toolInput, contributor = base.contributor, meta = base.meta, invocationMessage = a.invocationMessage, - toolInput = a.toolInput ?: pending?.toolInput, status = ToolCallStatus.PENDING_CONFIRMATION, confirmationTitle = a.confirmationTitle ?: pending?.confirmationTitle, riskAssessment = a.riskAssessment ?: pending?.riskAssessment, @@ -1014,10 +1007,10 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when toolName = base.toolName, displayName = base.displayName, intention = base.intention, + toolInput = tc.value.toolInput, contributor = base.contributor, meta = base.meta, invocationMessage = tc.value.invocationMessage, - toolInput = a.editedToolInput ?: tc.value.toolInput, status = ToolCallStatus.RUNNING, confirmed = a.confirmed ?: ToolCallConfirmationReason.USER_ACTION, @@ -1031,10 +1024,10 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when toolName = base.toolName, displayName = base.displayName, intention = base.intention, + toolInput = tc.value.toolInput, contributor = base.contributor, meta = base.meta, invocationMessage = tc.value.invocationMessage, - toolInput = tc.value.toolInput, status = ToolCallStatus.CANCELLED, reason = a.reason ?: ToolCallCancellationReason.DENIED, reasonMessage = a.reasonMessage, @@ -1102,10 +1095,10 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when toolName = base.toolName, displayName = base.displayName, intention = base.intention, + toolInput = toolInput, contributor = base.contributor, meta = base.meta, invocationMessage = invocationMessage, - toolInput = toolInput, success = result.success, pastTenseMessage = result.pastTenseMessage, content = content, @@ -1123,10 +1116,10 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when toolName = base.toolName, displayName = base.displayName, intention = base.intention, + toolInput = toolInput, contributor = base.contributor, meta = base.meta, invocationMessage = invocationMessage, - toolInput = toolInput, success = result.success, pastTenseMessage = result.pastTenseMessage, content = content, @@ -1155,10 +1148,10 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when toolName = base.toolName, displayName = base.displayName, intention = base.intention, + toolInput = tc.value.toolInput, contributor = base.contributor, meta = base.meta, invocationMessage = tc.value.invocationMessage, - toolInput = tc.value.toolInput, success = tc.value.success, pastTenseMessage = tc.value.pastTenseMessage, content = tc.value.content, @@ -1176,10 +1169,10 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when toolName = base.toolName, displayName = base.displayName, intention = base.intention, + toolInput = tc.value.toolInput, contributor = base.contributor, meta = base.meta, invocationMessage = tc.value.invocationMessage, - toolInput = tc.value.toolInput, status = ToolCallStatus.CANCELLED, reason = ToolCallCancellationReason.RESULT_DENIED, selectedOption = tc.value.selectedOption, @@ -1218,10 +1211,10 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when toolName = base.toolName, displayName = base.displayName, intention = base.intention, + toolInput = tc.value.toolInput, contributor = contributor, meta = base.meta, invocationMessage = tc.value.invocationMessage, - toolInput = tc.value.toolInput, confirmed = tc.value.confirmed, selectedOption = tc.value.selectedOption, status = ToolCallStatus.AUTH_REQUIRED, @@ -1249,10 +1242,10 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when toolName = base.toolName, displayName = base.displayName, intention = base.intention, + toolInput = tc.value.toolInput, contributor = base.contributor, meta = base.meta, invocationMessage = tc.value.invocationMessage, - toolInput = tc.value.toolInput, confirmed = tc.value.confirmed, selectedOption = tc.value.selectedOption, status = ToolCallStatus.RUNNING, @@ -1451,7 +1444,7 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when */ private data class CompleteCtx( val invocationMessage: com.microsoft.agenthostprotocol.generated.StringOrMarkdown, - val toolInput: String?, + val toolInput: ContentRef?, val confirmed: ToolCallConfirmationReason, val selectedOption: ConfirmationOption?, val preAuthContent: List?, 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 f696130b9..2aa91f257 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 @@ -441,13 +441,9 @@ data class ChatToolCallDeltaAction( val meta: Map? = null, val type: ActionType, /** - * Partial parameter content to append + * Updated display-ready progress message */ - val content: String, - /** - * Updated progress message - */ - val invocationMessage: StringOrMarkdown? = null + val invocationMessage: StringOrMarkdown ) @Serializable @@ -486,9 +482,9 @@ data class ChatToolCallReadyAction( */ val invocationMessage: StringOrMarkdown, /** - * Raw tool input + * Reference to the final raw tool input, readable with `resourceRead` */ - val toolInput: String? = null, + val toolInput: ContentRef? = null, /** * Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) */ 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 840fe3318..15f40a71f 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 @@ -2568,10 +2568,6 @@ data class ToolCallStreamingState( @SerialName("_meta") val meta: Map? = null, val status: ToolCallStatus, - /** - * Partial parameters accumulated so far - */ - val partialInput: String? = null, /** * Progress message shown while parameters are streaming */ @@ -2614,9 +2610,14 @@ data class ToolCallPendingConfirmationState( */ val invocationMessage: StringOrMarkdown, /** - * Raw tool input + * Reference to the final raw tool input, readable with `resourceRead`. + * + * The referenced resource is mutable until the tool call leaves + * `pending-confirmation`. When the client confirms with `editedToolInput`, + * the host MUST replace the resource contents before echoing the accepted + * confirmation action. Clients MUST NOT cache tool input across confirmation. */ - val toolInput: String? = null, + val toolInput: ContentRef? = null, val status: ToolCallStatus, /** * Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) @@ -2679,9 +2680,14 @@ data class ToolCallRunningState( */ val invocationMessage: StringOrMarkdown, /** - * Raw tool input + * Reference to the final raw tool input, readable with `resourceRead`. + * + * The referenced resource is mutable until the tool call leaves + * `pending-confirmation`. When the client confirms with `editedToolInput`, + * the host MUST replace the resource contents before echoing the accepted + * confirmation action. Clients MUST NOT cache tool input across confirmation. */ - val toolInput: String? = null, + val toolInput: ContentRef? = null, /** * How the tool was confirmed for execution */ @@ -2736,9 +2742,14 @@ data class ToolCallAuthRequiredState( */ val invocationMessage: StringOrMarkdown, /** - * Raw tool input + * Reference to the final raw tool input, readable with `resourceRead`. + * + * The referenced resource is mutable until the tool call leaves + * `pending-confirmation`. When the client confirms with `editedToolInput`, + * the host MUST replace the resource contents before echoing the accepted + * confirmation action. Clients MUST NOT cache tool input across confirmation. */ - val toolInput: String? = null, + val toolInput: ContentRef? = null, /** * How the tool was confirmed for execution */ @@ -2794,9 +2805,14 @@ data class ToolCallPendingResultConfirmationState( */ val invocationMessage: StringOrMarkdown, /** - * Raw tool input + * Reference to the final raw tool input, readable with `resourceRead`. + * + * The referenced resource is mutable until the tool call leaves + * `pending-confirmation`. When the client confirms with `editedToolInput`, + * the host MUST replace the resource contents before echoing the accepted + * confirmation action. Clients MUST NOT cache tool input across confirmation. */ - val toolInput: String? = null, + val toolInput: ContentRef? = null, /** * Whether the tool succeeded */ @@ -2868,9 +2884,14 @@ data class ToolCallCompletedState( */ val invocationMessage: StringOrMarkdown, /** - * Raw tool input + * Reference to the final raw tool input, readable with `resourceRead`. + * + * The referenced resource is mutable until the tool call leaves + * `pending-confirmation`. When the client confirms with `editedToolInput`, + * the host MUST replace the resource contents before echoing the accepted + * confirmation action. Clients MUST NOT cache tool input across confirmation. */ - val toolInput: String? = null, + val toolInput: ContentRef? = null, /** * Whether the tool succeeded */ @@ -2942,9 +2963,14 @@ data class ToolCallCancelledState( */ val invocationMessage: StringOrMarkdown, /** - * Raw tool input + * Reference to the final raw tool input, readable with `resourceRead`. + * + * The referenced resource is mutable until the tool call leaves + * `pending-confirmation`. When the client confirms with `editedToolInput`, + * the host MUST replace the resource contents before echoing the accepted + * confirmation action. Clients MUST NOT cache tool input across confirmation. */ - val toolInput: String? = null, + val toolInput: ContentRef? = null, val status: ToolCallStatus, /** * Why the tool was cancelled @@ -5661,7 +5687,7 @@ internal object ToolResultContentSerializer : KSerializer { /** * The state payload of a snapshot — root, session, chat, terminal, changeset, - * resource-watch, or annotations state. + * resource-watch, annotations, or content state. */ @Serializable(with = SnapshotStateSerializer::class) sealed interface SnapshotState { diff --git a/clients/kotlin/src/test/kotlin/com/microsoft/agenthostprotocol/FixtureDrivenReducerTest.kt b/clients/kotlin/src/test/kotlin/com/microsoft/agenthostprotocol/FixtureDrivenReducerTest.kt index 37cf486bc..a908a84c4 100644 --- a/clients/kotlin/src/test/kotlin/com/microsoft/agenthostprotocol/FixtureDrivenReducerTest.kt +++ b/clients/kotlin/src/test/kotlin/com/microsoft/agenthostprotocol/FixtureDrivenReducerTest.kt @@ -216,6 +216,7 @@ class FixtureDrivenReducerTest { }, ) + else -> fail("${file.name}: unsupported reducer '$reducer'") } } diff --git a/clients/rust/crates/ahp-types/src/actions.rs b/clients/rust/crates/ahp-types/src/actions.rs index 8cd2c8f45..b8d3cc954 100644 --- a/clients/rust/crates/ahp-types/src/actions.rs +++ b/clients/rust/crates/ahp-types/src/actions.rs @@ -16,11 +16,11 @@ use crate::state::{ AgentInfo, AgentSelection, Annotation, AnnotationEntry, Changeset, ChangesetFile, ChangesetOperation, ChangesetOperationStatus, ChangesetStatus, ChatInputAnswer, ChatInputRequest, ChatInputResponseKind, ChatInteractivity, ChatOrigin, ChatSummary, - ConfirmationOption, Customization, ErrorInfo, McpAuthRequirement, McpServerState, Message, - ModelSelection, PendingMessageKind, ResponsePart, SessionActiveClient, SessionInputRequest, - SideChatSelection, TerminalClaim, TerminalInfo, TextRange, ToolCallCancellationReason, - ToolCallConfirmationReason, ToolCallContributor, ToolCallResult, ToolCallRiskAssessment, - ToolDefinition, ToolResultContent, Turn, UsageInfo, + ConfirmationOption, ContentRef, Customization, ErrorInfo, McpAuthRequirement, McpServerState, + Message, ModelSelection, PendingMessageKind, ResponsePart, SessionActiveClient, + SessionInputRequest, SideChatSelection, TerminalClaim, TerminalInfo, TextRange, + ToolCallCancellationReason, ToolCallConfirmationReason, ToolCallContributor, ToolCallResult, + ToolCallRiskAssessment, ToolDefinition, ToolResultContent, Turn, UsageInfo, }; // ─── ActionType ────────────────────────────────────────────────────── @@ -446,11 +446,8 @@ pub struct ChatToolCallDeltaAction { /// contain escape sequences). #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")] pub meta: Option, - /// Partial parameter content to append - pub content: String, - /// Updated progress message - #[serde(default, skip_serializing_if = "Option::is_none")] - pub invocation_message: Option, + /// Updated display-ready progress message + pub invocation_message: StringOrMarkdown, } /// Tool call parameters are complete, or a running tool requires re-confirmation. @@ -491,9 +488,9 @@ pub struct ChatToolCallReadyAction { pub intention: Option, /// Message describing what the tool will do or what confirmation is needed pub invocation_message: StringOrMarkdown, - /// Raw tool input + /// Reference to the final raw tool input, readable with `resourceRead` #[serde(default, skip_serializing_if = "Option::is_none")] - pub tool_input: Option, + pub tool_input: Option, /// 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, diff --git a/clients/rust/crates/ahp-types/src/state.rs b/clients/rust/crates/ahp-types/src/state.rs index bd9787516..27daf08d9 100644 --- a/clients/rust/crates/ahp-types/src/state.rs +++ b/clients/rust/crates/ahp-types/src/state.rs @@ -2361,9 +2361,6 @@ pub struct ToolCallStreamingState { /// with the {@link contributor} to serve MCP Apps. #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")] pub meta: Option, - /// Partial parameters accumulated so far - #[serde(default, skip_serializing_if = "Option::is_none")] - pub partial_input: Option, /// Progress message shown while parameters are streaming #[serde(default, skip_serializing_if = "Option::is_none")] pub invocation_message: Option, @@ -2395,9 +2392,14 @@ pub struct ToolCallPendingConfirmationState { pub meta: Option, /// Message describing what the tool will do pub invocation_message: StringOrMarkdown, - /// Raw tool input + /// Reference to the final raw tool input, readable with `resourceRead`. + /// + /// The referenced resource is mutable until the tool call leaves + /// `pending-confirmation`. When the client confirms with `editedToolInput`, + /// the host MUST replace the resource contents before echoing the accepted + /// confirmation action. Clients MUST NOT cache tool input across confirmation. #[serde(default, skip_serializing_if = "Option::is_none")] - pub tool_input: Option, + pub tool_input: Option, /// 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, @@ -2443,9 +2445,14 @@ pub struct ToolCallRunningState { pub meta: Option, /// Message describing what the tool will do pub invocation_message: StringOrMarkdown, - /// Raw tool input + /// Reference to the final raw tool input, readable with `resourceRead`. + /// + /// The referenced resource is mutable until the tool call leaves + /// `pending-confirmation`. When the client confirms with `editedToolInput`, + /// the host MUST replace the resource contents before echoing the accepted + /// confirmation action. Clients MUST NOT cache tool input across confirmation. #[serde(default, skip_serializing_if = "Option::is_none")] - pub tool_input: Option, + pub tool_input: Option, /// How the tool was confirmed for execution pub confirmed: ToolCallConfirmationReason, /// The confirmation option the user selected, if confirmation options were provided @@ -2510,9 +2517,14 @@ pub struct ToolCallAuthRequiredState { pub meta: Option, /// Message describing what the tool will do pub invocation_message: StringOrMarkdown, - /// Raw tool input + /// Reference to the final raw tool input, readable with `resourceRead`. + /// + /// The referenced resource is mutable until the tool call leaves + /// `pending-confirmation`. When the client confirms with `editedToolInput`, + /// the host MUST replace the resource contents before echoing the accepted + /// confirmation action. Clients MUST NOT cache tool input across confirmation. #[serde(default, skip_serializing_if = "Option::is_none")] - pub tool_input: Option, + pub tool_input: Option, /// How the tool was confirmed for execution pub confirmed: ToolCallConfirmationReason, /// The confirmation option the user selected, if confirmation options were provided @@ -2551,9 +2563,14 @@ pub struct ToolCallPendingResultConfirmationState { pub meta: Option, /// Message describing what the tool will do pub invocation_message: StringOrMarkdown, - /// Raw tool input + /// Reference to the final raw tool input, readable with `resourceRead`. + /// + /// The referenced resource is mutable until the tool call leaves + /// `pending-confirmation`. When the client confirms with `editedToolInput`, + /// the host MUST replace the resource contents before echoing the accepted + /// confirmation action. Clients MUST NOT cache tool input across confirmation. #[serde(default, skip_serializing_if = "Option::is_none")] - pub tool_input: Option, + pub tool_input: Option, /// Whether the tool succeeded pub success: bool, /// Past-tense description of what the tool did @@ -2603,9 +2620,14 @@ pub struct ToolCallCompletedState { pub meta: Option, /// Message describing what the tool will do pub invocation_message: StringOrMarkdown, - /// Raw tool input + /// Reference to the final raw tool input, readable with `resourceRead`. + /// + /// The referenced resource is mutable until the tool call leaves + /// `pending-confirmation`. When the client confirms with `editedToolInput`, + /// the host MUST replace the resource contents before echoing the accepted + /// confirmation action. Clients MUST NOT cache tool input across confirmation. #[serde(default, skip_serializing_if = "Option::is_none")] - pub tool_input: Option, + pub tool_input: Option, /// Whether the tool succeeded pub success: bool, /// Past-tense description of what the tool did @@ -2655,9 +2677,14 @@ pub struct ToolCallCancelledState { pub meta: Option, /// Message describing what the tool will do pub invocation_message: StringOrMarkdown, - /// Raw tool input + /// Reference to the final raw tool input, readable with `resourceRead`. + /// + /// The referenced resource is mutable until the tool call leaves + /// `pending-confirmation`. When the client confirms with `editedToolInput`, + /// the host MUST replace the resource contents before echoing the accepted + /// confirmation action. Clients MUST NOT cache tool input across confirmation. #[serde(default, skip_serializing_if = "Option::is_none")] - pub tool_input: Option, + pub tool_input: Option, /// Why the tool was cancelled pub reason: ToolCallCancellationReason, /// Optional message explaining the cancellation @@ -4576,7 +4603,7 @@ pub enum SessionInputRequest { } /// The state payload of a snapshot — root, session, chat, terminal, -/// changeset, resource-watch, or annotations state. +/// changeset, resource-watch, annotations, or content state. /// /// Deserialized by trying session first (has required `lifecycle`), then /// chat (has required `turns`), then terminal (has required `content`), diff --git a/clients/rust/crates/ahp/src/multi_host_state_mirror.rs b/clients/rust/crates/ahp/src/multi_host_state_mirror.rs index 7288894b9..b5452714d 100644 --- a/clients/rust/crates/ahp/src/multi_host_state_mirror.rs +++ b/clients/rust/crates/ahp/src/multi_host_state_mirror.rs @@ -135,6 +135,7 @@ impl MultiHostStateMirror { &self.resource_watches } + /// Convenience: apply a [`HostSubscriptionEvent`] produced by /// [`crate::hosts::MultiHostClient::events`]. Action envelopes are /// routed through the reducer; non-action events (session-summary @@ -176,6 +177,7 @@ impl MultiHostStateMirror { } if let Some(terminal) = self.terminals.get_mut(&key) { apply_action_to_terminal(terminal, &envelope.action); + return; } // Changesets are seeded by `apply_snapshot` only — there's no // changeset reducer in the SDK today (matching the Swift diff --git a/clients/rust/crates/ahp/src/reducers.rs b/clients/rust/crates/ahp/src/reducers.rs index 59c62518b..f78a7e72c 100644 --- a/clients/rust/crates/ahp/src/reducers.rs +++ b/clients/rust/crates/ahp/src/reducers.rs @@ -59,7 +59,7 @@ use ahp_types::actions::{ }; use ahp_types::state::{ ActiveTurn, AnnotationsState, ChangesetOperationStatus, ChangesetState, ChangesetStatus, - ChatInputRequest, ChatState, ChildCustomization, ConfirmationOption, Customization, ErrorInfo, + ChatInputRequest, ChatState, ChildCustomization, ConfirmationOption, ContentRef, Customization, ErrorInfo, InputRequestResponsePart, McpServerStartingState, McpServerState, McpServerStoppedState, PendingMessage, PendingMessageKind, ResourceWatchState, ResponsePart, RootState, SessionInputRequest, SessionLifecycle, SessionState, SessionStatus, TerminalCommandPart, @@ -133,6 +133,7 @@ struct ToolCallBase { tool_name: String, display_name: String, intention: Option, + tool_input: Option, contributor: Option, meta: Option>, } @@ -165,6 +166,7 @@ fn tool_call_meta(tc: &ToolCallState) -> ToolCallBase { tool_name: s.tool_name.clone(), display_name: s.display_name.clone(), intention: s.intention.clone(), + tool_input: None, contributor: s.contributor.clone(), meta: s.meta.clone(), }, @@ -173,6 +175,7 @@ fn tool_call_meta(tc: &ToolCallState) -> ToolCallBase { tool_name: s.tool_name.clone(), display_name: s.display_name.clone(), intention: s.intention.clone(), + tool_input: s.tool_input.clone(), contributor: s.contributor.clone(), meta: s.meta.clone(), }, @@ -181,6 +184,7 @@ fn tool_call_meta(tc: &ToolCallState) -> ToolCallBase { tool_name: s.tool_name.clone(), display_name: s.display_name.clone(), intention: s.intention.clone(), + tool_input: s.tool_input.clone(), contributor: s.contributor.clone(), meta: s.meta.clone(), }, @@ -189,6 +193,7 @@ fn tool_call_meta(tc: &ToolCallState) -> ToolCallBase { tool_name: s.tool_name.clone(), display_name: s.display_name.clone(), intention: s.intention.clone(), + tool_input: s.tool_input.clone(), contributor: s.contributor.clone(), meta: s.meta.clone(), }, @@ -197,6 +202,7 @@ fn tool_call_meta(tc: &ToolCallState) -> ToolCallBase { tool_name: s.tool_name.clone(), display_name: s.display_name.clone(), intention: s.intention.clone(), + tool_input: s.tool_input.clone(), contributor: s.contributor.clone(), meta: s.meta.clone(), }, @@ -205,6 +211,7 @@ fn tool_call_meta(tc: &ToolCallState) -> ToolCallBase { tool_name: s.tool_name.clone(), display_name: s.display_name.clone(), intention: s.intention.clone(), + tool_input: s.tool_input.clone(), contributor: s.contributor.clone(), meta: s.meta.clone(), }, @@ -213,6 +220,7 @@ fn tool_call_meta(tc: &ToolCallState) -> ToolCallBase { tool_name: s.tool_name.clone(), display_name: s.display_name.clone(), intention: s.intention.clone(), + tool_input: s.tool_input.clone(), contributor: s.contributor.clone(), meta: s.meta.clone(), }, @@ -221,6 +229,7 @@ fn tool_call_meta(tc: &ToolCallState) -> ToolCallBase { tool_name: String::new(), display_name: String::new(), intention: None, + tool_input: None, contributor: None, meta: None, }, @@ -354,23 +363,15 @@ fn end_turn( } _ => Default::default(), }; - let tool_input = match &tc { - ToolCallState::Streaming(_) => None, - ToolCallState::PendingConfirmation(s) => s.tool_input.clone(), - ToolCallState::Running(s) => s.tool_input.clone(), - ToolCallState::AuthRequired(s) => s.tool_input.clone(), - ToolCallState::PendingResultConfirmation(s) => s.tool_input.clone(), - _ => None, - }; let cancelled = ToolCallCancelledState { tool_call_id: base.tool_call_id, tool_name: base.tool_name, display_name: base.display_name, intention: base.intention, + tool_input: base.tool_input, contributor: base.contributor, meta: base.meta, invocation_message, - tool_input, reason: ToolCallCancellationReason::Skipped, reason_message: None, user_suggestion: None, @@ -546,10 +547,10 @@ where tool_name: String::new(), display_name: String::new(), intention: None, + tool_input: None, contributor: None, meta: None, invocation_message: Default::default(), - tool_input: None, reason: ToolCallCancellationReason::Skipped, reason_message: None, user_suggestion: None, @@ -1021,7 +1022,6 @@ pub fn apply_action_to_chat(state: &mut ChatState, action: &StateAction) -> Redu intention: a.intention.clone(), contributor: a.contributor.clone(), meta: a.meta.clone(), - partial_input: None, invocation_message: None, }), }))); @@ -1239,14 +1239,10 @@ fn apply_turn_started(state: &mut ChatState, a: &ChatTurnStartedAction) -> Reduc fn apply_tool_call_delta(state: &mut ChatState, a: &ChatToolCallDeltaAction) -> ReduceOutcome { update_tool_call(state, &a.turn_id, &a.tool_call_id, |tc| match tc { ToolCallState::Streaming(mut s) => { - let current = s.partial_input.unwrap_or_default(); - s.partial_input = Some(current + &a.content); if let Some(meta) = &a.meta { s.meta = Some(meta.clone()); } - if let Some(im) = &a.invocation_message { - s.invocation_message = Some(im.clone()); - } + s.invocation_message = Some(a.invocation_message.clone()); ToolCallState::Streaming(s) } other => other, @@ -1257,6 +1253,7 @@ fn apply_tool_call_ready(state: &mut ChatState, a: &ChatToolCallReadyAction) -> update_tool_call(state, &a.turn_id, &a.tool_call_id, |tc| { let mut base = tool_call_meta(&tc); base.intention = a.intention.clone().or(base.intention); + base.tool_input = a.tool_input.clone().or(base.tool_input); base.contributor = refine_tool_call_contributor(base.contributor, a.contributor.clone()); let meta = a.meta.clone().or(base.meta); let pending = match &tc { @@ -1273,10 +1270,10 @@ fn apply_tool_call_ready(state: &mut ChatState, a: &ChatToolCallReadyAction) -> tool_name: base.tool_name, display_name: base.display_name, intention: base.intention, + tool_input: base.tool_input, contributor: base.contributor, meta, invocation_message: a.invocation_message.clone(), - tool_input: a.tool_input.clone(), confirmed, selected_option: None, content: None, @@ -1287,13 +1284,10 @@ fn apply_tool_call_ready(state: &mut ChatState, a: &ChatToolCallReadyAction) -> tool_name: base.tool_name, display_name: base.display_name, intention: base.intention, + tool_input: base.tool_input, 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()) }), @@ -1353,10 +1347,10 @@ fn apply_tool_call_confirmed( tool_name, display_name, intention, + tool_input, contributor, meta, invocation_message, - tool_input: a.edited_tool_input.clone().or(tool_input), confirmed: a.confirmed.unwrap_or(ToolCallConfirmationReason::NotNeeded), selected_option, content: None, @@ -1367,10 +1361,10 @@ fn apply_tool_call_confirmed( tool_name, display_name, intention, + tool_input, contributor, meta, invocation_message, - tool_input, reason: a.reason.unwrap_or(ToolCallCancellationReason::Denied), reason_message: a.reason_message.clone(), user_suggestion: a.user_suggestion.clone(), @@ -1443,10 +1437,10 @@ fn apply_tool_call_complete( tool_name: base.tool_name, display_name: base.display_name, intention: base.intention, + tool_input, contributor: base.contributor, meta, invocation_message, - tool_input, success: a.result.success, past_tense_message: a.result.past_tense_message.clone(), content, @@ -1461,10 +1455,10 @@ fn apply_tool_call_complete( tool_name: base.tool_name, display_name: base.display_name, intention: base.intention, + tool_input, contributor: base.contributor, meta, invocation_message, - tool_input, success: a.result.success, past_tense_message: a.result.past_tense_message.clone(), content, @@ -1491,10 +1485,10 @@ fn apply_tool_call_result_confirmed( tool_name: s.tool_name, display_name: s.display_name, intention: s.intention, + tool_input: s.tool_input, contributor: s.contributor, meta: a.meta.clone().or(s.meta), invocation_message: s.invocation_message, - tool_input: s.tool_input, success: s.success, past_tense_message: s.past_tense_message, content: s.content, @@ -1509,10 +1503,10 @@ fn apply_tool_call_result_confirmed( tool_name: s.tool_name, display_name: s.display_name, intention: s.intention, + tool_input: s.tool_input, contributor: s.contributor, meta: a.meta.clone().or(s.meta), invocation_message: s.invocation_message, - tool_input: s.tool_input, reason: ToolCallCancellationReason::ResultDenied, reason_message: None, user_suggestion: None, @@ -1555,10 +1549,10 @@ fn apply_tool_call_auth_required( tool_name: base.tool_name, display_name: base.display_name, intention: base.intention, + tool_input: s.tool_input, contributor: s.contributor, meta, invocation_message: s.invocation_message, - tool_input: s.tool_input, confirmed: s.confirmed, selected_option: s.selected_option, status: ToolCallStatus::AuthRequired, @@ -1584,10 +1578,10 @@ fn apply_tool_call_auth_resolved( tool_name: base.tool_name, display_name: base.display_name, intention: base.intention, + tool_input: s.tool_input, contributor: s.contributor, meta, invocation_message: s.invocation_message, - tool_input: s.tool_input, confirmed: s.confirmed, selected_option: s.selected_option, content: s.content, @@ -1944,6 +1938,7 @@ pub fn apply_action_to_resource_watch( } } + #[cfg(test)] mod tests { use super::*; diff --git a/clients/swift/AHPApp/AHPApp/Views/ChatView.swift b/clients/swift/AHPApp/AHPApp/Views/ChatView.swift index d20e9202d..72e5937d7 100644 --- a/clients/swift/AHPApp/AHPApp/Views/ChatView.swift +++ b/clients/swift/AHPApp/AHPApp/Views/ChatView.swift @@ -1128,7 +1128,7 @@ private struct InputBarPreviewWrapper: View { toolName: "readFile", displayName: "Read file", invocationMessage: .string("Reading src/auth.swift"), - toolInput: "{\"path\": \"src/auth.swift\"}", + toolInput: ContentRef(uri: "file:///tool-inputs/tc1.json"), success: true, pastTenseMessage: .string("Read src/auth.swift"), status: .completed, @@ -1139,7 +1139,7 @@ private struct InputBarPreviewWrapper: View { toolName: "editFile", displayName: "Edit file", invocationMessage: .string("Editing src/auth.swift"), - toolInput: "{\"path\": \"src/auth.swift\"}", + toolInput: ContentRef(uri: "file:///tool-inputs/tc2.json"), success: true, pastTenseMessage: .string("Edited src/auth.swift"), status: .completed, @@ -1161,7 +1161,7 @@ private struct InputBarPreviewWrapper: View { toolName: "bash", displayName: "Run command", invocationMessage: .string("Run: npm run deploy --production"), - toolInput: "{\"command\": \"npm run deploy --production\"}", + toolInput: ContentRef(uri: "file:///tool-inputs/tc3.json"), status: .pendingConfirmation, confirmationTitle: .string("Allow production deployment?") ))) @@ -1176,7 +1176,7 @@ private struct InputBarPreviewWrapper: View { toolName: "readFile", displayName: "Read file", invocationMessage: .string("Reading src/auth/token.swift"), - toolInput: "{\"path\": \"src/auth/token.swift\"}", + toolInput: ContentRef(uri: "file:///tool-inputs/tc4.json"), status: .running, confirmed: .notNeeded ))) diff --git a/clients/swift/AHPApp/AHPApp/Views/ResponsePartView.swift b/clients/swift/AHPApp/AHPApp/Views/ResponsePartView.swift index 9fcecc951..3440ee227 100644 --- a/clients/swift/AHPApp/AHPApp/Views/ResponsePartView.swift +++ b/clients/swift/AHPApp/AHPApp/Views/ResponsePartView.swift @@ -439,11 +439,11 @@ struct ToolCallPartView: View { private var toolInput: String? { switch toolCall { - case .streaming(let s): return s.partialInput - case .pendingConfirmation(let s): return s.toolInput - case .running(let s): return s.toolInput - case .pendingResultConfirmation(let s): return s.toolInput - case .completed(let s): return s.toolInput + case .pendingConfirmation(let s): return s.toolInput?.uri + case .running(let s): return s.toolInput?.uri + case .pendingResultConfirmation(let s): return s.toolInput?.uri + case .completed(let s): return s.toolInput?.uri + case .cancelled(let s): return s.toolInput?.uri default: return nil } } @@ -576,11 +576,11 @@ struct ToolCallDetailSheet: View { private var toolInput: String? { switch toolCall { - case .streaming(let s): return s.partialInput - case .pendingConfirmation(let s): return s.toolInput - case .running(let s): return s.toolInput - case .pendingResultConfirmation(let s): return s.toolInput - case .completed(let s): return s.toolInput + case .pendingConfirmation(let s): return s.toolInput?.uri + case .running(let s): return s.toolInput?.uri + case .pendingResultConfirmation(let s): return s.toolInput?.uri + case .completed(let s): return s.toolInput?.uri + case .cancelled(let s): return s.toolInput?.uri default: return nil } } @@ -796,8 +796,8 @@ struct ContentRefView: View { toolCallId: "tc0", toolName: "editFile", displayName: "Edit file", + toolInput: ContentRef(uri: "file:///tool-inputs/tc0.json"), status: .streaming, - partialInput: "{\"path\": \"src/main.ts\", \"content\": \"...", invocationMessage: .string("Editing src/main.ts") ))) @@ -808,7 +808,7 @@ struct ContentRefView: View { toolName: "bash", displayName: "Run command", invocationMessage: .string("Run: npm run deploy"), - toolInput: "{\"command\": \"npm run deploy\"}", + toolInput: ContentRef(uri: "file:///tool-inputs/tc0b.json"), status: .pendingConfirmation, confirmationTitle: .string("Allow deployment?") ))) @@ -820,7 +820,7 @@ struct ContentRefView: View { toolName: "bash", displayName: "Run command", invocationMessage: .string("Running: npm test"), - toolInput: "{\"command\": \"npm test\"}", + toolInput: ContentRef(uri: "file:///tool-inputs/tc1.json"), status: .running, confirmed: .notNeeded ))) @@ -832,7 +832,7 @@ struct ContentRefView: View { toolName: "readFile", displayName: "Read file", invocationMessage: .string("Reading package.json"), - toolInput: "{\"path\": \"package.json\"}", + toolInput: ContentRef(uri: "file:///tool-inputs/tc2.json"), success: true, pastTenseMessage: .string("Read package.json"), content: [.text(ToolResultTextContent(type: .text, text: "{\"name\": \"my-app\"}"))], @@ -847,7 +847,7 @@ struct ContentRefView: View { toolName: "bash", displayName: "Run command", invocationMessage: .string("Running: rm -rf /"), - toolInput: "{\"command\": \"rm -rf /\"}", + toolInput: ContentRef(uri: "file:///tool-inputs/tc3.json"), success: false, pastTenseMessage: .string("Command failed"), status: .completed, @@ -861,7 +861,7 @@ struct ContentRefView: View { toolName: "writeFile", displayName: "Write file", invocationMessage: .string("Writing config.json"), - toolInput: "{\"path\": \"config.json\"}", + toolInput: ContentRef(uri: "file:///tool-inputs/tc4.json"), success: true, pastTenseMessage: .string("Wrote config.json"), content: [.text(ToolResultTextContent(type: .text, text: "File written successfully"))], @@ -876,7 +876,7 @@ struct ContentRefView: View { toolName: "bash", displayName: "Run command", invocationMessage: .string("Running: git push --force"), - toolInput: "{\"command\": \"git push --force\"}", + toolInput: ContentRef(uri: "file:///tool-inputs/tc5.json"), status: .cancelled, reason: .denied, reasonMessage: .string("User denied force push") diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift index 809dd13b8..21bc65b6e 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift @@ -436,17 +436,14 @@ public struct ChatToolCallDeltaAction: Codable, Sendable { /// contain escape sequences). public var meta: [String: AnyCodable]? public var type: ActionType - /// Partial parameter content to append - public var content: String - /// Updated progress message - public var invocationMessage: StringOrMarkdown? + /// Updated display-ready progress message + public var invocationMessage: StringOrMarkdown enum CodingKeys: String, CodingKey { case turnId case toolCallId case meta = "_meta" case type - case content case invocationMessage } @@ -455,14 +452,12 @@ public struct ChatToolCallDeltaAction: Codable, Sendable { toolCallId: String, meta: [String: AnyCodable]? = nil, type: ActionType, - content: String, - invocationMessage: StringOrMarkdown? = nil + invocationMessage: StringOrMarkdown ) { self.turnId = turnId self.toolCallId = toolCallId self.meta = meta self.type = type - self.content = content self.invocationMessage = invocationMessage } } @@ -488,8 +483,8 @@ public struct ChatToolCallReadyAction: Codable, Sendable { public var intention: String? /// Message describing what the tool will do or what confirmation is needed public var invocationMessage: StringOrMarkdown - /// Raw tool input - public var toolInput: String? + /// Reference to the final raw tool input, readable with `resourceRead` + public var toolInput: ContentRef? /// Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) public var confirmationTitle: StringOrMarkdown? /// Risk assessment that informed the confirmation requirement. @@ -531,7 +526,7 @@ public struct ChatToolCallReadyAction: Codable, Sendable { contributor: ToolCallContributor? = nil, intention: String? = nil, invocationMessage: StringOrMarkdown, - toolInput: String? = nil, + toolInput: ContentRef? = nil, confirmationTitle: StringOrMarkdown? = nil, riskAssessment: ToolCallRiskAssessment? = nil, edits: AnyCodable? = nil, diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift index 515f9c4a1..6465f9969 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift @@ -2576,8 +2576,6 @@ public struct ToolCallStreamingState: Codable, Sendable { /// with the {@link contributor} to serve MCP Apps. public var meta: [String: AnyCodable]? public var status: ToolCallStatus - /// Partial parameters accumulated so far - public var partialInput: String? /// Progress message shown while parameters are streaming public var invocationMessage: StringOrMarkdown? @@ -2589,7 +2587,6 @@ public struct ToolCallStreamingState: Codable, Sendable { case contributor case meta = "_meta" case status - case partialInput case invocationMessage } @@ -2601,7 +2598,6 @@ public struct ToolCallStreamingState: Codable, Sendable { contributor: ToolCallContributor? = nil, meta: [String: AnyCodable]? = nil, status: ToolCallStatus, - partialInput: String? = nil, invocationMessage: StringOrMarkdown? = nil ) { self.toolCallId = toolCallId @@ -2611,7 +2607,6 @@ public struct ToolCallStreamingState: Codable, Sendable { self.contributor = contributor self.meta = meta self.status = status - self.partialInput = partialInput self.invocationMessage = invocationMessage } } @@ -2635,8 +2630,13 @@ public struct ToolCallPendingConfirmationState: Codable, Sendable { public var meta: [String: AnyCodable]? /// Message describing what the tool will do public var invocationMessage: StringOrMarkdown - /// Raw tool input - public var toolInput: String? + /// Reference to the final raw tool input, readable with `resourceRead`. + /// + /// The referenced resource is mutable until the tool call leaves + /// `pending-confirmation`. When the client confirms with `editedToolInput`, + /// the host MUST replace the resource contents before echoing the accepted + /// confirmation action. Clients MUST NOT cache tool input across confirmation. + public var toolInput: ContentRef? public var status: ToolCallStatus /// Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) public var confirmationTitle: StringOrMarkdown? @@ -2677,7 +2677,7 @@ public struct ToolCallPendingConfirmationState: Codable, Sendable { contributor: ToolCallContributor? = nil, meta: [String: AnyCodable]? = nil, invocationMessage: StringOrMarkdown, - toolInput: String? = nil, + toolInput: ContentRef? = nil, status: ToolCallStatus, confirmationTitle: StringOrMarkdown? = nil, riskAssessment: ToolCallRiskAssessment? = nil, @@ -2721,8 +2721,13 @@ public struct ToolCallRunningState: Codable, Sendable { public var meta: [String: AnyCodable]? /// Message describing what the tool will do public var invocationMessage: StringOrMarkdown - /// Raw tool input - public var toolInput: String? + /// Reference to the final raw tool input, readable with `resourceRead`. + /// + /// The referenced resource is mutable until the tool call leaves + /// `pending-confirmation`. When the client confirms with `editedToolInput`, + /// the host MUST replace the resource contents before echoing the accepted + /// confirmation action. Clients MUST NOT cache tool input across confirmation. + public var toolInput: ContentRef? /// How the tool was confirmed for execution public var confirmed: ToolCallConfirmationReason /// The confirmation option the user selected, if confirmation options were provided @@ -2757,7 +2762,7 @@ public struct ToolCallRunningState: Codable, Sendable { contributor: ToolCallContributor? = nil, meta: [String: AnyCodable]? = nil, invocationMessage: StringOrMarkdown, - toolInput: String? = nil, + toolInput: ContentRef? = nil, confirmed: ToolCallConfirmationReason, selectedOption: ConfirmationOption? = nil, status: ToolCallStatus, @@ -2797,8 +2802,13 @@ public struct ToolCallAuthRequiredState: Codable, Sendable { public var meta: [String: AnyCodable]? /// Message describing what the tool will do public var invocationMessage: StringOrMarkdown - /// Raw tool input - public var toolInput: String? + /// Reference to the final raw tool input, readable with `resourceRead`. + /// + /// The referenced resource is mutable until the tool call leaves + /// `pending-confirmation`. When the client confirms with `editedToolInput`, + /// the host MUST replace the resource contents before echoing the accepted + /// confirmation action. Clients MUST NOT cache tool input across confirmation. + public var toolInput: ContentRef? /// How the tool was confirmed for execution public var confirmed: ToolCallConfirmationReason /// The confirmation option the user selected, if confirmation options were provided @@ -2833,7 +2843,7 @@ public struct ToolCallAuthRequiredState: Codable, Sendable { contributor: ToolCallContributor? = nil, meta: [String: AnyCodable]? = nil, invocationMessage: StringOrMarkdown, - toolInput: String? = nil, + toolInput: ContentRef? = nil, confirmed: ToolCallConfirmationReason, selectedOption: ConfirmationOption? = nil, status: ToolCallStatus, @@ -2875,8 +2885,13 @@ public struct ToolCallPendingResultConfirmationState: Codable, Sendable { public var meta: [String: AnyCodable]? /// Message describing what the tool will do public var invocationMessage: StringOrMarkdown - /// Raw tool input - public var toolInput: String? + /// Reference to the final raw tool input, readable with `resourceRead`. + /// + /// The referenced resource is mutable until the tool call leaves + /// `pending-confirmation`. When the client confirms with `editedToolInput`, + /// the host MUST replace the resource contents before echoing the accepted + /// confirmation action. Clients MUST NOT cache tool input across confirmation. + public var toolInput: ContentRef? /// Whether the tool succeeded public var success: Bool /// Past-tense description of what the tool did @@ -2924,7 +2939,7 @@ public struct ToolCallPendingResultConfirmationState: Codable, Sendable { contributor: ToolCallContributor? = nil, meta: [String: AnyCodable]? = nil, invocationMessage: StringOrMarkdown, - toolInput: String? = nil, + toolInput: ContentRef? = nil, success: Bool, pastTenseMessage: StringOrMarkdown, content: [ToolResultContent]? = nil, @@ -2972,8 +2987,13 @@ public struct ToolCallCompletedState: Codable, Sendable { public var meta: [String: AnyCodable]? /// Message describing what the tool will do public var invocationMessage: StringOrMarkdown - /// Raw tool input - public var toolInput: String? + /// Reference to the final raw tool input, readable with `resourceRead`. + /// + /// The referenced resource is mutable until the tool call leaves + /// `pending-confirmation`. When the client confirms with `editedToolInput`, + /// the host MUST replace the resource contents before echoing the accepted + /// confirmation action. Clients MUST NOT cache tool input across confirmation. + public var toolInput: ContentRef? /// Whether the tool succeeded public var success: Bool /// Past-tense description of what the tool did @@ -3021,7 +3041,7 @@ public struct ToolCallCompletedState: Codable, Sendable { contributor: ToolCallContributor? = nil, meta: [String: AnyCodable]? = nil, invocationMessage: StringOrMarkdown, - toolInput: String? = nil, + toolInput: ContentRef? = nil, success: Bool, pastTenseMessage: StringOrMarkdown, content: [ToolResultContent]? = nil, @@ -3069,8 +3089,13 @@ public struct ToolCallCancelledState: Codable, Sendable { public var meta: [String: AnyCodable]? /// Message describing what the tool will do public var invocationMessage: StringOrMarkdown - /// Raw tool input - public var toolInput: String? + /// Reference to the final raw tool input, readable with `resourceRead`. + /// + /// The referenced resource is mutable until the tool call leaves + /// `pending-confirmation`. When the client confirms with `editedToolInput`, + /// the host MUST replace the resource contents before echoing the accepted + /// confirmation action. Clients MUST NOT cache tool input across confirmation. + public var toolInput: ContentRef? public var status: ToolCallStatus /// Why the tool was cancelled public var reason: ToolCallCancellationReason @@ -3105,7 +3130,7 @@ public struct ToolCallCancelledState: Codable, Sendable { contributor: ToolCallContributor? = nil, meta: [String: AnyCodable]? = nil, invocationMessage: StringOrMarkdown, - toolInput: String? = nil, + toolInput: ContentRef? = nil, status: ToolCallStatus, reason: ToolCallCancellationReason, reasonMessage: StringOrMarkdown? = nil, @@ -5976,7 +6001,7 @@ public enum ToolResultContent: Codable, Sendable { } } -/// The state payload of a snapshot — root, session, chat, terminal, changeset, resource-watch, or annotations state. +/// The state payload of a snapshot — root, session, chat, terminal, changeset, resource-watch, annotations, or content state. public enum SnapshotState: Codable, Sendable { case root(RootState) case session(SessionState) diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift index fc0f03fb2..07441e64c 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift @@ -207,10 +207,7 @@ public func chatReducer(state: ChatState, action: StateAction) -> ChatState { case .chatToolCallDelta(let a): return updateToolCall(state: state, turnId: a.turnId, toolCallId: a.toolCallId) { tc in guard case .streaming(var s) = tc else { return tc } - s.partialInput = (s.partialInput ?? "") + a.content - if let msg = a.invocationMessage { - s.invocationMessage = msg - } + s.invocationMessage = a.invocationMessage s.meta = a.meta ?? s.meta return .streaming(s) } @@ -223,6 +220,7 @@ public func chatReducer(state: ChatState, action: StateAction) -> ChatState { } let base = tc.baseFields let intention = a.intention ?? base.intention + let toolInput = a.toolInput ?? base.toolInput let contributor = refineToolCallContributor(base.contributor, a.contributor) let meta = a.meta ?? base.meta let pending: ToolCallPendingConfirmationState? @@ -240,7 +238,7 @@ public func chatReducer(state: ChatState, action: StateAction) -> ChatState { contributor: contributor, meta: meta, invocationMessage: a.invocationMessage, - toolInput: a.toolInput, + toolInput: toolInput, confirmed: confirmed, status: .running )) @@ -253,7 +251,7 @@ public func chatReducer(state: ChatState, action: StateAction) -> ChatState { contributor: contributor, meta: meta, invocationMessage: a.invocationMessage, - toolInput: a.toolInput ?? pending?.toolInput, + toolInput: toolInput, status: .pendingConfirmation, confirmationTitle: a.confirmationTitle ?? pending?.confirmationTitle, riskAssessment: a.riskAssessment ?? pending?.riskAssessment, @@ -278,7 +276,7 @@ public func chatReducer(state: ChatState, action: StateAction) -> ChatState { contributor: base.contributor, meta: meta, invocationMessage: pending.invocationMessage, - toolInput: a.editedToolInput ?? pending.toolInput, + toolInput: pending.toolInput, confirmed: a.confirmed ?? .notNeeded, selectedOption: selectedOption, status: .running @@ -307,7 +305,7 @@ public func chatReducer(state: ChatState, action: StateAction) -> ChatState { let meta = a.meta ?? base.meta let confirmed: ToolCallConfirmationReason let invocationMessage: StringOrMarkdown - let toolInput: String? + let toolInput: ContentRef? let selectedOption: ConfirmationOption? let preAuthContent: [ToolResultContent]? let fromAuthRequired: Bool @@ -1043,26 +1041,19 @@ private func endTurn( default: let base = tc.baseFields let invocationMessage: StringOrMarkdown - let toolInput: String? switch tc { case .streaming(let s): invocationMessage = s.invocationMessage ?? .string("") - toolInput = nil case .pendingConfirmation(let p): invocationMessage = p.invocationMessage - toolInput = p.toolInput case .running(let r): invocationMessage = r.invocationMessage - toolInput = r.toolInput case .authRequired(let a): invocationMessage = a.invocationMessage - toolInput = a.toolInput case .pendingResultConfirmation(let r): invocationMessage = r.invocationMessage - toolInput = r.toolInput default: invocationMessage = .string("") - toolInput = nil } return .toolCall(ToolCallResponsePart( kind: .toolCall, @@ -1074,7 +1065,7 @@ private func endTurn( contributor: base.contributor, meta: base.meta, invocationMessage: invocationMessage, - toolInput: toolInput, + toolInput: base.toolInput, status: .cancelled, reason: .skipped )) diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/ToolCallStateExtensions.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/ToolCallStateExtensions.swift index 72113daa6..e177e7ba3 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/ToolCallStateExtensions.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/ToolCallStateExtensions.swift @@ -32,6 +32,7 @@ public struct ToolCallBaseFields: Sendable { public let toolName: String public let displayName: String public let intention: String? + public let toolInput: ContentRef? public let contributor: ToolCallContributor? public let meta: [String: AnyCodable]? } @@ -45,30 +46,37 @@ extension ToolCallState { case .streaming(let s): return ToolCallBaseFields(toolCallId: s.toolCallId, toolName: s.toolName, displayName: s.displayName, intention: s.intention, + toolInput: nil, contributor: s.contributor, meta: s.meta) case .pendingConfirmation(let s): return ToolCallBaseFields(toolCallId: s.toolCallId, toolName: s.toolName, displayName: s.displayName, intention: s.intention, + toolInput: s.toolInput, contributor: s.contributor, meta: s.meta) case .running(let s): return ToolCallBaseFields(toolCallId: s.toolCallId, toolName: s.toolName, displayName: s.displayName, intention: s.intention, + toolInput: s.toolInput, contributor: s.contributor, meta: s.meta) case .authRequired(let s): return ToolCallBaseFields(toolCallId: s.toolCallId, toolName: s.toolName, displayName: s.displayName, intention: s.intention, + toolInput: s.toolInput, contributor: s.contributor, meta: s.meta) case .pendingResultConfirmation(let s): return ToolCallBaseFields(toolCallId: s.toolCallId, toolName: s.toolName, displayName: s.displayName, intention: s.intention, + toolInput: s.toolInput, contributor: s.contributor, meta: s.meta) case .completed(let s): return ToolCallBaseFields(toolCallId: s.toolCallId, toolName: s.toolName, displayName: s.displayName, intention: s.intention, + toolInput: s.toolInput, contributor: s.contributor, meta: s.meta) case .cancelled(let s): return ToolCallBaseFields(toolCallId: s.toolCallId, toolName: s.toolName, displayName: s.displayName, intention: s.intention, + toolInput: s.toolInput, contributor: s.contributor, meta: s.meta) case .unknown: // All callers guard on a known variant before reaching here. diff --git a/clients/typescript/src/client/hosts/state-mirror.ts b/clients/typescript/src/client/hosts/state-mirror.ts index 2722ff0c1..e418205ba 100644 --- a/clients/typescript/src/client/hosts/state-mirror.ts +++ b/clients/typescript/src/client/hosts/state-mirror.ts @@ -119,6 +119,7 @@ export class MultiHostStateMirror { return this.changesetsMap; } + /** Look up the root state for `hostId`. */ getRoot(hostId: HostId): RootState | undefined { return this.rootStatesMap.get(hostId); @@ -139,6 +140,7 @@ export class MultiHostStateMirror { return this.changesetsMap.get(hostedResourceKey(hostId, uri)); } + /** * Convenience: apply a {@link HostSubscriptionEvent} produced by * {@link MultiHostClient.events}. Action envelopes are routed through diff --git a/clients/typescript/src/client/state-mirror.ts b/clients/typescript/src/client/state-mirror.ts index 3722ca59f..c10839f34 100644 --- a/clients/typescript/src/client/state-mirror.ts +++ b/clients/typescript/src/client/state-mirror.ts @@ -61,6 +61,7 @@ export class AhpStateMirror { return this.changesetsMap; } + /** Look up a session by URI. */ getSession(uri: URI): SessionState | undefined { return this.sessionsMap.get(uri); @@ -71,6 +72,7 @@ export class AhpStateMirror { return this.terminalsMap.get(uri); } + /** * Apply a server snapshot, replacing the state for the resource the * snapshot covers. diff --git a/clients/typescript/test/hosts.test.ts b/clients/typescript/test/hosts.test.ts index 58dc72cef..830564b0c 100644 --- a/clients/typescript/test/hosts.test.ts +++ b/clients/typescript/test/hosts.test.ts @@ -334,6 +334,7 @@ test('MultiHostStateMirror applies root snapshots scoped to host', () => { state: { agents: [makeAgent('copilot')] }, fromSeq: 0, }); + mirror.applySnapshot('host-b', { resource: ROOT, state: { agents: [makeAgent('vscode')] }, diff --git a/docs/.changes/20260730-tool-input-content-ref.json b/docs/.changes/20260730-tool-input-content-ref.json new file mode 100644 index 000000000..a4d7f4554 --- /dev/null +++ b/docs/.changes/20260730-tool-input-content-ref.json @@ -0,0 +1,4 @@ +{ + "type": "changed", + "message": "Final tool input now uses a lazy `ContentRef`, while streaming deltas carry only invocation-message updates." +} diff --git a/docs/guide/actions.md b/docs/guide/actions.md index 8f08f3d05..d9ae734e6 100644 --- a/docs/guide/actions.md +++ b/docs/guide/actions.md @@ -66,7 +66,7 @@ Tool calls follow a discriminated-union state machine — see [State Model — T | Type | Client-dispatchable? | When | |---|---|---| | `chat/toolCallStart` | No | Tool call created; LM begins streaming parameters | -| `chat/toolCallDelta` | No | Streaming partial parameters appended | +| `chat/toolCallDelta` | No | Display-ready invocation message updated while parameters stream separately | | `chat/toolCallReady` | No | Parameters complete (or running tool needs re-confirmation) | | `chat/toolCallConfirmed` | **Yes** | Client approves or denies a pending tool call | | `chat/toolCallComplete` | **Yes**¹ | Tool execution finished | diff --git a/docs/guide/customizations.md b/docs/guide/customizations.md index e07037098..abd9b9df1 100644 --- a/docs/guide/customizations.md +++ b/docs/guide/customizations.md @@ -288,9 +288,9 @@ sequenceDiagram participant Client Note over Server: LLM selects a client tool - Server->>Client: toolCallStart (contributor.clientId = client's clientId) - Server->>Client: toolCallDelta (streaming parameters) - Server->>Client: toolCallReady (confirmed: 'not-needed') + Server->>Client: toolCallStart (client contributor) + Server->>Client: toolCallDelta (invocation message) + Server->>Client: toolCallReady (toolInput ref, confirmed: 'not-needed') Note over Client: Client sees contributor.clientId matches,
begins execution @@ -300,11 +300,11 @@ sequenceDiagram 1. **`chat/toolCallStart`** — The server dispatches this with the tool call's `contributor` set to a client contributor whose `clientId` is the owning client's. This tells the client it owns the tool call. -2. **`chat/toolCallDelta`** (zero or more) — The server streams partial parameters as the LLM generates them. The client can observe `partialInput` on the tool call state to preview the arguments. +2. **`chat/toolCallDelta`** (zero or more) — The server updates the display-ready invocation message while parameters stream. Raw streaming parameters are not exposed. 3. **`chat/toolCallReady`** — Parameters are complete. For client-provided tools, the server typically sets `confirmed: 'not-needed'` so the tool transitions directly to `running`. If the server wants user confirmation first, it omits `confirmed` and the standard confirmation flow applies. -4. **Client executes** — When the tool call reaches `running` status, the owning client begins execution using the `toolInput` from the tool call state. +4. **Client executes** — When the tool call reaches `running` status, the owning client reads the final `toolInput` reference with `resourceRead` and begins execution. Client-contributed tools MUST receive a readable input reference. If confirmation carried `editedToolInput`, the host updates that resource before echoing the accepted confirmation, so this read returns the edited parameters. 5. **`chat/toolCallContentChanged`** (zero or more, client-dispatched) — While executing, the client MAY stream intermediate content (e.g. terminal output, partial results) by dispatching this action. This replaces the `content` array on the running tool call state. diff --git a/docs/guide/state-model.md b/docs/guide/state-model.md index ab9f1458d..07aaeb179 100644 --- a/docs/guide/state-model.md +++ b/docs/guide/state-model.md @@ -324,8 +324,7 @@ ToolCallResponsePart { // Reference to large content stored outside the state tree ContentRef { - kind: 'contentRef' - uri: string // scheme://sessionId/contentId + uri: string sizeHint?: number contentType?: string } @@ -349,7 +348,7 @@ InputRequestResponsePart { Text content uses a **create-then-append** pattern: the server first emits a `chat/responsePart` action to create a new markdown (or reasoning) part with an `id`, then streams text into it via `chat/delta` (or `chat/reasoning`) actions targeting that `partId`. This pattern is extensible to future streaming content types. -Clients fetch `ContentRef` content separately via the `resourceRead(uri)` command. This keeps the state tree small and serializable. +Clients fetch `ContentRef` content separately via the `resourceRead(uri)` command. This keeps large content out of state snapshots and action traffic. Consumers can derive display text by concatenating all `markdown` parts, find tool calls by filtering for `toolCall` parts, and access reasoning by filtering for `reasoning` parts. @@ -386,8 +385,8 @@ stateDiagram-v2 | Status | Key Fields | Description | | ----------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `streaming` | `partialInput?` | LM is streaming tool call parameters. `partialInput` accumulates via `toolCallDelta`. | -| `pending-confirmation` | `invocationMessage`, `toolInput?`, `edits?`, `editable?`, `options?` | Parameters complete or mid-execution confirmation needed. `edits` previews file changes. `editable` indicates the client may edit parameters before confirming. `options` provides server-defined choices beyond simple approve/deny (see below). Uses `_meta` for additional context. | +| `streaming` | `invocationMessage?` | LM is streaming tool call parameters. Clients receive only display-ready invocation-message updates; raw parameters are unavailable until the call is ready. | +| `pending-confirmation` | `invocationMessage`, `toolInput?`, `edits?`, `editable?`, `options?` | Parameters complete or mid-execution confirmation needed. `toolInput` is a reference, not inline input. `edits` previews file changes. `editable` indicates the client may edit parameters before confirming. `options` provides server-defined choices beyond simple approve/deny (see below). Uses `_meta` for additional context. | | `running` | `confirmed`, `selectedOption?` | Tool is executing. `confirmed` records how it was approved. `selectedOption` holds the chosen confirmation option, if any. | | `auth-required` | `confirmed`, `selectedOption?`, `contributor` (MCP), `auth` | Execution paused pending MCP authentication (see below). Only reachable for MCP-contributed tool calls. | | `pending-result-confirmation` | `success`, `pastTenseMessage`, `content?`, `selectedOption?` | Execution finished, waiting for client to approve the result. | @@ -414,7 +413,7 @@ This is deliberately **separate** from `McpServerAuthRequiredState` (the MCP ser ### Editable Parameters -When `editable` is `true` on a `pending-confirmation` tool call, the client may allow the user to modify the tool's input parameters before confirming. If the user edits the parameters, the client includes `editedToolInput` on the `chat/toolCallConfirmed` action. The reducer uses `editedToolInput` (if present) in place of the original `toolInput` when transitioning to `running`. +When `editable` is `true` on a `pending-confirmation` tool call, the client may allow the user to modify the tool's input parameters before confirming. If the user edits the parameters, the client includes inline `editedToolInput` on the `chat/toolCallConfirmed` action. Before echoing that accepted action, the host MUST replace the contents of the existing `toolInput` resource with the edited value. The reducer keeps the same reference, and subsequent `resourceRead` calls return the input that was actually executed. Clients MUST NOT cache tool input across confirmation. When a turn completes, non-terminal tool calls in `responseParts` are force-cancelled with reason `'skipped'`. diff --git a/schema/actions.schema.json b/schema/actions.schema.json index 9a046769f..02a715b79 100644 --- a/schema/actions.schema.json +++ b/schema/actions.schema.json @@ -835,20 +835,16 @@ "type": { "const": "chat/toolCallDelta" }, - "content": { - "type": "string", - "description": "Partial parameter content to append" - }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", - "description": "Updated progress message" + "description": "Updated display-ready progress message" } }, "required": [ "turnId", "toolCallId", "type", - "content" + "invocationMessage" ] }, "ChatToolCallReadyAction": { @@ -884,8 +880,8 @@ "description": "Message describing what the tool will do or what confirmation is needed" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`" }, "confirmationTitle": { "$ref": "#/$defs/StringOrMarkdown", @@ -962,7 +958,7 @@ }, "editedToolInput": { "type": "string", - "description": "Edited tool input parameters, if the client modified them before confirming" + "description": "Edited tool input parameters, if the client modified them before confirming.\n\nBefore echoing the accepted action, the host MUST replace the contents of\nthe pending tool call's `toolInput` resource with this value." }, "selectedOptionId": { "type": "string", @@ -5755,8 +5751,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." } }, "required": [ @@ -5840,10 +5836,6 @@ "status": { "const": "streaming" }, - "partialInput": { - "type": "string", - "description": "Partial parameters accumulated so far" - }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", "description": "Progress message shown while parameters are streaming" @@ -5890,8 +5882,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "pending-confirmation" @@ -5990,8 +5982,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -6055,8 +6047,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -6126,8 +6118,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -6221,8 +6213,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -6316,8 +6308,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "cancelled" diff --git a/schema/commands.schema.json b/schema/commands.schema.json index 775ee1285..1230f0fe2 100644 --- a/schema/commands.schema.json +++ b/schema/commands.schema.json @@ -4918,8 +4918,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." } }, "required": [ @@ -5003,10 +5003,6 @@ "status": { "const": "streaming" }, - "partialInput": { - "type": "string", - "description": "Partial parameters accumulated so far" - }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", "description": "Progress message shown while parameters are streaming" @@ -5053,8 +5049,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "pending-confirmation" @@ -5153,8 +5149,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -5218,8 +5214,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -5289,8 +5285,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -5384,8 +5380,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -5479,8 +5475,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "cancelled" @@ -7075,20 +7071,16 @@ "type": { "const": "chat/toolCallDelta" }, - "content": { - "type": "string", - "description": "Partial parameter content to append" - }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", - "description": "Updated progress message" + "description": "Updated display-ready progress message" } }, "required": [ "turnId", "toolCallId", "type", - "content" + "invocationMessage" ] }, "ChatToolCallReadyAction": { @@ -7124,8 +7116,8 @@ "description": "Message describing what the tool will do or what confirmation is needed" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`" }, "confirmationTitle": { "$ref": "#/$defs/StringOrMarkdown", @@ -7202,7 +7194,7 @@ }, "editedToolInput": { "type": "string", - "description": "Edited tool input parameters, if the client modified them before confirming" + "description": "Edited tool input parameters, if the client modified them before confirming.\n\nBefore echoing the accepted action, the host MUST replace the contents of\nthe pending tool call's `toolInput` resource with this value." }, "selectedOptionId": { "type": "string", diff --git a/schema/errors.schema.json b/schema/errors.schema.json index c770002fc..e6f5bdfae 100644 --- a/schema/errors.schema.json +++ b/schema/errors.schema.json @@ -3654,8 +3654,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." } }, "required": [ @@ -3739,10 +3739,6 @@ "status": { "const": "streaming" }, - "partialInput": { - "type": "string", - "description": "Partial parameters accumulated so far" - }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", "description": "Progress message shown while parameters are streaming" @@ -3789,8 +3785,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "pending-confirmation" @@ -3889,8 +3885,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -3954,8 +3950,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -4025,8 +4021,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -4120,8 +4116,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -4215,8 +4211,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "cancelled" @@ -8068,20 +8064,16 @@ "type": { "const": "chat/toolCallDelta" }, - "content": { - "type": "string", - "description": "Partial parameter content to append" - }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", - "description": "Updated progress message" + "description": "Updated display-ready progress message" } }, "required": [ "turnId", "toolCallId", "type", - "content" + "invocationMessage" ] }, "ChatToolCallReadyAction": { @@ -8117,8 +8109,8 @@ "description": "Message describing what the tool will do or what confirmation is needed" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`" }, "confirmationTitle": { "$ref": "#/$defs/StringOrMarkdown", @@ -9267,7 +9259,7 @@ }, "editedToolInput": { "type": "string", - "description": "Edited tool input parameters, if the client modified them before confirming" + "description": "Edited tool input parameters, if the client modified them before confirming.\n\nBefore echoing the accepted action, the host MUST replace the contents of\nthe pending tool call's `toolInput` resource with this value." }, "selectedOptionId": { "type": "string", diff --git a/schema/notifications.schema.json b/schema/notifications.schema.json index a11260fd0..a02ac3ae1 100644 --- a/schema/notifications.schema.json +++ b/schema/notifications.schema.json @@ -3817,8 +3817,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." } }, "required": [ @@ -3902,10 +3902,6 @@ "status": { "const": "streaming" }, - "partialInput": { - "type": "string", - "description": "Partial parameters accumulated so far" - }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", "description": "Progress message shown while parameters are streaming" @@ -3952,8 +3948,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "pending-confirmation" @@ -4052,8 +4048,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -4117,8 +4113,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -4188,8 +4184,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -4283,8 +4279,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -4378,8 +4374,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "cancelled" diff --git a/schema/state.schema.json b/schema/state.schema.json index 0d347e2ed..7ac1d302b 100644 --- a/schema/state.schema.json +++ b/schema/state.schema.json @@ -3565,8 +3565,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." } }, "required": [ @@ -3650,10 +3650,6 @@ "status": { "const": "streaming" }, - "partialInput": { - "type": "string", - "description": "Partial parameters accumulated so far" - }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", "description": "Progress message shown while parameters are streaming" @@ -3700,8 +3696,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "pending-confirmation" @@ -3800,8 +3796,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -3865,8 +3861,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -3936,8 +3932,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -4031,8 +4027,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -4126,8 +4122,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "type": "string", - "description": "Raw tool input" + "$ref": "#/$defs/ContentRef", + "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "cancelled" diff --git a/scripts/generate-go.ts b/scripts/generate-go.ts index 33d7009c9..a934102c3 100644 --- a/scripts/generate-go.ts +++ b/scripts/generate-go.ts @@ -1153,7 +1153,7 @@ func (o ChatOrigin) MarshalJSON() ([]byte, error) { function generateSnapshotState(): string { return `// SnapshotState is the state payload of a snapshot — root, session, -// chat, terminal, changeset, resource-watch, or annotations state. The active +// chat, terminal, changeset, resource-watch, annotations, or content state. The active // variant is chosen by which pointer field is non-nil; UnmarshalJSON probes // for required fields in the canonical order // (session → chat → terminal → changeset → resourceWatch → annotations → root). diff --git a/scripts/generate-kotlin.ts b/scripts/generate-kotlin.ts index 4fad6f133..32075fa1d 100644 --- a/scripts/generate-kotlin.ts +++ b/scripts/generate-kotlin.ts @@ -726,7 +726,7 @@ internal object StringOrMarkdownSerializer : KSerializer { function generateSnapshotState(): string { return `/** * The state payload of a snapshot — root, session, chat, terminal, changeset, - * resource-watch, or annotations state. + * resource-watch, annotations, or content state. */ @Serializable(with = SnapshotStateSerializer::class) sealed interface SnapshotState { diff --git a/scripts/generate-markdown.ts b/scripts/generate-markdown.ts index 0e08372f4..38153690f 100644 --- a/scripts/generate-markdown.ts +++ b/scripts/generate-markdown.ts @@ -1078,6 +1078,7 @@ function generateOtlpChannelPage(project: Project): string { lines.push('The `ahp-otlp:` channels are stateless; the only state type is the capability descriptor the host advertises on `InitializeResult.telemetry`.\n'); lines.push(emitStateTypesSection([stateSf])); } + if (notificationsSf) { lines.push('## Notifications\n'); lines.push(schemaLink('notifications.schema.json')); @@ -1086,6 +1087,7 @@ function generateOtlpChannelPage(project: Project): string { return lines.join('\n'); } + // ─── Error Codes Page ──────────────────────────────────────────────────────── function generateErrorCodesPage(project: Project): string { diff --git a/scripts/generate-rust.ts b/scripts/generate-rust.ts index eaba75920..6fa164bce 100644 --- a/scripts/generate-rust.ts +++ b/scripts/generate-rust.ts @@ -1088,7 +1088,7 @@ pub enum ChatOrigin { function generateSnapshotState(): string { return `/// The state payload of a snapshot — root, session, chat, terminal, -/// changeset, resource-watch, or annotations state. +/// changeset, resource-watch, annotations, or content state. /// /// Deserialized by trying session first (has required \`lifecycle\`), then /// chat (has required \`turns\`), then terminal (has required \`content\`), @@ -1316,7 +1316,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, McpAuthRequirement, McpServerState, ModelSelection, ResponsePart, SessionActiveClient, SessionInputRequest, SideChatSelection, TerminalClaim, TerminalInfo, TextRange, ToolCallContributor, ToolCallResult, ToolCallRiskAssessment, 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, ContentRef, Customization, ErrorInfo, McpAuthRequirement, McpServerState, ModelSelection, ResponsePart, SessionActiveClient, SessionInputRequest, SideChatSelection, TerminalClaim, TerminalInfo, TextRange, ToolCallContributor, ToolCallResult, ToolCallRiskAssessment, 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 88d307d64..6e2b833d3 100644 --- a/scripts/generate-swift.ts +++ b/scripts/generate-swift.ts @@ -969,7 +969,7 @@ public enum StringOrMarkdown: Codable, Sendable, Equatable { } function generateSnapshotState(): string { - return `/// The state payload of a snapshot — root, session, chat, terminal, changeset, resource-watch, or annotations state. + return `/// The state payload of a snapshot — root, session, chat, terminal, changeset, resource-watch, annotations, or content state. public enum SnapshotState: Codable, Sendable { case root(RootState) case session(SessionState) diff --git a/types/channels-chat/actions.ts b/types/channels-chat/actions.ts index 35307ec19..2bc4dfb99 100644 --- a/types/channels-chat/actions.ts +++ b/types/channels-chat/actions.ts @@ -5,7 +5,7 @@ */ import { ActionType } from '../common/actions.js'; -import type { StringOrMarkdown, ErrorInfo, FileEdit, UsageInfo, URI } from '../common/state.js'; +import type { ContentRef, StringOrMarkdown, ErrorInfo, FileEdit, UsageInfo, URI } from '../common/state.js'; import type { McpAuthRequirement } from '../channels-session/state.js'; import type { Message, @@ -173,10 +173,8 @@ export interface ChatToolCallStartAction extends ToolCallActionBase { */ export interface ChatToolCallDeltaAction extends ToolCallActionBase { type: ActionType.ChatToolCallDelta; - /** Partial parameter content to append */ - content: string; - /** Updated progress message */ - invocationMessage?: StringOrMarkdown; + /** Updated display-ready progress message */ + invocationMessage: StringOrMarkdown; } /** @@ -211,8 +209,8 @@ export interface ChatToolCallReadyAction extends ToolCallActionBase { intention?: string; /** Message describing what the tool will do or what confirmation is needed */ invocationMessage: StringOrMarkdown; - /** Raw tool input */ - toolInput?: string; + /** Reference to the final raw tool input, readable with `resourceRead` */ + toolInput?: ContentRef; /** Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) */ confirmationTitle?: StringOrMarkdown; /** Risk assessment that informed the confirmation requirement. */ @@ -245,7 +243,12 @@ export interface ChatToolCallApprovedAction extends ToolCallActionBase { approved: true; /** How the tool was confirmed */ confirmed: ToolCallConfirmationReason; - /** Edited tool input parameters, if the client modified them before confirming */ + /** + * Edited tool input parameters, if the client modified them before confirming. + * + * Before echoing the accepted action, the host MUST replace the contents of + * the pending tool call's `toolInput` resource with this value. + */ editedToolInput?: string; /** ID of the selected confirmation option, if the server provided options */ selectedOptionId?: string; diff --git a/types/channels-chat/reducer.ts b/types/channels-chat/reducer.ts index 332eaaec0..04f4389e6 100644 --- a/types/channels-chat/reducer.ts +++ b/types/channels-chat/reducer.ts @@ -465,8 +465,7 @@ export function chatReducer(state: ChatState, action: ChatAction, log?: (msg: st return { ...tc, ...(action._meta !== undefined ? { _meta: action._meta } : {}), - partialInput: (tc.partialInput ?? '') + action.content, - invocationMessage: action.invocationMessage ?? tc.invocationMessage, + invocationMessage: action.invocationMessage, }; }); @@ -484,12 +483,14 @@ export function chatReducer(state: ChatState, action: ChatAction, log?: (msg: st contributor: refineToolCallContributor(tc.contributor, action.contributor, log), intention: action.intention ?? tc.intention, }; + const toolInput = action.toolInput + ?? (tc.status === ToolCallStatus.Streaming ? undefined : tc.toolInput); if (action.confirmed) { return { status: ToolCallStatus.Running, ...base, invocationMessage: action.invocationMessage, - toolInput: action.toolInput, + toolInput, confirmed: action.confirmed, }; } @@ -499,7 +500,7 @@ export function chatReducer(state: ChatState, action: ChatAction, log?: (msg: st status: ToolCallStatus.PendingConfirmation, ...base, invocationMessage: action.invocationMessage, - toolInput: action.toolInput ?? pending?.toolInput, + toolInput, confirmationTitle: action.confirmationTitle ?? pending?.confirmationTitle, riskAssessment: action.riskAssessment ?? pending?.riskAssessment, edits: action.edits ?? pending?.edits, @@ -520,7 +521,7 @@ export function chatReducer(state: ChatState, action: ChatAction, log?: (msg: st status: ToolCallStatus.Running, ...base, invocationMessage: tc.invocationMessage, - toolInput: action.editedToolInput ?? tc.toolInput, + toolInput: tc.toolInput, confirmed: action.confirmed, ...(selectedOption ? { selectedOption } : {}), }; diff --git a/types/channels-chat/state.ts b/types/channels-chat/state.ts index c26449958..d34f7510b 100644 --- a/types/channels-chat/state.ts +++ b/types/channels-chat/state.ts @@ -1185,8 +1185,15 @@ interface ToolCallBase { interface ToolCallParameterFields { /** Message describing what the tool will do */ invocationMessage: StringOrMarkdown; - /** Raw tool input */ - toolInput?: string; + /** + * Reference to the final raw tool input, readable with `resourceRead`. + * + * The referenced resource is mutable until the tool call leaves + * `pending-confirmation`. When the client confirms with `editedToolInput`, + * the host MUST replace the resource contents before echoing the accepted + * confirmation action. Clients MUST NOT cache tool input across confirmation. + */ + toolInput?: ContentRef; } /** @@ -1222,8 +1229,6 @@ export interface ToolCallResult { */ export interface ToolCallStreamingState extends ToolCallBase { status: ToolCallStatus.Streaming; - /** Partial parameters accumulated so far */ - partialInput?: string; /** Progress message shown while parameters are streaming */ invocationMessage?: StringOrMarkdown; } diff --git a/types/test-cases/reducers/019-tool-call-full-lifecycle-start-delta-ready-confirmed-complete.json b/types/test-cases/reducers/019-tool-call-full-lifecycle-start-delta-ready-confirmed-complete.json index 093915793..8d2d4a5f5 100644 --- a/types/test-cases/reducers/019-tool-call-full-lifecycle-start-delta-ready-confirmed-complete.json +++ b/types/test-cases/reducers/019-tool-call-full-lifecycle-start-delta-ready-confirmed-complete.json @@ -33,7 +33,6 @@ "type": "chat/toolCallDelta", "turnId": "turn-1", "toolCallId": "tc-1", - "content": "ls -la", "invocationMessage": "Listing files" }, { @@ -41,7 +40,9 @@ "turnId": "turn-1", "toolCallId": "tc-1", "invocationMessage": "Run: ls -la", - "toolInput": "ls -la" + "toolInput": { + "uri": "file:///tool-inputs/tc-1.json" + } }, { "type": "chat/toolCallConfirmed", @@ -83,7 +84,9 @@ "contributor": null, "_meta": null, "invocationMessage": "Run: ls -la", - "toolInput": "ls -la", + "toolInput": { + "uri": "file:///tool-inputs/tc-1.json" + }, "confirmed": "user-action", "success": true, "pastTenseMessage": "Ran command" diff --git a/types/test-cases/reducers/025-tool-call-actions-for-unknown-toolcallid-are-no-op.json b/types/test-cases/reducers/025-tool-call-actions-for-unknown-toolcallid-are-no-op.json index 543212f61..fca33067b 100644 --- a/types/test-cases/reducers/025-tool-call-actions-for-unknown-toolcallid-are-no-op.json +++ b/types/test-cases/reducers/025-tool-call-actions-for-unknown-toolcallid-are-no-op.json @@ -25,7 +25,7 @@ "type": "chat/toolCallDelta", "turnId": "turn-1", "toolCallId": "nonexistent", - "content": "data" + "invocationMessage": "Working" } ], "expected": { diff --git a/types/test-cases/reducers/084-toolcall-contentchanged-updates-running.json b/types/test-cases/reducers/084-toolcall-contentchanged-updates-running.json index 2cb785045..a15874b67 100644 --- a/types/test-cases/reducers/084-toolcall-contentchanged-updates-running.json +++ b/types/test-cases/reducers/084-toolcall-contentchanged-updates-running.json @@ -22,7 +22,9 @@ "displayName": "Run Command", "intention": null, "invocationMessage": "Running command", - "toolInput": "ls -la", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action" } } @@ -69,7 +71,9 @@ "displayName": "Run Command", "intention": null, "invocationMessage": "Running command", - "toolInput": "ls -la", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action", "content": [ { diff --git a/types/test-cases/reducers/085-toolcall-contentchanged-noop-non-running.json b/types/test-cases/reducers/085-toolcall-contentchanged-noop-non-running.json index 18582ffe4..69432a59a 100644 --- a/types/test-cases/reducers/085-toolcall-contentchanged-noop-non-running.json +++ b/types/test-cases/reducers/085-toolcall-contentchanged-noop-non-running.json @@ -22,7 +22,9 @@ "displayName": "Run Command", "intention": null, "invocationMessage": "Ran command", - "toolInput": "ls -la", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action", "success": true, "pastTenseMessage": "Ran command" @@ -71,7 +73,9 @@ "displayName": "Run Command", "intention": null, "invocationMessage": "Ran command", - "toolInput": "ls -la", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action", "success": true, "pastTenseMessage": "Ran command" diff --git a/types/test-cases/reducers/086-toolcall-contentchanged-replaces-existing.json b/types/test-cases/reducers/086-toolcall-contentchanged-replaces-existing.json index 905071151..4647c7260 100644 --- a/types/test-cases/reducers/086-toolcall-contentchanged-replaces-existing.json +++ b/types/test-cases/reducers/086-toolcall-contentchanged-replaces-existing.json @@ -22,7 +22,9 @@ "displayName": "Run Command", "intention": null, "invocationMessage": "Running command", - "toolInput": "ls -la", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action", "content": [ { @@ -80,7 +82,9 @@ "displayName": "Run Command", "intention": null, "invocationMessage": "Running command", - "toolInput": "ls -la", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action", "content": [ { diff --git a/types/test-cases/reducers/090-toolcalldelta-wrong-turnid-is-no-op.json b/types/test-cases/reducers/090-toolcalldelta-wrong-turnid-is-no-op.json index b640dc88f..3549288df 100644 --- a/types/test-cases/reducers/090-toolcalldelta-wrong-turnid-is-no-op.json +++ b/types/test-cases/reducers/090-toolcalldelta-wrong-turnid-is-no-op.json @@ -36,7 +36,7 @@ "type": "chat/toolCallDelta", "turnId": "wrong-turn", "toolCallId": "tc-1", - "content": "data" + "invocationMessage": "Working" } ], "expected": { diff --git a/types/test-cases/reducers/095-toolcalldelta-wrong-status-is-no-op.json b/types/test-cases/reducers/095-toolcalldelta-wrong-status-is-no-op.json index 93a0910e9..1c68eae20 100644 --- a/types/test-cases/reducers/095-toolcalldelta-wrong-status-is-no-op.json +++ b/types/test-cases/reducers/095-toolcalldelta-wrong-status-is-no-op.json @@ -22,7 +22,9 @@ "displayName": "Run Command", "intention": null, "invocationMessage": "Running", - "toolInput": "ls", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action" } } @@ -39,7 +41,7 @@ "type": "chat/toolCallDelta", "turnId": "turn-1", "toolCallId": "tc-1", - "content": "extra data" + "invocationMessage": "Working" } ], "expected": { @@ -63,7 +65,9 @@ "displayName": "Run Command", "intention": null, "invocationMessage": "Running", - "toolInput": "ls", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action" } } diff --git a/types/test-cases/reducers/096-toolcallconfirmed-wrong-status-is-no-op.json b/types/test-cases/reducers/096-toolcallconfirmed-wrong-status-is-no-op.json index f616ee6bb..812040255 100644 --- a/types/test-cases/reducers/096-toolcallconfirmed-wrong-status-is-no-op.json +++ b/types/test-cases/reducers/096-toolcallconfirmed-wrong-status-is-no-op.json @@ -22,7 +22,9 @@ "displayName": "Run Command", "intention": null, "invocationMessage": "Running", - "toolInput": "ls", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action" } } @@ -64,7 +66,9 @@ "displayName": "Run Command", "intention": null, "invocationMessage": "Running", - "toolInput": "ls", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action" } } diff --git a/types/test-cases/reducers/097-toolcallcomplete-wrong-status-is-no-op.json b/types/test-cases/reducers/097-toolcallcomplete-wrong-status-is-no-op.json index f4bc585f4..3cce8b9db 100644 --- a/types/test-cases/reducers/097-toolcallcomplete-wrong-status-is-no-op.json +++ b/types/test-cases/reducers/097-toolcallcomplete-wrong-status-is-no-op.json @@ -22,7 +22,9 @@ "displayName": "Run Command", "intention": null, "invocationMessage": "Ran command", - "toolInput": "ls", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action", "success": true, "pastTenseMessage": "Ran command" @@ -68,7 +70,9 @@ "displayName": "Run Command", "intention": null, "invocationMessage": "Ran command", - "toolInput": "ls", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action", "success": true, "pastTenseMessage": "Ran command" diff --git a/types/test-cases/reducers/098-toolcallresultconfirmed-wrong-status-is-no-op.json b/types/test-cases/reducers/098-toolcallresultconfirmed-wrong-status-is-no-op.json index 44f6c44d4..9112938a9 100644 --- a/types/test-cases/reducers/098-toolcallresultconfirmed-wrong-status-is-no-op.json +++ b/types/test-cases/reducers/098-toolcallresultconfirmed-wrong-status-is-no-op.json @@ -22,7 +22,9 @@ "displayName": "Run Command", "intention": null, "invocationMessage": "Running", - "toolInput": "ls", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action" } } @@ -63,7 +65,9 @@ "displayName": "Run Command", "intention": null, "invocationMessage": "Running", - "toolInput": "ls", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action" } } diff --git a/types/test-cases/reducers/099-endturn-force-cancels-running-tool-call.json b/types/test-cases/reducers/099-endturn-force-cancels-running-tool-call.json index 937e2c6f2..5ab99dc42 100644 --- a/types/test-cases/reducers/099-endturn-force-cancels-running-tool-call.json +++ b/types/test-cases/reducers/099-endturn-force-cancels-running-tool-call.json @@ -22,7 +22,9 @@ "displayName": "Run Command", "intention": null, "invocationMessage": "Running command", - "toolInput": "ls -la", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action" } } @@ -65,7 +67,9 @@ "contributor": null, "_meta": null, "invocationMessage": "Running command", - "toolInput": "ls -la", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "reason": "skipped" } } diff --git a/types/test-cases/reducers/100-delta-targeting-toolcall-partid-is-no-op.json b/types/test-cases/reducers/100-delta-targeting-toolcall-partid-is-no-op.json index 2eee6a8d8..6091b04ea 100644 --- a/types/test-cases/reducers/100-delta-targeting-toolcall-partid-is-no-op.json +++ b/types/test-cases/reducers/100-delta-targeting-toolcall-partid-is-no-op.json @@ -22,7 +22,9 @@ "displayName": "Run Command", "intention": null, "invocationMessage": "Running", - "toolInput": "ls", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action" } } @@ -63,7 +65,9 @@ "displayName": "Run Command", "intention": null, "invocationMessage": "Running", - "toolInput": "ls", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action" } } diff --git a/types/test-cases/reducers/101-toolcalldelta-without-invocationmessage.json b/types/test-cases/reducers/101-toolcalldelta-without-invocationmessage.json index f8c0e1f56..10c94c64c 100644 --- a/types/test-cases/reducers/101-toolcalldelta-without-invocationmessage.json +++ b/types/test-cases/reducers/101-toolcalldelta-without-invocationmessage.json @@ -1,5 +1,5 @@ { - "description": "toolCallDelta without invocationMessage preserves existing", + "description": "toolCallDelta replaces the streaming invocationMessage", "reducer": "chat", "initial": { "turns": [], @@ -37,7 +37,7 @@ "type": "chat/toolCallDelta", "turnId": "turn-1", "toolCallId": "tc-1", - "content": "data" + "invocationMessage": "Working" } ], "expected": { @@ -60,8 +60,7 @@ "toolName": "bash", "displayName": "Run Command", "intention": null, - "invocationMessage": "Original message", - "partialInput": "data" + "invocationMessage": "Working" } } ], 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 f2d01c3f7..072edf95e 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 @@ -33,7 +33,9 @@ "turnId": "turn-1", "toolCallId": "tc-1", "invocationMessage": "Run: rm -rf /tmp/test", - "toolInput": "rm -rf /tmp/test" + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + } } ], "expected": { @@ -59,7 +61,9 @@ "contributor": null, "_meta": null, "invocationMessage": "Run: rm -rf /tmp/test", - "toolInput": "rm -rf /tmp/test", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmationTitle": null, "riskAssessment": null, "edits": null, diff --git a/types/test-cases/reducers/158-toolcallconfirmed-approved-with-editedtoolinput-overrides-original.json b/types/test-cases/reducers/158-toolcallconfirmed-approved-with-editedtoolinput-overrides-original.json index 4fd274f36..37debaa79 100644 --- a/types/test-cases/reducers/158-toolcallconfirmed-approved-with-editedtoolinput-overrides-original.json +++ b/types/test-cases/reducers/158-toolcallconfirmed-approved-with-editedtoolinput-overrides-original.json @@ -1,5 +1,5 @@ { - "description": "toolCallConfirmed approved with editedToolInput overrides the original toolInput in the running state", + "description": "toolCallConfirmed preserves the input ref when edited input is handled by the host", "reducer": "chat", "initial": { "turns": [], @@ -33,7 +33,9 @@ "turnId": "turn-1", "toolCallId": "tc-1", "invocationMessage": "Run: ls -la", - "toolInput": "ls -la" + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + } }, { "type": "chat/toolCallConfirmed", @@ -76,7 +78,9 @@ "contributor": null, "_meta": null, "invocationMessage": "Run: ls -la", - "toolInput": "ls -la /tmp", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action", "success": true, "pastTenseMessage": "Ran command" diff --git a/types/test-cases/reducers/163-toolcallstart-carries-mcp-contributor-through-lifecycle.json b/types/test-cases/reducers/163-toolcallstart-carries-mcp-contributor-through-lifecycle.json index a01886f2e..77699f890 100644 --- a/types/test-cases/reducers/163-toolcallstart-carries-mcp-contributor-through-lifecycle.json +++ b/types/test-cases/reducers/163-toolcallstart-carries-mcp-contributor-through-lifecycle.json @@ -37,7 +37,9 @@ "turnId": "turn-1", "toolCallId": "tc-1", "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "not-needed" }, { @@ -76,7 +78,9 @@ }, "_meta": null, "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "not-needed", "success": true, "pastTenseMessage": "Searched files" 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 e46ac0358..ce28c10f9 100644 --- a/types/test-cases/reducers/220-toolcall-actions-update-meta.json +++ b/types/test-cases/reducers/220-toolcall-actions-update-meta.json @@ -35,7 +35,6 @@ "type": "chat/toolCallDelta", "turnId": "turn-1", "toolCallId": "tc-delta", - "content": "abc", "invocationMessage": "Streaming input", "_meta": { "phase": "delta" @@ -53,7 +52,9 @@ "turnId": "turn-1", "toolCallId": "tc-ready-running", "invocationMessage": "Run now", - "toolInput": "{}", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "not-needed", "_meta": { "phase": "ready-running" @@ -237,7 +238,6 @@ "phase": "delta" }, "status": "streaming", - "partialInput": "abc", "invocationMessage": "Streaming input" } }, @@ -254,7 +254,9 @@ "phase": "ready-running" }, "invocationMessage": "Run now", - "toolInput": "{}", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "not-needed" } }, diff --git a/types/test-cases/reducers/242-toolcallready-completes-risk-assessment.json b/types/test-cases/reducers/242-toolcallready-completes-risk-assessment.json index 56d548d52..f2e736985 100644 --- a/types/test-cases/reducers/242-toolcallready-completes-risk-assessment.json +++ b/types/test-cases/reducers/242-toolcallready-completes-risk-assessment.json @@ -24,7 +24,9 @@ "contributor": null, "_meta": null, "invocationMessage": "Checking command safety", - "toolInput": "rm -rf /tmp/test", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmationTitle": "Run in terminal", "riskAssessment": { "kind": "judge", @@ -88,7 +90,9 @@ "contributor": null, "_meta": null, "invocationMessage": "Run: rm -rf /tmp/test", - "toolInput": "rm -rf /tmp/test", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmationTitle": "Run in terminal", "riskAssessment": { "kind": "judge", diff --git a/types/test-cases/reducers/243-toolcallauthrequired-full-lifecycle-running-authrequired-running-completed.json b/types/test-cases/reducers/243-toolcallauthrequired-full-lifecycle-running-authrequired-running-completed.json index 02abe2960..55549fc33 100644 --- a/types/test-cases/reducers/243-toolcallauthrequired-full-lifecycle-running-authrequired-running-completed.json +++ b/types/test-cases/reducers/243-toolcallauthrequired-full-lifecycle-running-authrequired-running-completed.json @@ -37,7 +37,9 @@ "turnId": "turn-1", "toolCallId": "tc-1", "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "not-needed" }, { @@ -49,7 +51,9 @@ "resource": { "resource": "https://mcp.example.com" }, - "requiredScopes": ["repo:read"], + "requiredScopes": [ + "repo:read" + ], "description": "Needs repo:read" } }, @@ -94,7 +98,9 @@ }, "_meta": null, "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "not-needed", "success": true, "pastTenseMessage": "Searched repo" diff --git a/types/test-cases/reducers/247-toolcallauthresolved-noop-when-not-auth-required.json b/types/test-cases/reducers/247-toolcallauthresolved-noop-when-not-auth-required.json index 095a26fe0..cceed08f3 100644 --- a/types/test-cases/reducers/247-toolcallauthresolved-noop-when-not-auth-required.json +++ b/types/test-cases/reducers/247-toolcallauthresolved-noop-when-not-auth-required.json @@ -37,7 +37,9 @@ "turnId": "turn-1", "toolCallId": "tc-4", "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "not-needed" }, { @@ -72,7 +74,9 @@ }, "_meta": null, "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "not-needed" } } diff --git a/types/test-cases/reducers/248-toolcallauthrequired-sets-input-needed-status-and-preserves-metadata.json b/types/test-cases/reducers/248-toolcallauthrequired-sets-input-needed-status-and-preserves-metadata.json index 33e2ab02d..9859badc2 100644 --- a/types/test-cases/reducers/248-toolcallauthrequired-sets-input-needed-status-and-preserves-metadata.json +++ b/types/test-cases/reducers/248-toolcallauthrequired-sets-input-needed-status-and-preserves-metadata.json @@ -40,7 +40,9 @@ "turnId": "turn-1", "toolCallId": "tc-5", "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmationTitle": "Search repo", "options": [ { @@ -78,7 +80,9 @@ "resource": { "resource": "https://mcp.example.com" }, - "requiredScopes": ["repo:read"] + "requiredScopes": [ + "repo:read" + ] }, "_meta": { "phase": "auth-required" @@ -113,7 +117,9 @@ "phase": "auth-required" }, "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action", "selectedOption": { "id": "opt-1", @@ -131,7 +137,9 @@ "resource": { "resource": "https://mcp.example.com" }, - "requiredScopes": ["repo:read"] + "requiredScopes": [ + "repo:read" + ] } } } diff --git a/types/test-cases/reducers/249-toolcallauthresolved-preserves-fields-and-clears-input-needed.json b/types/test-cases/reducers/249-toolcallauthresolved-preserves-fields-and-clears-input-needed.json index cdc94c6a6..54586a464 100644 --- a/types/test-cases/reducers/249-toolcallauthresolved-preserves-fields-and-clears-input-needed.json +++ b/types/test-cases/reducers/249-toolcallauthresolved-preserves-fields-and-clears-input-needed.json @@ -37,7 +37,9 @@ "turnId": "turn-1", "toolCallId": "tc-6", "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "options": [ { "id": "opt-1", @@ -113,7 +115,9 @@ "phase": "resolved" }, "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action", "selectedOption": { "id": "opt-1", diff --git a/types/test-cases/reducers/250-turncomplete-force-cancels-auth-required-tool-call.json b/types/test-cases/reducers/250-turncomplete-force-cancels-auth-required-tool-call.json index f2e0b7d0b..ae0ddefaa 100644 --- a/types/test-cases/reducers/250-turncomplete-force-cancels-auth-required-tool-call.json +++ b/types/test-cases/reducers/250-turncomplete-force-cancels-auth-required-tool-call.json @@ -37,7 +37,9 @@ "turnId": "turn-1", "toolCallId": "tc-7", "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "not-needed" }, { @@ -84,7 +86,9 @@ }, "_meta": null, "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "reason": "skipped" } } diff --git a/types/test-cases/reducers/251-session-inputneededset-appends-tool-authentication.json b/types/test-cases/reducers/251-session-inputneededset-appends-tool-authentication.json index a8725b335..0ca318124 100644 --- a/types/test-cases/reducers/251-session-inputneededset-appends-tool-authentication.json +++ b/types/test-cases/reducers/251-session-inputneededset-appends-tool-authentication.json @@ -13,7 +13,10 @@ "kind": "chatInput", "id": "copilot:/test-session/chat-1#req-1", "chat": "copilot:/test-session/chat-1", - "request": { "id": "req-1", "message": "Which environment?" } + "request": { + "id": "req-1", + "message": "Which environment?" + } } ] }, @@ -35,15 +38,21 @@ "customizationId": "mcp-1" }, "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "not-needed", "auth": { "reason": "insufficientScope", "resource": { "resource": "https://mcp.example.com", - "authorization_servers": ["https://auth.example.com"] + "authorization_servers": [ + "https://auth.example.com" + ] }, - "requiredScopes": ["repo:read"] + "requiredScopes": [ + "repo:read" + ] } } } @@ -61,7 +70,10 @@ "kind": "chatInput", "id": "copilot:/test-session/chat-1#req-1", "chat": "copilot:/test-session/chat-1", - "request": { "id": "req-1", "message": "Which environment?" } + "request": { + "id": "req-1", + "message": "Which environment?" + } }, { "kind": "toolAuthentication", @@ -78,15 +90,21 @@ "customizationId": "mcp-1" }, "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "not-needed", "auth": { "reason": "insufficientScope", "resource": { "resource": "https://mcp.example.com", - "authorization_servers": ["https://auth.example.com"] + "authorization_servers": [ + "https://auth.example.com" + ] }, - "requiredScopes": ["repo:read"] + "requiredScopes": [ + "repo:read" + ] } } } diff --git a/types/test-cases/reducers/252-session-inputneededremoved-removes-tool-authentication.json b/types/test-cases/reducers/252-session-inputneededremoved-removes-tool-authentication.json index 3b51b8479..b6862ea0a 100644 --- a/types/test-cases/reducers/252-session-inputneededremoved-removes-tool-authentication.json +++ b/types/test-cases/reducers/252-session-inputneededremoved-removes-tool-authentication.json @@ -24,7 +24,9 @@ "customizationId": "mcp-1" }, "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "not-needed", "auth": { "reason": "required", diff --git a/types/test-cases/reducers/253-toolcallcomplete-cancels-auth-required-tool-call.json b/types/test-cases/reducers/253-toolcallcomplete-cancels-auth-required-tool-call.json index 6e6d7e017..37b66b56d 100644 --- a/types/test-cases/reducers/253-toolcallcomplete-cancels-auth-required-tool-call.json +++ b/types/test-cases/reducers/253-toolcallcomplete-cancels-auth-required-tool-call.json @@ -40,7 +40,9 @@ "turnId": "turn-1", "toolCallId": "tc-8", "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmationTitle": "Search repo", "options": [ { @@ -78,7 +80,9 @@ "resource": { "resource": "https://mcp.example.com" }, - "requiredScopes": ["repo:read"] + "requiredScopes": [ + "repo:read" + ] }, "_meta": { "phase": "auth-required" @@ -129,7 +133,9 @@ "phase": "cancelled" }, "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action", "selectedOption": { "id": "opt-1", diff --git a/types/test-cases/reducers/254-toolcallcomplete-ignores-successful-result-from-auth-required.json b/types/test-cases/reducers/254-toolcallcomplete-ignores-successful-result-from-auth-required.json index 74c8a207a..6a2d14865 100644 --- a/types/test-cases/reducers/254-toolcallcomplete-ignores-successful-result-from-auth-required.json +++ b/types/test-cases/reducers/254-toolcallcomplete-ignores-successful-result-from-auth-required.json @@ -40,7 +40,9 @@ "turnId": "turn-1", "toolCallId": "tc-9", "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmationTitle": "Search repo", "options": [ { @@ -78,7 +80,9 @@ "resource": { "resource": "https://mcp.example.com" }, - "requiredScopes": ["repo:read"] + "requiredScopes": [ + "repo:read" + ] }, "_meta": { "phase": "auth-required" @@ -131,7 +135,9 @@ "phase": "auth-required" }, "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action", "selectedOption": { "id": "opt-1", @@ -149,7 +155,9 @@ "resource": { "resource": "https://mcp.example.com" }, - "requiredScopes": ["repo:read"] + "requiredScopes": [ + "repo:read" + ] } } } diff --git a/types/test-cases/reducers/255-toolcallcomplete-ignores-requiresresultconfirmation-when-cancelling-auth-required.json b/types/test-cases/reducers/255-toolcallcomplete-ignores-requiresresultconfirmation-when-cancelling-auth-required.json index c8e1f44dc..d518f65c1 100644 --- a/types/test-cases/reducers/255-toolcallcomplete-ignores-requiresresultconfirmation-when-cancelling-auth-required.json +++ b/types/test-cases/reducers/255-toolcallcomplete-ignores-requiresresultconfirmation-when-cancelling-auth-required.json @@ -40,7 +40,9 @@ "turnId": "turn-1", "toolCallId": "tc-10", "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmationTitle": "Search repo", "options": [ { @@ -78,7 +80,9 @@ "resource": { "resource": "https://mcp.example.com" }, - "requiredScopes": ["repo:read"] + "requiredScopes": [ + "repo:read" + ] }, "_meta": { "phase": "auth-required" @@ -130,7 +134,9 @@ "phase": "cancelled" }, "invocationMessage": "Search: foo", - "toolInput": "foo", + "toolInput": { + "uri": "file:///tool-inputs/tool-input.json" + }, "confirmed": "user-action", "selectedOption": { "id": "opt-1", diff --git a/types/test-cases/reducers/260-edited-tool-input-survives-reconfirmation.json b/types/test-cases/reducers/260-edited-tool-input-survives-reconfirmation.json new file mode 100644 index 000000000..4b58a9e41 --- /dev/null +++ b/types/test-cases/reducers/260-edited-tool-input-survives-reconfirmation.json @@ -0,0 +1,99 @@ +{ + "description": "tool input ref survives re-confirmation after an edited confirmation", + "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": "Run", + "toolInput": { + "uri": "file:///tool-inputs/tc-1.json" + } + }, + { + "type": "chat/toolCallConfirmed", + "turnId": "turn-1", + "toolCallId": "tc-1", + "approved": true, + "confirmed": "user-action", + "editedToolInput": "{\"command\":\"echo edited\"}" + }, + { + "type": "chat/toolCallReady", + "turnId": "turn-1", + "toolCallId": "tc-1", + "invocationMessage": "Additional permission needed" + }, + { + "type": "chat/toolCallConfirmed", + "turnId": "turn-1", + "toolCallId": "tc-1", + "approved": true, + "confirmed": "user-action" + } + ], + "expected": { + "turns": [], + "activeTurn": { + "id": "turn-1", + "startedAt": "1970-01-01T00:00:01.000Z", + "message": { + "text": "Hello", + "origin": { + "kind": "user" + } + }, + "responseParts": [ + { + "kind": "toolCall", + "toolCall": { + "status": "running", + "toolCallId": "tc-1", + "toolName": "bash", + "displayName": "Run Command", + "intention": null, + "toolInput": { + "uri": "file:///tool-inputs/tc-1.json" + }, + "contributor": null, + "_meta": null, + "invocationMessage": "Additional permission needed", + "confirmed": "user-action" + } + } + ], + "usage": null + }, + "resource": "copilot:/test-session", + "title": "Test Session", + "status": 8, + "modifiedAt": "1970-01-01T00:00:02.000Z" + } +} From ce85e8660f729887b37ca67292e828813eaa840c Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Thu, 30 Jul 2026 20:19:06 -0700 Subject: [PATCH 2/6] rust: format tool input changes Apply rustfmt output required by the Rust CI job. (Written by Copilot) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../crates/ahp/src/multi_host_state_mirror.rs | 2 -- clients/rust/crates/ahp/src/reducers.rs | 19 +++++++++---------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/clients/rust/crates/ahp/src/multi_host_state_mirror.rs b/clients/rust/crates/ahp/src/multi_host_state_mirror.rs index b5452714d..7288894b9 100644 --- a/clients/rust/crates/ahp/src/multi_host_state_mirror.rs +++ b/clients/rust/crates/ahp/src/multi_host_state_mirror.rs @@ -135,7 +135,6 @@ impl MultiHostStateMirror { &self.resource_watches } - /// Convenience: apply a [`HostSubscriptionEvent`] produced by /// [`crate::hosts::MultiHostClient::events`]. Action envelopes are /// routed through the reducer; non-action events (session-summary @@ -177,7 +176,6 @@ impl MultiHostStateMirror { } if let Some(terminal) = self.terminals.get_mut(&key) { apply_action_to_terminal(terminal, &envelope.action); - return; } // Changesets are seeded by `apply_snapshot` only — there's no // changeset reducer in the SDK today (matching the Swift diff --git a/clients/rust/crates/ahp/src/reducers.rs b/clients/rust/crates/ahp/src/reducers.rs index f78a7e72c..7756e6a82 100644 --- a/clients/rust/crates/ahp/src/reducers.rs +++ b/clients/rust/crates/ahp/src/reducers.rs @@ -59,15 +59,15 @@ use ahp_types::actions::{ }; use ahp_types::state::{ ActiveTurn, AnnotationsState, ChangesetOperationStatus, ChangesetState, ChangesetStatus, - ChatInputRequest, ChatState, ChildCustomization, ConfirmationOption, ContentRef, Customization, ErrorInfo, - InputRequestResponsePart, McpServerStartingState, McpServerState, McpServerStoppedState, - PendingMessage, PendingMessageKind, ResourceWatchState, ResponsePart, RootState, - SessionInputRequest, SessionLifecycle, SessionState, SessionStatus, TerminalCommandPart, - TerminalContentPart, TerminalState, TerminalUnclassifiedPart, ToolCallAuthRequiredState, - ToolCallCancellationReason, ToolCallCancelledState, ToolCallCompletedState, - ToolCallConfirmationReason, ToolCallContributor, ToolCallPendingConfirmationState, - ToolCallPendingResultConfirmationState, ToolCallResponsePart, ToolCallRunningState, - ToolCallState, ToolCallStatus, ToolCallStreamingState, Turn, TurnState, + ChatInputRequest, ChatState, ChildCustomization, ConfirmationOption, ContentRef, Customization, + ErrorInfo, InputRequestResponsePart, McpServerStartingState, McpServerState, + McpServerStoppedState, PendingMessage, PendingMessageKind, ResourceWatchState, ResponsePart, + RootState, SessionInputRequest, SessionLifecycle, SessionState, SessionStatus, + TerminalCommandPart, TerminalContentPart, TerminalState, TerminalUnclassifiedPart, + ToolCallAuthRequiredState, ToolCallCancellationReason, ToolCallCancelledState, + ToolCallCompletedState, ToolCallConfirmationReason, ToolCallContributor, + ToolCallPendingConfirmationState, ToolCallPendingResultConfirmationState, ToolCallResponsePart, + ToolCallRunningState, ToolCallState, ToolCallStatus, ToolCallStreamingState, Turn, TurnState, }; /// What happened when an action was applied. @@ -1938,7 +1938,6 @@ pub fn apply_action_to_resource_watch( } } - #[cfg(test)] mod tests { use super::*; From 84dc10d70e882f8d0216243dca6a2004b1823361 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 31 Jul 2026 08:17:24 -0700 Subject: [PATCH 3/6] chat: address tool input review feedback Avoid aliasing the Go action payload in reducer state and document the ContentRef nonce field. (Written by Copilot) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- clients/go/ahp/reducers.go | 3 ++- docs/guide/state-model.md | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/clients/go/ahp/reducers.go b/clients/go/ahp/reducers.go index ccd683e50..33b0f4cb2 100644 --- a/clients/go/ahp/reducers.go +++ b/clients/go/ahp/reducers.go @@ -1029,7 +1029,8 @@ func applyToolCallDelta(state *ahptypes.ChatState, a *ahptypes.ChatToolCallDelta if a.Meta != nil { s.Meta = a.Meta } - s.InvocationMessage = &a.InvocationMessage + invocationMessage := a.InvocationMessage + s.InvocationMessage = &invocationMessage return tc }) } diff --git a/docs/guide/state-model.md b/docs/guide/state-model.md index 07aaeb179..c963dc200 100644 --- a/docs/guide/state-model.md +++ b/docs/guide/state-model.md @@ -327,6 +327,7 @@ ContentRef { uri: string sizeHint?: number contentType?: string + nonce?: string // changes when the referenced content changes } // Harness-authored notification surfaced in the stream (e.g. "subagent finished") From f427b9413c8b429b63ee53271f21d872b1c1b295 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 31 Jul 2026 11:10:10 -0700 Subject: [PATCH 4/6] chat: allow inline or referenced tool input Let hosts choose between inline strings and ContentRef values for final tool input, and restore optional partial argument chunks on tool-call deltas. (Written by Copilot) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- clients/go/ahp/reducers.go | 19 ++++- clients/go/ahptypes/actions.generated.go | 6 +- clients/go/ahptypes/state.generated.go | 69 +++++++++++----- .../microsoft/agenthostprotocol/Reducers.kt | 16 +++- .../generated/Actions.generated.kt | 8 +- .../generated/State.generated.kt | 81 ++++++++++++++----- clients/rust/crates/ahp-types/src/actions.rs | 9 ++- clients/rust/crates/ahp-types/src/state.rs | 47 ++++++----- clients/rust/crates/ahp/src/reducers.rs | 30 ++++--- .../swift/AHPApp/AHPApp/Views/ChatView.swift | 8 +- .../AHPApp/Views/ResponsePartView.swift | 42 ++++++---- .../Generated/Actions.generated.swift | 11 ++- .../Generated/State.generated.swift | 78 ++++++++++++------ .../Sources/AgentHostProtocol/Reducers.swift | 13 ++- .../ToolCallStateExtensions.swift | 2 +- .../20260730-tool-input-content-ref.json | 2 +- docs/guide/actions.md | 2 +- docs/guide/customizations.md | 8 +- docs/guide/state-model.md | 11 +-- schema/actions.schema.json | 53 ++++++++---- schema/commands.schema.json | 53 ++++++++---- schema/errors.schema.json | 53 ++++++++---- schema/notifications.schema.json | 43 ++++++---- schema/state.schema.json | 43 ++++++---- scripts/generate-go.ts | 38 +++++++++ scripts/generate-kotlin.ts | 48 +++++++++++ scripts/generate-rust.ts | 17 +++- scripts/generate-swift.ts | 31 +++++++ types/channels-chat/actions.ts | 14 ++-- types/channels-chat/reducer.ts | 8 +- types/channels-chat/state.ts | 15 +++- types/index.ts | 1 + ...olcalldelta-without-invocationmessage.json | 4 +- ...th-editedtoolinput-overrides-original.json | 10 +-- 34 files changed, 657 insertions(+), 236 deletions(-) diff --git a/clients/go/ahp/reducers.go b/clients/go/ahp/reducers.go index 33b0f4cb2..13edef10d 100644 --- a/clients/go/ahp/reducers.go +++ b/clients/go/ahp/reducers.go @@ -91,7 +91,7 @@ type toolCallCommon struct { name string displayName string intention *string - toolInput *ahptypes.ContentRef + toolInput *ahptypes.ToolInput contributor *ahptypes.ToolCallContributor meta ahptypes.JSONObject } @@ -1029,6 +1029,14 @@ func applyToolCallDelta(state *ahptypes.ChatState, a *ahptypes.ChatToolCallDelta if a.Meta != nil { s.Meta = a.Meta } + if a.Content != nil { + partial := "" + if s.PartialInput != nil { + partial = *s.PartialInput + } + partial += *a.Content + s.PartialInput = &partial + } invocationMessage := a.InvocationMessage s.InvocationMessage = &invocationMessage return tc @@ -1148,6 +1156,11 @@ func applyToolCallConfirmed(state *ahptypes.ChatState, a *ahptypes.ChatToolCallC } selected := resolveSelectedOption(s.Options, a.SelectedOptionId) if a.Approved { + toolInput := s.ToolInput + if a.EditedToolInput != nil && toolInput != nil && toolInput.Inline != nil { + inline := *a.EditedToolInput + toolInput = &ahptypes.ToolInput{Inline: &inline} + } meta := s.Meta if a.Meta != nil { meta = a.Meta @@ -1162,7 +1175,7 @@ func applyToolCallConfirmed(state *ahptypes.ChatState, a *ahptypes.ChatToolCallC ToolName: s.ToolName, DisplayName: s.DisplayName, Intention: s.Intention, - ToolInput: s.ToolInput, + ToolInput: toolInput, Contributor: s.Contributor, Meta: meta, InvocationMessage: s.InvocationMessage, @@ -1204,7 +1217,7 @@ func applyToolCallComplete(state *ahptypes.ChatState, a *ahptypes.ChatToolCallCo } var ( invocation ahptypes.StringOrMarkdown - toolInput *ahptypes.ContentRef + toolInput *ahptypes.ToolInput confirmed = ahptypes.ToolCallConfirmationReasonNotNeeded selectedOption *ahptypes.ConfirmationOption preAuthContent []ahptypes.ToolResultContent diff --git a/clients/go/ahptypes/actions.generated.go b/clients/go/ahptypes/actions.generated.go index 2afdba076..96ea6abb5 100644 --- a/clients/go/ahptypes/actions.generated.go +++ b/clients/go/ahptypes/actions.generated.go @@ -318,6 +318,8 @@ type ChatToolCallDeltaAction struct { // contain escape sequences). Meta map[string]json.RawMessage `json:"_meta,omitempty"` Type ActionType `json:"type"` + // Optional partial raw parameter content to append. + Content *string `json:"content,omitempty"` // Updated display-ready progress message InvocationMessage StringOrMarkdown `json:"invocationMessage"` } @@ -356,8 +358,8 @@ type ChatToolCallReadyAction struct { Intention *string `json:"intention,omitempty"` // Message describing what the tool will do or what confirmation is needed InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Reference to the final raw tool input, readable with `resourceRead` - ToolInput *ContentRef `json:"toolInput,omitempty"` + // Final raw tool input, inline or readable with `resourceRead` + ToolInput *ToolInput `json:"toolInput,omitempty"` // Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) ConfirmationTitle *StringOrMarkdown `json:"confirmationTitle,omitempty"` // Risk assessment that informed the confirmation requirement. diff --git a/clients/go/ahptypes/state.generated.go b/clients/go/ahptypes/state.generated.go index 5a12260fe..9c87cbbce 100644 --- a/clients/go/ahptypes/state.generated.go +++ b/clients/go/ahptypes/state.generated.go @@ -1920,6 +1920,8 @@ type ToolCallStreamingState struct { // with the {@link contributor} to serve MCP Apps. Meta map[string]json.RawMessage `json:"_meta,omitempty"` Status ToolCallStatus `json:"status"` + // Partial raw parameters accumulated from optional tool-call deltas. + PartialInput *string `json:"partialInput,omitempty"` // Progress message shown while parameters are streaming InvocationMessage *StringOrMarkdown `json:"invocationMessage,omitempty"` } @@ -1945,13 +1947,13 @@ type ToolCallPendingConfirmationState struct { Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Message describing what the tool will do InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Reference to the final raw tool input, readable with `resourceRead`. + // Final raw tool input, either inline or readable with `resourceRead`. // - // The referenced resource is mutable until the tool call leaves + // Referenced input is mutable until the tool call leaves // `pending-confirmation`. When the client confirms with `editedToolInput`, // the host MUST replace the resource contents before echoing the accepted // confirmation action. Clients MUST NOT cache tool input across confirmation. - ToolInput *ContentRef `json:"toolInput,omitempty"` + ToolInput *ToolInput `json:"toolInput,omitempty"` Status ToolCallStatus `json:"status"` // Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) ConfirmationTitle *StringOrMarkdown `json:"confirmationTitle,omitempty"` @@ -1988,13 +1990,13 @@ type ToolCallRunningState struct { Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Message describing what the tool will do InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Reference to the final raw tool input, readable with `resourceRead`. + // Final raw tool input, either inline or readable with `resourceRead`. // - // The referenced resource is mutable until the tool call leaves + // Referenced input is mutable until the tool call leaves // `pending-confirmation`. When the client confirms with `editedToolInput`, // the host MUST replace the resource contents before echoing the accepted // confirmation action. Clients MUST NOT cache tool input across confirmation. - ToolInput *ContentRef `json:"toolInput,omitempty"` + ToolInput *ToolInput `json:"toolInput,omitempty"` // How the tool was confirmed for execution Confirmed ToolCallConfirmationReason `json:"confirmed"` // The confirmation option the user selected, if confirmation options were provided @@ -2053,13 +2055,13 @@ type ToolCallAuthRequiredState struct { Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Message describing what the tool will do InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Reference to the final raw tool input, readable with `resourceRead`. + // Final raw tool input, either inline or readable with `resourceRead`. // - // The referenced resource is mutable until the tool call leaves + // Referenced input is mutable until the tool call leaves // `pending-confirmation`. When the client confirms with `editedToolInput`, // the host MUST replace the resource contents before echoing the accepted // confirmation action. Clients MUST NOT cache tool input across confirmation. - ToolInput *ContentRef `json:"toolInput,omitempty"` + ToolInput *ToolInput `json:"toolInput,omitempty"` // How the tool was confirmed for execution Confirmed ToolCallConfirmationReason `json:"confirmed"` // The confirmation option the user selected, if confirmation options were provided @@ -2091,13 +2093,13 @@ type ToolCallPendingResultConfirmationState struct { Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Message describing what the tool will do InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Reference to the final raw tool input, readable with `resourceRead`. + // Final raw tool input, either inline or readable with `resourceRead`. // - // The referenced resource is mutable until the tool call leaves + // Referenced input is mutable until the tool call leaves // `pending-confirmation`. When the client confirms with `editedToolInput`, // the host MUST replace the resource contents before echoing the accepted // confirmation action. Clients MUST NOT cache tool input across confirmation. - ToolInput *ContentRef `json:"toolInput,omitempty"` + ToolInput *ToolInput `json:"toolInput,omitempty"` // Whether the tool succeeded Success bool `json:"success"` // Past-tense description of what the tool did @@ -2139,13 +2141,13 @@ type ToolCallCompletedState struct { Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Message describing what the tool will do InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Reference to the final raw tool input, readable with `resourceRead`. + // Final raw tool input, either inline or readable with `resourceRead`. // - // The referenced resource is mutable until the tool call leaves + // Referenced input is mutable until the tool call leaves // `pending-confirmation`. When the client confirms with `editedToolInput`, // the host MUST replace the resource contents before echoing the accepted // confirmation action. Clients MUST NOT cache tool input across confirmation. - ToolInput *ContentRef `json:"toolInput,omitempty"` + ToolInput *ToolInput `json:"toolInput,omitempty"` // Whether the tool succeeded Success bool `json:"success"` // Past-tense description of what the tool did @@ -2187,13 +2189,13 @@ type ToolCallCancelledState struct { Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Message describing what the tool will do InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Reference to the final raw tool input, readable with `resourceRead`. + // Final raw tool input, either inline or readable with `resourceRead`. // - // The referenced resource is mutable until the tool call leaves + // Referenced input is mutable until the tool call leaves // `pending-confirmation`. When the client confirms with `editedToolInput`, // the host MUST replace the resource contents before echoing the accepted // confirmation action. Clients MUST NOT cache tool input across confirmation. - ToolInput *ContentRef `json:"toolInput,omitempty"` + ToolInput *ToolInput `json:"toolInput,omitempty"` Status ToolCallStatus `json:"status"` // Why the tool was cancelled Reason ToolCallCancellationReason `json:"reason"` @@ -3547,6 +3549,37 @@ type ResourceChange struct { Type ResourceChangeType `json:"type"` } +// ToolInput is raw tool input represented inline or by content reference. +type ToolInput struct { + Inline *string + ContentRef *ContentRef +} + +func (t ToolInput) MarshalJSON() ([]byte, error) { + if t.Inline != nil { + return json.Marshal(*t.Inline) + } + if t.ContentRef != nil { + return json.Marshal(t.ContentRef) + } + return []byte("null"), nil +} + +func (t *ToolInput) UnmarshalJSON(data []byte) error { + *t = ToolInput{} + var inline string + if err := json.Unmarshal(data, &inline); err == nil { + t.Inline = &inline + return nil + } + var ref ContentRef + if err := json.Unmarshal(data, &ref); err != nil { + return err + } + t.ContentRef = &ref + return nil +} + // ─── Discriminated Unions ───────────────────────────────────────────── // ResponsePart is a single part of a response stream (text, tool call, reasoning, content reference). 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 09844f447..cf71b5722 100644 --- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt +++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt @@ -166,7 +166,7 @@ private data class ToolCallBase( val toolName: String, val displayName: String, val intention: String?, - val toolInput: ContentRef?, + val toolInput: ToolInput?, val contributor: ToolCallContributor?, val meta: Map?, ) { @@ -928,6 +928,8 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when ToolCallStateStreaming( tc.value.copy( meta = a.meta ?: tc.value.meta, + partialInput = a.content?.let { (tc.value.partialInput ?: "") + it } + ?: tc.value.partialInput, invocationMessage = a.invocationMessage, ), ) @@ -1001,13 +1003,21 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when val base = toolCallBase(tc).withMeta(a.meta) val selectedOption = resolveSelectedOption(tc.value.options, a.selectedOptionId) if (a.approved) { + val toolInput = if ( + a.editedToolInput != null + && tc.value.toolInput is ToolInput.Inline + ) { + ToolInput.Inline(a.editedToolInput) + } else { + tc.value.toolInput + } ToolCallStateRunning( ToolCallRunningState( toolCallId = base.toolCallId, toolName = base.toolName, displayName = base.displayName, intention = base.intention, - toolInput = tc.value.toolInput, + toolInput = toolInput, contributor = base.contributor, meta = base.meta, invocationMessage = tc.value.invocationMessage, @@ -1444,7 +1454,7 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when */ private data class CompleteCtx( val invocationMessage: com.microsoft.agenthostprotocol.generated.StringOrMarkdown, - val toolInput: ContentRef?, + val toolInput: ToolInput?, val confirmed: ToolCallConfirmationReason, val selectedOption: ConfirmationOption?, val preAuthContent: List?, 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 2aa91f257..fd7fb5113 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 @@ -440,6 +440,10 @@ data class ChatToolCallDeltaAction( @SerialName("_meta") val meta: Map? = null, val type: ActionType, + /** + * Optional partial raw parameter content to append. + */ + val content: String? = null, /** * Updated display-ready progress message */ @@ -482,9 +486,9 @@ data class ChatToolCallReadyAction( */ val invocationMessage: StringOrMarkdown, /** - * Reference to the final raw tool input, readable with `resourceRead` + * Final raw tool input, inline or readable with `resourceRead` */ - val toolInput: ContentRef? = null, + val toolInput: ToolInput? = null, /** * Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) */ 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 15f40a71f..90bd79f34 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 @@ -2568,6 +2568,10 @@ data class ToolCallStreamingState( @SerialName("_meta") val meta: Map? = null, val status: ToolCallStatus, + /** + * Partial raw parameters accumulated from optional tool-call deltas. + */ + val partialInput: String? = null, /** * Progress message shown while parameters are streaming */ @@ -2610,14 +2614,14 @@ data class ToolCallPendingConfirmationState( */ val invocationMessage: StringOrMarkdown, /** - * Reference to the final raw tool input, readable with `resourceRead`. + * Final raw tool input, either inline or readable with `resourceRead`. * - * The referenced resource is mutable until the tool call leaves + * Referenced input is mutable until the tool call leaves * `pending-confirmation`. When the client confirms with `editedToolInput`, * the host MUST replace the resource contents before echoing the accepted * confirmation action. Clients MUST NOT cache tool input across confirmation. */ - val toolInput: ContentRef? = null, + val toolInput: ToolInput? = null, val status: ToolCallStatus, /** * Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) @@ -2680,14 +2684,14 @@ data class ToolCallRunningState( */ val invocationMessage: StringOrMarkdown, /** - * Reference to the final raw tool input, readable with `resourceRead`. + * Final raw tool input, either inline or readable with `resourceRead`. * - * The referenced resource is mutable until the tool call leaves + * Referenced input is mutable until the tool call leaves * `pending-confirmation`. When the client confirms with `editedToolInput`, * the host MUST replace the resource contents before echoing the accepted * confirmation action. Clients MUST NOT cache tool input across confirmation. */ - val toolInput: ContentRef? = null, + val toolInput: ToolInput? = null, /** * How the tool was confirmed for execution */ @@ -2742,14 +2746,14 @@ data class ToolCallAuthRequiredState( */ val invocationMessage: StringOrMarkdown, /** - * Reference to the final raw tool input, readable with `resourceRead`. + * Final raw tool input, either inline or readable with `resourceRead`. * - * The referenced resource is mutable until the tool call leaves + * Referenced input is mutable until the tool call leaves * `pending-confirmation`. When the client confirms with `editedToolInput`, * the host MUST replace the resource contents before echoing the accepted * confirmation action. Clients MUST NOT cache tool input across confirmation. */ - val toolInput: ContentRef? = null, + val toolInput: ToolInput? = null, /** * How the tool was confirmed for execution */ @@ -2805,14 +2809,14 @@ data class ToolCallPendingResultConfirmationState( */ val invocationMessage: StringOrMarkdown, /** - * Reference to the final raw tool input, readable with `resourceRead`. + * Final raw tool input, either inline or readable with `resourceRead`. * - * The referenced resource is mutable until the tool call leaves + * Referenced input is mutable until the tool call leaves * `pending-confirmation`. When the client confirms with `editedToolInput`, * the host MUST replace the resource contents before echoing the accepted * confirmation action. Clients MUST NOT cache tool input across confirmation. */ - val toolInput: ContentRef? = null, + val toolInput: ToolInput? = null, /** * Whether the tool succeeded */ @@ -2884,14 +2888,14 @@ data class ToolCallCompletedState( */ val invocationMessage: StringOrMarkdown, /** - * Reference to the final raw tool input, readable with `resourceRead`. + * Final raw tool input, either inline or readable with `resourceRead`. * - * The referenced resource is mutable until the tool call leaves + * Referenced input is mutable until the tool call leaves * `pending-confirmation`. When the client confirms with `editedToolInput`, * the host MUST replace the resource contents before echoing the accepted * confirmation action. Clients MUST NOT cache tool input across confirmation. */ - val toolInput: ContentRef? = null, + val toolInput: ToolInput? = null, /** * Whether the tool succeeded */ @@ -2963,14 +2967,14 @@ data class ToolCallCancelledState( */ val invocationMessage: StringOrMarkdown, /** - * Reference to the final raw tool input, readable with `resourceRead`. + * Final raw tool input, either inline or readable with `resourceRead`. * - * The referenced resource is mutable until the tool call leaves + * Referenced input is mutable until the tool call leaves * `pending-confirmation`. When the client confirms with `editedToolInput`, * the host MUST replace the resource contents before echoing the accepted * confirmation action. Clients MUST NOT cache tool input across confirmation. */ - val toolInput: ContentRef? = null, + val toolInput: ToolInput? = null, val status: ToolCallStatus, /** * Why the tool was cancelled @@ -4655,6 +4659,47 @@ data class ResourceChange( val type: ResourceChangeType ) +// ─── Tool Input ────────────────────────────────────────────────────────────── + +/** + * Raw tool input represented inline or by content reference. + */ +@Serializable(with = ToolInputSerializer::class) +sealed interface ToolInput { + @JvmInline value class Inline(val value: String) : ToolInput + @JvmInline value class ContentReference(val value: ContentRef) : ToolInput +} + +internal object ToolInputSerializer : KSerializer { + override val descriptor: SerialDescriptor = + buildClassSerialDescriptor("ToolInput") + + override fun deserialize(decoder: Decoder): ToolInput { + val input = decoder as? JsonDecoder + ?: error("ToolInput can only be deserialized from JSON") + return when (val element = input.decodeJsonElement()) { + is JsonPrimitive -> ToolInput.Inline( + element.contentOrNull ?: error("ToolInput string must not be null"), + ) + is JsonObject -> ToolInput.ContentReference( + input.json.decodeFromJsonElement(ContentRef.serializer(), element), + ) + else -> error("ToolInput must be a string or ContentRef object") + } + } + + override fun serialize(encoder: Encoder, value: ToolInput) { + val output = encoder as? JsonEncoder + ?: error("ToolInput can only be serialized to JSON") + val element = when (value) { + is ToolInput.Inline -> JsonPrimitive(value.value) + is ToolInput.ContentReference -> + output.json.encodeToJsonElement(ContentRef.serializer(), value.value) + } + output.encodeJsonElement(element) + } +} + // ─── Discriminated Unions ─────────────────────────────────────────────────── @Serializable(with = ChatOriginSerializer::class) diff --git a/clients/rust/crates/ahp-types/src/actions.rs b/clients/rust/crates/ahp-types/src/actions.rs index b8d3cc954..5da76ec60 100644 --- a/clients/rust/crates/ahp-types/src/actions.rs +++ b/clients/rust/crates/ahp-types/src/actions.rs @@ -20,7 +20,7 @@ use crate::state::{ Message, ModelSelection, PendingMessageKind, ResponsePart, SessionActiveClient, SessionInputRequest, SideChatSelection, TerminalClaim, TerminalInfo, TextRange, ToolCallCancellationReason, ToolCallConfirmationReason, ToolCallContributor, ToolCallResult, - ToolCallRiskAssessment, ToolDefinition, ToolResultContent, Turn, UsageInfo, + ToolCallRiskAssessment, ToolDefinition, ToolInput, ToolResultContent, Turn, UsageInfo, }; // ─── ActionType ────────────────────────────────────────────────────── @@ -446,6 +446,9 @@ pub struct ChatToolCallDeltaAction { /// contain escape sequences). #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")] pub meta: Option, + /// Optional partial raw parameter content to append. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub content: Option, /// Updated display-ready progress message pub invocation_message: StringOrMarkdown, } @@ -488,9 +491,9 @@ pub struct ChatToolCallReadyAction { pub intention: Option, /// Message describing what the tool will do or what confirmation is needed pub invocation_message: StringOrMarkdown, - /// Reference to the final raw tool input, readable with `resourceRead` + /// Final raw tool input, inline or readable with `resourceRead` #[serde(default, skip_serializing_if = "Option::is_none")] - pub tool_input: Option, + pub tool_input: Option, /// 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, diff --git a/clients/rust/crates/ahp-types/src/state.rs b/clients/rust/crates/ahp-types/src/state.rs index 27daf08d9..261c9a9ce 100644 --- a/clients/rust/crates/ahp-types/src/state.rs +++ b/clients/rust/crates/ahp-types/src/state.rs @@ -2361,6 +2361,9 @@ pub struct ToolCallStreamingState { /// with the {@link contributor} to serve MCP Apps. #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")] pub meta: Option, + /// Partial raw parameters accumulated from optional tool-call deltas. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub partial_input: Option, /// Progress message shown while parameters are streaming #[serde(default, skip_serializing_if = "Option::is_none")] pub invocation_message: Option, @@ -2392,14 +2395,14 @@ pub struct ToolCallPendingConfirmationState { pub meta: Option, /// Message describing what the tool will do pub invocation_message: StringOrMarkdown, - /// Reference to the final raw tool input, readable with `resourceRead`. + /// Final raw tool input, either inline or readable with `resourceRead`. /// - /// The referenced resource is mutable until the tool call leaves + /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, /// the host MUST replace the resource contents before echoing the accepted /// confirmation action. Clients MUST NOT cache tool input across confirmation. #[serde(default, skip_serializing_if = "Option::is_none")] - pub tool_input: Option, + pub tool_input: Option, /// 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, @@ -2445,14 +2448,14 @@ pub struct ToolCallRunningState { pub meta: Option, /// Message describing what the tool will do pub invocation_message: StringOrMarkdown, - /// Reference to the final raw tool input, readable with `resourceRead`. + /// Final raw tool input, either inline or readable with `resourceRead`. /// - /// The referenced resource is mutable until the tool call leaves + /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, /// the host MUST replace the resource contents before echoing the accepted /// confirmation action. Clients MUST NOT cache tool input across confirmation. #[serde(default, skip_serializing_if = "Option::is_none")] - pub tool_input: Option, + pub tool_input: Option, /// How the tool was confirmed for execution pub confirmed: ToolCallConfirmationReason, /// The confirmation option the user selected, if confirmation options were provided @@ -2517,14 +2520,14 @@ pub struct ToolCallAuthRequiredState { pub meta: Option, /// Message describing what the tool will do pub invocation_message: StringOrMarkdown, - /// Reference to the final raw tool input, readable with `resourceRead`. + /// Final raw tool input, either inline or readable with `resourceRead`. /// - /// The referenced resource is mutable until the tool call leaves + /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, /// the host MUST replace the resource contents before echoing the accepted /// confirmation action. Clients MUST NOT cache tool input across confirmation. #[serde(default, skip_serializing_if = "Option::is_none")] - pub tool_input: Option, + pub tool_input: Option, /// How the tool was confirmed for execution pub confirmed: ToolCallConfirmationReason, /// The confirmation option the user selected, if confirmation options were provided @@ -2563,14 +2566,14 @@ pub struct ToolCallPendingResultConfirmationState { pub meta: Option, /// Message describing what the tool will do pub invocation_message: StringOrMarkdown, - /// Reference to the final raw tool input, readable with `resourceRead`. + /// Final raw tool input, either inline or readable with `resourceRead`. /// - /// The referenced resource is mutable until the tool call leaves + /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, /// the host MUST replace the resource contents before echoing the accepted /// confirmation action. Clients MUST NOT cache tool input across confirmation. #[serde(default, skip_serializing_if = "Option::is_none")] - pub tool_input: Option, + pub tool_input: Option, /// Whether the tool succeeded pub success: bool, /// Past-tense description of what the tool did @@ -2620,14 +2623,14 @@ pub struct ToolCallCompletedState { pub meta: Option, /// Message describing what the tool will do pub invocation_message: StringOrMarkdown, - /// Reference to the final raw tool input, readable with `resourceRead`. + /// Final raw tool input, either inline or readable with `resourceRead`. /// - /// The referenced resource is mutable until the tool call leaves + /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, /// the host MUST replace the resource contents before echoing the accepted /// confirmation action. Clients MUST NOT cache tool input across confirmation. #[serde(default, skip_serializing_if = "Option::is_none")] - pub tool_input: Option, + pub tool_input: Option, /// Whether the tool succeeded pub success: bool, /// Past-tense description of what the tool did @@ -2677,14 +2680,14 @@ pub struct ToolCallCancelledState { pub meta: Option, /// Message describing what the tool will do pub invocation_message: StringOrMarkdown, - /// Reference to the final raw tool input, readable with `resourceRead`. + /// Final raw tool input, either inline or readable with `resourceRead`. /// - /// The referenced resource is mutable until the tool call leaves + /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, /// the host MUST replace the resource contents before echoing the accepted /// confirmation action. Clients MUST NOT cache tool input across confirmation. #[serde(default, skip_serializing_if = "Option::is_none")] - pub tool_input: Option, + pub tool_input: Option, /// Why the tool was cancelled pub reason: ToolCallCancellationReason, /// Optional message explaining the cancellation @@ -4247,6 +4250,14 @@ pub struct ResourceChange { pub r#type: ResourceChangeType, } +/// Raw tool input represented inline or by content reference. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum ToolInput { + Inline(String), + ContentRef(ContentRef), +} + // ─── Discriminated Unions ───────────────────────────────────────────── /// How a chat came into existence. diff --git a/clients/rust/crates/ahp/src/reducers.rs b/clients/rust/crates/ahp/src/reducers.rs index 7756e6a82..e82bb484a 100644 --- a/clients/rust/crates/ahp/src/reducers.rs +++ b/clients/rust/crates/ahp/src/reducers.rs @@ -59,15 +59,15 @@ use ahp_types::actions::{ }; use ahp_types::state::{ ActiveTurn, AnnotationsState, ChangesetOperationStatus, ChangesetState, ChangesetStatus, - ChatInputRequest, ChatState, ChildCustomization, ConfirmationOption, ContentRef, Customization, - ErrorInfo, InputRequestResponsePart, McpServerStartingState, McpServerState, - McpServerStoppedState, PendingMessage, PendingMessageKind, ResourceWatchState, ResponsePart, - RootState, SessionInputRequest, SessionLifecycle, SessionState, SessionStatus, - TerminalCommandPart, TerminalContentPart, TerminalState, TerminalUnclassifiedPart, - ToolCallAuthRequiredState, ToolCallCancellationReason, ToolCallCancelledState, - ToolCallCompletedState, ToolCallConfirmationReason, ToolCallContributor, - ToolCallPendingConfirmationState, ToolCallPendingResultConfirmationState, ToolCallResponsePart, - ToolCallRunningState, ToolCallState, ToolCallStatus, ToolCallStreamingState, Turn, TurnState, + ChatInputRequest, ChatState, ChildCustomization, ConfirmationOption, Customization, ErrorInfo, + InputRequestResponsePart, McpServerStartingState, McpServerState, McpServerStoppedState, + PendingMessage, PendingMessageKind, ResourceWatchState, ResponsePart, RootState, + SessionInputRequest, SessionLifecycle, SessionState, SessionStatus, TerminalCommandPart, + TerminalContentPart, TerminalState, TerminalUnclassifiedPart, ToolCallAuthRequiredState, + ToolCallCancellationReason, ToolCallCancelledState, ToolCallCompletedState, + ToolCallConfirmationReason, ToolCallContributor, ToolCallPendingConfirmationState, + ToolCallPendingResultConfirmationState, ToolCallResponsePart, ToolCallRunningState, + ToolCallState, ToolCallStatus, ToolCallStreamingState, ToolInput, Turn, TurnState, }; /// What happened when an action was applied. @@ -133,7 +133,7 @@ struct ToolCallBase { tool_name: String, display_name: String, intention: Option, - tool_input: Option, + tool_input: Option, contributor: Option, meta: Option>, } @@ -1022,6 +1022,7 @@ pub fn apply_action_to_chat(state: &mut ChatState, action: &StateAction) -> Redu intention: a.intention.clone(), contributor: a.contributor.clone(), meta: a.meta.clone(), + partial_input: None, invocation_message: None, }), }))); @@ -1239,6 +1240,11 @@ fn apply_turn_started(state: &mut ChatState, a: &ChatTurnStartedAction) -> Reduc fn apply_tool_call_delta(state: &mut ChatState, a: &ChatToolCallDeltaAction) -> ReduceOutcome { update_tool_call(state, &a.turn_id, &a.tool_call_id, |tc| match tc { ToolCallState::Streaming(mut s) => { + if let Some(content) = &a.content { + let mut partial = s.partial_input.unwrap_or_default(); + partial.push_str(content); + s.partial_input = Some(partial); + } if let Some(meta) = &a.meta { s.meta = Some(meta.clone()); } @@ -1342,6 +1348,10 @@ fn apply_tool_call_confirmed( let invocation_message = s.invocation_message; let tool_input = s.tool_input; if a.approved { + let tool_input = match (a.edited_tool_input.clone(), tool_input) { + (Some(edited), Some(ToolInput::Inline(_))) => Some(ToolInput::Inline(edited)), + (_, tool_input) => tool_input, + }; ToolCallState::Running(ToolCallRunningState { tool_call_id, tool_name, diff --git a/clients/swift/AHPApp/AHPApp/Views/ChatView.swift b/clients/swift/AHPApp/AHPApp/Views/ChatView.swift index 72e5937d7..060e4b9b1 100644 --- a/clients/swift/AHPApp/AHPApp/Views/ChatView.swift +++ b/clients/swift/AHPApp/AHPApp/Views/ChatView.swift @@ -1128,7 +1128,7 @@ private struct InputBarPreviewWrapper: View { toolName: "readFile", displayName: "Read file", invocationMessage: .string("Reading src/auth.swift"), - toolInput: ContentRef(uri: "file:///tool-inputs/tc1.json"), + toolInput: .contentRef(ContentRef(uri: "file:///tool-inputs/tc1.json")), success: true, pastTenseMessage: .string("Read src/auth.swift"), status: .completed, @@ -1139,7 +1139,7 @@ private struct InputBarPreviewWrapper: View { toolName: "editFile", displayName: "Edit file", invocationMessage: .string("Editing src/auth.swift"), - toolInput: ContentRef(uri: "file:///tool-inputs/tc2.json"), + toolInput: .contentRef(ContentRef(uri: "file:///tool-inputs/tc2.json")), success: true, pastTenseMessage: .string("Edited src/auth.swift"), status: .completed, @@ -1161,7 +1161,7 @@ private struct InputBarPreviewWrapper: View { toolName: "bash", displayName: "Run command", invocationMessage: .string("Run: npm run deploy --production"), - toolInput: ContentRef(uri: "file:///tool-inputs/tc3.json"), + toolInput: .inline("{\"command\": \"npm run deploy --production\"}"), status: .pendingConfirmation, confirmationTitle: .string("Allow production deployment?") ))) @@ -1176,7 +1176,7 @@ private struct InputBarPreviewWrapper: View { toolName: "readFile", displayName: "Read file", invocationMessage: .string("Reading src/auth/token.swift"), - toolInput: ContentRef(uri: "file:///tool-inputs/tc4.json"), + toolInput: .contentRef(ContentRef(uri: "file:///tool-inputs/tc4.json")), status: .running, confirmed: .notNeeded ))) diff --git a/clients/swift/AHPApp/AHPApp/Views/ResponsePartView.swift b/clients/swift/AHPApp/AHPApp/Views/ResponsePartView.swift index 3440ee227..fd59358dd 100644 --- a/clients/swift/AHPApp/AHPApp/Views/ResponsePartView.swift +++ b/clients/swift/AHPApp/AHPApp/Views/ResponsePartView.swift @@ -2,6 +2,14 @@ import AgentHostProtocol import SwiftUI import UIKit +private func toolInputText(_ input: ToolInput?) -> String? { + switch input { + case .inline(let value): return value + case .contentRef(let ref): return ref.uri + case nil: return nil + } +} + /// Renders a single response part: markdown text, reasoning, tool call, or content ref. struct ResponsePartView: View { let part: ResponsePart @@ -439,11 +447,11 @@ struct ToolCallPartView: View { private var toolInput: String? { switch toolCall { - case .pendingConfirmation(let s): return s.toolInput?.uri - case .running(let s): return s.toolInput?.uri - case .pendingResultConfirmation(let s): return s.toolInput?.uri - case .completed(let s): return s.toolInput?.uri - case .cancelled(let s): return s.toolInput?.uri + case .pendingConfirmation(let s): return toolInputText(s.toolInput) + case .running(let s): return toolInputText(s.toolInput) + case .pendingResultConfirmation(let s): return toolInputText(s.toolInput) + case .completed(let s): return toolInputText(s.toolInput) + case .cancelled(let s): return toolInputText(s.toolInput) default: return nil } } @@ -576,11 +584,11 @@ struct ToolCallDetailSheet: View { private var toolInput: String? { switch toolCall { - case .pendingConfirmation(let s): return s.toolInput?.uri - case .running(let s): return s.toolInput?.uri - case .pendingResultConfirmation(let s): return s.toolInput?.uri - case .completed(let s): return s.toolInput?.uri - case .cancelled(let s): return s.toolInput?.uri + case .pendingConfirmation(let s): return toolInputText(s.toolInput) + case .running(let s): return toolInputText(s.toolInput) + case .pendingResultConfirmation(let s): return toolInputText(s.toolInput) + case .completed(let s): return toolInputText(s.toolInput) + case .cancelled(let s): return toolInputText(s.toolInput) default: return nil } } @@ -796,7 +804,7 @@ struct ContentRefView: View { toolCallId: "tc0", toolName: "editFile", displayName: "Edit file", - toolInput: ContentRef(uri: "file:///tool-inputs/tc0.json"), + toolInput: .contentRef(ContentRef(uri: "file:///tool-inputs/tc0.json")), status: .streaming, invocationMessage: .string("Editing src/main.ts") ))) @@ -808,7 +816,7 @@ struct ContentRefView: View { toolName: "bash", displayName: "Run command", invocationMessage: .string("Run: npm run deploy"), - toolInput: ContentRef(uri: "file:///tool-inputs/tc0b.json"), + toolInput: .inline("{\"command\": \"npm run deploy\"}"), status: .pendingConfirmation, confirmationTitle: .string("Allow deployment?") ))) @@ -820,7 +828,7 @@ struct ContentRefView: View { toolName: "bash", displayName: "Run command", invocationMessage: .string("Running: npm test"), - toolInput: ContentRef(uri: "file:///tool-inputs/tc1.json"), + toolInput: .inline("{\"command\": \"npm test\"}"), status: .running, confirmed: .notNeeded ))) @@ -832,7 +840,7 @@ struct ContentRefView: View { toolName: "readFile", displayName: "Read file", invocationMessage: .string("Reading package.json"), - toolInput: ContentRef(uri: "file:///tool-inputs/tc2.json"), + toolInput: .contentRef(ContentRef(uri: "file:///tool-inputs/tc2.json")), success: true, pastTenseMessage: .string("Read package.json"), content: [.text(ToolResultTextContent(type: .text, text: "{\"name\": \"my-app\"}"))], @@ -847,7 +855,7 @@ struct ContentRefView: View { toolName: "bash", displayName: "Run command", invocationMessage: .string("Running: rm -rf /"), - toolInput: ContentRef(uri: "file:///tool-inputs/tc3.json"), + toolInput: .inline("{\"command\": \"rm -rf /\"}"), success: false, pastTenseMessage: .string("Command failed"), status: .completed, @@ -861,7 +869,7 @@ struct ContentRefView: View { toolName: "writeFile", displayName: "Write file", invocationMessage: .string("Writing config.json"), - toolInput: ContentRef(uri: "file:///tool-inputs/tc4.json"), + toolInput: .contentRef(ContentRef(uri: "file:///tool-inputs/tc4.json")), success: true, pastTenseMessage: .string("Wrote config.json"), content: [.text(ToolResultTextContent(type: .text, text: "File written successfully"))], @@ -876,7 +884,7 @@ struct ContentRefView: View { toolName: "bash", displayName: "Run command", invocationMessage: .string("Running: git push --force"), - toolInput: ContentRef(uri: "file:///tool-inputs/tc5.json"), + toolInput: .inline("{\"command\": \"git push --force\"}"), status: .cancelled, reason: .denied, reasonMessage: .string("User denied force push") diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift index 21bc65b6e..8e5b36ce2 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift @@ -436,6 +436,8 @@ public struct ChatToolCallDeltaAction: Codable, Sendable { /// contain escape sequences). public var meta: [String: AnyCodable]? public var type: ActionType + /// Optional partial raw parameter content to append. + public var content: String? /// Updated display-ready progress message public var invocationMessage: StringOrMarkdown @@ -444,6 +446,7 @@ public struct ChatToolCallDeltaAction: Codable, Sendable { case toolCallId case meta = "_meta" case type + case content case invocationMessage } @@ -452,12 +455,14 @@ public struct ChatToolCallDeltaAction: Codable, Sendable { toolCallId: String, meta: [String: AnyCodable]? = nil, type: ActionType, + content: String? = nil, invocationMessage: StringOrMarkdown ) { self.turnId = turnId self.toolCallId = toolCallId self.meta = meta self.type = type + self.content = content self.invocationMessage = invocationMessage } } @@ -483,8 +488,8 @@ public struct ChatToolCallReadyAction: Codable, Sendable { public var intention: String? /// Message describing what the tool will do or what confirmation is needed public var invocationMessage: StringOrMarkdown - /// Reference to the final raw tool input, readable with `resourceRead` - public var toolInput: ContentRef? + /// Final raw tool input, inline or readable with `resourceRead` + public var toolInput: ToolInput? /// Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) public var confirmationTitle: StringOrMarkdown? /// Risk assessment that informed the confirmation requirement. @@ -526,7 +531,7 @@ public struct ChatToolCallReadyAction: Codable, Sendable { contributor: ToolCallContributor? = nil, intention: String? = nil, invocationMessage: StringOrMarkdown, - toolInput: ContentRef? = nil, + toolInput: ToolInput? = nil, confirmationTitle: StringOrMarkdown? = nil, riskAssessment: ToolCallRiskAssessment? = nil, edits: AnyCodable? = nil, diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift index 6465f9969..24188d7d2 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift @@ -2576,6 +2576,8 @@ public struct ToolCallStreamingState: Codable, Sendable { /// with the {@link contributor} to serve MCP Apps. public var meta: [String: AnyCodable]? public var status: ToolCallStatus + /// Partial raw parameters accumulated from optional tool-call deltas. + public var partialInput: String? /// Progress message shown while parameters are streaming public var invocationMessage: StringOrMarkdown? @@ -2587,6 +2589,7 @@ public struct ToolCallStreamingState: Codable, Sendable { case contributor case meta = "_meta" case status + case partialInput case invocationMessage } @@ -2598,6 +2601,7 @@ public struct ToolCallStreamingState: Codable, Sendable { contributor: ToolCallContributor? = nil, meta: [String: AnyCodable]? = nil, status: ToolCallStatus, + partialInput: String? = nil, invocationMessage: StringOrMarkdown? = nil ) { self.toolCallId = toolCallId @@ -2607,6 +2611,7 @@ public struct ToolCallStreamingState: Codable, Sendable { self.contributor = contributor self.meta = meta self.status = status + self.partialInput = partialInput self.invocationMessage = invocationMessage } } @@ -2630,13 +2635,13 @@ public struct ToolCallPendingConfirmationState: Codable, Sendable { public var meta: [String: AnyCodable]? /// Message describing what the tool will do public var invocationMessage: StringOrMarkdown - /// Reference to the final raw tool input, readable with `resourceRead`. + /// Final raw tool input, either inline or readable with `resourceRead`. /// - /// The referenced resource is mutable until the tool call leaves + /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, /// the host MUST replace the resource contents before echoing the accepted /// confirmation action. Clients MUST NOT cache tool input across confirmation. - public var toolInput: ContentRef? + public var toolInput: ToolInput? public var status: ToolCallStatus /// Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) public var confirmationTitle: StringOrMarkdown? @@ -2677,7 +2682,7 @@ public struct ToolCallPendingConfirmationState: Codable, Sendable { contributor: ToolCallContributor? = nil, meta: [String: AnyCodable]? = nil, invocationMessage: StringOrMarkdown, - toolInput: ContentRef? = nil, + toolInput: ToolInput? = nil, status: ToolCallStatus, confirmationTitle: StringOrMarkdown? = nil, riskAssessment: ToolCallRiskAssessment? = nil, @@ -2721,13 +2726,13 @@ public struct ToolCallRunningState: Codable, Sendable { public var meta: [String: AnyCodable]? /// Message describing what the tool will do public var invocationMessage: StringOrMarkdown - /// Reference to the final raw tool input, readable with `resourceRead`. + /// Final raw tool input, either inline or readable with `resourceRead`. /// - /// The referenced resource is mutable until the tool call leaves + /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, /// the host MUST replace the resource contents before echoing the accepted /// confirmation action. Clients MUST NOT cache tool input across confirmation. - public var toolInput: ContentRef? + public var toolInput: ToolInput? /// How the tool was confirmed for execution public var confirmed: ToolCallConfirmationReason /// The confirmation option the user selected, if confirmation options were provided @@ -2762,7 +2767,7 @@ public struct ToolCallRunningState: Codable, Sendable { contributor: ToolCallContributor? = nil, meta: [String: AnyCodable]? = nil, invocationMessage: StringOrMarkdown, - toolInput: ContentRef? = nil, + toolInput: ToolInput? = nil, confirmed: ToolCallConfirmationReason, selectedOption: ConfirmationOption? = nil, status: ToolCallStatus, @@ -2802,13 +2807,13 @@ public struct ToolCallAuthRequiredState: Codable, Sendable { public var meta: [String: AnyCodable]? /// Message describing what the tool will do public var invocationMessage: StringOrMarkdown - /// Reference to the final raw tool input, readable with `resourceRead`. + /// Final raw tool input, either inline or readable with `resourceRead`. /// - /// The referenced resource is mutable until the tool call leaves + /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, /// the host MUST replace the resource contents before echoing the accepted /// confirmation action. Clients MUST NOT cache tool input across confirmation. - public var toolInput: ContentRef? + public var toolInput: ToolInput? /// How the tool was confirmed for execution public var confirmed: ToolCallConfirmationReason /// The confirmation option the user selected, if confirmation options were provided @@ -2843,7 +2848,7 @@ public struct ToolCallAuthRequiredState: Codable, Sendable { contributor: ToolCallContributor? = nil, meta: [String: AnyCodable]? = nil, invocationMessage: StringOrMarkdown, - toolInput: ContentRef? = nil, + toolInput: ToolInput? = nil, confirmed: ToolCallConfirmationReason, selectedOption: ConfirmationOption? = nil, status: ToolCallStatus, @@ -2885,13 +2890,13 @@ public struct ToolCallPendingResultConfirmationState: Codable, Sendable { public var meta: [String: AnyCodable]? /// Message describing what the tool will do public var invocationMessage: StringOrMarkdown - /// Reference to the final raw tool input, readable with `resourceRead`. + /// Final raw tool input, either inline or readable with `resourceRead`. /// - /// The referenced resource is mutable until the tool call leaves + /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, /// the host MUST replace the resource contents before echoing the accepted /// confirmation action. Clients MUST NOT cache tool input across confirmation. - public var toolInput: ContentRef? + public var toolInput: ToolInput? /// Whether the tool succeeded public var success: Bool /// Past-tense description of what the tool did @@ -2939,7 +2944,7 @@ public struct ToolCallPendingResultConfirmationState: Codable, Sendable { contributor: ToolCallContributor? = nil, meta: [String: AnyCodable]? = nil, invocationMessage: StringOrMarkdown, - toolInput: ContentRef? = nil, + toolInput: ToolInput? = nil, success: Bool, pastTenseMessage: StringOrMarkdown, content: [ToolResultContent]? = nil, @@ -2987,13 +2992,13 @@ public struct ToolCallCompletedState: Codable, Sendable { public var meta: [String: AnyCodable]? /// Message describing what the tool will do public var invocationMessage: StringOrMarkdown - /// Reference to the final raw tool input, readable with `resourceRead`. + /// Final raw tool input, either inline or readable with `resourceRead`. /// - /// The referenced resource is mutable until the tool call leaves + /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, /// the host MUST replace the resource contents before echoing the accepted /// confirmation action. Clients MUST NOT cache tool input across confirmation. - public var toolInput: ContentRef? + public var toolInput: ToolInput? /// Whether the tool succeeded public var success: Bool /// Past-tense description of what the tool did @@ -3041,7 +3046,7 @@ public struct ToolCallCompletedState: Codable, Sendable { contributor: ToolCallContributor? = nil, meta: [String: AnyCodable]? = nil, invocationMessage: StringOrMarkdown, - toolInput: ContentRef? = nil, + toolInput: ToolInput? = nil, success: Bool, pastTenseMessage: StringOrMarkdown, content: [ToolResultContent]? = nil, @@ -3089,13 +3094,13 @@ public struct ToolCallCancelledState: Codable, Sendable { public var meta: [String: AnyCodable]? /// Message describing what the tool will do public var invocationMessage: StringOrMarkdown - /// Reference to the final raw tool input, readable with `resourceRead`. + /// Final raw tool input, either inline or readable with `resourceRead`. /// - /// The referenced resource is mutable until the tool call leaves + /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, /// the host MUST replace the resource contents before echoing the accepted /// confirmation action. Clients MUST NOT cache tool input across confirmation. - public var toolInput: ContentRef? + public var toolInput: ToolInput? public var status: ToolCallStatus /// Why the tool was cancelled public var reason: ToolCallCancellationReason @@ -3130,7 +3135,7 @@ public struct ToolCallCancelledState: Codable, Sendable { contributor: ToolCallContributor? = nil, meta: [String: AnyCodable]? = nil, invocationMessage: StringOrMarkdown, - toolInput: ContentRef? = nil, + toolInput: ToolInput? = nil, status: ToolCallStatus, reason: ToolCallCancellationReason, reasonMessage: StringOrMarkdown? = nil, @@ -5219,6 +5224,31 @@ public struct ResourceChange: Codable, Sendable { } } +// MARK: - Tool Input + +/// Raw tool input represented inline or by content reference. +public enum ToolInput: Codable, Sendable { + case inline(String) + case contentRef(ContentRef) + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + if let value = try? container.decode(String.self) { + self = .inline(value) + } else { + self = .contentRef(try container.decode(ContentRef.self)) + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + switch self { + case .inline(let value): try container.encode(value) + case .contentRef(let value): try container.encode(value) + } + } +} + // MARK: - Discriminated Unions public struct ChatOriginUser: Codable, Sendable { diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift index 07441e64c..43d12e6d6 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift @@ -207,6 +207,9 @@ public func chatReducer(state: ChatState, action: StateAction) -> ChatState { case .chatToolCallDelta(let a): return updateToolCall(state: state, turnId: a.turnId, toolCallId: a.toolCallId) { tc in guard case .streaming(var s) = tc else { return tc } + if let content = a.content { + s.partialInput = (s.partialInput ?? "") + content + } s.invocationMessage = a.invocationMessage s.meta = a.meta ?? s.meta return .streaming(s) @@ -268,6 +271,12 @@ public func chatReducer(state: ChatState, action: StateAction) -> ChatState { let meta = a.meta ?? base.meta let selectedOption = resolveSelectedOption(pending.options, id: a.selectedOptionId) if a.approved { + let toolInput: ToolInput? + if let edited = a.editedToolInput, case .inline = pending.toolInput { + toolInput = .inline(edited) + } else { + toolInput = pending.toolInput + } return .running(ToolCallRunningState( toolCallId: base.toolCallId, toolName: base.toolName, @@ -276,7 +285,7 @@ public func chatReducer(state: ChatState, action: StateAction) -> ChatState { contributor: base.contributor, meta: meta, invocationMessage: pending.invocationMessage, - toolInput: pending.toolInput, + toolInput: toolInput, confirmed: a.confirmed ?? .notNeeded, selectedOption: selectedOption, status: .running @@ -305,7 +314,7 @@ public func chatReducer(state: ChatState, action: StateAction) -> ChatState { let meta = a.meta ?? base.meta let confirmed: ToolCallConfirmationReason let invocationMessage: StringOrMarkdown - let toolInput: ContentRef? + let toolInput: ToolInput? let selectedOption: ConfirmationOption? let preAuthContent: [ToolResultContent]? let fromAuthRequired: Bool diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/ToolCallStateExtensions.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/ToolCallStateExtensions.swift index e177e7ba3..93e7ecb20 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/ToolCallStateExtensions.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/ToolCallStateExtensions.swift @@ -32,7 +32,7 @@ public struct ToolCallBaseFields: Sendable { public let toolName: String public let displayName: String public let intention: String? - public let toolInput: ContentRef? + public let toolInput: ToolInput? public let contributor: ToolCallContributor? public let meta: [String: AnyCodable]? } diff --git a/docs/.changes/20260730-tool-input-content-ref.json b/docs/.changes/20260730-tool-input-content-ref.json index a4d7f4554..81e9d255b 100644 --- a/docs/.changes/20260730-tool-input-content-ref.json +++ b/docs/.changes/20260730-tool-input-content-ref.json @@ -1,4 +1,4 @@ { "type": "changed", - "message": "Final tool input now uses a lazy `ContentRef`, while streaming deltas carry only invocation-message updates." + "message": "Final tool input may be inline or a lazy `ContentRef`, and streaming deltas may include partial parameters." } diff --git a/docs/guide/actions.md b/docs/guide/actions.md index d9ae734e6..552da4a25 100644 --- a/docs/guide/actions.md +++ b/docs/guide/actions.md @@ -66,7 +66,7 @@ Tool calls follow a discriminated-union state machine — see [State Model — T | Type | Client-dispatchable? | When | |---|---|---| | `chat/toolCallStart` | No | Tool call created; LM begins streaming parameters | -| `chat/toolCallDelta` | No | Display-ready invocation message updated while parameters stream separately | +| `chat/toolCallDelta` | No | Invocation message updated, optionally with partial raw parameters | | `chat/toolCallReady` | No | Parameters complete (or running tool needs re-confirmation) | | `chat/toolCallConfirmed` | **Yes** | Client approves or denies a pending tool call | | `chat/toolCallComplete` | **Yes**¹ | Tool execution finished | diff --git a/docs/guide/customizations.md b/docs/guide/customizations.md index abd9b9df1..c60be3b47 100644 --- a/docs/guide/customizations.md +++ b/docs/guide/customizations.md @@ -289,8 +289,8 @@ sequenceDiagram Note over Server: LLM selects a client tool Server->>Client: toolCallStart (client contributor) - Server->>Client: toolCallDelta (invocation message) - Server->>Client: toolCallReady (toolInput ref, confirmed: 'not-needed') + Server->>Client: toolCallDelta (invocation message, optional partial args) + Server->>Client: toolCallReady (inline or referenced toolInput, confirmed: 'not-needed') Note over Client: Client sees contributor.clientId matches,
begins execution @@ -300,11 +300,11 @@ sequenceDiagram 1. **`chat/toolCallStart`** — The server dispatches this with the tool call's `contributor` set to a client contributor whose `clientId` is the owning client's. This tells the client it owns the tool call. -2. **`chat/toolCallDelta`** (zero or more) — The server updates the display-ready invocation message while parameters stream. Raw streaming parameters are not exposed. +2. **`chat/toolCallDelta`** (zero or more) — The server updates the display-ready invocation message while parameters stream and MAY include partial raw arguments. 3. **`chat/toolCallReady`** — Parameters are complete. For client-provided tools, the server typically sets `confirmed: 'not-needed'` so the tool transitions directly to `running`. If the server wants user confirmation first, it omits `confirmed` and the standard confirmation flow applies. -4. **Client executes** — When the tool call reaches `running` status, the owning client reads the final `toolInput` reference with `resourceRead` and begins execution. Client-contributed tools MUST receive a readable input reference. If confirmation carried `editedToolInput`, the host updates that resource before echoing the accepted confirmation, so this read returns the edited parameters. +4. **Client executes** — When the tool call reaches `running` status, the owning client uses inline `toolInput` directly or reads a referenced input with `resourceRead`. If confirmation carried `editedToolInput`, inline state is updated by the reducer; for referenced input, the host updates the resource before echoing the accepted confirmation. 5. **`chat/toolCallContentChanged`** (zero or more, client-dispatched) — While executing, the client MAY stream intermediate content (e.g. terminal output, partial results) by dispatching this action. This replaces the `content` array on the running tool call state. diff --git a/docs/guide/state-model.md b/docs/guide/state-model.md index c963dc200..e0965201d 100644 --- a/docs/guide/state-model.md +++ b/docs/guide/state-model.md @@ -322,8 +322,9 @@ ToolCallResponsePart { toolCall: ToolCallState // full lifecycle state } -// Reference to large content stored outside the state tree -ContentRef { +// Response-part wrapper around a large content reference +ResourceReponsePart { + kind: 'contentRef' uri: string sizeHint?: number contentType?: string @@ -386,8 +387,8 @@ stateDiagram-v2 | Status | Key Fields | Description | | ----------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `streaming` | `invocationMessage?` | LM is streaming tool call parameters. Clients receive only display-ready invocation-message updates; raw parameters are unavailable until the call is ready. | -| `pending-confirmation` | `invocationMessage`, `toolInput?`, `edits?`, `editable?`, `options?` | Parameters complete or mid-execution confirmation needed. `toolInput` is a reference, not inline input. `edits` previews file changes. `editable` indicates the client may edit parameters before confirming. `options` provides server-defined choices beyond simple approve/deny (see below). Uses `_meta` for additional context. | +| `streaming` | `partialInput?`, `invocationMessage?` | LM is streaming tool call parameters. Hosts may include partial raw arguments on deltas; clients that do not need them can ignore the field. | +| `pending-confirmation` | `invocationMessage`, `toolInput?`, `edits?`, `editable?`, `options?` | Parameters complete or mid-execution confirmation needed. `toolInput` may be inline or a `ContentRef`, at the host's discretion. `edits` previews file changes. `editable` indicates the client may edit parameters before confirming. `options` provides server-defined choices beyond simple approve/deny (see below). Uses `_meta` for additional context. | | `running` | `confirmed`, `selectedOption?` | Tool is executing. `confirmed` records how it was approved. `selectedOption` holds the chosen confirmation option, if any. | | `auth-required` | `confirmed`, `selectedOption?`, `contributor` (MCP), `auth` | Execution paused pending MCP authentication (see below). Only reachable for MCP-contributed tool calls. | | `pending-result-confirmation` | `success`, `pastTenseMessage`, `content?`, `selectedOption?` | Execution finished, waiting for client to approve the result. | @@ -414,7 +415,7 @@ This is deliberately **separate** from `McpServerAuthRequiredState` (the MCP ser ### Editable Parameters -When `editable` is `true` on a `pending-confirmation` tool call, the client may allow the user to modify the tool's input parameters before confirming. If the user edits the parameters, the client includes inline `editedToolInput` on the `chat/toolCallConfirmed` action. Before echoing that accepted action, the host MUST replace the contents of the existing `toolInput` resource with the edited value. The reducer keeps the same reference, and subsequent `resourceRead` calls return the input that was actually executed. Clients MUST NOT cache tool input across confirmation. +When `editable` is `true` on a `pending-confirmation` tool call, the client may allow the user to modify the tool's input parameters before confirming. If the user edits the parameters, the client includes `editedToolInput` on the `chat/toolCallConfirmed` action. For inline input, the reducer replaces the state value directly. For referenced input, the host MUST replace the resource contents before echoing the accepted action; the reducer keeps the same reference, and subsequent `resourceRead` calls return the input that was actually executed. Clients MUST NOT cache referenced tool input across confirmation. When a turn completes, non-terminal tool calls in `responseParts` are force-cancelled with reason `'skipped'`. diff --git a/schema/actions.schema.json b/schema/actions.schema.json index 02a715b79..1950ee4ae 100644 --- a/schema/actions.schema.json +++ b/schema/actions.schema.json @@ -835,6 +835,10 @@ "type": { "const": "chat/toolCallDelta" }, + "content": { + "type": "string", + "description": "Optional partial raw parameter content to append." + }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", "description": "Updated display-ready progress message" @@ -880,8 +884,8 @@ "description": "Message describing what the tool will do or what confirmation is needed" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`" + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, inline or readable with `resourceRead`" }, "confirmationTitle": { "$ref": "#/$defs/StringOrMarkdown", @@ -958,7 +962,7 @@ }, "editedToolInput": { "type": "string", - "description": "Edited tool input parameters, if the client modified them before confirming.\n\nBefore echoing the accepted action, the host MUST replace the contents of\nthe pending tool call's `toolInput` resource with this value." + "description": "Edited tool input parameters, if the client modified them before confirming.\n\nFor inline `toolInput`, the reducer replaces the state value directly.\nFor referenced input, the host MUST replace the resource contents before\nechoing the accepted action." }, "selectedOptionId": { "type": "string", @@ -5751,8 +5755,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." } }, "required": [ @@ -5836,6 +5840,10 @@ "status": { "const": "streaming" }, + "partialInput": { + "type": "string", + "description": "Partial raw parameters accumulated from optional tool-call deltas." + }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", "description": "Progress message shown while parameters are streaming" @@ -5882,8 +5890,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "pending-confirmation" @@ -5982,8 +5990,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -6047,8 +6055,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -6118,8 +6126,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -6213,8 +6221,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -6308,8 +6316,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "cancelled" @@ -7412,6 +7420,17 @@ } ] }, + "ToolInput": { + "oneOf": [ + { + "type": "string" + }, + { + "$ref": "#/$defs/ContentRef" + } + ], + "description": "Raw tool input represented inline or by reference, at the host's discretion." + }, "ToolCallState": { "oneOf": [ { diff --git a/schema/commands.schema.json b/schema/commands.schema.json index 1230f0fe2..2dae1b03c 100644 --- a/schema/commands.schema.json +++ b/schema/commands.schema.json @@ -4918,8 +4918,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." } }, "required": [ @@ -5003,6 +5003,10 @@ "status": { "const": "streaming" }, + "partialInput": { + "type": "string", + "description": "Partial raw parameters accumulated from optional tool-call deltas." + }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", "description": "Progress message shown while parameters are streaming" @@ -5049,8 +5053,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "pending-confirmation" @@ -5149,8 +5153,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -5214,8 +5218,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -5285,8 +5289,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -5380,8 +5384,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -5475,8 +5479,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "cancelled" @@ -7071,6 +7075,10 @@ "type": { "const": "chat/toolCallDelta" }, + "content": { + "type": "string", + "description": "Optional partial raw parameter content to append." + }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", "description": "Updated display-ready progress message" @@ -7116,8 +7124,8 @@ "description": "Message describing what the tool will do or what confirmation is needed" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`" + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, inline or readable with `resourceRead`" }, "confirmationTitle": { "$ref": "#/$defs/StringOrMarkdown", @@ -7194,7 +7202,7 @@ }, "editedToolInput": { "type": "string", - "description": "Edited tool input parameters, if the client modified them before confirming.\n\nBefore echoing the accepted action, the host MUST replace the contents of\nthe pending tool call's `toolInput` resource with this value." + "description": "Edited tool input parameters, if the client modified them before confirming.\n\nFor inline `toolInput`, the reducer replaces the state value directly.\nFor referenced input, the host MUST replace the resource contents before\nechoing the accepted action." }, "selectedOptionId": { "type": "string", @@ -9153,6 +9161,17 @@ } ] }, + "ToolInput": { + "oneOf": [ + { + "type": "string" + }, + { + "$ref": "#/$defs/ContentRef" + } + ], + "description": "Raw tool input represented inline or by reference, at the host's discretion." + }, "ToolResultContent": { "oneOf": [ { diff --git a/schema/errors.schema.json b/schema/errors.schema.json index e6f5bdfae..e6c005288 100644 --- a/schema/errors.schema.json +++ b/schema/errors.schema.json @@ -3654,8 +3654,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." } }, "required": [ @@ -3739,6 +3739,10 @@ "status": { "const": "streaming" }, + "partialInput": { + "type": "string", + "description": "Partial raw parameters accumulated from optional tool-call deltas." + }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", "description": "Progress message shown while parameters are streaming" @@ -3785,8 +3789,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "pending-confirmation" @@ -3885,8 +3889,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -3950,8 +3954,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -4021,8 +4025,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -4116,8 +4120,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -4211,8 +4215,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "cancelled" @@ -6790,6 +6794,17 @@ } ] }, + "ToolInput": { + "oneOf": [ + { + "type": "string" + }, + { + "$ref": "#/$defs/ContentRef" + } + ], + "description": "Raw tool input represented inline or by reference, at the host's discretion." + }, "ToolResultContent": { "oneOf": [ { @@ -8064,6 +8079,10 @@ "type": { "const": "chat/toolCallDelta" }, + "content": { + "type": "string", + "description": "Optional partial raw parameter content to append." + }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", "description": "Updated display-ready progress message" @@ -8109,8 +8128,8 @@ "description": "Message describing what the tool will do or what confirmation is needed" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`" + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, inline or readable with `resourceRead`" }, "confirmationTitle": { "$ref": "#/$defs/StringOrMarkdown", @@ -9259,7 +9278,7 @@ }, "editedToolInput": { "type": "string", - "description": "Edited tool input parameters, if the client modified them before confirming.\n\nBefore echoing the accepted action, the host MUST replace the contents of\nthe pending tool call's `toolInput` resource with this value." + "description": "Edited tool input parameters, if the client modified them before confirming.\n\nFor inline `toolInput`, the reducer replaces the state value directly.\nFor referenced input, the host MUST replace the resource contents before\nechoing the accepted action." }, "selectedOptionId": { "type": "string", diff --git a/schema/notifications.schema.json b/schema/notifications.schema.json index a02ac3ae1..cd077dd32 100644 --- a/schema/notifications.schema.json +++ b/schema/notifications.schema.json @@ -3817,8 +3817,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." } }, "required": [ @@ -3902,6 +3902,10 @@ "status": { "const": "streaming" }, + "partialInput": { + "type": "string", + "description": "Partial raw parameters accumulated from optional tool-call deltas." + }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", "description": "Progress message shown while parameters are streaming" @@ -3948,8 +3952,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "pending-confirmation" @@ -4048,8 +4052,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -4113,8 +4117,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -4184,8 +4188,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -4279,8 +4283,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -4374,8 +4378,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "cancelled" @@ -5608,6 +5612,17 @@ } ] }, + "ToolInput": { + "oneOf": [ + { + "type": "string" + }, + { + "$ref": "#/$defs/ContentRef" + } + ], + "description": "Raw tool input represented inline or by reference, at the host's discretion." + }, "ToolResultContent": { "oneOf": [ { diff --git a/schema/state.schema.json b/schema/state.schema.json index 7ac1d302b..64cc38638 100644 --- a/schema/state.schema.json +++ b/schema/state.schema.json @@ -3565,8 +3565,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." } }, "required": [ @@ -3650,6 +3650,10 @@ "status": { "const": "streaming" }, + "partialInput": { + "type": "string", + "description": "Partial raw parameters accumulated from optional tool-call deltas." + }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", "description": "Progress message shown while parameters are streaming" @@ -3696,8 +3700,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "pending-confirmation" @@ -3796,8 +3800,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -3861,8 +3865,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -3932,8 +3936,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -4027,8 +4031,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -4122,8 +4126,8 @@ "description": "Message describing what the tool will do" }, "toolInput": { - "$ref": "#/$defs/ContentRef", - "description": "Reference to the final raw tool input, readable with `resourceRead`.\n\nThe referenced resource is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "$ref": "#/$defs/ToolInput", + "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "cancelled" @@ -5226,6 +5230,17 @@ } ] }, + "ToolInput": { + "oneOf": [ + { + "type": "string" + }, + { + "$ref": "#/$defs/ContentRef" + } + ], + "description": "Raw tool input represented inline or by reference, at the host's discretion." + }, "ToolCallState": { "oneOf": [ { diff --git a/scripts/generate-go.ts b/scripts/generate-go.ts index a934102c3..25753a2e2 100644 --- a/scripts/generate-go.ts +++ b/scripts/generate-go.ts @@ -155,6 +155,7 @@ function mapType(tsType: string): string { if (tsType === 'URI') return 'URI'; if (tsType === 'StringOrMarkdown') return 'StringOrMarkdown'; + if (tsType === 'ToolInput') return 'ToolInput'; // ChildCustomizationType is a TS-only subset alias of CustomizationType. if (tsType === 'ChildCustomizationType') return 'CustomizationType'; @@ -1254,6 +1255,39 @@ func containsAll(m map[string]json.RawMessage, keys ...string) bool { }`; } +function generateToolInput(): string { + return `// ToolInput is raw tool input represented inline or by content reference. +type ToolInput struct { +\tInline *string +\tContentRef *ContentRef +} + +func (t ToolInput) MarshalJSON() ([]byte, error) { +\tif t.Inline != nil { +\t\treturn json.Marshal(*t.Inline) +\t} +\tif t.ContentRef != nil { +\t\treturn json.Marshal(t.ContentRef) +\t} +\treturn []byte("null"), nil +} + +func (t *ToolInput) UnmarshalJSON(data []byte) error { +\t*t = ToolInput{} +\tvar inline string +\tif err := json.Unmarshal(data, &inline); err == nil { +\t\tt.Inline = &inline +\t\treturn nil +\t} +\tvar ref ContentRef +\tif err := json.Unmarshal(data, &ref); err != nil { +\t\treturn err +\t} +\tt.ContentRef = &ref +\treturn nil +}`; +} + function generateStateFile(project: Project): string { const lines: string[] = [HEADER_WITH_IMPORTS]; @@ -1281,6 +1315,9 @@ function generateStateFile(project: Project): string { } } + lines.push(generateToolInput()); + lines.push(''); + lines.push('// ─── Discriminated Unions ─────────────────────────────────────────────\n'); lines.push(generateDiscriminatedUnion(RESPONSE_PART_UNION)); lines.push(''); @@ -2014,6 +2051,7 @@ function checkExhaustiveness(project: Project): void { 'PaginatedParams', 'PaginatedResult', 'StringOrMarkdown', + 'ToolInput', 'ToolCallState', 'StateAction', 'ActionEnvelope', diff --git a/scripts/generate-kotlin.ts b/scripts/generate-kotlin.ts index 32075fa1d..e86113b77 100644 --- a/scripts/generate-kotlin.ts +++ b/scripts/generate-kotlin.ts @@ -136,6 +136,7 @@ function mapType(tsType: string): string { // Type aliases if (tsType === 'URI') return 'String'; if (tsType === 'StringOrMarkdown') return 'StringOrMarkdown'; + if (tsType === 'ToolInput') return 'ToolInput'; // ChildCustomizationType is a TS-only subset alias of CustomizationType. if (tsType === 'ChildCustomizationType') return 'CustomizationType'; @@ -723,6 +724,47 @@ internal object StringOrMarkdownSerializer : KSerializer { }`; } +function generateToolInput(): string { + return `/** + * Raw tool input represented inline or by content reference. + */ +@Serializable(with = ToolInputSerializer::class) +sealed interface ToolInput { + @JvmInline value class Inline(val value: String) : ToolInput + @JvmInline value class ContentReference(val value: ContentRef) : ToolInput +} + +internal object ToolInputSerializer : KSerializer { + override val descriptor: SerialDescriptor = + buildClassSerialDescriptor("ToolInput") + + override fun deserialize(decoder: Decoder): ToolInput { + val input = decoder as? JsonDecoder + ?: error("ToolInput can only be deserialized from JSON") + return when (val element = input.decodeJsonElement()) { + is JsonPrimitive -> ToolInput.Inline( + element.contentOrNull ?: error("ToolInput string must not be null"), + ) + is JsonObject -> ToolInput.ContentReference( + input.json.decodeFromJsonElement(ContentRef.serializer(), element), + ) + else -> error("ToolInput must be a string or ContentRef object") + } + } + + override fun serialize(encoder: Encoder, value: ToolInput) { + val output = encoder as? JsonEncoder + ?: error("ToolInput can only be serialized to JSON") + val element = when (value) { + is ToolInput.Inline -> JsonPrimitive(value.value) + is ToolInput.ContentReference -> + output.json.encodeToJsonElement(ContentRef.serializer(), value.value) + } + output.encodeJsonElement(element) + } +}`; +} + function generateSnapshotState(): string { return `/** * The state payload of a snapshot — root, session, chat, terminal, changeset, @@ -1214,6 +1256,11 @@ function generateStateFile(project: Project): string { } } + lines.push('// ─── Tool Input ──────────────────────────────────────────────────────────────'); + lines.push(''); + lines.push(generateToolInput()); + lines.push(''); + lines.push('// ─── Discriminated Unions ───────────────────────────────────────────────────'); lines.push(''); lines.push(generateChatOriginKotlin()); @@ -2028,6 +2075,7 @@ function checkExhaustiveness(project: Project): void { 'ActionType', // emitted directly by generateActionsFile(), not via STATE_ENUMS 'ChangesetOperationTargetKind', // discriminator enum embedded in the hand-rolled ChangesetOperationTarget union 'StringOrMarkdown', // generateStringOrMarkdown() + 'ToolInput', // generateToolInput() 'ToolCallState', // TOOL_CALL_STATE_UNION discriminated union 'StateAction', // StateAction enum in generateActionsFile() 'ActionEnvelope', // generateDataClassFromInterface() call in generateActionsFile() diff --git a/scripts/generate-rust.ts b/scripts/generate-rust.ts index 6fa164bce..7fb9044dd 100644 --- a/scripts/generate-rust.ts +++ b/scripts/generate-rust.ts @@ -145,6 +145,7 @@ function mapType(tsType: string, propName?: string, containerName?: string): str if (tsType === 'URI') return 'Uri'; if (tsType === 'StringOrMarkdown') return 'StringOrMarkdown'; + if (tsType === 'ToolInput') return 'ToolInput'; // ChildCustomizationType is a TS-only subset alias of CustomizationType. if (tsType === 'ChildCustomizationType') return 'CustomizationType'; @@ -1108,6 +1109,16 @@ pub enum SnapshotState { }`; } +function generateToolInput(): string { + return `/// Raw tool input represented inline or by content reference. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum ToolInput { + Inline(String), + ContentRef(ContentRef), +}`; +} + function generateStateFile(project: Project): string { const lines: string[] = [GENERATED_HEADER]; @@ -1140,6 +1151,9 @@ function generateStateFile(project: Project): string { } } + lines.push(generateToolInput()); + lines.push(''); + lines.push('// ─── Discriminated Unions ─────────────────────────────────────────────\n'); lines.push(generateChatOrigin()); lines.push(''); @@ -1316,7 +1330,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, ContentRef, Customization, ErrorInfo, McpAuthRequirement, McpServerState, ModelSelection, ResponsePart, SessionActiveClient, SessionInputRequest, SideChatSelection, TerminalClaim, TerminalInfo, TextRange, ToolCallContributor, ToolCallResult, ToolCallRiskAssessment, 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, ContentRef, Customization, ErrorInfo, McpAuthRequirement, McpServerState, ModelSelection, ResponsePart, SessionActiveClient, SessionInputRequest, SideChatSelection, TerminalClaim, TerminalInfo, TextRange, ToolCallContributor, ToolCallResult, ToolCallRiskAssessment, ToolCallConfirmationReason, ToolCallCancellationReason, ToolDefinition, ToolInput, ToolResultContent, UsageInfo, Message, PendingMessageKind, Turn, ChangesetStatus, ChangesetFile, ChangesetOperation, ChangesetOperationStatus, Changeset, ChatSummary};'); lines.push(''); // ActionType enum @@ -1866,6 +1880,7 @@ function checkExhaustiveness(project: Project): void { 'PaginatedParams', // base interface; flattened into each paginated command params struct 'PaginatedResult', // base interface; flattened into each paginated command result struct 'StringOrMarkdown', + 'ToolInput', 'ToolCallState', 'StateAction', 'ActionEnvelope', diff --git a/scripts/generate-swift.ts b/scripts/generate-swift.ts index 6e2b833d3..086f86593 100644 --- a/scripts/generate-swift.ts +++ b/scripts/generate-swift.ts @@ -104,6 +104,7 @@ function mapType(tsType: string, propName?: string, containerName?: string): str // Type aliases if (tsType === 'URI') return 'String'; if (tsType === 'StringOrMarkdown') return 'StringOrMarkdown'; + if (tsType === 'ToolInput') return 'ToolInput'; // ChildCustomizationType is a TS-only subset alias of CustomizationType. if (tsType === 'ChildCustomizationType') return 'CustomizationType'; @@ -968,6 +969,31 @@ public enum StringOrMarkdown: Codable, Sendable, Equatable { }`; } +function generateToolInput(): string { + return `/// Raw tool input represented inline or by content reference. +public enum ToolInput: Codable, Sendable { + case inline(String) + case contentRef(ContentRef) + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + if let value = try? container.decode(String.self) { + self = .inline(value) + } else { + self = .contentRef(try container.decode(ContentRef.self)) + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + switch self { + case .inline(let value): try container.encode(value) + case .contentRef(let value): try container.encode(value) + } + } +}`; +} + function generateSnapshotState(): string { return `/// The state payload of a snapshot — root, session, chat, terminal, changeset, resource-watch, annotations, or content state. public enum SnapshotState: Codable, Sendable { @@ -1125,6 +1151,10 @@ function generateStateFile(project: Project): string { } } + lines.push('// MARK: - Tool Input\n'); + lines.push(generateToolInput()); + lines.push(''); + lines.push('// MARK: - Discriminated Unions\n'); lines.push(generateChatOriginSwift()); lines.push(''); @@ -2063,6 +2093,7 @@ function checkExhaustiveness(project: Project): void { 'PaginatedParams', // base interface; flattened into each paginated command params struct 'PaginatedResult', // base interface; flattened into each paginated command result struct 'StringOrMarkdown', // generateStringOrMarkdown() + 'ToolInput', // generateToolInput() 'ToolCallState', // TOOL_CALL_STATE_UNION discriminated union 'StateAction', // StateAction enum in generateActionsFile() 'ActionEnvelope', // generateStructFromInterface() call in generateActionsFile() diff --git a/types/channels-chat/actions.ts b/types/channels-chat/actions.ts index 2bc4dfb99..aaf0f27fa 100644 --- a/types/channels-chat/actions.ts +++ b/types/channels-chat/actions.ts @@ -5,7 +5,7 @@ */ import { ActionType } from '../common/actions.js'; -import type { ContentRef, StringOrMarkdown, ErrorInfo, FileEdit, UsageInfo, URI } from '../common/state.js'; +import type { StringOrMarkdown, ErrorInfo, FileEdit, UsageInfo, URI } from '../common/state.js'; import type { McpAuthRequirement } from '../channels-session/state.js'; import type { Message, @@ -18,6 +18,7 @@ import type { ConfirmationOption, ToolCallContributor, ToolCallRiskAssessment, + ToolInput, Turn, } from './state.js'; import { @@ -173,6 +174,8 @@ export interface ChatToolCallStartAction extends ToolCallActionBase { */ export interface ChatToolCallDeltaAction extends ToolCallActionBase { type: ActionType.ChatToolCallDelta; + /** Optional partial raw parameter content to append. */ + content?: string; /** Updated display-ready progress message */ invocationMessage: StringOrMarkdown; } @@ -209,8 +212,8 @@ export interface ChatToolCallReadyAction extends ToolCallActionBase { intention?: string; /** Message describing what the tool will do or what confirmation is needed */ invocationMessage: StringOrMarkdown; - /** Reference to the final raw tool input, readable with `resourceRead` */ - toolInput?: ContentRef; + /** Final raw tool input, inline or readable with `resourceRead` */ + toolInput?: ToolInput; /** Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) */ confirmationTitle?: StringOrMarkdown; /** Risk assessment that informed the confirmation requirement. */ @@ -246,8 +249,9 @@ export interface ChatToolCallApprovedAction extends ToolCallActionBase { /** * Edited tool input parameters, if the client modified them before confirming. * - * Before echoing the accepted action, the host MUST replace the contents of - * the pending tool call's `toolInput` resource with this value. + * For inline `toolInput`, the reducer replaces the state value directly. + * For referenced input, the host MUST replace the resource contents before + * echoing the accepted action. */ editedToolInput?: string; /** ID of the selected confirmation option, if the server provided options */ diff --git a/types/channels-chat/reducer.ts b/types/channels-chat/reducer.ts index 04f4389e6..d847617ca 100644 --- a/types/channels-chat/reducer.ts +++ b/types/channels-chat/reducer.ts @@ -465,6 +465,9 @@ export function chatReducer(state: ChatState, action: ChatAction, log?: (msg: st return { ...tc, ...(action._meta !== undefined ? { _meta: action._meta } : {}), + ...(action.content !== undefined + ? { partialInput: (tc.partialInput ?? '') + action.content } + : {}), invocationMessage: action.invocationMessage, }; }); @@ -517,11 +520,14 @@ export function chatReducer(state: ChatState, action: ChatAction, log?: (msg: st const base = tcBaseWithMeta(tc, action._meta); const selectedOption = resolveSelectedOption(tc.options, action.selectedOptionId); if (action.approved) { + const toolInput = action.editedToolInput !== undefined && typeof tc.toolInput === 'string' + ? action.editedToolInput + : tc.toolInput; return { status: ToolCallStatus.Running, ...base, invocationMessage: tc.invocationMessage, - toolInput: tc.toolInput, + toolInput, confirmed: action.confirmed, ...(selectedOption ? { selectedOption } : {}), }; diff --git a/types/channels-chat/state.ts b/types/channels-chat/state.ts index d34f7510b..6c3062ccf 100644 --- a/types/channels-chat/state.ts +++ b/types/channels-chat/state.ts @@ -1186,16 +1186,23 @@ interface ToolCallParameterFields { /** Message describing what the tool will do */ invocationMessage: StringOrMarkdown; /** - * Reference to the final raw tool input, readable with `resourceRead`. + * Final raw tool input, either inline or readable with `resourceRead`. * - * The referenced resource is mutable until the tool call leaves + * Referenced input is mutable until the tool call leaves * `pending-confirmation`. When the client confirms with `editedToolInput`, * the host MUST replace the resource contents before echoing the accepted * confirmation action. Clients MUST NOT cache tool input across confirmation. */ - toolInput?: ContentRef; + toolInput?: ToolInput; } +/** + * Raw tool input represented inline or by reference, at the host's discretion. + * + * @category Tool Call Types + */ +export type ToolInput = string | ContentRef; + /** * Tool execution result details, available after execution completes. * @@ -1229,6 +1236,8 @@ export interface ToolCallResult { */ export interface ToolCallStreamingState extends ToolCallBase { status: ToolCallStatus.Streaming; + /** Partial raw parameters accumulated from optional tool-call deltas. */ + partialInput?: string; /** Progress message shown while parameters are streaming */ invocationMessage?: StringOrMarkdown; } diff --git a/types/index.ts b/types/index.ts index b91e0dd4a..172400d52 100644 --- a/types/index.ts +++ b/types/index.ts @@ -50,6 +50,7 @@ export type { SystemNotificationResponsePart, ResponsePart, ToolCallResult, + ToolInput, ToolCallStreamingState, ToolCallPendingConfirmationState, ToolCallRunningState, diff --git a/types/test-cases/reducers/101-toolcalldelta-without-invocationmessage.json b/types/test-cases/reducers/101-toolcalldelta-without-invocationmessage.json index 10c94c64c..6328b51f0 100644 --- a/types/test-cases/reducers/101-toolcalldelta-without-invocationmessage.json +++ b/types/test-cases/reducers/101-toolcalldelta-without-invocationmessage.json @@ -1,5 +1,5 @@ { - "description": "toolCallDelta replaces the streaming invocationMessage", + "description": "toolCallDelta appends optional partial input and replaces invocationMessage", "reducer": "chat", "initial": { "turns": [], @@ -37,6 +37,7 @@ "type": "chat/toolCallDelta", "turnId": "turn-1", "toolCallId": "tc-1", + "content": "{\"command\":\"ls", "invocationMessage": "Working" } ], @@ -60,6 +61,7 @@ "toolName": "bash", "displayName": "Run Command", "intention": null, + "partialInput": "{\"command\":\"ls", "invocationMessage": "Working" } } diff --git a/types/test-cases/reducers/158-toolcallconfirmed-approved-with-editedtoolinput-overrides-original.json b/types/test-cases/reducers/158-toolcallconfirmed-approved-with-editedtoolinput-overrides-original.json index 37debaa79..022c4f911 100644 --- a/types/test-cases/reducers/158-toolcallconfirmed-approved-with-editedtoolinput-overrides-original.json +++ b/types/test-cases/reducers/158-toolcallconfirmed-approved-with-editedtoolinput-overrides-original.json @@ -1,5 +1,5 @@ { - "description": "toolCallConfirmed preserves the input ref when edited input is handled by the host", + "description": "toolCallConfirmed replaces inline tool input with edited input", "reducer": "chat", "initial": { "turns": [], @@ -33,9 +33,7 @@ "turnId": "turn-1", "toolCallId": "tc-1", "invocationMessage": "Run: ls -la", - "toolInput": { - "uri": "file:///tool-inputs/tool-input.json" - } + "toolInput": "ls -la" }, { "type": "chat/toolCallConfirmed", @@ -78,9 +76,7 @@ "contributor": null, "_meta": null, "invocationMessage": "Run: ls -la", - "toolInput": { - "uri": "file:///tool-inputs/tool-input.json" - }, + "toolInput": "ls -la /tmp", "confirmed": "user-action", "success": true, "pastTenseMessage": "Ran command" From fe30c69a65fa31f83ddd21ca9a4d4faf259822a6 Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 31 Jul 2026 12:44:01 -0700 Subject: [PATCH 5/6] chat: simplify tool input wording Remove unnecessary display-ready and raw qualifiers while retaining only comments that define wire behavior. (Written by Copilot) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- clients/go/ahptypes/actions.generated.go | 6 ++--- clients/go/ahptypes/state.generated.go | 14 +++++------ .../generated/Actions.generated.kt | 6 ++--- .../generated/State.generated.kt | 14 +++++------ clients/rust/crates/ahp-types/src/actions.rs | 6 ++--- clients/rust/crates/ahp-types/src/state.rs | 14 +++++------ .../Generated/Actions.generated.swift | 6 ++--- .../Generated/State.generated.swift | 14 +++++------ docs/guide/actions.md | 2 +- docs/guide/customizations.md | 2 +- docs/guide/state-model.md | 4 ++-- schema/actions.schema.json | 24 +++++++++---------- schema/commands.schema.json | 24 +++++++++---------- schema/errors.schema.json | 24 +++++++++---------- schema/notifications.schema.json | 18 +++++++------- schema/state.schema.json | 18 +++++++------- types/channels-chat/actions.ts | 6 ++--- types/channels-chat/state.ts | 6 ++--- 18 files changed, 104 insertions(+), 104 deletions(-) diff --git a/clients/go/ahptypes/actions.generated.go b/clients/go/ahptypes/actions.generated.go index 96ea6abb5..6dc5eb5aa 100644 --- a/clients/go/ahptypes/actions.generated.go +++ b/clients/go/ahptypes/actions.generated.go @@ -318,9 +318,9 @@ type ChatToolCallDeltaAction struct { // contain escape sequences). Meta map[string]json.RawMessage `json:"_meta,omitempty"` Type ActionType `json:"type"` - // Optional partial raw parameter content to append. + // Partial parameter content to append, if provided by the host. Content *string `json:"content,omitempty"` - // Updated display-ready progress message + // Updated progress message InvocationMessage StringOrMarkdown `json:"invocationMessage"` } @@ -358,7 +358,7 @@ type ChatToolCallReadyAction struct { Intention *string `json:"intention,omitempty"` // Message describing what the tool will do or what confirmation is needed InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Final raw tool input, inline or readable with `resourceRead` + // Final tool input ToolInput *ToolInput `json:"toolInput,omitempty"` // Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) ConfirmationTitle *StringOrMarkdown `json:"confirmationTitle,omitempty"` diff --git a/clients/go/ahptypes/state.generated.go b/clients/go/ahptypes/state.generated.go index 9c87cbbce..d800edbe9 100644 --- a/clients/go/ahptypes/state.generated.go +++ b/clients/go/ahptypes/state.generated.go @@ -1920,7 +1920,7 @@ type ToolCallStreamingState struct { // with the {@link contributor} to serve MCP Apps. Meta map[string]json.RawMessage `json:"_meta,omitempty"` Status ToolCallStatus `json:"status"` - // Partial raw parameters accumulated from optional tool-call deltas. + // Partial parameters accumulated from tool-call deltas. PartialInput *string `json:"partialInput,omitempty"` // Progress message shown while parameters are streaming InvocationMessage *StringOrMarkdown `json:"invocationMessage,omitempty"` @@ -1947,7 +1947,7 @@ type ToolCallPendingConfirmationState struct { Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Message describing what the tool will do InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Final raw tool input, either inline or readable with `resourceRead`. + // Final tool input. // // Referenced input is mutable until the tool call leaves // `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -1990,7 +1990,7 @@ type ToolCallRunningState struct { Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Message describing what the tool will do InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Final raw tool input, either inline or readable with `resourceRead`. + // Final tool input. // // Referenced input is mutable until the tool call leaves // `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -2055,7 +2055,7 @@ type ToolCallAuthRequiredState struct { Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Message describing what the tool will do InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Final raw tool input, either inline or readable with `resourceRead`. + // Final tool input. // // Referenced input is mutable until the tool call leaves // `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -2093,7 +2093,7 @@ type ToolCallPendingResultConfirmationState struct { Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Message describing what the tool will do InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Final raw tool input, either inline or readable with `resourceRead`. + // Final tool input. // // Referenced input is mutable until the tool call leaves // `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -2141,7 +2141,7 @@ type ToolCallCompletedState struct { Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Message describing what the tool will do InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Final raw tool input, either inline or readable with `resourceRead`. + // Final tool input. // // Referenced input is mutable until the tool call leaves // `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -2189,7 +2189,7 @@ type ToolCallCancelledState struct { Meta map[string]json.RawMessage `json:"_meta,omitempty"` // Message describing what the tool will do InvocationMessage StringOrMarkdown `json:"invocationMessage"` - // Final raw tool input, either inline or readable with `resourceRead`. + // Final tool input. // // Referenced input is mutable until the tool call leaves // `pending-confirmation`. When the client confirms with `editedToolInput`, 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 fd7fb5113..f114be727 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 @@ -441,11 +441,11 @@ data class ChatToolCallDeltaAction( val meta: Map? = null, val type: ActionType, /** - * Optional partial raw parameter content to append. + * Partial parameter content to append, if provided by the host. */ val content: String? = null, /** - * Updated display-ready progress message + * Updated progress message */ val invocationMessage: StringOrMarkdown ) @@ -486,7 +486,7 @@ data class ChatToolCallReadyAction( */ val invocationMessage: StringOrMarkdown, /** - * Final raw tool input, inline or readable with `resourceRead` + * Final tool input */ val toolInput: ToolInput? = null, /** 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 90bd79f34..eae16d99c 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 @@ -2569,7 +2569,7 @@ data class ToolCallStreamingState( val meta: Map? = null, val status: ToolCallStatus, /** - * Partial raw parameters accumulated from optional tool-call deltas. + * Partial parameters accumulated from tool-call deltas. */ val partialInput: String? = null, /** @@ -2614,7 +2614,7 @@ data class ToolCallPendingConfirmationState( */ val invocationMessage: StringOrMarkdown, /** - * Final raw tool input, either inline or readable with `resourceRead`. + * Final tool input. * * Referenced input is mutable until the tool call leaves * `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -2684,7 +2684,7 @@ data class ToolCallRunningState( */ val invocationMessage: StringOrMarkdown, /** - * Final raw tool input, either inline or readable with `resourceRead`. + * Final tool input. * * Referenced input is mutable until the tool call leaves * `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -2746,7 +2746,7 @@ data class ToolCallAuthRequiredState( */ val invocationMessage: StringOrMarkdown, /** - * Final raw tool input, either inline or readable with `resourceRead`. + * Final tool input. * * Referenced input is mutable until the tool call leaves * `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -2809,7 +2809,7 @@ data class ToolCallPendingResultConfirmationState( */ val invocationMessage: StringOrMarkdown, /** - * Final raw tool input, either inline or readable with `resourceRead`. + * Final tool input. * * Referenced input is mutable until the tool call leaves * `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -2888,7 +2888,7 @@ data class ToolCallCompletedState( */ val invocationMessage: StringOrMarkdown, /** - * Final raw tool input, either inline or readable with `resourceRead`. + * Final tool input. * * Referenced input is mutable until the tool call leaves * `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -2967,7 +2967,7 @@ data class ToolCallCancelledState( */ val invocationMessage: StringOrMarkdown, /** - * Final raw tool input, either inline or readable with `resourceRead`. + * Final tool input. * * Referenced input is mutable until the tool call leaves * `pending-confirmation`. When the client confirms with `editedToolInput`, diff --git a/clients/rust/crates/ahp-types/src/actions.rs b/clients/rust/crates/ahp-types/src/actions.rs index 5da76ec60..82797882e 100644 --- a/clients/rust/crates/ahp-types/src/actions.rs +++ b/clients/rust/crates/ahp-types/src/actions.rs @@ -446,10 +446,10 @@ pub struct ChatToolCallDeltaAction { /// contain escape sequences). #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")] pub meta: Option, - /// Optional partial raw parameter content to append. + /// Partial parameter content to append, if provided by the host. #[serde(default, skip_serializing_if = "Option::is_none")] pub content: Option, - /// Updated display-ready progress message + /// Updated progress message pub invocation_message: StringOrMarkdown, } @@ -491,7 +491,7 @@ pub struct ChatToolCallReadyAction { pub intention: Option, /// Message describing what the tool will do or what confirmation is needed pub invocation_message: StringOrMarkdown, - /// Final raw tool input, inline or readable with `resourceRead` + /// Final tool input #[serde(default, skip_serializing_if = "Option::is_none")] pub tool_input: Option, /// Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) diff --git a/clients/rust/crates/ahp-types/src/state.rs b/clients/rust/crates/ahp-types/src/state.rs index 261c9a9ce..c4cef0026 100644 --- a/clients/rust/crates/ahp-types/src/state.rs +++ b/clients/rust/crates/ahp-types/src/state.rs @@ -2361,7 +2361,7 @@ pub struct ToolCallStreamingState { /// with the {@link contributor} to serve MCP Apps. #[serde(rename = "_meta", default, skip_serializing_if = "Option::is_none")] pub meta: Option, - /// Partial raw parameters accumulated from optional tool-call deltas. + /// Partial parameters accumulated from tool-call deltas. #[serde(default, skip_serializing_if = "Option::is_none")] pub partial_input: Option, /// Progress message shown while parameters are streaming @@ -2395,7 +2395,7 @@ pub struct ToolCallPendingConfirmationState { pub meta: Option, /// Message describing what the tool will do pub invocation_message: StringOrMarkdown, - /// Final raw tool input, either inline or readable with `resourceRead`. + /// Final tool input. /// /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -2448,7 +2448,7 @@ pub struct ToolCallRunningState { pub meta: Option, /// Message describing what the tool will do pub invocation_message: StringOrMarkdown, - /// Final raw tool input, either inline or readable with `resourceRead`. + /// Final tool input. /// /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -2520,7 +2520,7 @@ pub struct ToolCallAuthRequiredState { pub meta: Option, /// Message describing what the tool will do pub invocation_message: StringOrMarkdown, - /// Final raw tool input, either inline or readable with `resourceRead`. + /// Final tool input. /// /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -2566,7 +2566,7 @@ pub struct ToolCallPendingResultConfirmationState { pub meta: Option, /// Message describing what the tool will do pub invocation_message: StringOrMarkdown, - /// Final raw tool input, either inline or readable with `resourceRead`. + /// Final tool input. /// /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -2623,7 +2623,7 @@ pub struct ToolCallCompletedState { pub meta: Option, /// Message describing what the tool will do pub invocation_message: StringOrMarkdown, - /// Final raw tool input, either inline or readable with `resourceRead`. + /// Final tool input. /// /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -2680,7 +2680,7 @@ pub struct ToolCallCancelledState { pub meta: Option, /// Message describing what the tool will do pub invocation_message: StringOrMarkdown, - /// Final raw tool input, either inline or readable with `resourceRead`. + /// Final tool input. /// /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift index 8e5b36ce2..01628a2eb 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift @@ -436,9 +436,9 @@ public struct ChatToolCallDeltaAction: Codable, Sendable { /// contain escape sequences). public var meta: [String: AnyCodable]? public var type: ActionType - /// Optional partial raw parameter content to append. + /// Partial parameter content to append, if provided by the host. public var content: String? - /// Updated display-ready progress message + /// Updated progress message public var invocationMessage: StringOrMarkdown enum CodingKeys: String, CodingKey { @@ -488,7 +488,7 @@ public struct ChatToolCallReadyAction: Codable, Sendable { public var intention: String? /// Message describing what the tool will do or what confirmation is needed public var invocationMessage: StringOrMarkdown - /// Final raw tool input, inline or readable with `resourceRead` + /// Final tool input public var toolInput: ToolInput? /// Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) public var confirmationTitle: StringOrMarkdown? diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift index 24188d7d2..ffa760e89 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/State.generated.swift @@ -2576,7 +2576,7 @@ public struct ToolCallStreamingState: Codable, Sendable { /// with the {@link contributor} to serve MCP Apps. public var meta: [String: AnyCodable]? public var status: ToolCallStatus - /// Partial raw parameters accumulated from optional tool-call deltas. + /// Partial parameters accumulated from tool-call deltas. public var partialInput: String? /// Progress message shown while parameters are streaming public var invocationMessage: StringOrMarkdown? @@ -2635,7 +2635,7 @@ public struct ToolCallPendingConfirmationState: Codable, Sendable { public var meta: [String: AnyCodable]? /// Message describing what the tool will do public var invocationMessage: StringOrMarkdown - /// Final raw tool input, either inline or readable with `resourceRead`. + /// Final tool input. /// /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -2726,7 +2726,7 @@ public struct ToolCallRunningState: Codable, Sendable { public var meta: [String: AnyCodable]? /// Message describing what the tool will do public var invocationMessage: StringOrMarkdown - /// Final raw tool input, either inline or readable with `resourceRead`. + /// Final tool input. /// /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -2807,7 +2807,7 @@ public struct ToolCallAuthRequiredState: Codable, Sendable { public var meta: [String: AnyCodable]? /// Message describing what the tool will do public var invocationMessage: StringOrMarkdown - /// Final raw tool input, either inline or readable with `resourceRead`. + /// Final tool input. /// /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -2890,7 +2890,7 @@ public struct ToolCallPendingResultConfirmationState: Codable, Sendable { public var meta: [String: AnyCodable]? /// Message describing what the tool will do public var invocationMessage: StringOrMarkdown - /// Final raw tool input, either inline or readable with `resourceRead`. + /// Final tool input. /// /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -2992,7 +2992,7 @@ public struct ToolCallCompletedState: Codable, Sendable { public var meta: [String: AnyCodable]? /// Message describing what the tool will do public var invocationMessage: StringOrMarkdown - /// Final raw tool input, either inline or readable with `resourceRead`. + /// Final tool input. /// /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -3094,7 +3094,7 @@ public struct ToolCallCancelledState: Codable, Sendable { public var meta: [String: AnyCodable]? /// Message describing what the tool will do public var invocationMessage: StringOrMarkdown - /// Final raw tool input, either inline or readable with `resourceRead`. + /// Final tool input. /// /// Referenced input is mutable until the tool call leaves /// `pending-confirmation`. When the client confirms with `editedToolInput`, diff --git a/docs/guide/actions.md b/docs/guide/actions.md index 552da4a25..b863ff52e 100644 --- a/docs/guide/actions.md +++ b/docs/guide/actions.md @@ -66,7 +66,7 @@ Tool calls follow a discriminated-union state machine — see [State Model — T | Type | Client-dispatchable? | When | |---|---|---| | `chat/toolCallStart` | No | Tool call created; LM begins streaming parameters | -| `chat/toolCallDelta` | No | Invocation message updated, optionally with partial raw parameters | +| `chat/toolCallDelta` | No | Invocation message updated, optionally with partial parameters | | `chat/toolCallReady` | No | Parameters complete (or running tool needs re-confirmation) | | `chat/toolCallConfirmed` | **Yes** | Client approves or denies a pending tool call | | `chat/toolCallComplete` | **Yes**¹ | Tool execution finished | diff --git a/docs/guide/customizations.md b/docs/guide/customizations.md index c60be3b47..4b51c1a6b 100644 --- a/docs/guide/customizations.md +++ b/docs/guide/customizations.md @@ -300,7 +300,7 @@ sequenceDiagram 1. **`chat/toolCallStart`** — The server dispatches this with the tool call's `contributor` set to a client contributor whose `clientId` is the owning client's. This tells the client it owns the tool call. -2. **`chat/toolCallDelta`** (zero or more) — The server updates the display-ready invocation message while parameters stream and MAY include partial raw arguments. +2. **`chat/toolCallDelta`** (zero or more) — The server updates the invocation message while parameters stream and MAY include partial arguments. 3. **`chat/toolCallReady`** — Parameters are complete. For client-provided tools, the server typically sets `confirmed: 'not-needed'` so the tool transitions directly to `running`. If the server wants user confirmation first, it omits `confirmed` and the standard confirmation flow applies. diff --git a/docs/guide/state-model.md b/docs/guide/state-model.md index e0965201d..642952e75 100644 --- a/docs/guide/state-model.md +++ b/docs/guide/state-model.md @@ -350,7 +350,7 @@ InputRequestResponsePart { Text content uses a **create-then-append** pattern: the server first emits a `chat/responsePart` action to create a new markdown (or reasoning) part with an `id`, then streams text into it via `chat/delta` (or `chat/reasoning`) actions targeting that `partId`. This pattern is extensible to future streaming content types. -Clients fetch `ContentRef` content separately via the `resourceRead(uri)` command. This keeps large content out of state snapshots and action traffic. +Clients fetch `ContentRef` content separately via the `resourceRead(uri)` command. This keeps the state tree small and serializable. Consumers can derive display text by concatenating all `markdown` parts, find tool calls by filtering for `toolCall` parts, and access reasoning by filtering for `reasoning` parts. @@ -387,7 +387,7 @@ stateDiagram-v2 | Status | Key Fields | Description | | ----------------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `streaming` | `partialInput?`, `invocationMessage?` | LM is streaming tool call parameters. Hosts may include partial raw arguments on deltas; clients that do not need them can ignore the field. | +| `streaming` | `partialInput?`, `invocationMessage?` | LM is streaming tool call parameters. `partialInput` accumulates when deltas include parameter content. | | `pending-confirmation` | `invocationMessage`, `toolInput?`, `edits?`, `editable?`, `options?` | Parameters complete or mid-execution confirmation needed. `toolInput` may be inline or a `ContentRef`, at the host's discretion. `edits` previews file changes. `editable` indicates the client may edit parameters before confirming. `options` provides server-defined choices beyond simple approve/deny (see below). Uses `_meta` for additional context. | | `running` | `confirmed`, `selectedOption?` | Tool is executing. `confirmed` records how it was approved. `selectedOption` holds the chosen confirmation option, if any. | | `auth-required` | `confirmed`, `selectedOption?`, `contributor` (MCP), `auth` | Execution paused pending MCP authentication (see below). Only reachable for MCP-contributed tool calls. | diff --git a/schema/actions.schema.json b/schema/actions.schema.json index 1950ee4ae..87857c9a2 100644 --- a/schema/actions.schema.json +++ b/schema/actions.schema.json @@ -837,11 +837,11 @@ }, "content": { "type": "string", - "description": "Optional partial raw parameter content to append." + "description": "Partial parameter content to append, if provided by the host." }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", - "description": "Updated display-ready progress message" + "description": "Updated progress message" } }, "required": [ @@ -885,7 +885,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, inline or readable with `resourceRead`" + "description": "Final tool input" }, "confirmationTitle": { "$ref": "#/$defs/StringOrMarkdown", @@ -5756,7 +5756,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." } }, "required": [ @@ -5842,7 +5842,7 @@ }, "partialInput": { "type": "string", - "description": "Partial raw parameters accumulated from optional tool-call deltas." + "description": "Partial parameters accumulated from tool-call deltas." }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", @@ -5891,7 +5891,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "pending-confirmation" @@ -5991,7 +5991,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -6056,7 +6056,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -6127,7 +6127,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -6222,7 +6222,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -6317,7 +6317,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "cancelled" @@ -7429,7 +7429,7 @@ "$ref": "#/$defs/ContentRef" } ], - "description": "Raw tool input represented inline or by reference, at the host's discretion." + "description": "Tool input represented inline or by reference." }, "ToolCallState": { "oneOf": [ diff --git a/schema/commands.schema.json b/schema/commands.schema.json index 2dae1b03c..ee9129a65 100644 --- a/schema/commands.schema.json +++ b/schema/commands.schema.json @@ -4919,7 +4919,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." } }, "required": [ @@ -5005,7 +5005,7 @@ }, "partialInput": { "type": "string", - "description": "Partial raw parameters accumulated from optional tool-call deltas." + "description": "Partial parameters accumulated from tool-call deltas." }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", @@ -5054,7 +5054,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "pending-confirmation" @@ -5154,7 +5154,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -5219,7 +5219,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -5290,7 +5290,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -5385,7 +5385,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -5480,7 +5480,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "cancelled" @@ -7077,11 +7077,11 @@ }, "content": { "type": "string", - "description": "Optional partial raw parameter content to append." + "description": "Partial parameter content to append, if provided by the host." }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", - "description": "Updated display-ready progress message" + "description": "Updated progress message" } }, "required": [ @@ -7125,7 +7125,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, inline or readable with `resourceRead`" + "description": "Final tool input" }, "confirmationTitle": { "$ref": "#/$defs/StringOrMarkdown", @@ -9170,7 +9170,7 @@ "$ref": "#/$defs/ContentRef" } ], - "description": "Raw tool input represented inline or by reference, at the host's discretion." + "description": "Tool input represented inline or by reference." }, "ToolResultContent": { "oneOf": [ diff --git a/schema/errors.schema.json b/schema/errors.schema.json index e6c005288..545ebc3c0 100644 --- a/schema/errors.schema.json +++ b/schema/errors.schema.json @@ -3655,7 +3655,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." } }, "required": [ @@ -3741,7 +3741,7 @@ }, "partialInput": { "type": "string", - "description": "Partial raw parameters accumulated from optional tool-call deltas." + "description": "Partial parameters accumulated from tool-call deltas." }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", @@ -3790,7 +3790,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "pending-confirmation" @@ -3890,7 +3890,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -3955,7 +3955,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -4026,7 +4026,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -4121,7 +4121,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -4216,7 +4216,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "cancelled" @@ -6803,7 +6803,7 @@ "$ref": "#/$defs/ContentRef" } ], - "description": "Raw tool input represented inline or by reference, at the host's discretion." + "description": "Tool input represented inline or by reference." }, "ToolResultContent": { "oneOf": [ @@ -8081,11 +8081,11 @@ }, "content": { "type": "string", - "description": "Optional partial raw parameter content to append." + "description": "Partial parameter content to append, if provided by the host." }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", - "description": "Updated display-ready progress message" + "description": "Updated progress message" } }, "required": [ @@ -8129,7 +8129,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, inline or readable with `resourceRead`" + "description": "Final tool input" }, "confirmationTitle": { "$ref": "#/$defs/StringOrMarkdown", diff --git a/schema/notifications.schema.json b/schema/notifications.schema.json index cd077dd32..9ffe995fe 100644 --- a/schema/notifications.schema.json +++ b/schema/notifications.schema.json @@ -3818,7 +3818,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." } }, "required": [ @@ -3904,7 +3904,7 @@ }, "partialInput": { "type": "string", - "description": "Partial raw parameters accumulated from optional tool-call deltas." + "description": "Partial parameters accumulated from tool-call deltas." }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", @@ -3953,7 +3953,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "pending-confirmation" @@ -4053,7 +4053,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -4118,7 +4118,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -4189,7 +4189,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -4284,7 +4284,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -4379,7 +4379,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "cancelled" @@ -5621,7 +5621,7 @@ "$ref": "#/$defs/ContentRef" } ], - "description": "Raw tool input represented inline or by reference, at the host's discretion." + "description": "Tool input represented inline or by reference." }, "ToolResultContent": { "oneOf": [ diff --git a/schema/state.schema.json b/schema/state.schema.json index 64cc38638..ab63a1da9 100644 --- a/schema/state.schema.json +++ b/schema/state.schema.json @@ -3566,7 +3566,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." } }, "required": [ @@ -3652,7 +3652,7 @@ }, "partialInput": { "type": "string", - "description": "Partial raw parameters accumulated from optional tool-call deltas." + "description": "Partial parameters accumulated from tool-call deltas." }, "invocationMessage": { "$ref": "#/$defs/StringOrMarkdown", @@ -3701,7 +3701,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "pending-confirmation" @@ -3801,7 +3801,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -3866,7 +3866,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "confirmed": { "$ref": "#/$defs/ToolCallConfirmationReason", @@ -3937,7 +3937,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -4032,7 +4032,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "success": { "type": "boolean", @@ -4127,7 +4127,7 @@ }, "toolInput": { "$ref": "#/$defs/ToolInput", - "description": "Final raw tool input, either inline or readable with `resourceRead`.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." + "description": "Final tool input.\n\nReferenced input is mutable until the tool call leaves\n`pending-confirmation`. When the client confirms with `editedToolInput`,\nthe host MUST replace the resource contents before echoing the accepted\nconfirmation action. Clients MUST NOT cache tool input across confirmation." }, "status": { "const": "cancelled" @@ -5239,7 +5239,7 @@ "$ref": "#/$defs/ContentRef" } ], - "description": "Raw tool input represented inline or by reference, at the host's discretion." + "description": "Tool input represented inline or by reference." }, "ToolCallState": { "oneOf": [ diff --git a/types/channels-chat/actions.ts b/types/channels-chat/actions.ts index aaf0f27fa..2a435f890 100644 --- a/types/channels-chat/actions.ts +++ b/types/channels-chat/actions.ts @@ -174,9 +174,9 @@ export interface ChatToolCallStartAction extends ToolCallActionBase { */ export interface ChatToolCallDeltaAction extends ToolCallActionBase { type: ActionType.ChatToolCallDelta; - /** Optional partial raw parameter content to append. */ + /** Partial parameter content to append, if provided by the host. */ content?: string; - /** Updated display-ready progress message */ + /** Updated progress message */ invocationMessage: StringOrMarkdown; } @@ -212,7 +212,7 @@ export interface ChatToolCallReadyAction extends ToolCallActionBase { intention?: string; /** Message describing what the tool will do or what confirmation is needed */ invocationMessage: StringOrMarkdown; - /** Final raw tool input, inline or readable with `resourceRead` */ + /** Final tool input */ toolInput?: ToolInput; /** Short title for the confirmation prompt (e.g. `"Run in terminal"`, `"Write file"`) */ confirmationTitle?: StringOrMarkdown; diff --git a/types/channels-chat/state.ts b/types/channels-chat/state.ts index 6c3062ccf..726443173 100644 --- a/types/channels-chat/state.ts +++ b/types/channels-chat/state.ts @@ -1186,7 +1186,7 @@ interface ToolCallParameterFields { /** Message describing what the tool will do */ invocationMessage: StringOrMarkdown; /** - * Final raw tool input, either inline or readable with `resourceRead`. + * Final tool input. * * Referenced input is mutable until the tool call leaves * `pending-confirmation`. When the client confirms with `editedToolInput`, @@ -1197,7 +1197,7 @@ interface ToolCallParameterFields { } /** - * Raw tool input represented inline or by reference, at the host's discretion. + * Tool input represented inline or by reference. * * @category Tool Call Types */ @@ -1236,7 +1236,7 @@ export interface ToolCallResult { */ export interface ToolCallStreamingState extends ToolCallBase { status: ToolCallStatus.Streaming; - /** Partial raw parameters accumulated from optional tool-call deltas. */ + /** Partial parameters accumulated from tool-call deltas. */ partialInput?: string; /** Progress message shown while parameters are streaming */ invocationMessage?: StringOrMarkdown; From 4a7aed246f2955ee5fabe9264e3172d134f2798f Mon Sep 17 00:00:00 2001 From: Rob Lourens Date: Fri, 31 Jul 2026 12:48:59 -0700 Subject: [PATCH 6/6] chat: allow input-only tool call deltas Make invocationMessage optional so hosts may stream only parameter content, only progress text, or both. (Written by Copilot) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- clients/go/ahp/reducers.go | 6 ++++-- clients/go/ahptypes/actions.generated.go | 2 +- .../kotlin/com/microsoft/agenthostprotocol/Reducers.kt | 2 +- .../agenthostprotocol/generated/Actions.generated.kt | 2 +- clients/rust/crates/ahp-types/src/actions.rs | 3 ++- clients/rust/crates/ahp/src/reducers.rs | 4 +++- .../AgentHostProtocol/Generated/Actions.generated.swift | 4 ++-- .../Sources/AgentHostProtocol/Reducers.swift | 2 +- schema/actions.schema.json | 3 +-- schema/commands.schema.json | 3 +-- schema/errors.schema.json | 3 +-- types/channels-chat/actions.ts | 2 +- types/channels-chat/reducer.ts | 2 +- .../101-toolcalldelta-without-invocationmessage.json | 7 +++---- 14 files changed, 23 insertions(+), 22 deletions(-) diff --git a/clients/go/ahp/reducers.go b/clients/go/ahp/reducers.go index 13edef10d..f912928ec 100644 --- a/clients/go/ahp/reducers.go +++ b/clients/go/ahp/reducers.go @@ -1037,8 +1037,10 @@ func applyToolCallDelta(state *ahptypes.ChatState, a *ahptypes.ChatToolCallDelta partial += *a.Content s.PartialInput = &partial } - invocationMessage := a.InvocationMessage - s.InvocationMessage = &invocationMessage + if a.InvocationMessage != nil { + invocationMessage := *a.InvocationMessage + s.InvocationMessage = &invocationMessage + } return tc }) } diff --git a/clients/go/ahptypes/actions.generated.go b/clients/go/ahptypes/actions.generated.go index 6dc5eb5aa..fccdb904b 100644 --- a/clients/go/ahptypes/actions.generated.go +++ b/clients/go/ahptypes/actions.generated.go @@ -321,7 +321,7 @@ type ChatToolCallDeltaAction struct { // Partial parameter content to append, if provided by the host. Content *string `json:"content,omitempty"` // Updated progress message - InvocationMessage StringOrMarkdown `json:"invocationMessage"` + InvocationMessage *StringOrMarkdown `json:"invocationMessage,omitempty"` } // Tool call parameters are complete, or a running tool requires re-confirmation. 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 cf71b5722..d1579ce14 100644 --- a/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt +++ b/clients/kotlin/src/main/kotlin/com/microsoft/agenthostprotocol/Reducers.kt @@ -930,7 +930,7 @@ public fun chatReducer(state: ChatState, action: StateAction): ChatState = when meta = a.meta ?: tc.value.meta, partialInput = a.content?.let { (tc.value.partialInput ?: "") + it } ?: tc.value.partialInput, - invocationMessage = a.invocationMessage, + invocationMessage = a.invocationMessage ?: tc.value.invocationMessage, ), ) } 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 f114be727..cde9f9ede 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 @@ -447,7 +447,7 @@ data class ChatToolCallDeltaAction( /** * Updated progress message */ - val invocationMessage: StringOrMarkdown + val invocationMessage: StringOrMarkdown? = null ) @Serializable diff --git a/clients/rust/crates/ahp-types/src/actions.rs b/clients/rust/crates/ahp-types/src/actions.rs index 82797882e..849a339c5 100644 --- a/clients/rust/crates/ahp-types/src/actions.rs +++ b/clients/rust/crates/ahp-types/src/actions.rs @@ -450,7 +450,8 @@ pub struct ChatToolCallDeltaAction { #[serde(default, skip_serializing_if = "Option::is_none")] pub content: Option, /// Updated progress message - pub invocation_message: StringOrMarkdown, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub invocation_message: Option, } /// Tool call parameters are complete, or a running tool requires re-confirmation. diff --git a/clients/rust/crates/ahp/src/reducers.rs b/clients/rust/crates/ahp/src/reducers.rs index e82bb484a..a2cf5109a 100644 --- a/clients/rust/crates/ahp/src/reducers.rs +++ b/clients/rust/crates/ahp/src/reducers.rs @@ -1248,7 +1248,9 @@ fn apply_tool_call_delta(state: &mut ChatState, a: &ChatToolCallDeltaAction) -> if let Some(meta) = &a.meta { s.meta = Some(meta.clone()); } - s.invocation_message = Some(a.invocation_message.clone()); + if let Some(invocation_message) = &a.invocation_message { + s.invocation_message = Some(invocation_message.clone()); + } ToolCallState::Streaming(s) } other => other, diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift index 01628a2eb..da101cfd4 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Generated/Actions.generated.swift @@ -439,7 +439,7 @@ public struct ChatToolCallDeltaAction: Codable, Sendable { /// Partial parameter content to append, if provided by the host. public var content: String? /// Updated progress message - public var invocationMessage: StringOrMarkdown + public var invocationMessage: StringOrMarkdown? enum CodingKeys: String, CodingKey { case turnId @@ -456,7 +456,7 @@ public struct ChatToolCallDeltaAction: Codable, Sendable { meta: [String: AnyCodable]? = nil, type: ActionType, content: String? = nil, - invocationMessage: StringOrMarkdown + invocationMessage: StringOrMarkdown? = nil ) { self.turnId = turnId self.toolCallId = toolCallId diff --git a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift index 43d12e6d6..4e22c8e23 100644 --- a/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift +++ b/clients/swift/AgentHostProtocol/Sources/AgentHostProtocol/Reducers.swift @@ -210,7 +210,7 @@ public func chatReducer(state: ChatState, action: StateAction) -> ChatState { if let content = a.content { s.partialInput = (s.partialInput ?? "") + content } - s.invocationMessage = a.invocationMessage + s.invocationMessage = a.invocationMessage ?? s.invocationMessage s.meta = a.meta ?? s.meta return .streaming(s) } diff --git a/schema/actions.schema.json b/schema/actions.schema.json index 87857c9a2..c65bec234 100644 --- a/schema/actions.schema.json +++ b/schema/actions.schema.json @@ -847,8 +847,7 @@ "required": [ "turnId", "toolCallId", - "type", - "invocationMessage" + "type" ] }, "ChatToolCallReadyAction": { diff --git a/schema/commands.schema.json b/schema/commands.schema.json index ee9129a65..1d8e841f6 100644 --- a/schema/commands.schema.json +++ b/schema/commands.schema.json @@ -7087,8 +7087,7 @@ "required": [ "turnId", "toolCallId", - "type", - "invocationMessage" + "type" ] }, "ChatToolCallReadyAction": { diff --git a/schema/errors.schema.json b/schema/errors.schema.json index 545ebc3c0..1ba061e40 100644 --- a/schema/errors.schema.json +++ b/schema/errors.schema.json @@ -8091,8 +8091,7 @@ "required": [ "turnId", "toolCallId", - "type", - "invocationMessage" + "type" ] }, "ChatToolCallReadyAction": { diff --git a/types/channels-chat/actions.ts b/types/channels-chat/actions.ts index 2a435f890..caecaeb11 100644 --- a/types/channels-chat/actions.ts +++ b/types/channels-chat/actions.ts @@ -177,7 +177,7 @@ export interface ChatToolCallDeltaAction extends ToolCallActionBase { /** Partial parameter content to append, if provided by the host. */ content?: string; /** Updated progress message */ - invocationMessage: StringOrMarkdown; + invocationMessage?: StringOrMarkdown; } /** diff --git a/types/channels-chat/reducer.ts b/types/channels-chat/reducer.ts index d847617ca..b170cefb2 100644 --- a/types/channels-chat/reducer.ts +++ b/types/channels-chat/reducer.ts @@ -468,7 +468,7 @@ export function chatReducer(state: ChatState, action: ChatAction, log?: (msg: st ...(action.content !== undefined ? { partialInput: (tc.partialInput ?? '') + action.content } : {}), - invocationMessage: action.invocationMessage, + invocationMessage: action.invocationMessage ?? tc.invocationMessage, }; }); diff --git a/types/test-cases/reducers/101-toolcalldelta-without-invocationmessage.json b/types/test-cases/reducers/101-toolcalldelta-without-invocationmessage.json index 6328b51f0..5892b15fd 100644 --- a/types/test-cases/reducers/101-toolcalldelta-without-invocationmessage.json +++ b/types/test-cases/reducers/101-toolcalldelta-without-invocationmessage.json @@ -1,5 +1,5 @@ { - "description": "toolCallDelta appends optional partial input and replaces invocationMessage", + "description": "toolCallDelta appends input without changing invocationMessage when omitted", "reducer": "chat", "initial": { "turns": [], @@ -37,8 +37,7 @@ "type": "chat/toolCallDelta", "turnId": "turn-1", "toolCallId": "tc-1", - "content": "{\"command\":\"ls", - "invocationMessage": "Working" + "content": "{\"command\":\"ls" } ], "expected": { @@ -62,7 +61,7 @@ "displayName": "Run Command", "intention": null, "partialInput": "{\"command\":\"ls", - "invocationMessage": "Working" + "invocationMessage": "Original message" } } ],