Skip to content

Commit f3ca194

Browse files
stephentoubCopilot
andcommitted
Add Rust SDK
Adds a complete Rust implementation of the Copilot SDK alongside the existing TypeScript, Go, Python, and .NET SDKs, integrated into the mono-repo so it builds and is checked the same way as the others. Crate layout (rust/): - copilot-sdk crate (lib name copilot) targeting tokio/serde/async-trait - Public client (Client, ClientOptions, Transport: Stdio/Tcp/External) with stdio, TCP, and external transports; child process management with stderr draining; protocol version negotiation; and graceful Drop-time cleanup. - Session API (Session, SessionConfig, ResumeSessionConfig) covering create/resume, send_message, get_messages, set_model / set_model_with_options, list-sessions, attachments, hooks, and reload helpers. - Handler traits: SessionHandler, SessionHooks, SystemMessageTransform, SessionFsHandler, ListModelsHandler with idiomatic async-trait bounds and blanket impls for closures where appropriate. - Typed session events generated from the shared schema, with full enum coverage and pattern-matching ergonomics. - Custom session filesystem provider: connection-level SessionFsConfig + validation, sessionFs.setProvider registration after protocol verification, and per-session dispatch of all 10 sessionFs.* RPCs. - Custom onListModels handler with thread-safe, double-checked cache matching the other SDKs' semantics. - Model capability overrides via SetModelOptions / ModelCapabilitiesOverride and extended SessionConfig/ResumeSessionConfig fields (session_id, agent, model_capabilities, config_dir, working_directory, available_tools, provider, custom_agents, infinite_sessions, commands, disabled_skills, disable_resume). - Permission, elicitation, exit-plan-mode, and user-input request routing with strongly typed results. - Duration serde helper and codegen support for format: "duration", "deprecated": true, and $ref resolution. Code generation (scripts/codegen/rust.ts): - New TypeScript generator producing rust/src/generated/{rpc,session_events}.rs - Mirrors the existing Go/Python/.NET generators: shared type registration, snake_case <-> camelCase serde renames, optional field handling, anonymous struct flattening, enum variant generation, and special-case handling (duration, deprecated, $ref). - Run via: cd scripts/codegen && npm run generate:rust CI / repo integration: - GitHub Actions workflow for the Rust SDK (build, fmt, clippy, test) - justfile tasks updated so just install / format / lint / test cover Rust - Consistency-agent coverage so the Rust surface is checked against the other SDKs Scenarios / E2E: - Rust implementations of the shared E2E scenarios under test/scenarios/** so the replaying CAPI proxy harness exercises the Rust SDK alongside the others. Docs: - rust/README.md with quick start, API reference, and parity notes for the new handlers and extended config fields. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent dbcea81 commit f3ca194

135 files changed

