Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/lsp.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"rootUri": "dotnet"
},
"go": {
"command": "${HOME}/go/bin/gopls",
"command": "gopls",
"args": ["serve"],
"fileExtensions": {
".go": "go"
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/dotnet-sdk-tests.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
name: ".NET SDK Tests"

on:
push:
branches:
- main
pull_request:
paths:
- 'dotnet/**'
- 'test/**'
- 'nodejs/package.json'
- '.github/workflows/dotnet-sdk-tests.yml'
- '.github/actions/setup-copilot/**'
- '!**/*.md'
- '!**/LICENSE*'
- '!**/.gitignore'
Expand Down Expand Up @@ -39,17 +41,16 @@ jobs:
working-directory: ./dotnet
steps:
- uses: actions/checkout@v6.0.2
- uses: ./.github/actions/setup-copilot
id: setup-copilot
- uses: actions/setup-dotnet@v5
with:
dotnet-version: "8.0.x"
- uses: actions/setup-node@v6
with:
node-version: "24"
cache: "npm"
cache-dependency-path: "./nodejs/package-lock.json"

- name: Install Node.js dependencies (for CLI)
- name: Install Node.js dependencies (for CLI version extraction)
working-directory: ./nodejs
run: npm ci --ignore-scripts

Expand Down Expand Up @@ -80,5 +81,4 @@ jobs:
- name: Run .NET SDK tests
env:
COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }}
COPILOT_CLI_PATH: ${{ steps.setup-copilot.outputs.cli-path }}
run: dotnet test --no-build -v n
3 changes: 3 additions & 0 deletions .github/workflows/go-sdk-tests.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
name: "Go SDK Tests"

on:
push:
branches:
- main
pull_request:
paths:
- 'go/**'
Expand Down
9 changes: 4 additions & 5 deletions .github/workflows/nodejs-sdk-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ env:
HUSKY: 0

on:
push:
branches:
- main
pull_request:
paths:
- 'nodejs/**'
- 'test/**'
- '.github/workflows/nodejs-sdk-tests.yml'
- '.github/actions/setup-copilot/**'
- '!**/*.md'
- '!**/LICENSE*'
- '!**/.gitignore'
Expand Down Expand Up @@ -45,9 +47,7 @@ jobs:
with:
cache: "npm"
cache-dependency-path: "./nodejs/package-lock.json"
node-version: 22
- uses: ./.github/actions/setup-copilot
id: setup-copilot
node-version: 24
- name: Install dependencies
run: npm ci --ignore-scripts

Expand All @@ -72,5 +72,4 @@ jobs:
- name: Run Node.js SDK tests
env:
COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }}
COPILOT_CLI_PATH: ${{ steps.setup-copilot.outputs.cli-path }}
run: npm test
14 changes: 12 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ jobs:
name: nodejs-package
path: nodejs/*.tgz
- name: Publish to npm
if: github.ref == 'refs/heads/main'
run: npm publish --tag ${{ github.event.inputs.dist-tag }} --access public --registry https://registry.npmjs.org

publish-dotnet:
Expand All @@ -130,6 +131,7 @@ jobs:
name: dotnet-package
path: dotnet/artifacts/*.nupkg
- name: NuGet login (OIDC)
if: github.ref == 'refs/heads/main'
uses: NuGet/login@v1
id: nuget-login
with:
Expand All @@ -139,6 +141,7 @@ jobs:
# are associated with individual maintainers' accounts too.
user: stevesanderson
- name: Publish to NuGet
if: github.ref == 'refs/heads/main'
run: dotnet nuget push ./artifacts/*.nupkg --api-key ${{ steps.nuget-login.outputs.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate

publish-python:
Expand All @@ -153,18 +156,25 @@ jobs:
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- uses: actions/setup-node@v6
with:
node-version: "22.x"
- name: Set up uv
uses: astral-sh/setup-uv@v7
- name: Install Node.js dependencies (for CLI version)
working-directory: ./nodejs
run: npm ci --ignore-scripts
- name: Set version
run: sed -i "s/^version = .*/version = \"${{ needs.version.outputs.version }}\"/" pyproject.toml
- name: Build package
run: uv build
- name: Build platform wheels
run: node scripts/build-wheels.mjs --output-dir dist
- name: Upload artifact
uses: actions/upload-artifact@v6
with:
name: python-package
path: python/dist/*
- name: Publish to PyPI
if: github.ref == 'refs/heads/main'
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: python/dist/
Expand Down
16 changes: 12 additions & 4 deletions .github/workflows/python-sdk-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ env:
PYTHONUTF8: 1

on:
push:
branches:
- main
pull_request:
paths:
- 'python/**'
- 'test/**'
- 'nodejs/package.json'
- '.github/workflows/python-sdk-tests.yml'
- '.github/actions/setup-copilot/**'
- '!**/*.md'
- '!**/LICENSE*'
- '!**/.gitignore'
Expand Down Expand Up @@ -42,11 +44,14 @@ jobs:
working-directory: ./python
steps:
- uses: actions/checkout@v6.0.2
- uses: ./.github/actions/setup-copilot
id: setup-copilot
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- uses: actions/setup-node@v6
with:
node-version: "24"
cache: "npm"
cache-dependency-path: "./nodejs/package-lock.json"

