Skip to content

Port validation and lifecycle fixes to Node, Python, and Go#1341

Open
stephentoub wants to merge 6 commits into
mainfrom
stephentoub/port-csharp-validation
Open

Port validation and lifecycle fixes to Node, Python, and Go#1341
stephentoub wants to merge 6 commits into
mainfrom
stephentoub/port-csharp-validation

Conversation

@stephentoub
Copy link
Copy Markdown
Collaborator

C# recently tightened generated RPC argument validation and session lifecycle cleanup. This ports the commensurate behavior to the SDKs that had matching gaps so clients fail earlier, do not keep stale active sessions around, and reject duplicate active local sessions consistently.

Summary

  • Updates the TypeScript, Python, and Go RPC generators so generated session APIs validate required params before sending and reject session-scoped RPC calls after disconnect.
  • Cleans up Node, Python, and Go session/client lifecycle handling: direct disconnect unregisters from the parent client, stop/force-stop/delete paths clear active session maps safely, and duplicate active session IDs are rejected.
  • Adds focused lifecycle and generated-RPC regression coverage, plus adjusts Go e2e resume coverage for the new duplicate-active-session contract.

Rust was reviewed but left unchanged because its existing ownership/lifecycle model already covers the comparable behavior.

Validation

  • cd nodejs && npm run typecheck
  • cd nodejs && npm test -- client.test.ts --testNamePattern "directly disconnected|reports stop errors|replacement session|duplicate active|validates required"
  • cd python && python -m pytest -q test_client.py test_rpc_generated.py
  • cd python && python -m ruff check test_client.py test_rpc_generated.py copilot\client.py copilot\session.py
  • cd go && go test -timeout 20m ./...
  • git diff --check