Lines changed: 49958 additions & 18 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitattributes

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ nodejs/src/generated/* eol=lf linguist-generated=true
55
dotnet/src/Generated/* eol=lf linguist-generated=true
66
python/copilot/generated/* eol=lf linguist-generated=true
77
go/generated_session_events.go eol=lf linguist-generated=true
8-
go/rpc/generated_rpc.go eol=lf linguist-generated=true
8+
go/rpc/generated_rpc.go eol=lf linguist-generated=true
9+
rust/src/generated/* eol=lf linguist-generated=true

.github/copilot-instructions.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44

55
## Big picture 🔧
66

7-
- The repo implements language SDKs (Node/TS, Python, Go, .NET) that speak to the **Copilot CLI** via **JSON‑RPC** (see `README.md` and `nodejs/src/client.ts`).
8-
- Typical flow: your App → SDK client → JSON-RPC → Copilot CLI (server mode). The CLI must be installed or you can connect to an external CLI server via the `CLI URL option (language-specific casing)` (Node: `cliUrl`, Go: `CLIUrl`, .NET: `CliUrl`, Python: `cli_url`).
7+
- The repo implements language SDKs (Node/TS, Python, Go, .NET, Rust) that speak to the **Copilot CLI** via **JSON‑RPC** (see `README.md` and `nodejs/src/client.ts`).
8+
- Typical flow: your App → SDK client → JSON-RPC → Copilot CLI (server mode). The CLI must be installed or you can connect to an external CLI server via the `CLI URL option (language-specific casing)` (Node: `cliUrl`, Go: `CLIUrl`, .NET: `CliUrl`, Python: `cli_url`, Rust: `cli_url`).
99

1010
## Most important files to read first 📚
1111

1212
- Top-level: `README.md` (architecture + quick start)
13-
- Language entry points: `nodejs/src/client.ts`, `python/README.md`, `go/README.md`, `dotnet/README.md`
13+
- Language entry points: `nodejs/src/client.ts`, `python/README.md`, `go/README.md`, `dotnet/README.md`, `rust/README.md`
1414
- Test harness & E2E: `test/harness/*`, Python harness wrapper `python/e2e/testharness/proxy.py`
1515
- Schemas & type generation: `nodejs/scripts/generate-session-types.ts`
1616
- Session snapshots used by E2E: `test/snapshots/` (used by the replay proxy)
@@ -25,6 +25,7 @@
2525
- Python: `cd python && uv pip install -e ".[dev]"``uv run pytest` (E2E tests use the test harness)
2626
- Go: `cd go && go test ./...`
2727
- .NET: `cd dotnet && dotnet test test/GitHub.Copilot.SDK.Test.csproj`
28+
- Rust: `cd rust && cargo test`
2829
- **.NET testing note:** Never add `InternalsVisibleTo` to any project file when writing tests. Tests must only access public APIs.
2930

3031
## Testing & E2E tips ⚙️
@@ -35,20 +36,20 @@
3536

3637
## Project-specific conventions & patterns ✅
3738

38-
- Tools: each SDK has helper APIs to expose functions as tools; prefer the language's `DefineTool`/`@define_tool`/`AIFunctionFactory.Create` patterns (see language READMEs).
39+
- Tools: each SDK has helper APIs to expose functions as tools; prefer the language's `DefineTool`/`@define_tool`/`AIFunctionFactory.Create`/`ToolHandler` trait patterns (see language READMEs).
3940
- Infinite sessions are enabled by default and persist workspace state to `~/.copilot/session-state/{sessionId}`; compaction events are emitted (`session.compaction_start`, `session.compaction_complete`). See language READMEs for usage.
4041
- Streaming: when `streaming`/`Streaming=true` you receive delta events (`assistant.message_delta`, `assistant.reasoning_delta`) and final events (`assistant.message`, `assistant.reasoning`) — tests expect this behavior.
4142
- Type generation is centralized in `nodejs/scripts/generate-session-types.ts` and requires the `@github/copilot` schema to be present (often via `npm link` or installed package).
4243

4344
## Integration & environment notes ⚠️
4445

45-
- The SDK requires a Copilot CLI installation or an external server reachable via the `CLI URL option (language-specific casing)` (Node: `cliUrl`, Go: `CLIUrl`, .NET: `CliUrl`, Python: `cli_url`) or `COPILOT_CLI_PATH`.
46+
- The SDK requires a Copilot CLI installation or an external server reachable via the `CLI URL option (language-specific casing)` (Node: `cliUrl`, Go: `CLIUrl`, .NET: `CliUrl`, Python: `cli_url`, Rust: `cli_url`) or `COPILOT_CLI_PATH`.
4647
- Some scripts (typegen, formatting) call external tools: `gofmt`, `dotnet format`, `tsx` (available via npm), `quicktype`/`quicktype-core` (used by the Node typegen script), and `prettier` (provided as an npm devDependency). Most of these are available through the repo's package scripts or devDependencies—run `just install` (and `cd nodejs && npm ci`) to install them. Ensure the required tools are available in CI / developer machines.
4748
- Tests may assume `node >= 18`, `python >= 3.9`, platform differences handled (Windows uses `shell=True` for npx in harness).
4849

4950
## Where to add new code or tests 🧭
5051

51-
- SDK code: `nodejs/src`, `python/copilot`, `go`, `dotnet/src`
52-
- Unit tests: `nodejs/test`, `python/*`, `go/*`, `dotnet/test`
52+
- SDK code: `nodejs/src`, `python/copilot`, `go`, `dotnet/src`, `rust/src`
53+
- Unit tests: `nodejs/test`, `python/*`, `go/*`, `dotnet/test`, `rust/tests`
5354
- E2E tests: `*/e2e/` folders that use the shared replay proxy and `test/snapshots/`
5455
- Generated types: update schema in `@github/copilot` then run `cd nodejs && npm run generate:session-types` and commit generated files in `src/generated` or language generated location.

.github/workflows/codegen-check.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ on:
1313
- 'python/copilot/generated/**'
1414
- 'go/generated_*.go'
1515
- 'go/rpc/**'
16+
- 'rust/src/generated/**'
1617
- '.github/workflows/codegen-check.yml'
1718
workflow_dispatch:
1819

.github/workflows/docs-validation.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ on:
99
- 'python/copilot/**'
1010
- 'go/**/*.go'
1111
- 'dotnet/src/**'
12+
- 'rust/src/**'
1213
- 'scripts/docs-validation/**'
1314
- '.github/workflows/docs-validation.yml'
1415
workflow_dispatch:
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: "Rust SDK Tests"
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
types: [opened, synchronize, reopened, ready_for_review]
9+
paths:
10+
- 'rust/**'
11+
- 'test/**'
12+
- 'nodejs/package.json'
13+
- '.github/workflows/rust-sdk-tests.yml'
14+
- '.github/actions/setup-copilot/**'
15+
- '!**/*.md'
16+
- '!**/LICENSE*'
17+
- '!**/.gitignore'
18+
- '!**/.editorconfig'
19+
- '!**/*.png'
20+
- '!**/*.jpg'
21+
- '!**/*.jpeg'
22+
- '!**/*.gif'
23+
- '!**/*.svg'
24+
workflow_dispatch:
25+
merge_group:
26+
27+
permissions:
28+
contents: read
29+
30+
jobs:
31+
test:
32+
name: "Rust SDK Tests"
33+
env:
34+
POWERSHELL_UPDATECHECK: Off
35+
strategy:
36+
fail-fast: false
37+
matrix:
38+
os: [ubuntu-latest, macos-latest, windows-latest]
39+
runs-on: ${{ matrix.os }}
40+
defaults:
41+
run:
42+
shell: bash
43+
working-directory: ./rust
44+
steps:
45+
- uses: actions/checkout@v6.0.2
46+
- uses: ./.github/actions/setup-copilot
47+
id: setup-copilot
48+
- uses: dtolnay/rust-toolchain@stable
49+
with:
50+
components: rustfmt, clippy
51+
52+
- uses: Swatinem/rust-cache@v2
53+
with:
54+
workspaces: "rust -> target"
55+
56+
- name: Run cargo fmt check
57+
if: runner.os == 'Linux'
58+
working-directory: ./rust
59+
run: |
60+
cargo fmt -- --check
61+
echo "✅ cargo fmt produced no changes"
62+
63+
- name: Run cargo clippy
64+
if: runner.os == 'Linux'
65+
working-directory: ./rust
66+
run: cargo clippy --all-targets --all-features -- -D warnings
67+
68+
- name: Install test harness dependencies
69+
working-directory: ./test/harness
70+
run: npm ci --ignore-scripts
71+
72+
- name: Warm up PowerShell
73+
if: runner.os == 'Windows'
74+
run: pwsh.exe -Command "Write-Host 'PowerShell ready'"
75+
76+
- name: Run Rust SDK tests
77+
env:
78+
COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }}
79+
COPILOT_CLI_PATH: ${{ steps.setup-copilot.outputs.cli-path }}
80+
run: cargo test

.github/workflows/scenario-builds.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ on:
99
- "python/copilot/**"
1010
- "go/**/*.go"
1111
- "dotnet/src/**"
12+
- "rust/src/**"
13+
- "rust/Cargo.toml"
1214
- ".github/workflows/scenario-builds.yml"
1315
push:
1416
branches:
@@ -185,3 +187,41 @@ jobs:
185187
echo -e "Failures:$FAILURES"
186188
exit 1
187189
fi
190+
191+
# ── Rust ────────────────────────────────────────────────────────────
192+
build-rust:
193+
name: "Rust scenarios"
194+
runs-on: ubuntu-latest
195+
steps:
196+
- uses: actions/checkout@v6
197+
198+
- uses: dtolnay/rust-toolchain@stable
199+
200+
- uses: Swatinem/rust-cache@v2
201+
with:
202+
workspaces: "rust -> target"
203+
cache-targets: false
204+
205+
- name: Check all Rust scenarios
206+
run: |
207+
PASS=0; FAIL=0; FAILURES=""
208+
for manifest in $(find test/scenarios -path '*/rust/Cargo.toml' | sort); do
209+
dir=$(dirname "$manifest")
210+
scenario="${dir#test/scenarios/}"
211+
echo "::group::$scenario"
212+
if (cd "$dir" && cargo check 2>&1); then
213+
echo "✅ $scenario"
214+
PASS=$((PASS + 1))
215+
else
216+
echo "❌ $scenario"
217+
FAIL=$((FAIL + 1))
218+
FAILURES="$FAILURES\n $scenario"
219+
fi
220+
echo "::endgroup::"
221+
done
222+
echo ""
223+
echo "Rust checks: $PASS passed, $FAIL failed"
224+
if [ "$FAIL" -gt 0 ]; then
225+
echo -e "Failures:$FAILURES"
226+
exit 1
227+
fi

.github/workflows/sdk-consistency-review.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ on:
1010
- 'python/**'
1111
- 'go/**'
1212
- 'dotnet/**'
13+
- 'rust/**'
1314
workflow_dispatch:
1415
inputs:
1516
pr_number:
@@ -35,7 +36,7 @@ timeout-minutes: 15
3536

3637
# SDK Consistency Review Agent
3738

38-
You are an AI code reviewer specialized in ensuring consistency across multi-language SDK implementations. This repository contains four SDK implementations (Node.js/TypeScript, Python, Go, and .NET) that should maintain feature parity and consistent API design.
39+
You are an AI code reviewer specialized in ensuring consistency across multi-language SDK implementations. This repository contains five SDK implementations (Node.js/TypeScript, Python, Go, .NET, and Rust) that should maintain feature parity and consistent API design.
3940

4041
## Your Task
4142

@@ -69,6 +70,7 @@ When a pull request modifies any SDK client code, review it to ensure:
6970
- **Python**: `python/copilot/`
7071
- **Go**: `go/`
7172
- **.NET**: `dotnet/src/`
73+
- **Rust**: `rust/src/`
7274

7375
## Review Process
7476

@@ -90,6 +92,7 @@ When a pull request modifies any SDK client code, review it to ensure:
9092
- Python uses snake_case (e.g., `create_session`)
9193
- Go uses PascalCase for exported/public functions (e.g., `CreateSession`) and camelCase for unexported/private functions
9294
- .NET uses PascalCase (e.g., `CreateSession`)
95+
- Rust uses snake_case for functions (e.g., `create_session`) and PascalCase for types (e.g., `SessionConfig`)
9396
- Focus on public API methods when comparing across languages
9497
3. **Focus on API surface**: Prioritize public APIs over internal implementation details
9598
4. **Distinguish between bugs and features**:

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
Agents for every app.
1010

11-
Embed Copilot's agentic workflows in your application—now available in public preview as a programmable SDK for Python, TypeScript, Go, .NET, and Java.
11+
Embed Copilot's agentic workflows in your application—now available in public preview as a programmable SDK for Python, TypeScript, Go, .NET, Rust, and Java.
1212

1313
The GitHub Copilot SDK exposes the same engine behind Copilot CLI: a production-tested agent runtime you can invoke programmatically. No need to build your own orchestration—you define agent behavior, Copilot handles planning, tool invocation, file edits, and more.
1414

@@ -20,6 +20,7 @@ The GitHub Copilot SDK exposes the same engine behind Copilot CLI: a production-
2020
| **Python** | [`python/`](./python/) | [Cookbook](https://github.com/github/awesome-copilot/blob/main/cookbook/copilot-sdk/python/README.md) | `pip install github-copilot-sdk` |
2121
| **Go** | [`go/`](./go/) | [Cookbook](https://github.com/github/awesome-copilot/blob/main/cookbook/copilot-sdk/go/README.md) | `go get github.com/github/copilot-sdk/go` |
2222
| **.NET** | [`dotnet/`](./dotnet/) | [Cookbook](https://github.com/github/awesome-copilot/blob/main/cookbook/copilot-sdk/dotnet/README.md) | `dotnet add package GitHub.Copilot.SDK` |
23+
| **Rust** | [`rust/`](./rust/) | | `copilot-sdk = { git = "https://github.com/github/copilot-sdk" }` |
2324
| **Java** | [`github/copilot-sdk-java`](https://github.com/github/copilot-sdk-java) | [Cookbook](https://github.com/github/awesome-copilot/blob/main/cookbook/copilot-sdk/java/README.md) | Maven coordinates<br>`com.github:copilot-sdk-java`<br>See instructions for [Maven](https://github.com/github/copilot-sdk-java?tab=readme-ov-file#maven) and [Gradle](https://github.com/github/copilot-sdk-java?tab=readme-ov-file#gradle) |
2425

2526
See the individual SDK READMEs for installation, usage examples, and API reference.
@@ -32,7 +33,7 @@ Quick steps:
3233

3334
1. **(Optional) Install the Copilot CLI**
3435

35-
For Node.js, Python, and .NET SDKs, the Copilot CLI is bundled automatically and no separate installation is required.
36+
For Node.js, Python, .NET, and Rust SDKs, the Copilot CLI is bundled automatically and no separate installation is required.
3637
For the Go SDK, [install the CLI manually](https://github.com/features/copilot/cli) or ensure `copilot` is available in your PATH.
3738

3839
2. **Install your preferred SDK** using the commands above.

justfile

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ default:
33
@just --list
44

55
# Format all code across all languages
6-
format: format-go format-python format-nodejs format-dotnet
6+
format: format-go format-python format-nodejs format-dotnet format-rust
77

88
# Lint all code across all languages
9-
lint: lint-go lint-python lint-nodejs lint-dotnet
9+
lint: lint-go lint-python lint-nodejs lint-dotnet lint-rust
1010

1111
# Run tests for all languages
12-
test: test-go test-python test-nodejs test-dotnet test-corrections
12+
test: test-go test-python test-nodejs test-dotnet test-corrections test-rust
1313

1414
# Format Go code
1515
format-go:
@@ -31,6 +31,11 @@ format-dotnet:
3131
@echo "=== Formatting .NET code ==="
3232
@cd dotnet && dotnet format src/GitHub.Copilot.SDK.csproj
3333

34+
# Format Rust code
35+
format-rust:
36+
@echo "=== Formatting Rust code ==="
37+
@cd rust && cargo fmt
38+
3439
# Lint Go code
3540
lint-go:
3641
@echo "=== Linting Go code ==="
@@ -51,6 +56,11 @@ lint-dotnet:
5156
@echo "=== Linting .NET code ==="
5257
@cd dotnet && dotnet format src/GitHub.Copilot.SDK.csproj --verify-no-changes
5358

59+
# Lint Rust code
60+
lint-rust:
61+
@echo "=== Linting Rust code ==="
62+
@cd rust && cargo clippy --all-targets --all-features -- -D warnings
63+
5464
# Test Go code
5565
test-go:
5666
@echo "=== Testing Go code ==="
@@ -71,13 +81,18 @@ test-dotnet:
7181
@echo "=== Testing .NET code ==="
7282
@cd dotnet && dotnet test test/GitHub.Copilot.SDK.Test.csproj
7383

84+
# Test Rust code
85+
test-rust:
86+
@echo "=== Testing Rust code ==="
87+
@cd rust && cargo test
88+
7489
# Test correction collection scripts
7590
test-corrections:
7691
@echo "=== Testing correction scripts ==="
7792
@cd scripts/corrections && npm test
7893

7994
# Install all dependencies across all languages
80-
install: install-go install-python install-nodejs install-dotnet install-corrections
95+
install: install-go install-python install-nodejs install-dotnet install-corrections install-rust
8196
@echo "✅ All dependencies installed"
8297

8398
# Install Go dependencies and prerequisites for tests
@@ -95,6 +110,11 @@ install-dotnet: install-nodejs install-test-harness
95110
@echo "=== Installing .NET dependencies ==="
96111
@cd dotnet && dotnet restore
97112

113+
# Install Rust dependencies
114+
install-rust:
115+
@echo "=== Installing Rust dependencies ==="
116+
@cd rust && cargo fetch
117+
98118
# Install Node.js dependencies
99119
install-nodejs:
100120
@echo "=== Installing Node.js dependencies ==="
@@ -187,6 +207,9 @@ scenario-build:
187207
# C#: dotnet build
188208
build_lang "C#" "-name '*.csproj' -path '*/csharp/*'" "dotnet build --nologo -v quiet"
189209

210+
# Rust: cargo check
211+
build_lang "Rust" "-path '*/rust/Cargo.toml'" "cargo check --quiet"
212+
190213
echo ""
191214
echo "══════════════════════════════════════"
192215
echo " Scenario build summary: $PASS passed, $FAIL failed (of $TOTAL)"
@@ -247,8 +270,18 @@ scenario-build-lang LANG:
247270
fi
248271
done
249272
;;
273+
rust)
274+
for target in $(find test/scenarios -path '*/rust/Cargo.toml' | sort); do
275+
dir=$(dirname "$target"); scenario="${dir#test/scenarios/}"
276+
if (cd "$dir" && cargo check --quiet >/dev/null 2>&1); then
277+
printf " ✅ %s\n" "$scenario"; PASS=$((PASS + 1))
278+
else
279+
printf " ❌ %s\n" "$scenario"; FAIL=$((FAIL + 1))
280+
fi
281+
done
282+
;;
250283
*)
251-
echo "Unknown language: {{LANG}}. Use: typescript, python, go, csharp"
284+
echo "Unknown language: {{LANG}}. Use: typescript, python, go, csharp, rust"
252285
exit 1
253286
;;
254287
esac

nodejs/scripts/update-protocol-version.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,19 @@ internal static class SdkProtocolVersion
117117
fs.writeFileSync(path.join(rootDir, "dotnet", "src", "SdkProtocolVersion.cs"), csharpCode);
118118
console.log(" ✓ dotnet/src/SdkProtocolVersion.cs");
119119

120+
// Generate Rust
121+
const rustCode = `// Code generated by update-protocol-version.ts. DO NOT EDIT.
122+
123+
/// The SDK protocol version.
124+
/// This must match the version expected by the copilot-agent-runtime server.
125+
pub const SDK_PROTOCOL_VERSION: u32 = ${version};
126+
127+
/// Gets the SDK protocol version.
128+
pub fn get_sdk_protocol_version() -> u32 {
129+
SDK_PROTOCOL_VERSION
130+
}
131+
`;
132+
fs.writeFileSync(path.join(rootDir, "rust", "src", "generated", "mod.rs"), rustCode);
133+
console.log(" ✓ rust/src/generated/mod.rs");
134+
120135
console.log("Done!");

0 commit comments

Comments
 (0)