You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Outbound (client→server): the SDK calls into the runtime.
Inbound (server→client): the runtime calls back into the SDK — e.g. clientSession.* (canvas, sessionFs) and the new clientGlobal.* (llmInference) callbacks added in HTTP request callback support #1689.
For inbound dispatch, the four SDKs split into two camps:
C#, Go, Python, TypeScript code-generate the inbound handler scaffolding (handler interfaces + the dispatch/registration glue) from api.schema.json. Adding the clientGlobal bucket in HTTP request callback support #1689 required teaching all four scripts/codegen/*.ts generators about it.
Rust generates only the inbound wire types (generated/api_types.rs) and method-name constants (rpc_methods::* in generated/rpc.rs). The per-group dispatch + handler trait is hand-written, consistently, across all three inbound groups:
Each follows the identical shape: prefix-check → match rpc_methods::* constant → deserialize generated params → call the hand-written handler trait → serialize the result.
Java has no codegen pipeline at all (entire RPC surface hand-authored), so it's out of scope here.
Proposal
Bring Rust to parity with the other generated SDKs by code-generating the inbound handler trait + dispatch helper per group into rust/src/generated/, so future inbound callbacks (new clientSession / clientGlobal groups) come for free, as they already do in C#/Go/Python/TS.
This was investigated during #1689 and deliberately deferred:
Do all three groups, not a one-off. Rust's hand-written-dispatch convention is currently uniform across canvas, sessionFs, and llmInference. Generating only llmInference (the group HTTP request callback support #1689 touches) would trade Rust's internal consistency for cross-SDK symmetry and leave a confusing one-off. The clean change converts all three groups together — a cross-cutting refactor of shipped, well-tested dispatchers and their public trait surfaces (CanvasHandler, SessionFsProvider, CopilotRequestHandler), out of scope for a callbacks PR.
Generate only the low-level wire trait; keep ergonomic traits + streaming bridges hand-written. The public CopilotRequestHandler (send_request + open_websocket) does not mirror the wire methods (httpRequestStart + httpRequestChunk); ~1200 lines bridge frame-oriented streaming ↔ that 2-method seam with stateful exchange correlation. Codegen should emit only the thin wire-level trait + dispatch (mirroring what TS generates), with the ergonomic traits and the llmInference bridge staying hand-written. Net hand-written savings are small (≈ the dispatch match + method constants); the value is future-proofing and symmetry, not LOC.
Validation. The streaming handler is heavily covered by Rust e2e (cancel / error / session-id) record-replay tests that should gate the refactor in CI.
Suggested scope of work
Add inbound handler-trait + dispatch emission to scripts/codegen/rust.ts (read clientSession + clientGlobal), emitting into rust/src/generated/.
Migrate canvas_dispatch.rs, session_fs_dispatch.rs, and copilot_request_handler.rs to implement/use the generated trait + dispatch instead of their hand-rolled match + local method-name constants.
Keep ergonomic public traits (CanvasHandler, SessionFsProvider, CopilotRequestHandler) and the llmInference streaming bridge hand-written.
Verify cargo build + clippy + the full Rust e2e suite stay green.
References
PR HTTP request callback support #1689 (LLM inference callbacks) — where the clientGlobal bucket and the C#/Go/Python/TS generator changes landed.
Generators with inbound support: scripts/codegen/{csharp,go,python,typescript}.ts (emitClientGlobalApiRegistration / emitClientSessionApiRegistration).
Rust generator (outbound only today): scripts/codegen/rust.ts.
Background
The SDK protocol has two directions of RPC:
clientSession.*(canvas,sessionFs) and the newclientGlobal.*(llmInference) callbacks added in HTTP request callback support #1689.For inbound dispatch, the four SDKs split into two camps:
C#, Go, Python, TypeScript code-generate the inbound handler scaffolding (handler interfaces + the dispatch/registration glue) from
api.schema.json. Adding theclientGlobalbucket in HTTP request callback support #1689 required teaching all fourscripts/codegen/*.tsgenerators about it.Rust generates only the inbound wire types (
generated/api_types.rs) and method-name constants (rpc_methods::*ingenerated/rpc.rs). The per-group dispatch + handler trait is hand-written, consistently, across all three inbound groups:canvas.*→rust/src/canvas_dispatch.rssessionFs.*→rust/src/session_fs_dispatch.rsllmInference.*→rust/src/copilot_request_handler.rs(dispatch)Each follows the identical shape: prefix-check → match
rpc_methods::*constant → deserialize generated params → call the hand-written handler trait → serialize the result.Java has no codegen pipeline at all (entire RPC surface hand-authored), so it's out of scope here.
Proposal
Bring Rust to parity with the other generated SDKs by code-generating the inbound handler trait + dispatch helper per group into
rust/src/generated/, so future inbound callbacks (newclientSession/clientGlobalgroups) come for free, as they already do in C#/Go/Python/TS.Why this is its own PR, not part of #1689
This was investigated during #1689 and deliberately deferred:
Do all three groups, not a one-off. Rust's hand-written-dispatch convention is currently uniform across
canvas,sessionFs, andllmInference. Generating onlyllmInference(the group HTTP request callback support #1689 touches) would trade Rust's internal consistency for cross-SDK symmetry and leave a confusing one-off. The clean change converts all three groups together — a cross-cutting refactor of shipped, well-tested dispatchers and their public trait surfaces (CanvasHandler,SessionFsProvider,CopilotRequestHandler), out of scope for a callbacks PR.Generate only the low-level wire trait; keep ergonomic traits + streaming bridges hand-written. The public
CopilotRequestHandler(send_request+open_websocket) does not mirror the wire methods (httpRequestStart+httpRequestChunk); ~1200 lines bridge frame-oriented streaming ↔ that 2-method seam with stateful exchange correlation. Codegen should emit only the thin wire-level trait + dispatch (mirroring what TS generates), with the ergonomic traits and the llmInference bridge staying hand-written. Net hand-written savings are small (≈ the dispatchmatch+ method constants); the value is future-proofing and symmetry, not LOC.Validation. The streaming handler is heavily covered by Rust e2e (cancel / error / session-id) record-replay tests that should gate the refactor in CI.
Suggested scope of work
scripts/codegen/rust.ts(readclientSession+clientGlobal), emitting intorust/src/generated/.canvas_dispatch.rs,session_fs_dispatch.rs, andcopilot_request_handler.rsto implement/use the generated trait + dispatch instead of their hand-rolledmatch+ local method-name constants.CanvasHandler,SessionFsProvider,CopilotRequestHandler) and the llmInference streaming bridge hand-written.cargo build+ clippy + the full Rust e2e suite stay green.References
clientGlobalbucket and the C#/Go/Python/TS generator changes landed.scripts/codegen/{csharp,go,python,typescript}.ts(emitClientGlobalApiRegistration/emitClientSessionApiRegistration).scripts/codegen/rust.ts.