@stephentoub stephentoub requested a review from a team as a code owner May 20, 2026 03:07
Copilot AI review requested due to automatic review settings May 20, 2026 03:07
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR ports stricter generated-RPC argument validation and session lifecycle cleanup (previously tightened in C#) to the Node.js, Python, and Go SDKs, so clients fail earlier on invalid usage and don’t retain stale/duplicate active sessions.

Changes:

  • Updated TS/Python/Go RPC generators (and regenerated outputs) to validate required request objects before sending and to reject session-scoped RPC calls once a session is disconnected.
  • Hardened session/client lifecycle cleanup across Node/Python/Go (disconnect unregisters from the owning client; stop/force-stop/delete ensure sessions are marked unusable; duplicate active session IDs are rejected).
  • Added/updated targeted unit + E2E regression coverage to lock in lifecycle/validation behavior, including updated Go resume tests for the new “duplicate active session” contract.
Show a summary per file
File Description
scripts/codegen/typescript.ts Emit session “active” assertions and required-params checks in generated TS RPC methods.
scripts/codegen/python.ts Emit session “active” assertions and required-params checks in generated Python RPC methods.
scripts/codegen/go.ts Emit session “active” assertions and required-params checks in generated Go RPC methods.
python/test_rpc_generated.py Adds regression tests for required-params validation and active-check behavior.
python/test_client.py Adds/updates lifecycle tests for disconnect/unregister, duplicates, and failure cleanup paths.
python/copilot/session.py Implements disconnect idempotency + active-use rejection; clears handlers/hooks on disconnect and supports unregister callback.
python/copilot/generated/rpc.py Regenerated RPC surface with params validation and assert-active hooks for session APIs.
python/copilot/client.py Adds session registration helpers; enforces duplicate-active rejection and consistent cleanup on stop/force-stop/delete.
nodejs/test/client.test.ts Adds unit coverage for lifecycle cleanup, stop errors, duplicate registration, and params validation.
nodejs/src/session.ts Adds disconnect state, active assertions, idempotent disconnect, forced-disconnect hook, and unregister callback.
nodejs/src/generated/rpc.ts Regenerated RPC surface with params validation and assert-active hooks for session APIs.
nodejs/src/client.ts Enforces duplicate-active session IDs; ensures stop/force-stop/delete mark sessions disconnected and clears internal RPC state.
go/session.go Adds session active-state tracking, idempotent Disconnect, and client unregister on disconnect; rejects usage after disconnect.
go/session_test.go Adds unit tests covering lifecycle cleanup and duplicate-active session registration behavior.
go/rpc/zrpc.go Regenerated Go RPC surface with params validation and assert-active checks for session APIs.
go/rpc/generated_rpc_api_shape_test.go Adds regression tests for required-params validation and active-check ordering.
go/internal/e2e/session_e2e_test.go Updates E2E expectations for post-disconnect behavior and validates duplicate-active resume rejection; adds resume-client helper.
go/internal/e2e/session_config_e2e_test.go Updates resume scenarios to use a separate TCP client consistent with the new “active session” contract.
go/internal/e2e/permissions_e2e_test.go Updates resume permissions scenario to use separate resume client and aligns with new join behavior.
go/internal/e2e/mcp_and_agents_e2e_test.go Updates resume scenarios to use separate resume client (TCP mode).
go/internal/e2e/commands_and_elicitation_e2e_test.go Updates resume scenario to use separate resume client (TCP mode).
go/client.go Enforces duplicate-active session IDs and centralizes session snapshot/clear helpers; ensures stop/force-stop disconnects and marks sessions unusable.

Copilot's findings

Files not reviewed (1)
  • go/rpc/zrpc.go: Language not supported
  • Files reviewed: 19/22 changed files
  • Comments generated: 2

Comment thread python/copilot/session.py
Comment thread go/internal/e2e/permissions_e2e_test.go Outdated
@github-actions

This comment has been minimized.

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Generated by SDK Consistency Review Agent for issue #1341 · ● 2.6M

Copilot AI added 3 commits May 20, 2026 08:38
Port C# argument validation and lifecycle cleanup behavior to Node, Python, and Go. Generated session RPC APIs now validate required params and reject use after disconnect, while clients clean up active session maps consistently and reject duplicate active session IDs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Apply ruff formatting to the new Python lifecycle regression tests so CI format checks pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@stephentoub stephentoub force-pushed the stephentoub/port-csharp-validation branch from bac3c1c to ce8aa9e Compare May 20, 2026 13:25
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

This comment has been minimized.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

This comment has been minimized.

Mark Python test sessions inactive before same-client resume so the duplicate active-session guard is preserved without destroying the server-side session.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

Cross-SDK Consistency Review

This PR ports C# validation and lifecycle behaviors to Node.js, Python, and Go. Overall the implementation is consistent and well-structured across all three modified SDKs.

✅ What's consistent

All three SDKs (Node.js, Python, Go) receive the same set of changes in parallel:

Feature Node.js Python Go .NET Rust
Reject duplicate active session IDs registerSession _register_session registerSession ✅ (reference) N/A (ownership model)
Session auto-unregisters on disconnect onDisconnected callback on_disconnected callback owner back-reference RemoveFromClient() N/A
assertActive guard on session APIs ThrowIfDisposed() N/A
assertActive in generated session RPC methods N/A
markDisconnected on stop()/forceStop() DisposeAsync() N/A
Thread-safe disconnect() deduplication disconnectPromise _disconnect_task closing channel Interlocked.Exchange N/A

Rust is correctly excluded — its ownership model prevents the described failure modes structurally.

💡 Minor follow-up suggestion for .NET parity

The PR adds a new behavior in Node.js, Python, and Go: calling deleteSession/delete_session/DeleteSession now marks the local session object as disconnected (preventing subsequent method calls from succeeding). For example, in Node.js (client.ts line 1258–1264):

const session = this.sessions.get(sessionId);
if (session) {
    session._markDisconnected();
} else {
    this.sessions.delete(sessionId);
}

The .NET DeleteSessionAsync currently only removes the session from the client map (RemoveSession(sessionId)) without calling DisposeAsync() on it — so after deletion, a caller holding the session object can still call methods on it without getting a ThrowIfDisposed error (the call would ultimately fail at the server side instead). Consider adding a similar MarkDisposed()/DisposeAsync() call to .NET's DeleteSessionAsync in a follow-up for full parity. This is a pre-existing gap in .NET, not something introduced by this PR.

Generated by SDK Consistency Review Agent for issue #1341 · ● 1.9M ·

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.

3 participants