Skip to main content

Client

Struct Client 

Source
pub struct Client { /* private fields */ }
Expand description

Connection to a GitHub Copilot CLI server (stdio, TCP, or external).

Cheaply cloneable — cloning shares the underlying connection. The child process (if any) is killed when the last clone drops.

Implementations§

Source§

impl Client

Source

pub async fn create_session( &self, config: SessionConfig, ) -> Result<Session, Error>

Create a new session on the CLI.

Sends session.create, registers the session on the router, and spawns an internal event loop that dispatches to the handler.

All callbacks (event handler, hooks, transform) are configured via SessionConfig using with_handler, with_hooks, and with_transform.

If hooks_handler is set, the wire-level hooks flag is automatically enabled.

If transform is set, the SDK injects action: "transform" sections into the SystemMessageConfig wire format and handles systemMessage.transform RPC callbacks during the session.

If handler is None, the session uses DenyAllHandler — permission requests are denied; other events are no-ops.

Source

pub async fn resume_session( &self, config: ResumeSessionConfig, ) -> Result<Session, Error>

Resume an existing session on the CLI.

Sends session.resume and session.skills.reload, registers the session on the router, and spawns the event loop.

All callbacks (event handler, hooks, transform) are configured via ResumeSessionConfig using its with_* builder methods.

See Self::create_session for the defaults applied when callback fields are unset.

Source§

impl Client

Source

pub async fn start(options: ClientOptions) -> Result<Self, Error>

Start a CLI server process with the given options.

For Transport::Stdio, spawns the CLI with --stdio and communicates over stdin/stdout pipes. For Transport::Tcp, spawns with --port and connects via TCP once the server reports it is listening. For Transport::External, connects to an already-running server.

After establishing the connection, calls verify_protocol_version to ensure the CLI server speaks a compatible protocol version. When ClientOptions::session_fs is set, also calls sessionFs.setProvider to register the SDK as the filesystem backend.

Source

pub fn from_streams( reader: impl AsyncRead + Unpin + Send + 'static, writer: impl AsyncWrite + Unpin + Send + 'static, cwd: PathBuf, ) -> Result<Self, Error>

Create a Client from raw async streams (no child process).

Useful for testing or connecting to a server over a custom transport.

Source

pub fn from_streams_with_trace_provider( reader: impl AsyncRead + Unpin + Send + 'static, writer: impl AsyncWrite + Unpin + Send + 'static, cwd: PathBuf, provider: Arc<dyn TraceContextProvider>, ) -> Result<Self, Error>

Construct a Client from raw streams with a TraceContextProvider preset, for integration testing.

Mirrors from_streams but exposes the on_get_trace_context plumbing so tests can verify outbound traceparent / tracestate injection on session.create, session.resume, and session.send.

Source

pub fn from_streams_with_connection_token( reader: impl AsyncRead + Unpin + Send + 'static, writer: impl AsyncWrite + Unpin + Send + 'static, cwd: PathBuf, token: Option<String>, ) -> Result<Self, Error>

Construct a Client from raw streams with a preset effective_connection_token, for integration testing the connect handshake’s token-forwarding path.

Source

pub fn generate_connection_token_for_test() -> String

Public test-only wrapper around the random connection-token generator used by Client::start when the SDK spawns a TCP server without an explicit token. Lets integration tests validate the token shape (32-char lowercase hex, 128 bits of entropy) without re-implementing the helper.

Source

pub fn cwd(&self) -> &PathBuf

Returns the working directory of the CLI process.

Source

pub fn rpc(&self) -> ClientRpc<'_>

Typed RPC namespace for server-level methods.

Every protocol method lives here under its schema-aligned path — e.g. client.rpc().models().list(). Wire method names and request/ response types are generated from the protocol schema, so the typed namespace can’t drift from the wire contract.

The hand-authored helpers on Client delegate to this namespace and remain the recommended entry point for everyday use; reach for rpc() when you want a method without a hand-written wrapper.

Source

pub async fn call( &self, method: &str, params: Option<Value>, ) -> Result<Value, Error>

Send a JSON-RPC request, check for errors, and return the result value.

This is the primary method for session-level RPC calls. It wraps the internal send/receive cycle with error checking so callers don’t need to inspect the response manually.

§Cancel safety

Cancel-safe. The frame is committed to the wire via the writer-actor task before the future yields; cancelling the await (via tokio::time::timeout, select!, or dropped JoinHandle) drops the response oneshot but does not desync the transport. The pending-requests entry is cleaned up by an RAII guard. However, the call’s side effect on the CLI may still occur — the CLI receives the request and processes it; the caller just won’t see the response. For idempotent methods this is fine; for non-idempotent methods (e.g. session.create) the caller should avoid wrapping the call in a timeout shorter than the expected CLI processing window.

Source

pub fn protocol_version(&self) -> Option<u32>

Returns the protocol version negotiated with the CLI server, if any.

Set during start. Returns None if the server didn’t report a version, or if the client was created via from_streams without calling verify_protocol_version.

Source

pub async fn verify_protocol_version(&self) -> Result<(), Error>

Verify the CLI server’s protocol version is within the supported range.

Called automatically by start. Call manually after from_streams if you need version verification on a custom transport.

§Handshake sequence
  1. Sends the connect JSON-RPC method, forwarding ClientOptions::tcp_connection_token (or the auto-generated token for SDK-spawned TCP servers) as the token param. This is the canonical handshake used by all SDK languages and is what the CLI uses to enforce loopback authentication when started with COPILOT_CONNECTION_TOKEN.
  2. If the server returns -32601 (MethodNotFound), falls back to the legacy ping RPC. This preserves compatibility with older CLI versions that predate connect.
