openpencil/crates/copilot-sdk
Kayshen-X f3f57081da chore(crates): move vendored SDKs into workspace as forkable crates
Per user direction "可以不放在 vendor 里面,我们移动到自己的工程,
后面就和他们分叉" — promote the two community SDKs from vendor/ to
crates/ so they become first-class OP workspace members we own and
evolve, instead of read-only vendored snapshots.

Moves:
  vendor/anthropic-agent-sdk/  →  crates/anthropic-agent-sdk/
  vendor/copilot-sdk-rust/     →  crates/copilot-sdk/

Workspace integration:
  - Root `Cargo.toml` exclude list drops both vendor entries; the
    existing `members = ["crates/*"]` glob auto-includes them.
  - `crates/copilot-sdk/Cargo.toml`: stripped all `[[example]]`
    blocks (22 of them) — the examples/ dir was already removed
    during the import, and leaving the entries broke
    `cargo test --workspace --no-run`.
  - `crates/anthropic-agent-sdk/Cargo.toml`: already had its
    `[[example]]` blocks pruned in the previous commit.

Lockfile pins (workspace `Cargo.lock`):
  Pulling reqwest 0.12.28 (via anthropic-agent-sdk) into the
  unified workspace dep graph re-resolved several `icu_*` crates to
  the 2.2 line, which requires rustc 1.86. OP's toolchain is 1.85
  (locked to stay compatible with the skia-safe-op fork). Pinned:
    icu_collections      2.2.0 → 2.1.1
    icu_locale_core      2.2.0 → 2.1.1
    icu_normalizer       2.2.0 → 2.1.1
    icu_normalizer_data  2.2.0 → 2.1.1
    icu_properties       2.2.0 → 2.1.2
    icu_properties_data  2.2.0 → 2.1.2
    icu_provider         2.2.0 → 2.1.1
    idna_adapter         1.2.2 → 1.2.1
  All eight pins are the latest versions on each crate's 2.1.x /
  1.2.x line that compile on rustc 1.85.

Verification:
  - `cargo check -p anthropic-agent-sdk` ✓
  - `cargo check -p copilot-sdk` ✓
  - `cargo test --workspace --no-run` ✓
  - `cargo test -p openpencil-shell-core --lib` → 250 pass
  - `cargo test -p openpencil-desktop chat_` → 16 pass

Next: replace the hand-rolled subprocess parser in chat_subprocess.rs
with thin per-CLI adapters that route Claude Code through
`anthropic_agent_sdk::SubprocessTransport` and Copilot through
`copilot_sdk::Client + Session`. Gemini stays on the generic stdin
bridge until an upstream Rust SDK exists. Codex + OpenCode get an
HttpServerProvider that spawns `<bin> serve` then connects via a
local HTTP client.
2026-05-14 16:49:17 +08:00
..
.githooks chore(crates): move vendored SDKs into workspace as forkable crates 2026-05-14 16:49:17 +08:00
.github chore(crates): move vendored SDKs into workspace as forkable crates 2026-05-14 16:49:17 +08:00
src chore(crates): move vendored SDKs into workspace as forkable crates 2026-05-14 16:49:17 +08:00
.gitattributes chore(crates): move vendored SDKs into workspace as forkable crates 2026-05-14 16:49:17 +08:00
.gitignore chore(crates): move vendored SDKs into workspace as forkable crates 2026-05-14 16:49:17 +08:00
AGENTS.md chore(crates): move vendored SDKs into workspace as forkable crates 2026-05-14 16:49:17 +08:00
Cargo.toml chore(crates): move vendored SDKs into workspace as forkable crates 2026-05-14 16:49:17 +08:00
LICENSE chore(crates): move vendored SDKs into workspace as forkable crates 2026-05-14 16:49:17 +08:00
README.md chore(crates): move vendored SDKs into workspace as forkable crates 2026-05-14 16:49:17 +08:00
rust-toolchain.toml chore(crates): move vendored SDKs into workspace as forkable crates 2026-05-14 16:49:17 +08:00

copilot-sdk (Rust)

Rust SDK for interacting with the GitHub Copilot CLI agent runtime (JSON-RPC over stdio or TCP).

This is a Rust port of the upstream SDKs and is currently in technical preview.

Requirements

  • Rust 1.85+ (Edition 2024)
  • GitHub Copilot CLI installed and authenticated
  • copilot available in PATH, or set COPILOT_CLI_PATH to the CLI executable/script

Install

Once published, add:

[dependencies]
copilot-sdk = "0.1"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }

For development from this repository:

[dependencies]
copilot-sdk = { path = "." }

Quick Start

use copilot_sdk::{Client, SessionConfig};

#[tokio::main]
async fn main() -> copilot_sdk::Result<()> {
    let client = Client::builder().build()?;
    client.start().await?;

    let session = client.create_session(SessionConfig::default()).await?;
    let response = session.send_and_collect("Hello!", None).await?;
    println!("{}", response);

    client.stop().await;
    Ok(())
}

Features

Session Management

Full session lifecycle with create, resume, list, delete, and foreground control:

let session = client.create_session(SessionConfig {
    model: Some("gpt-4.1".into()),
    streaming: true,
    client_name: Some("my-app".into()),
    ..Default::default()
}).await?;

Model Management

Switch models and reasoning effort mid-session:

let model = session.get_model().await?;
session.set_model("claude-sonnet-4", Some(SetModelOptions {
    reasoning_effort: Some("high".into()),
})).await?;

Mode Switching

Switch between interactive, plan, and autopilot modes:

session.set_mode(SessionMode::Plan).await?;
session.set_mode(SessionMode::Autopilot).await?;
session.set_mode(SessionMode::Interactive).await?;

