Skip to content

go: plumb context cancellation through ToolInvocation for session.Abort()#1705

Open
gimenete wants to merge 3 commits into
github:mainfrom
gimenete:gimenete/go-sdk-abort-signal-tool-invocation
Open

go: plumb context cancellation through ToolInvocation for session.Abort()#1705
gimenete wants to merge 3 commits into
github:mainfrom
gimenete:gimenete/go-sdk-abort-signal-tool-invocation

Conversation

@gimenete

@gimenete gimenete commented Jun 17, 2026

Copy link
Copy Markdown

Summary

Closes #1433 (Go SDK portion)

When session.Abort() is called, in-flight tool handlers now receive a cooperative cancellation signal via ToolInvocation.Context. A new session.CancelToolCall(toolCallID) method lets callers cancel a single handler without affecting others or the agentic loop.

Changes

go/types.go

  • Added Context context.Context to ToolInvocation — carries W3C Trace Context (OTel) and is cancelled when session.Abort() or session.CancelToolCall() is called.
  • Deprecated TraceContext in favour of Context (same value; existing code using TraceContext continues to work unchanged).

go/session.go

  • Added toolCallCancels map[string]context.CancelFunc + mutex to Session to track in-flight tool call cancel funcs.
  • executeToolAndRespond creates a context.WithCancel child of the trace context and registers its cancel func; cleans up (deregisters + calls cancel()) when the handler returns or panics.
  • Two separate defers (LIFO) ensure panic recovery runs before cleanup, so the error RPC response is still sent when a panic occurs.
  • RPC response calls (HandlePendingToolCall) use traceCtx (non-cancellable) so they succeed even if Abort() already fired.
  • Abort() cancels all stored cancel funcs and removes them from the map after the RPC acknowledgment.
  • CancelToolCall(toolCallID string) bool — cancels a single in-flight handler by ID. Returns true if found and cancelled, false if not in flight. Idempotent.

go/session_test.go

  • Extract newRPCDrainSession helper (pipe-based mock RPC, drains all requests with empty success responses).
  • TestToolInvocation_ContextCancelledOnAbort — handler context cancelled by abort simulation; map cleaned up.
  • TestToolInvocation_ContextPopulatedContext and TraceContext both set and equal.
  • TestCancelToolCall_cancelsTargetedHandlerOnly — unknown ID returns false; targeted handler cancelled; sibling handler stays live; second call on same ID returns false.

go/README.md

  • "Cooperative Cancellation via session.Abort" section with HTTP example.
  • "Cancelling a single tool call" section with CancelToolCall example and ToolCallID capture pattern.

Backwards compatibility

Existing handlers that ignore inv.Context / inv.TraceContext are unaffected. TraceContext holds the same value as before (additive change).

…rt()

Add a Context field to ToolInvocation that is cancelled when session.Abort
is called. This lets tool handlers cooperatively stop in-flight work (HTTP
requests, DB queries, sleeps) when the session is aborted, without requiring
OS-level process kills.

Changes:
- Add Context context.Context to ToolInvocation; it carries OTel trace
  propagation AND is cancelled on Abort()
- Deprecate TraceContext in favour of Context (same value, new name that
  better communicates its dual role)
- Track per-tool-call cancel funcs in Session.toolCallCancels; clean up
  after each call completes
- In Abort(), cancel all in-flight cancel funcs after the RPC call
- RPC response calls (HandlePendingToolCall) use traceCtx (non-cancellable)
  so they succeed even when the handler context was aborted
- Add TestToolInvocation_ContextCancelledOnAbort and
  TestToolInvocation_ContextPopulated unit tests
- Document the cancellation pattern in go/README.md

Fixes github#1433

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 17, 2026 12:30
@gimenete gimenete requested a review from a team as a code owner June 17, 2026 12:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR introduces cooperative cancellation for tool handlers by propagating session.Abort() into a new ToolInvocation.Context, while preserving trace propagation for OpenTelemetry.

Changes:

  • Add ToolInvocation.Context (cancelled on Session.Abort) and deprecate direct usage of ToolInvocation.TraceContext.
  • Track in-flight tool call cancel functions in Session and cancel them during Abort.
  • Add tests and documentation describing cancellation behavior for tool handlers.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
go/types.go Adds ToolInvocation.Context and deprecation guidance for TraceContext.
go/session.go Implements per-tool-call cancellation tracking and abort-triggered cancellation; uses a non-cancelled context for RPC responses.
go/session_test.go Adds tests validating handler context cancellation on abort and context population.
go/README.md Documents cooperative cancellation via ToolInvocation.Context.

Comment thread go/session.go
Comment thread go/session_test.go Outdated
gimenete and others added 2 commits June 17, 2026 14:34
Add Session.CancelToolCall(toolCallID string) bool — cancels a single
in-flight tool handler by its tool call ID without affecting other
concurrent handlers or the agentic loop.

- CancelToolCall looks up the cancel func in toolCallCancels, calls it,
  removes the entry, and returns true; returns false if not in flight
- Abort() now also removes entries after cancelling them, so a subsequent
  CancelToolCall on the same ID correctly returns false
- Extract newRPCDrainSession test helper to eliminate boilerplate across
  the three tool-context tests
- Add TestCancelToolCall_cancelsTargetedHandlerOnly covering: unknown ID
  returns false, targeted handler context is cancelled, sibling handler
  context stays live, idempotent false on second call
- Document CancelToolCall in go/README.md alongside Abort cancellation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Set TraceContext to traceCtx (non-cancellable) to preserve backward
  compatibility; TraceContext is no longer affected by session.Abort() or
  CancelToolCall(). Only Context (the new field) is cancelled.
- Fix newRPCDrainSession drain goroutine: replace bufio.Scanner + io.ReadFull
  on the same reader (which causes buffer-ahead corruption) with a single
  bufio.Reader used for both header line reads and body ReadFull calls.
- Update TestToolInvocation_ContextPopulated assertion: Context and
  TraceContext are now different instances (Context is a cancellable child
  of TraceContext), so assert they differ rather than being equal.
- Clarify TraceContext deprecation comment: document it is never cancelled.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: Plumb AbortSignal through ToolInvocation so session.abort() can cancel in-flight tool handlers

2 participants