Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
03a316b
Note that workflow runs can't be re-run while the workflow is disable…
kranthi0003 Oct 20, 2026
70e7a59
Remove required reviewers rule from GHES 3.22 release notes and docs …
pararohan Oct 20, 2026
8c87487
Explain how disabling a workflow affects existing workflow runs (#64256)
kranthi0003 Oct 20, 2026
6151e48
Clarify webhook delivery for locked repositories (#64270)
misalcedo Oct 20, 2026
3e6eca1
Sync Copilot SDK docs (auto-generated) (#64291)
docs-bot Oct 20, 2026
9e4223c
Fix per-page exit and referrer data after client-side navigation (#63…
heiskr Oct 20, 2026
5e05e0a
Run nested test folders in the Test workflow (#63987)
heiskr Oct 20, 2026
bc5837d
Keep punctuation in octicon aria-label values (#63989)
heiskr Oct 20, 2026
c455b1a
Stop rendering sidebar cookie state into cached pages (#64007)
heiskr Oct 20, 2026
d4f1b02
Strip raw HTML and comments from search record content (#64009)
heiskr Oct 20, 2026
9721203
Keep the app download fallback on Android tablets in desktop mode (#6…
heiskr Oct 20, 2026
ae992dd
Check only the fence language comment syntax in GHD045 (#64038)
heiskr Oct 20, 2026
e4ba087
Land in-article jumps below the sticky bars and mark them active (#64…
heiskr Oct 20, 2026
931bd57
Redirect archived enterprise URLs with double slashes instead of 404 …
heiskr Oct 20, 2026
9e2fd85
Warm the remotejson cache for the archives test suite (#64042)
heiskr Oct 20, 2026
0587456
Run article API docs check when the README or generator changes (#64043)
heiskr Oct 20, 2026
4289db8
Resolve language-less pathnames in the Article API (#64045)
heiskr Oct 20, 2026
bbf8e29
Stop cancelled Ask AI requests from changing the next answer (#64048)
heiskr Oct 20, 2026
a2a327a
Keep query and fragment on Ask AI answer links (#64050)
heiskr Oct 20, 2026
96e41d7
Fix broken ifversion tags in 5 translated intros (#64274)
heiskr Oct 20, 2026
92991ed
docs: update copilot-cli content from source docs (#64265)
docs-bot Oct 20, 2026
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
4 changes: 4 additions & 0 deletions .github/rulesets/docs-internal/main-branch-protection.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@
"context": "early-access",
"integration_id": 15368
},
{
"context": "eslint-rules",
"integration_id": 15368
},
{
"context": "events",
"integration_id": 15368
Expand Down
4 changes: 4 additions & 0 deletions .github/rulesets/docs/main-branch-protection.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@
"context": "early-access",
"integration_id": 15368
},
{
"context": "eslint-rules",
"integration_id": 15368
},
{
"context": "events",
"integration_id": 15368
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/article-api-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ on:
paths:
- 'src/article-api/middleware/article.ts'
- 'src/article-api/middleware/pagelist.ts'
- 'src/article-api/scripts/generate-api-docs.ts'
# Manual edits to generated docs must fail this check.
- 'src/article-api/README.md'
- .github/workflows/article-api-docs.yml

permissions:
contents: read

jobs:
check-content-linter-rules-docs:
check-article-api-docs:
runs-on: ubuntu-latest
if: github.repository == 'github/docs-internal' || github.repository == 'github/docs'
steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/sync-sdk-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ jobs:
# Keep relocated pages in the rsync input. RELOCATED_PAGES in
# src/workflows/sync-sdk-docs/normalize-sdk-docs.ts removes them and
# repoints inbound links.
rsync -av --exclude='.validation/' --exclude='developer-docs/' "$SDK_TMP/docs/" "$SDK_DOCS_TARGET/"
rsync -av --exclude='.validation/' --exclude='developer-docs/' --exclude='AGENTS.md' --exclude='/runtime-supervised-host.md' "$SDK_TMP/docs/" "$SDK_DOCS_TARGET/"
echo "Copied $(find "$SDK_DOCS_TARGET" -name '*.md' | wc -l | tr -d ' ') markdown files"
- name: Normalize content
Expand Down
14 changes: 8 additions & 6 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
matrix:
# Add new matrix suites to branch protection required checks too.
name:
# Lists every src directory. Commented-out entries have no suite-specific tests.
# Lists every src directory. Commented-out entries have no tests unless noted.
# - app
- archives
- article-api
Expand All @@ -48,7 +48,7 @@ jobs:
# - deployments
# - dev-toc
- early-access
# - eslint-rules
- eslint-rules
- events
- fixtures
- frame
Expand Down Expand Up @@ -85,7 +85,7 @@ jobs:
env:
# These suites make no HTTP requests, so they skip the Next.js build and test server.
# A suite that adds an HTTP test fails with a connection error until it's removed from this list.
START_VITEST_SERVER: ${{ contains(fromJSON('["color-schemes", "content-linter", "data-directory", "ghes-releases", "journeys", "links", "observability", "products", "tools", "workflows"]'), matrix.name) && 'false' || 'true' }}
START_VITEST_SERVER: ${{ contains(fromJSON('["color-schemes", "content-linter", "data-directory", "eslint-rules", "ghes-releases", "journeys", "links", "observability", "products", "tools", "workflows"]'), matrix.name) && 'false' || 'true' }}

steps:
# Repeat each if on its step so skipped work still leaves the required check present.
Expand Down Expand Up @@ -171,8 +171,9 @@ jobs:
run: npm run build

- uses: ./.github/actions/warmup-remotejson-cache
# Only routing tests cover archived enterprise server URLs.
if: ${{ matrix.name == 'redirects' }}
# The archives and redirects suites request archived GHES redirects.json files.
# keep-caches-warm.yml seeds this cache in docs-internal only; a cold warmup fetches every archived version.
if: ${{ matrix.name == 'redirects' || (matrix.name == 'archives' && github.repository == 'github/docs-internal') }}

- uses: ./.github/actions/setup-elasticsearch
if: ${{ matrix.name == 'search' || matrix.name == 'languages' }}
Expand All @@ -197,4 +198,5 @@ jobs:
VITEST_FLAGS: ${{ matrix.name == 'article-api' && '--no-file-parallelism --maxWorkers=1' || '' }}
# PRs render pinned autogenerated pages unless they change pipeline code or output.
AUTOGENERATED_RENDER_ALL: ${{ matrix.name == 'automated-pipelines' && (github.event_name != 'pull_request' || steps.pipeline_files.outputs.any_modified == 'true') }}
run: npm test -- $VITEST_FLAGS src/${{ matrix.name }}/tests/
# Filter on the whole src directory so nested tests/ folders, like src/webhooks/lib/tests/, run too.
run: npm test -- $VITEST_FLAGS src/${{ matrix.name }}/
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-3.png
Binary file modified assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-5.png
Binary file modified assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-6.png
Binary file modified assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-7.png
Binary file modified assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-8.png
Binary file modified assets/images/help/copilot/copilot-sdk/setup-scaling-diagram-9.png
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ contentType: how-tos

Disabling a workflow allows you to stop a workflow from being triggered without having to delete the file from the repo. You can easily re-enable the workflow again on {% data variables.product.prodname_dotcom %}.

Disabling a workflow doesn't cancel its existing runs, but you can't re-run those runs or their jobs while the workflow is disabled. Enable the workflow first to re-run it.

Temporarily disabling a workflow can be useful in many scenarios. These are a few examples where disabling a workflow might be helpful:

* A workflow error that produces too many or wrong requests, impacting external services negatively.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ Re-runs use the privileges of the actor who initially triggered the workflow, no

A workflow run can be re-run a maximum of 50 times. This limit includes both full re-runs and re-runs of a subset of jobs.

You can't re-run a workflow run, or any of its jobs, while the workflow is disabled. You need to enable the workflow first. See [AUTOTITLE](/actions/how-tos/manage-workflow-runs/disable-and-enable-workflows).

## Re-running all the jobs in a workflow

{% webui %}
Expand Down
3 changes: 2 additions & 1 deletion content/copilot/how-tos/copilot-sdk/auth/byok.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,9 @@ client.stop().get();
| `type` | `"openai"` \| `"azure"` \| `"anthropic"` | Provider type (default: `"openai"`) |
| `baseUrl` / `base_url` | string | **Required.** API endpoint URL |
| `apiKey` / `api_key` | string | API key (optional for local providers like Ollama) |
| `apiKeyCommand` / `api_key_command` | string | Command run by the runtime before each provider request to obtain a fresh API key. Also exposed as `ApiKeyCommand` in .NET and `APIKeyCommand` in Go. Credential-command failures fail the turn before sending a model request. |
| `bearerToken` / `bearer_token` | string | Bearer token auth (takes precedence over apiKey) |
| `bearerTokenProvider` / `bearer_token_provider` | callback | Returns a bearer token on demand (takes precedence over `apiKey` and `bearerToken`) |
| `bearerTokenProvider` / `bearer_token_provider` | callback | Returns a bearer token on demand (takes precedence over `apiKey`, `apiKeyCommand`, and `bearerToken`; the command does not run) |
| `wireApi` / `wire_api` | `"completions"` \| `"responses"` | Select `"completions"` for broad model compatibility (the Chat Completions API); select `"responses"` for multi-turn state management, tool namespacing, and reasoning support (the Responses API). Anthropic models always use the Messages API regardless of this setting. |
| `azure.apiVersion` / `azure.api_version` | string | Azure API version. When set, the runtime uses the versioned deployment route; when omitted, it uses the GA versionless `v1` route. |

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Server-to-server authentication
shortTitle: Server-to-server tokens
shortTitle: Server To Server Tokens
intro: >-
Use a short-lived installation access token when a service needs to make
Copilot requests on behalf of an organization without a user's credentials. In
Expand Down
192 changes: 192 additions & 0 deletions content/copilot/how-tos/copilot-sdk/features/changing-tools.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
---
title: Changing tools during a session
shortTitle: Changing Tools
intro: >-
An application can replace the tools it supplies to a live session without
recreating it. For example, a web page can offer different tools as the user
navigates, or a client that takes over a session can bring its own tools. Each
SDK replaces the client's complete tool set and the handlers that serve it in
one call.
versions:
fpt: '*'
ghec: '*'
contentType: how-tos
---

<!-- markdownlint-disable GHD046 GHD005 -->
<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->

> **Experimental.** Tool replacement wraps the experimental `session.tools.set` RPC and requires a runtime that supports it.
## Replace this client's tools

Pass the complete set of tools this client should supply. It replaces the tools the client supplied when the session was created or resumed, or in an earlier replacement. Built-in, MCP, and plugin tools, and tools that other clients connected to the same session supply, are unaffected. Pass an empty list to remove all of this client's tools.

Tools are defined exactly as they are for creating a session, and a tool without a handler behaves the same way it does there.

{% codetabs %}
{% codetab typescript %}

```typescript
import { defineTool } from "@github/copilot-sdk";
import { z } from "zod";

const searchIssues = defineTool("search_issues", {
description: "Search the issues shown on the current page",
parameters: z.object({ query: z.string().describe("Search text") }),
handler: async ({ query }) => findIssues(query),
});

// Supply only the tools the current page provides.
await session.setTools([searchIssues]);

// Remove all of this client's tools.
await session.setTools([]);
```

{% endcodetab %}
{% codetab python %}

```python
from pydantic import BaseModel, Field
from copilot.tools import define_tool

class SearchIssuesParams(BaseModel):
query: str = Field(description="Search text")

@define_tool(description="Search the issues shown on the current page")
async def search_issues(params: SearchIssuesParams) -> str:
return await find_issues(params.query)

# Supply only the tools the current page provides.
await session.set_tools([search_issues])

# Remove all of this client's tools.
await session.set_tools([])
```

{% endcodetab %}
{% codetab go %}

```golang
type SearchIssuesParams struct {
Query string `json:"query" jsonschema:"Search text"`
}

searchIssues := copilot.DefineTool(
"search_issues",
"Search the issues shown on the current page",
func(params SearchIssuesParams, inv copilot.ToolInvocation) (string, error) {
return findIssues(params.Query)
},
)

// Supply only the tools the current page provides.
if err := session.SetTools(ctx, []copilot.Tool{searchIssues}); err != nil {
log.Fatal(err)
}

// Remove all of this client's tools.
if err := session.SetTools(ctx, nil); err != nil {
log.Fatal(err)
}
```

{% endcodetab %}
{% codetab dotnet %}

```csharp
var searchIssues = CopilotTool.DefineTool(
([Description("Search text")] string query) => FindIssues(query),
factoryOptions: new AIFunctionFactoryOptions
{
Name = "search_issues",
Description = "Search the issues shown on the current page",
});

// Supply only the tools the current page provides.
await session.SetToolsAsync([searchIssues]);

// Remove all of this client's tools.
await session.SetToolsAsync([]);
```

`SetToolsAsync` raises the `GHCP001` experimental diagnostic, which you suppress with `#pragma warning disable GHCP001` or a project-level `<NoWarn>GHCP001</NoWarn>`.

{% endcodetab %}
{% codetab java %}

```java
var searchIssues = ToolDefinition.create(
"search_issues",
"Search the issues shown on the current page",
Map.of(
"type", "object",
"properties", Map.of("query", Map.of("type", "string", "description", "Search text")),
"required", List.of("query")),
invocation -> CompletableFuture.completedFuture(
findIssues((String) invocation.getArguments().get("query"))));

// Supply only the tools the current page provides.
session.setTools(List.of(searchIssues)).get();

// Remove all of this client's tools.
session.setTools(List.of()).get();
```

`setTools` is `@CopilotExperimental`, so the consuming class or method must opt in with `@AllowCopilotExperimental`. See [Using experimental APIs](https://github.com/github/copilot-sdk/tree/main/java/README.md#using-experimental-apis).

{% endcodetab %}
{% codetab rust %}

<!-- docs-validate: skip -->

```rust
#[derive(Deserialize, JsonSchema)]
struct SearchIssuesParams {
/// Search text
query: String,
}

let search_issues = define_tool(
"search_issues",
"Search the issues shown on the current page",
|_inv, params: SearchIssuesParams| async move {
Ok(ToolResult::Text(find_issues(&params.query).await))
},
);

// Supply only the tools the current page provides.
session.set_tools(vec![search_issues]).await?;

// Remove all of this client's tools.
session.set_tools(Vec::new()).await?;
```

{% endcodetab %}
{% endcodetabs %}

## When the new tools take effect

- **Model requests.** The runtime offers the new tools from the agent's next model request. That request can be part of a turn that is already in progress.
- **Handlers.** As soon as the runtime accepts the replacement, every tool call the session dispatches uses the new handlers. Calls that are already running finish on the handlers that started them.
- **Rejection.** If the runtime rejects the replacement, the call fails and the previous tools and handlers stay in place. The runtime rejects tool names with invalid characters and names that another connected client already supplies.
- **Ordering.** Concurrent replacements on the same session are applied one at a time, in the order they're made.
- **Cancellation.** In SDKs that let you cancel the call, cancelling it while an earlier replacement is still in flight sends nothing. Once the request is sent, cancelling only stops the wait: if the runtime accepts the replacement, the new handlers still take effect.

## Replacing tools during a turn

A model request that is already in flight was made with the previous tools, so the agent can still call a tool you just removed. The session doesn't answer that call, because another connected client might supply a tool with the same name, so the call can stay pending until the turn is aborted.

If a running turn might still call a tool you remove, replace tools while the session is idle, for example after the `session.idle` event, or abort the turn first. Replacing a tool's handler under the same name is safe during a turn: calls dispatched after the runtime accepts the replacement use the new handler.

## SDK reference

| SDK | Method |
|---|---|
| TypeScript | `session.setTools(tools)` |
| Python | `await session.set_tools(tools)` |
| Go | `session.SetTools(ctx, tools)` |
| .NET | `await session.SetToolsAsync(tools, cancellationToken)` |
| Java | `session.setTools(tools)`, which returns a `CompletableFuture<Void>` |
| Rust | `session.set_tools(tools).await` |
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Client info
shortTitle: Client info
shortTitle: Client Info
intro: >-
Client info identifies the application using the Copilot SDK and, when
applicable, a specific integration within it. An integration is an
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Context clearing and terminal tools
shortTitle: Context management
shortTitle: Context Management
intro: >-
Use `session.history.clearContext` when a host needs to replace the current
conversation context without replacing the session. Typical uses include
Expand Down
2 changes: 2 additions & 0 deletions content/copilot/how-tos/copilot-sdk/features/custom-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ Custom agents are lightweight agent definitions you attach to a session. Each ag

## Defining custom agents

To discover Markdown definitions from versioned packages or vendored folders, use `agentDirectories` or [AUTOTITLE](/copilot/how-tos/copilot-sdk/features/customization-locations).

Pass `customAgents` when creating a session. Each agent needs at minimum a `name` and `prompt`.

{% codetabs %}
Expand Down
Loading
Loading