- name: Set up uv
uses: astral-sh/setup-uv@v7
Expand All @@ -56,6 +61,10 @@ jobs:
- name: Install Python dev dependencies
run: uv sync --locked --all-extras --dev

- name: Install Node.js dependencies (for CLI in tests)
working-directory: ./nodejs
run: npm ci --ignore-scripts

- name: Run ruff format check
run: uv run ruff format --check .

Expand All @@ -76,5 +85,4 @@ jobs:
- name: Run Python SDK tests
env:
COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }}
COPILOT_CLI_PATH: ${{ steps.setup-copilot.outputs.cli-path }}
run: uv run pytest -v -s
8 changes: 6 additions & 2 deletions docs/auth/byok.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,19 +272,23 @@ provider: {
}
```

> **Note:** The `bearerToken` option accepts a **static token string** only. The SDK does not refresh this token automatically. If your token expires, requests will fail and you'll need to create a new session with a fresh token.

## Limitations

When using BYOK, be aware of these limitations:

### Identity Limitations

BYOK authentication is **key-based only**. The following identity providers are NOT supported:
BYOK authentication uses **static credentials only**. The following identity providers are NOT supported:

- ❌ **Microsoft Entra ID (Azure AD)** - No support for Entra managed identities or service principals
- ❌ **Third-party identity providers** - No OIDC, SAML, or other federated identity
- ❌ **Managed identities** - Azure Managed Identity is not supported

You must use an API key or bearer token that you manage yourself.
You must use an API key or static bearer token that you manage yourself.

**Why not Entra ID?** While Entra ID does issue bearer tokens, these tokens are short-lived (typically 1 hour) and require automatic refresh via the Azure Identity SDK. The `bearerToken` option only accepts a static string—there is no callback mechanism for the SDK to request fresh tokens. For long-running workloads requiring Entra authentication, you would need to implement your own token refresh logic and create new sessions with updated tokens.

### Feature Limitations

Expand Down
3 changes: 3 additions & 0 deletions dotnet/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
bin/
obj/

# Generated build props (contains CLI version)
src/build/GitHub.Copilot.SDK.props

# NuGet packages
*.nupkg
*.snupkg
Expand Down
21 changes: 12 additions & 9 deletions dotnet/src/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -873,15 +873,17 @@ private async Task VerifyProtocolVersionAsync(Connection connection, Cancellatio

private static async Task<(Process Process, int? DetectedLocalhostTcpPort)> StartCliServerAsync(CopilotClientOptions options, ILogger logger, CancellationToken cancellationToken)
{
var cliPath = options.CliPath ?? "copilot";
// Use explicit path or bundled CLI - no PATH fallback
var cliPath = options.CliPath ?? GetBundledCliPath(out var searchedPath)
?? throw new InvalidOperationException($"Copilot CLI not found at '{searchedPath}'. Ensure the SDK NuGet package was restored correctly or provide an explicit CliPath.");
var args = new List<string>();

if (options.CliArgs != null)
{
args.AddRange(options.CliArgs);
}

args.AddRange(["--headless", "--log-level", options.LogLevel]);
args.AddRange(["--headless", "--no-auto-update", "--log-level", options.LogLevel]);

if (options.UseStdio)
{
Expand Down Expand Up @@ -976,6 +978,14 @@ private async Task VerifyProtocolVersionAsync(Connection connection, Cancellatio
return (cliProcess, detectedLocalhostTcpPort);
}

private static string? GetBundledCliPath(out string searchedPath)
{
var binaryName = OperatingSystem.IsWindows() ? "copilot.exe" : "copilot";
var rid = Path.GetFileName(System.Runtime.InteropServices.RuntimeInformation.RuntimeIdentifier);
searchedPath = Path.Combine(AppContext.BaseDirectory, "runtimes", rid, "native", binaryName);
return File.Exists(searchedPath) ? searchedPath : null;
}

private static (string FileName, IEnumerable<string> Args) ResolveCliCommand(string cliPath, IEnumerable<string> args)
{
var isJsFile = cliPath.EndsWith(".js", StringComparison.OrdinalIgnoreCase);
Expand All @@ -985,13 +995,6 @@ private static (string FileName, IEnumerable<string> Args) ResolveCliCommand(str
return ("node", new[] { cliPath }.Concat(args));
}

// On Windows with UseShellExecute=false, Process.Start doesn't search PATHEXT,
// so use cmd /c to let the shell resolve the executable
if (OperatingSystem.IsWindows() && !Path.IsPathRooted(cliPath))
{
return ("cmd", new[] { "/c", cliPath }.Concat(args));
}

return (cliPath, args);
}

Expand Down
6 changes: 5 additions & 1 deletion dotnet/src/Generated/SessionEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//
// Generated from: @github/copilot/session-events.schema.json
// Generated by: scripts/generate-session-types.ts
// Generated at: 2026-02-03T20:40:49.743Z
// Generated at: 2026-02-06T20:38:23.832Z
//
// To update these types:
// 1. Update the schema in copilot-agent-runtime
Expand Down Expand Up @@ -765,6 +765,10 @@ public partial class SessionCompactionCompleteData
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("compactionTokensUsed")]
public SessionCompactionCompleteDataCompactionTokensUsed? CompactionTokensUsed { get; set; }

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("requestId")]
public string? RequestId { get; set; }
}

public partial class UserMessageData
Expand Down
77 changes: 53 additions & 24 deletions dotnet/src/GitHub.Copilot.SDK.csproj
Original file line number Diff line number Diff line change
@@ -1,31 +1,60 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>0.1.0</Version>
<Description>SDK for programmatic control of GitHub Copilot CLI</Description>
<Authors>GitHub</Authors>
<Company>GitHub</Company>
<Copyright>Copyright (c) Microsoft Corporation. All rights reserved.</Copyright>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/github/copilot-sdk</RepositoryUrl>
<PackageTags>github;copilot;sdk;jsonrpc;agent</PackageTags>
<IsAotCompatible>true</IsAotCompatible>
</PropertyGroup>

<ItemGroup>
<None Include="../README.md" Pack="true" PackagePath="/" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.AI.Abstractions" Version="10.2.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.2" />
<PackageReference Include="StreamJsonRpc" Version="2.24.84" PrivateAssets="compile" />
<PackageReference Include="System.Text.Json" Version="10.0.2" />
</ItemGroup>

<!-- Generate version props file at build time (gitignored) -->
<Target Name="_GenerateVersionProps" BeforeTargets="BeforeBuild;Pack">
<Exec Command="node -e &quot;console.log(require('./nodejs/package-lock.json').packages['node_modules/@github/copilot'].version)&quot;" WorkingDirectory="$(MSBuildThisFileDirectory)../.." ConsoleToMSBuild="true" StandardOutputImportance="low">
<Output TaskParameter="ConsoleOutput" PropertyName="CopilotCliVersion" />
</Exec>
<Error Condition="'$(CopilotCliVersion)' == ''" Text="CopilotCliVersion could not be read from nodejs/package-lock.json" />
<PropertyGroup>
<_VersionPropsContent>
<![CDATA[<Project>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Version>0.1.0</Version>
<Description>SDK for programmatic control of GitHub Copilot CLI</Description>
<Authors>GitHub</Authors>
<Company>GitHub</Company>
<Copyright>Copyright (c) Microsoft Corporation. All rights reserved.</Copyright>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/github/copilot-sdk</RepositoryUrl>
<PackageTags>github;copilot;sdk;jsonrpc;agent</PackageTags>
<IsAotCompatible>true</IsAotCompatible>
<CopilotCliVersion>$(CopilotCliVersion)</CopilotCliVersion>
</PropertyGroup>
</Project>]]>
</_VersionPropsContent>
</PropertyGroup>
<WriteLinesToFile File="$(MSBuildThisFileDirectory)build\GitHub.Copilot.SDK.props" Lines="$(_VersionPropsContent)" Overwrite="true" WriteOnlyWhenDifferent="true" />
<!-- Explicitly add props file to package content after generation -->
<ItemGroup>
<None Include="build\GitHub.Copilot.SDK.props" Pack="true" PackagePath="build\" />
</ItemGroup>
</Target>

<ItemGroup>
<None Include="../README.md" Pack="true" PackagePath="/" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.AI.Abstractions" Version="10.2.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.2" />
<PackageReference Include="StreamJsonRpc" Version="2.24.84" PrivateAssets="compile" />
<PackageReference Include="System.Text.Json" Version="10.0.2" />
</ItemGroup>
<!-- Include .targets file in package (props is added dynamically by _GenerateVersionProps) -->
<!-- Also import the .targets for local dev (same logic consumers get) -->
<ItemGroup>
<None Include="build\GitHub.Copilot.SDK.targets" Pack="true" PackagePath="build\" CopyToOutputDirectory="Never" />
</ItemGroup>
<Import Project="build\GitHub.Copilot.SDK.targets" />

</Project>
3 changes: 3 additions & 0 deletions dotnet/src/Types.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ public enum ConnectionState

public class CopilotClientOptions
{
/// <summary>
/// Path to the Copilot CLI executable. If not specified, uses the bundled CLI from the SDK.
/// </summary>
public string? CliPath { get; set; }
public string[]? CliArgs { get; set; }
public string? Cwd { get; set; }
Expand Down
Loading
Loading