Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ changes accumulate. Track in-flight protocol changes via PRs touching
point-in-time snapshot. Existing variants (root, session, terminal,
changeset, annotations) are unchanged.

### Fixed

- Session reducers now apply `_meta` updates from every tool-call-scoped
action, not only `session/toolCallStart`.

## [0.4.0] — Unreleased

Spec version: `0.4.0`
Expand Down
5 changes: 5 additions & 0 deletions clients/go/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ tag whose matching `## [X.Y.Z]` heading is missing from this file.
`root` + `recursive` keys (ordered between the existing changeset and
annotations probes).

### Fixed

- Reducer parity fixtures now require `_meta` updates from every
tool-call-scoped action, not only `session/toolCallStart`.

### Added

- `AnnotationsUpdatedAction` (`annotations/updated`) — partially updates an
Expand Down
36 changes: 32 additions & 4 deletions clients/go/ahp/reducers.go
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,9 @@ func ApplyActionToSession(state *ahptypes.SessionState, action ahptypes.StateAct
case *ahptypes.SessionToolCallContentChangedAction:
return updateToolCall(state, a.TurnId, a.ToolCallId, func(tc ahptypes.ToolCallState) ahptypes.ToolCallState {
if r, ok := tc.Value.(*ahptypes.ToolCallRunningState); ok {
if a.Meta != nil {
r.Meta = a.Meta
}
r.Content = append([]ahptypes.ToolResultContent(nil), a.Content...)
}
return tc
Expand Down Expand Up @@ -760,6 +763,9 @@ func applyToolCallDelta(state *ahptypes.SessionState, a *ahptypes.SessionToolCal
}
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
Expand All @@ -771,6 +777,9 @@ func applyToolCallDelta(state *ahptypes.SessionState, a *ahptypes.SessionToolCal
func applyToolCallReady(state *ahptypes.SessionState, a *ahptypes.SessionToolCallReadyAction) ReduceOutcome {
return updateToolCall(state, a.TurnId, a.ToolCallId, func(tc ahptypes.ToolCallState) ahptypes.ToolCallState {
common := toolCallMeta(tc)
if a.Meta != nil {
common.meta = a.Meta
}
switch tc.Value.(type) {
case *ahptypes.ToolCallStreamingState, *ahptypes.ToolCallRunningState:
if a.Confirmed != nil {
Expand Down Expand Up @@ -830,6 +839,10 @@ func applyToolCallConfirmed(state *ahptypes.SessionState, a *ahptypes.SessionToo
if a.EditedToolInput != nil {
toolInput = a.EditedToolInput
}
meta := s.Meta
if a.Meta != nil {
meta = a.Meta
}
confirmed := ahptypes.ToolCallConfirmationReasonNotNeeded
if a.Confirmed != nil {
confirmed = *a.Confirmed
Expand All @@ -840,7 +853,7 @@ func applyToolCallConfirmed(state *ahptypes.SessionState, a *ahptypes.SessionToo
ToolName: s.ToolName,
DisplayName: s.DisplayName,
Contributor: s.Contributor,
Meta: s.Meta,
Meta: meta,
InvocationMessage: s.InvocationMessage,
ToolInput: toolInput,
Confirmed: confirmed,
Expand All @@ -851,13 +864,17 @@ func applyToolCallConfirmed(state *ahptypes.SessionState, a *ahptypes.SessionToo
if a.Reason != nil {
reason = *a.Reason
}
meta := s.Meta
if a.Meta != nil {
meta = a.Meta
}
return ahptypes.ToolCallState{Value: &ahptypes.ToolCallCancelledState{
Status: ahptypes.ToolCallStatusCancelled,
ToolCallId: s.ToolCallId,
ToolName: s.ToolName,
DisplayName: s.DisplayName,
Contributor: s.Contributor,
Meta: s.Meta,
Meta: meta,
InvocationMessage: s.InvocationMessage,
ToolInput: s.ToolInput,
Reason: reason,
Expand All @@ -871,6 +888,9 @@ func applyToolCallConfirmed(state *ahptypes.SessionState, a *ahptypes.SessionToo
func applyToolCallComplete(state *ahptypes.SessionState, a *ahptypes.SessionToolCallCompleteAction) ReduceOutcome {
return updateToolCall(state, a.TurnId, a.ToolCallId, func(tc ahptypes.ToolCallState) ahptypes.ToolCallState {
common := toolCallMeta(tc)
if a.Meta != nil {
common.meta = a.Meta
}
var (
invocation ahptypes.StringOrMarkdown
toolInput *string
Expand Down Expand Up @@ -936,13 +956,17 @@ func applyToolCallResultConfirmed(state *ahptypes.SessionState, a *ahptypes.Sess
return tc
}
if a.Approved {
meta := s.Meta
if a.Meta != nil {
meta = a.Meta
}
return ahptypes.ToolCallState{Value: &ahptypes.ToolCallCompletedState{
Status: ahptypes.ToolCallStatusCompleted,
ToolCallId: s.ToolCallId,
ToolName: s.ToolName,
DisplayName: s.DisplayName,
Contributor: s.Contributor,
Meta: s.Meta,
Meta: meta,
InvocationMessage: s.InvocationMessage,
ToolInput: s.ToolInput,
Success: s.Success,
Expand All @@ -954,13 +978,17 @@ func applyToolCallResultConfirmed(state *ahptypes.SessionState, a *ahptypes.Sess
SelectedOption: s.SelectedOption,
}}
}
meta := s.Meta
if a.Meta != nil {
meta = a.Meta
}
return ahptypes.ToolCallState{Value: &ahptypes.ToolCallCancelledState{
Status: ahptypes.ToolCallStatusCancelled,
ToolCallId: s.ToolCallId,
ToolName: s.ToolName,
DisplayName: s.DisplayName,
Contributor: s.Contributor,
Meta: s.Meta,
Meta: meta,
InvocationMessage: s.InvocationMessage,
ToolInput: s.ToolInput,
Reason: ahptypes.ToolCallCancellationReasonResultDenied,
Expand Down
5 changes: 5 additions & 0 deletions clients/kotlin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ versions (`*-SNAPSHOT`) are explicitly rejected by the publish pipeline; bump
channel decodes via the existing `SnapshotStateSerializer` shape probe
(required `root` + `recursive` keys).

### Fixed

- `sessionReducer` now applies `_meta` (`meta`) updates from every
tool-call-scoped action, not only `session/toolCallStart`.

### Added

- `AnnotationsUpdatedAction` (`annotations/updated`) — partially updates an
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,9 @@ private data class ToolCallBase(
val displayName: String,
val contributor: ToolCallContributor?,
val meta: Map<String, JsonElement>?,
)
) {
fun withMeta(meta: Map<String, JsonElement>?): ToolCallBase = copy(meta = meta ?: this.meta)
}

private fun toolCallBase(tc: ToolCallState): ToolCallBase = when (tc) {
is ToolCallStateStreaming -> tc.value.let {
Expand Down Expand Up @@ -672,6 +674,7 @@ public fun sessionReducer(state: SessionState, action: StateAction): SessionStat
if (tc !is ToolCallStateStreaming) tc else {
ToolCallStateStreaming(
tc.value.copy(
meta = a.meta ?: tc.value.meta,
partialInput = (tc.value.partialInput ?: "") + a.content,
invocationMessage = a.invocationMessage ?: tc.value.invocationMessage,
),
Expand All @@ -687,7 +690,7 @@ public fun sessionReducer(state: SessionState, action: StateAction): SessionStat
if (tc !is ToolCallStateStreaming && tc !is ToolCallStateRunning) {
tc
} else {
val base = toolCallBase(tc)
val base = toolCallBase(tc).withMeta(a.meta)
if (a.confirmed != null) {
ToolCallStateRunning(
ToolCallRunningState(
Expand Down Expand Up @@ -730,7 +733,7 @@ public fun sessionReducer(state: SessionState, action: StateAction): SessionStat
refreshSummaryStatus(
updateToolCallInParts(state, a.turnId, a.toolCallId) { tc ->
if (tc !is ToolCallStatePendingConfirmation) tc else {
val base = toolCallBase(tc)
val base = toolCallBase(tc).withMeta(a.meta)
val selectedOption = resolveSelectedOption(tc.value.options, a.selectedOptionId)
if (a.approved) {
ToolCallStateRunning(
Expand Down Expand Up @@ -791,7 +794,7 @@ public fun sessionReducer(state: SessionState, action: StateAction): SessionStat
)
else -> return@updateToolCallInParts tc
}
val base = toolCallBase(tc)
val base = toolCallBase(tc).withMeta(a.meta)
if (a.requiresResultConfirmation == true) {
ToolCallStatePendingResultConfirmation(
ToolCallPendingResultConfirmationState(
Expand Down Expand Up @@ -842,7 +845,7 @@ public fun sessionReducer(state: SessionState, action: StateAction): SessionStat
refreshSummaryStatus(
updateToolCallInParts(state, a.turnId, a.toolCallId) { tc ->
if (tc !is ToolCallStatePendingResultConfirmation) tc else {
val base = toolCallBase(tc)
val base = toolCallBase(tc).withMeta(a.meta)
if (a.approved) {
ToolCallStateCompleted(
ToolCallCompletedState(
Expand Down Expand Up @@ -888,7 +891,7 @@ public fun sessionReducer(state: SessionState, action: StateAction): SessionStat
val a = action.value
updateToolCallInParts(state, a.turnId, a.toolCallId) { tc ->
if (tc !is ToolCallStateRunning) tc else {
ToolCallStateRunning(tc.value.copy(content = a.content))
ToolCallStateRunning(tc.value.copy(meta = a.meta ?: tc.value.meta, content = a.content))
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions clients/rust/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ matching `## [X.Y.Z]` heading is missing from this file.
terminal / changeset / annotations slots. `reset_host` / `reset` clear the
new slot.

### Fixed

- Session reducers now apply `_meta` (`meta`) updates from every
tool-call-scoped action, not only `session/toolCallStart`.

### Added

- `AnnotationsUpdatedAction` (`annotations/updated`) — partially updates an
Expand Down
14 changes: 11 additions & 3 deletions clients/rust/crates/ahp/src/reducers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,9 @@ fn apply_tool_call_delta(
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());
}
Expand All @@ -890,6 +893,7 @@ fn apply_tool_call_ready(
) -> ReduceOutcome {
update_tool_call(state, &a.turn_id, &a.tool_call_id, |tc| {
let (tool_call_id, tool_name, display_name, contributor, meta) = tool_call_meta(&tc);
let meta = a.meta.clone().or(meta);
match tc {
ToolCallState::Streaming(_) | ToolCallState::Running(_) => {
if let Some(confirmed) = a.confirmed {
Expand Down Expand Up @@ -949,7 +953,7 @@ fn apply_tool_call_confirmed(
let tool_name = s.tool_name;
let display_name = s.display_name;
let contributor = s.contributor;
let meta = s.meta;
let meta = a.meta.clone().or(s.meta);
let invocation_message = s.invocation_message;
let tool_input = s.tool_input;
if a.approved {
Expand Down Expand Up @@ -989,6 +993,7 @@ fn apply_tool_call_complete(
) -> ReduceOutcome {
update_tool_call(state, &a.turn_id, &a.tool_call_id, |tc| {
let (tool_call_id, tool_name, display_name, contributor, meta) = tool_call_meta(&tc);
let meta = a.meta.clone().or(meta);
let (invocation_message, tool_input, confirmed, selected_option) = match tc {
ToolCallState::Running(s) => (
s.invocation_message,
Expand Down Expand Up @@ -1056,7 +1061,7 @@ fn apply_tool_call_result_confirmed(
tool_name: s.tool_name,
display_name: s.display_name,
contributor: s.contributor,
meta: s.meta,
meta: a.meta.clone().or(s.meta),
invocation_message: s.invocation_message,
tool_input: s.tool_input,
success: s.success,
Expand All @@ -1073,7 +1078,7 @@ fn apply_tool_call_result_confirmed(
tool_name: s.tool_name,
display_name: s.display_name,
contributor: s.contributor,
meta: s.meta,
meta: a.meta.clone().or(s.meta),
invocation_message: s.invocation_message,
tool_input: s.tool_input,
reason: ToolCallCancellationReason::ResultDenied,
Expand All @@ -1091,6 +1096,9 @@ fn apply_tool_call_content_changed(
) -> ReduceOutcome {
update_tool_call(state, &a.turn_id, &a.tool_call_id, |tc| match tc {
ToolCallState::Running(mut s) => {
if let Some(meta) = &a.meta {
s.meta = Some(meta.clone());
}
s.content = Some(a.content.clone());
ToolCallState::Running(s)
}
Expand Down
Loading
Loading