Plan Management

Read, update, and delete session plans:

session.update_plan(&PlanData {
    content: Some("Step 1: Implement\nStep 2: Test".into()),
    title: Some("Implementation Plan".into()),
}).await?;
let plan = session.read_plan().await?;
session.delete_plan().await?;

Agent Management

List, select, and deselect custom agents:

let agents = session.list_agents().await?;
session.select_agent("code-reviewer").await?;
session.deselect_agent().await?;

Custom Tools

Register tools that the assistant can invoke, with permission control:

let tool = Tool::new("get_weather")
    .description("Get current weather")
    .parameter("city", "string", "City name", true)
    .skip_permission(true);

session.register_tool_with_handler(tool, Some(handler)).await;

Infinite Sessions

Automatic context window management with manual compaction support:

let config = SessionConfig {
    infinite_sessions: Some(InfiniteSessionConfig::enabled()),
    ..Default::default()
};
// Trigger manual compaction
session.compact().await?;

Session Logging

Add log entries to sessions:

session.log("Processing step complete", Some(LogOptions {
    level: Some(SessionLogLevel::Info),
    ephemeral: Some(false),
})).await?;

Shell Operations

Execute shell commands and manage processes:

let result = session.shell_exec(ShellExecOptions {
    command: "cargo test".into(),
    cwd: Some("/my/project".into()),
    env: None,
}).await?;
session.shell_kill(&result.process_id, ShellSignal::SIGTERM).await?;

Workspace File Operations

List, read, and create files in the session workspace:

let files = session.workspace_list_files().await?;
let content = session.workspace_read_file("plan.md").await?;
session.workspace_create_file("notes.md", "# Notes").await?;

Fleet Management

Start parallel agent fleets:

session.start_fleet(Some(FleetStartOptions {
    prompt: Some("Build and test the project".into()),
})).await?;

Client Utilities

let status = client.get_status().await?;       // CLI version info
let auth = client.get_auth_status().await?;    // Authentication state
let models = client.list_models().await?;      // Available models
let tools = client.tools_list(None).await?;    // Available tools
let quota = client.get_quota().await?;         // Account quota

OpenTelemetry Integration

Configure distributed tracing for the CLI process:

let client = Client::builder()
    .telemetry(TelemetryConfig {
        otlp_endpoint: Some("http://localhost:4318".into()),
        exporter_type: Some("otlp-http".into()),
        source_name: Some("my-app".into()),
        capture_content: Some(true),
        file_path: None,
    })
    .build()?;

BYOK (Bring Your Own Key)

Use your own API keys with compatible providers, with custom model listing:

let client = Client::builder()
    .on_list_models(|| async {
        Ok(vec![ModelInfo { /* ... */ }])
    })
    .build()?;

let config = SessionConfig {
    provider: Some(ProviderConfig {
        base_url: "https://api.openai.com/v1".into(),
        api_key: Some("sk-...".into()),
        ..Default::default()
    }),
    auto_byok_from_env: true,
    ..Default::default()
};

Hooks

Intercept session lifecycle at key points:

let config = SessionConfig {
    hooks: Some(SessionHooks {
        on_pre_tool_use: Some(Arc::new(|input| {
            println!("Tool: {}", input.tool_name);
            PreToolUseHookOutput::default()
        })),
        ..Default::default()
    }),
    ..Default::default()
};

Examples

cargo run --example basic_chat          # Simple Q&A
cargo run --example streaming           # Streaming responses
cargo run --example tool_usage          # Custom tools
cargo run --example set_model           # Model switching
cargo run --example mode_switching      # Mode management
cargo run --example plan_ops            # Plan CRUD
cargo run --example agent_management    # Agent operations
cargo run --example telemetry           # OpenTelemetry setup
cargo run --example shell_exec          # Shell commands
cargo run --example hooks               # Session hooks
cargo run --example byok                # Bring Your Own Key

Development

Setup

Enable pre-commit hooks to catch formatting/linting issues before push:

git config core.hooksPath .githooks

Commands

cargo fmt --all
cargo clippy --all-targets --all-features -- -D warnings
cargo test

E2E tests (real Copilot CLI):

cargo test --features e2e -- --test-threads=1

Snapshot conformance tests (optional, against upstream YAML snapshots):

cargo test --features snapshots --test snapshot_conformance

Set COPILOT_SDK_RUST_SNAPSHOT_DIR or UPSTREAM_SNAPSHOTS to point at copilot-sdk/test/snapshots if it cannot be auto-detected.

Protocol Compatibility

  • SDK Protocol Version: 3 (minimum: 2)
  • Transport: stdio (spawned CLI) and TCP (spawned or external server)
  • JSON-RPC: v2.0 with Content-Length framing

Feature Parity

This port targets feature parity with the official SDKs (Go, TypeScript, Python, .NET):

Feature Status
Session CRUD (create/resume/list/delete) ✅
Model management (get/switch) ✅
Mode management (interactive/plan/autopilot) ✅
Plan management (read/update/delete) ✅
Agent management (list/select/deselect) ✅
Tool system (register/invoke/permissions) ✅
Hook system (6 lifecycle hooks) ✅
Permission handling ✅
User input handling ✅
Infinite sessions & compaction ✅
Shell operations (exec/kill) ✅
Workspace file operations ✅
Fleet management ✅
Session logging ✅
BYOK (custom providers) ✅
OpenTelemetry configuration ✅
Custom model list callback ✅
MCP server integration ✅
Custom agent configuration ✅
Streaming events (40+ types) ✅
Protocol v2/v3 negotiation ✅
CLI bundling ❌ (planned)

License

MIT License - see LICENSE.