§Result

Returns an error if the negotiated protocolVersion is outside MIN_PROTOCOL_VERSION..=SDK_PROTOCOL_VERSION. If the server doesn’t report a version, logs a warning and succeeds.

Source

pub async fn ping(&self, message: Option<&str>) -> Result<PingResponse, Error>

Send a ping RPC and return the typed PingResponse.

Pass Some(message) to have the server echo it back; pass None for a bare health check. The response includes a protocolVersion when the CLI reports one.

Source

pub async fn list_sessions( &self, filter: Option<SessionListFilter>, ) -> Result<Vec<SessionMetadata>, Error>

List persisted sessions, optionally filtered by working directory, repository, or git context.

Source

pub async fn get_session_metadata( &self, session_id: &SessionId, ) -> Result<Option<SessionMetadata>, Error>

Fetch metadata for a specific persisted session by ID.

Returns Ok(None) if no session with the given ID exists. More efficient than calling list_sessions and filtering when you only need data for a single session.

§Example
use github_copilot_sdk::types::SessionId;
if let Some(metadata) = client.get_session_metadata(&SessionId::new("session-123")).await? {
    println!("Session started at: {}", metadata.start_time);
}
Source

pub async fn delete_session(&self, session_id: &SessionId) -> Result<(), Error>

Delete a persisted session by ID.

Source

pub async fn get_last_session_id(&self) -> Result<Option<SessionId>, Error>

Return the ID of the most recently updated session, if any.

Useful for resuming the last conversation when the session ID was not stored. Returns Ok(None) if no sessions exist.

§Example
if let Some(last_id) = client.get_last_session_id().await? {
    println!("Last session: {last_id}");
}
Source

pub async fn get_foreground_session_id( &self, ) -> Result<Option<SessionId>, Error>

Return the ID of the session currently displayed in the TUI, if any.

Only meaningful when connected to a server running in TUI+server mode (--ui-server). Returns Ok(None) if no foreground session is set.

Source

pub async fn set_foreground_session_id( &self, session_id: &SessionId, ) -> Result<(), Error>

Request that the TUI switch to displaying the specified session.

Only meaningful when connected to a server running in TUI+server mode (--ui-server).

Source

pub async fn get_status(&self) -> Result<GetStatusResponse, Error>

Get the CLI server status.

Source

pub async fn get_auth_status(&self) -> Result<GetAuthStatusResponse, Error>

Get authentication status.

Source

pub async fn list_models(&self) -> Result<Vec<Model>, Error>

List available models.

When ClientOptions::on_list_models is set, returns the handler’s result without making a models.list RPC. Otherwise queries the CLI.

Source

pub fn pid(&self) -> Option<u32>

Return the OS process ID of the CLI child process, if one was spawned.

Source

pub async fn stop(&self) -> Result<(), StopErrors>

Cooperatively shut down the client and the CLI child process.

Walks every still-registered session and sends session.destroy for each one, then kills the CLI child. Errors from per-session destroys and the final child-kill are collected into StopErrors rather than short-circuiting on the first failure — so callers see the full picture of teardown.

If you have already called Session::disconnect on every session this client created, the per-session destroy step is a no-op (the router map is empty); only the child-kill remains.

§Cancel safety

Cancel-unsafe but recoverable. The body sequentially destroys every registered session (each via Client::call, individually cancel-safe) before killing the child. Cancelling stop() mid-loop leaves some sessions still in the router map and the child still running. Recovery: call force_stop (sync, kills the child unconditionally and clears router state) or call stop() again with a fresh future. The documented tokio::time::timeout(..., client.stop()) pattern in the example below uses force_stop as the fallback for exactly this case.

Source

pub fn force_stop(&self)

Forcibly stop the CLI process without waiting for it to exit.

Synchronous fallback when stop is unsuitable — for example when the awaiting tokio runtime is shutting down or the process is wedged on I/O. Sends a kill signal without awaiting reaper completion and immediately drops all per-session router state so dependent tasks observe a closed channel rather than a hang.

§Cancel safety

Synchronous and infallible by construction. Not async; cannot be cancelled. Designed as the recovery path when stop is wrapped in a timeout that elapses.

§Example
// Try graceful shutdown first; fall back to force_stop if hung.
match tokio::time::timeout(
    std::time::Duration::from_secs(5),
    client.stop(),
).await {
    Ok(_) => {}
    Err(_) => client.force_stop(),
}
Source

pub fn subscribe_lifecycle(&self) -> LifecycleSubscription

Subscribe to lifecycle events.

Returns a LifecycleSubscription that yields every SessionLifecycleEvent sent by the CLI. Drop the value to unsubscribe; there is no separate cancel handle.

The returned handle implements both an inherent recv method and Stream, so callers can use a while let loop or any combinator from tokio_stream::StreamExt / futures::StreamExt.

Each subscriber maintains its own queue. If a consumer cannot keep up, the oldest events are dropped and recv returns RecvError::Lagged with the count of skipped events; consumers should match on it and continue. Slow consumers do not block the producer.

To filter by event type, match on event.event_type in the consumer task. There is no built-in typed filter — match is more flexible and keeps the API surface small.

§Example
let mut events = client.subscribe_lifecycle();
tokio::spawn(async move {
    while let Ok(event) = events.recv().await {
        println!("session {} -> {:?}", event.session_id, event.event_type);
    }
});
Source

pub fn state(&self) -> ConnectionState

Return the current ConnectionState.

The state advances to Connected once Client::start / Client::from_streams returns successfully and drops to Disconnected after stop or force_stop.

Trait Implementations§

Source§

impl Clone for Client

Source§

fn clone(&self) -> Client

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Client

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more