diff --git a/.github/actions/java-test-report/action.yml b/.github/actions/java-test-report/action.yml
index 7d610e6b6..e826628a0 100644
--- a/.github/actions/java-test-report/action.yml
+++ b/.github/actions/java-test-report/action.yml
@@ -66,10 +66,10 @@ runs:
for file in ${{ inputs.report-path }}; do
if [ -f "$file" ]; then
CLASS=$(basename "$file" .xml | sed 's/TEST-//')
- T=$(grep -o 'tests="[0-9]*"' "$file" | head -1 | sed 's/[^0-9]//g')
- F=$(grep -o 'failures="[0-9]*"' "$file" | head -1 | sed 's/[^0-9]//g')
- E=$(grep -o 'errors="[0-9]*"' "$file" | head -1 | sed 's/[^0-9]//g')
- TIME=$(grep -o 'time="[0-9.]*"' "$file" | head -1 | sed 's/[^0-9.]//g')
+ T=$(grep -m 1 -o 'tests="[0-9]*"' "$file" | sed 's/[^0-9]//g')
+ F=$(grep -m 1 -o 'failures="[0-9]*"' "$file" | sed 's/[^0-9]//g')
+ E=$(grep -m 1 -o 'errors="[0-9]*"' "$file" | sed 's/[^0-9]//g')
+ TIME=$(grep -m 1 -o 'time="[0-9.]*"' "$file" | sed 's/[^0-9.]//g')
P=$((T - F - E))
STATUS="✅"
diff --git a/.github/agents/docs-maintenance.agent.md b/.github/agents/docs-maintenance.agent.md
index b1bf95ae8..bf7fa8518 100644
--- a/.github/agents/docs-maintenance.agent.md
+++ b/.github/agents/docs-maintenance.agent.md
@@ -377,7 +377,7 @@ cat go/types.go | grep -A 15 "type SessionHooks struct"
```
**Must match (PascalCase for exported):**
-- `ClientOptions` fields: `CLIPath`, `CLIUrl`, `UseStdio`, `Port`, `LogLevel`, `AutoStart`, `Env`, `GithubToken`, `UseLoggedInUser`
+- `ClientOptions` fields: `CLIPath`, `CLIUrl`, `UseStdio`, `Port`, `LogLevel`, `AutoStart`, `Env`, `GitHubToken`, `UseLoggedInUser`
- `SessionConfig` fields: `Model`, `Tools`, `Hooks`, `SystemMessage`, `MCPServers`, `AvailableTools`, `ExcludedTools`, `Streaming`, `ReasoningEffort`, `Provider`, `InfiniteSessions`, `CustomAgents`, `WorkingDirectory`
- `Session` methods: `Send()`, `SendAndWait()`, `GetMessages()`, `Disconnect()`, `Abort()`, `ExportSession()`
- Hook fields: `OnPreToolUse`, `OnPostToolUse`, `OnPostToolUseFailure`, `OnUserPromptSubmitted`, `OnSessionStart`, `OnSessionEnd`, `OnErrorOccurred`
@@ -395,7 +395,7 @@ cat dotnet/src/Types.cs | grep -A 15 "public class SessionHooks"
```
**Must match (PascalCase):**
-- `CopilotClientOptions` properties: `CliPath`, `CliUrl`, `UseStdio`, `Port`, `LogLevel`, `AutoStart`, `Environment`, `GithubToken`, `UseLoggedInUser`
+- `CopilotClientOptions` properties: `CliPath`, `CliUrl`, `UseStdio`, `Port`, `LogLevel`, `AutoStart`, `Environment`, `GitHubToken`, `UseLoggedInUser`
- `SessionConfig` properties: `Model`, `Tools`, `Hooks`, `SystemMessage`, `McpServers`, `AvailableTools`, `ExcludedTools`, `Streaming`, `ReasoningEffort`, `Provider`, `InfiniteSessions`, `CustomAgents`, `WorkingDirectory`
- `CopilotSession` methods: `SendAsync()`, `SendAndWaitAsync()`, `GetMessagesAsync()`, `DisposeAsync()`, `AbortAsync()`, `ExportSessionAsync()`
- Hook properties: `OnPreToolUse`, `OnPostToolUse`, `OnPostToolUseFailure`, `OnUserPromptSubmitted`, `OnSessionStart`, `OnSessionEnd`, `OnErrorOccurred`
diff --git a/.github/aw/actions-lock.json b/.github/aw/actions-lock.json
index 64a9e8923..20f250316 100644
--- a/.github/aw/actions-lock.json
+++ b/.github/aw/actions-lock.json
@@ -25,10 +25,10 @@
"version": "v7.0.0",
"sha": "bbbca2ddaa5d8feaa63e36b76fdaad77386f024f"
},
- "github/gh-aw-actions/setup@v0.74.4": {
+ "github/gh-aw-actions/setup@v0.77.5": {
"repo": "github/gh-aw-actions/setup",
- "version": "v0.74.4",
- "sha": "d3abfe96a194bce3a523ed2093ddedd5704cdf62"
+ "version": "v0.77.5",
+ "sha": "3ea13c02d765410340d533515cb31a7eef2baaf0"
},
"github/gh-aw/actions/setup@v0.52.1": {
"repo": "github/gh-aw/actions/setup",
diff --git a/.github/badges/jacoco-generated.svg b/.github/badges/jacoco-generated.svg
new file mode 100644
index 000000000..bd7223a65
--- /dev/null
+++ b/.github/badges/jacoco-generated.svg
@@ -0,0 +1,18 @@
+
diff --git a/.github/badges/jacoco-handwritten.svg b/.github/badges/jacoco-handwritten.svg
new file mode 100644
index 000000000..bfb6196f6
--- /dev/null
+++ b/.github/badges/jacoco-handwritten.svg
@@ -0,0 +1,18 @@
+
diff --git a/.github/scripts/generate-java-coverage-badge.sh b/.github/scripts/generate-java-coverage-badge.sh
old mode 100644
new mode 100755
index 324b3194f..3c68d830d
--- a/.github/scripts/generate-java-coverage-badge.sh
+++ b/.github/scripts/generate-java-coverage-badge.sh
@@ -8,7 +8,7 @@ set -euo pipefail
CSV="${1:-target/site/jacoco-coverage/jacoco.csv}"
BADGES_DIR="${2:-.github/badges}"
-GENERATED_PREFIX="com.github.copilot.sdk.generated"
+GENERATED_PREFIX="com.github.copilot.generated"
if [ ! -f "$CSV" ]; then
echo "⚠️ No JaCoCo CSV report found at $CSV"
@@ -89,19 +89,15 @@ EOF
mkdir -p "$BADGES_DIR"
-read -r overall_missed overall_covered <<< "$(calc_totals overall)"
read -r handwritten_missed handwritten_covered <<< "$(calc_totals handwritten)"
read -r generated_missed generated_covered <<< "$(calc_totals generated)"
-overall_pct=$(format_pct "$overall_missed" "$overall_covered")
handwritten_pct=$(format_pct "$handwritten_missed" "$handwritten_covered")
generated_pct=$(format_pct "$generated_missed" "$generated_covered")
-echo "Overall coverage: ${overall_pct}%"
echo "Handwritten coverage: ${handwritten_pct}%"
echo "Generated coverage: ${generated_pct}%"
-generate_badge "coverage" "${overall_pct}%" "${BADGES_DIR}/jacoco.svg"
generate_badge "coverage handwritten" "${handwritten_pct}%" "${BADGES_DIR}/jacoco-handwritten.svg"
generate_badge "coverage generated" "${generated_pct}%" "${BADGES_DIR}/jacoco-generated.svg"
diff --git a/.github/skills/java-coding-skill/SKILL.md b/.github/skills/java-coding-skill/SKILL.md
index e48ad00ed..4e120d2cc 100644
--- a/.github/skills/java-coding-skill/SKILL.md
+++ b/.github/skills/java-coding-skill/SKILL.md
@@ -1,17 +1,17 @@
---
name: java-coding-skill
-description: "Use this skill whenever editing `*.java` files in the `java/` SDK in order to write idiomatic, well-structured Java code for the Copilot SDK"
+description: "Use this skill whenever editing `*.java` files in the `java/` directore of the SDK in order to write idiomatic, well-structured Java code for the Copilot SDK"
---
# Java Coding Skill
## Core Principles
-- The SDK is in public preview and may have breaking changes
-- Requires Java 17 or later
-- Requires GitHub Copilot CLI installed and in PATH
-- Uses `CompletableFuture` for all async operations
-- Implements `AutoCloseable` for resource cleanup (try-with-resources)
+- Requires Java 25 or later for building the jar artifact for Copilot SDK for java.
+- Uses the Multi-Relase jar feature JEP 238 https://openjdk.org/jeps/238 with `maven.compiler.release` 17 so that uses running JDK 17 can use the jar.
+- Requires GitHub Copilot CLI installed and in PATH.
+- Uses `CompletableFuture` for all async operations.
+- Implements `AutoCloseable` for resource cleanup (try-with-resources).
## Installation
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644
index 000000000..e7d5bf4f3
--- /dev/null
+++ b/.github/workflows/codeql.yml
@@ -0,0 +1,159 @@
+name: "CodeQL"
+
+on:
+ push:
+ branches: [main]
+ pull_request:
+ branches: [main]
+ schedule:
+ - cron: "0 6 * * 1" # Weekly on Monday at 06:00 UTC
+
+permissions:
+ contents: read
+ security-events: write
+
+jobs:
+ changes:
+ name: Detect changed paths
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ pull-requests: read
+ outputs:
+ matrix: ${{ steps.build-matrix.outputs.matrix }}
+ skipped-matrix: ${{ steps.build-matrix.outputs.skipped-matrix }}
+ steps:
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+
+ - uses: dorny/paths-filter@6852f92c20ea7fd3b0c25de3b5112db3a98da050 # v3
+ id: filter
+ if: github.event_name == 'pull_request'
+ with:
+ filters: |
+ java:
+ - 'java/**'
+ - '!java/docs/**'
+ - '!java/*.txt'
+ - '!java/*.md'
+ js:
+ - 'nodejs/**'
+ - 'scripts/**'
+ - 'test/harness/**'
+ python:
+ - 'python/**'
+ go:
+ - 'go/**'
+ rust:
+ - 'rust/**'
+ csharp:
+ - 'dotnet/**'
+ actions:
+ - '.github/workflows/**'
+ - '.github/actions/**'
+
+ - name: Build language matrix
+ id: build-matrix
+ run: |
+ ALL_LANGUAGES=("java-kotlin" "javascript-typescript" "python" "go" "rust" "csharp" "actions")
+ ALL_GATES=("java" "js" "python" "go" "rust" "csharp" "actions")
+
+ # On push/schedule, analyse ALL languages; skip none.
+ if [[ "${{ github.event_name }}" != "pull_request" ]]; then
+ entries=()
+ for lang in "${ALL_LANGUAGES[@]}"; do
+ entries+=("{\"language\":\"${lang}\"}")
+ done
+ joined=$(IFS=,; echo "${entries[*]}")
+ echo "matrix={\"include\":[${joined}]}" >> "$GITHUB_OUTPUT"
+ echo 'skipped-matrix={"include":[]}' >> "$GITHUB_OUTPUT"
+ else
+ entries=()
+ skipped=()
+ filter_outputs=("${{ steps.filter.outputs.java }}" "${{ steps.filter.outputs.js }}" "${{ steps.filter.outputs.python }}" "${{ steps.filter.outputs.go }}" "${{ steps.filter.outputs.rust }}" "${{ steps.filter.outputs.csharp }}" "${{ steps.filter.outputs.actions }}")
+
+ for i in "${!ALL_LANGUAGES[@]}"; do
+ lang="${ALL_LANGUAGES[$i]}"
+ changed="${filter_outputs[$i]}"
+ if [[ "$changed" == "true" ]]; then
+ entries+=("{\"language\":\"${lang}\"}")
+ else
+ skipped+=("{\"language\":\"${lang}\"}")
+ fi
+ done
+
+ if [[ ${#entries[@]} -eq 0 ]]; then
+ echo 'matrix={"include":[]}' >> "$GITHUB_OUTPUT"
+ else
+ joined=$(IFS=,; echo "${entries[*]}")
+ echo "matrix={\"include\":[${joined}]}" >> "$GITHUB_OUTPUT"
+ fi
+
+ if [[ ${#skipped[@]} -eq 0 ]]; then
+ echo 'skipped-matrix={"include":[]}' >> "$GITHUB_OUTPUT"
+ else
+ joined=$(IFS=,; echo "${skipped[*]}")
+ echo "skipped-matrix={\"include\":[${joined}]}" >> "$GITHUB_OUTPUT"
+ fi
+ fi
+
+ analyze:
+ name: Analyze (${{ matrix.language }})
+ needs: changes
+ if: ${{ fromJson(needs.changes.outputs.matrix).include[0] != null }}
+ runs-on: ubuntu-latest
+ permissions:
+ security-events: write
+ contents: read
+ strategy:
+ fail-fast: false
+ matrix: ${{ fromJson(needs.changes.outputs.matrix) }}
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
+
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@a6fd1787519fd23e68309fad43738e41a6ff2a9d # v4
+ with:
+ languages: ${{ matrix.language }}
+ queries: security-and-quality
+
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@a6fd1787519fd23e68309fad43738e41a6ff2a9d # v4
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@a6fd1787519fd23e68309fad43738e41a6ff2a9d # v4
+ with:
+ category: "/language:${{ matrix.language }}"
+
+ # Upload empty SARIF for languages that were NOT analysed in this PR.
+ # Code scanning branch protection expects results for every category that
+ # has ever been uploaded on the default branch; missing categories block merge.
+ skip-analysis:
+ name: Skip (${{ matrix.language }})
+ needs: changes
+ if: ${{ github.event_name == 'pull_request' && fromJson(needs.changes.outputs.skipped-matrix).include[0] != null }}
+ runs-on: ubuntu-latest
+ permissions:
+ security-events: write
+ strategy:
+ fail-fast: false
+ matrix: ${{ fromJson(needs.changes.outputs.skipped-matrix) }}
+ steps:
+ - name: Create empty SARIF
+ run: |
+ cat > "$RUNNER_TEMP/empty.sarif" <<'EOF'
+ {
+ "version": "2.1.0",
+ "$schema": "https://json.schemastore.org/sarif-2.1.0.json",
+ "runs": [{
+ "tool": { "driver": { "name": "CodeQL", "version": "0.0.0" } },
+ "results": []
+ }]
+ }
+ EOF
+
+ - name: Upload empty SARIF
+ uses: github/codeql-action/upload-sarif@a6fd1787519fd23e68309fad43738e41a6ff2a9d # v4
+ with:
+ sarif_file: ${{ runner.temp }}/empty.sarif
+ category: "/language:${{ matrix.language }}"
diff --git a/.github/workflows/cross-repo-issue-analysis.lock.yml b/.github/workflows/cross-repo-issue-analysis.lock.yml
index a16753799..697ecc0ee 100644
--- a/.github/workflows/cross-repo-issue-analysis.lock.yml
+++ b/.github/workflows/cross-repo-issue-analysis.lock.yml
@@ -1,5 +1,5 @@
-# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"97b961391ad56ae223a93f2ff91267fed96ce49805bdd921de7549138893d637","compiler_version":"v0.74.4","strict":true,"agent_id":"copilot"}
-# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN","RUNTIME_TRIAGE_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"d3abfe96a194bce3a523ed2093ddedd5704cdf62","version":"v0.74.4"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.46"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.9","digest":"sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388"},{"image":"ghcr.io/github/github-mcp-server:v1.0.4"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]}
+# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"97b961391ad56ae223a93f2ff91267fed96ce49805bdd921de7549138893d637","body_hash":"653dfb46c89df98eca22ddfb802149d6ade32e9a7ad40dbdc51bfb6b0ba1c4a3","compiler_version":"v0.77.5","strict":true,"agent_id":"copilot"}
+# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN","RUNTIME_TRIAGE_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"3ea13c02d765410340d533515cb31a7eef2baaf0","version":"v0.77.5"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.58"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.22"},{"image":"ghcr.io/github/github-mcp-server:v1.1.0"},{"image":"node:lts-alpine","digest":"sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14","pinned_image":"node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14"}]}
# ___ _ _
# / _ \ | | (_)
# | |_| | __ _ ___ _ __ | |_ _ ___
@@ -14,7 +14,7 @@
# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
#
-# This file was automatically generated by gh-aw (v0.74.4). DO NOT EDIT.
+# This file was automatically generated by gh-aw (v0.77.5). DO NOT EDIT.
#
# To update this file, edit the corresponding .md file and run:
# gh aw compile
@@ -38,15 +38,15 @@
# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9)
# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
# - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
-# - github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+# - github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
#
# Container images used:
-# - ghcr.io/github/gh-aw-firewall/agent:0.25.46
-# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46
-# - ghcr.io/github/gh-aw-firewall/squid:0.25.46
-# - ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388
-# - ghcr.io/github/github-mcp-server:v1.0.4
-# - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+# - ghcr.io/github/gh-aw-firewall/agent:0.25.58
+# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58
+# - ghcr.io/github/gh-aw-firewall/squid:0.25.58
+# - ghcr.io/github/gh-aw-mcpg:v0.3.22
+# - ghcr.io/github/github-mcp-server:v1.1.0
+# - node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
name: "SDK Runtime Triage"
on:
@@ -57,7 +57,7 @@ on:
inputs:
aw_context:
default: ""
- description: Agent caller context (used internally by Agentic Workflows).
+ description: "Agent caller context (used internally by Agentic Workflows)."
required: false
type: string
issue_number:
@@ -98,7 +98,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -107,24 +107,25 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "SDK Runtime Triage"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/cross-repo-issue-analysis.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Generate agentic run info
id: generate_aw_info
env:
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI"
- GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
- GH_AW_INFO_VERSION: "1.0.48"
- GH_AW_INFO_AGENT_VERSION: "1.0.48"
- GH_AW_INFO_CLI_VERSION: "v0.74.4"
+ GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AGENT_VERSION: "1.0.55"
+ GH_AW_INFO_CLI_VERSION: "v0.77.5"
GH_AW_INFO_WORKFLOW_NAME: "SDK Runtime Triage"
GH_AW_INFO_EXPERIMENTAL: "false"
GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
GH_AW_INFO_STAGED: "false"
GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]'
GH_AW_INFO_FIREWALL_ENABLED: "true"
- GH_AW_INFO_AWF_VERSION: "v0.25.46"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_AWMG_VERSION: ""
GH_AW_INFO_FIREWALL_TYPE: "squid"
GH_AW_COMPILED_STRICT: "true"
@@ -147,6 +148,7 @@ jobs:
sparse-checkout: |
.github
.agents
+ .antigravity
.claude
.codex
.crush
@@ -157,8 +159,8 @@ jobs:
fetch-depth: 1
- name: Save agent config folders for base branch restoration
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
# poutine:ignore untrusted_checkout_exec
run: bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh"
- name: Check workflow lock file
@@ -176,7 +178,7 @@ jobs:
- name: Check compile-agentic version
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
- GH_AW_COMPILED_VERSION: "v0.74.4"
+ GH_AW_COMPILED_VERSION: "v0.77.5"
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@@ -208,6 +210,7 @@ jobs:
GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
+ GH_AW_INPUTS_ISSUE_NUMBER: ${{ inputs.issue_number }}
# poutine:ignore untrusted_checkout_exec
run: |
bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh"
@@ -269,6 +272,7 @@ jobs:
GH_AW_EXPR_54492A5B: ${{ github.event.issue.number || inputs.issue_number }}
GH_AW_GITHUB_EVENT_ISSUE_TITLE: ${{ github.event.issue.title }}
GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
+ GH_AW_INPUTS_ISSUE_NUMBER: ${{ inputs.issue_number }}
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@@ -289,6 +293,7 @@ jobs:
GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
+ GH_AW_INPUTS_ISSUE_NUMBER: ${{ inputs.issue_number }}
GH_AW_MCP_CLI_SERVERS_LIST: '- `safeoutputs` — run `safeoutputs --help` to see available tools'
GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }}
with:
@@ -312,6 +317,7 @@ jobs:
GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY,
GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID,
GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE,
+ GH_AW_INPUTS_ISSUE_NUMBER: process.env.GH_AW_INPUTS_ISSUE_NUMBER,
GH_AW_MCP_CLI_SERVERS_LIST: process.env.GH_AW_MCP_CLI_SERVERS_LIST,
GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED
}
@@ -334,12 +340,14 @@ jobs:
include-hidden-files: true
path: |
/tmp/gh-aw/aw_info.json
+ /tmp/gh-aw/model_multipliers.json
/tmp/gh-aw/aw-prompts/prompt.txt
/tmp/gh-aw/aw-prompts/prompt-template.txt
/tmp/gh-aw/aw-prompts/prompt-import-tree.json
/tmp/gh-aw/github_rate_limits.jsonl
/tmp/gh-aw/base
/tmp/gh-aw/.github/agents
+ /tmp/gh-aw/.github/skills
if-no-files-found: ignore
retention-days: 1
@@ -358,15 +366,15 @@ jobs:
GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
GH_AW_WORKFLOW_ID_SANITIZED: crossrepoissueanalysis
outputs:
- agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }}
+ agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }}
checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }}
effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }}
has_patch: ${{ steps.collect_output.outputs.has_patch }}
- inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }}
- mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }}
+ inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }}
+ mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }}
model: ${{ needs.activation.outputs.model }}
- model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }}
+ model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }}
output: ${{ steps.collect_output.outputs.output }}
output_types: ${{ steps.collect_output.outputs.output_types }}
setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
@@ -375,7 +383,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -384,7 +392,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "SDK Runtime Triage"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/cross-repo-issue-analysis.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Set runtime paths
id: set-runtime-paths
@@ -438,11 +447,11 @@ jobs:
const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs');
await main();
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Determine automatic lockdown mode for GitHub MCP Server
id: determine-automatic-lockdown
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9)
@@ -461,16 +470,20 @@ jobs:
- name: Restore agent config folders from base branch
if: steps.checkout-pr.outcome == 'success'
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh"
- name: Restore inline sub-agents from activation artifact
env:
GH_AW_SUB_AGENT_DIR: ".github/agents"
GH_AW_SUB_AGENT_EXT: ".agent.md"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh"
+ - name: Restore inline skills from activation artifact
+ env:
+ GH_AW_SKILL_DIR: ".github/skills"
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh"
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46 ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388 ghcr.io/github/github-mcp-server:v1.0.4 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58 ghcr.io/github/gh-aw-mcpg:v0.3.22 ghcr.io/github/github-mcp-server:v1.1.0 node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
- name: Generate Safe Outputs Config
run: |
mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
@@ -702,7 +715,7 @@ jobs:
* ) DOCKER_SOCK_PATH=/var/run/docker.sock ;;
esac
DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0')
- export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.9'
+ export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.22'
mkdir -p /home/runner/.copilot
GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node)
@@ -711,7 +724,7 @@ jobs:
"mcpServers": {
"github": {
"type": "stdio",
- "container": "ghcr.io/github/github-mcp-server:v1.0.4",
+ "container": "ghcr.io/github/github-mcp-server:v1.1.0",
"env": {
"GITHUB_HOST": "\${GITHUB_SERVER_URL}",
"GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
@@ -803,26 +816,38 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/agent-stdio.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"auto":["large"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5.3","gemini-pro","any"],"antigravity":["copilot/antigravity*","google/antigravity*","gemini/antigravity*"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"claude":["agent"],"codex":["agent"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"computer-use":["copilot/*computer-use*","google/*computer-use*","gemini/*computer-use*","openai/*computer-use*"],"copilot":["agent"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent"],"gemini-3-flash":["copilot/gemini-3*flash*","google/gemini-3*flash*","gemini/gemini-3*flash*"],"gemini-3-pro":["copilot/gemini-3*pro*","google/gemini-3*pro*","gemini/gemini-3*pro*"],"gemini-3.1-flash":["copilot/gemini-3.1*flash*","google/gemini-3.1*flash*","gemini/gemini-3.1*flash*"],"gemini-3.1-pro":["copilot/gemini-3.1*pro*","google/gemini-3.1*pro*","gemini/gemini-3.1*pro*"],"gemini-3.5-flash":["copilot/gemini-3.5*flash*","google/gemini-3.5*flash*","gemini/gemini-3.5*flash*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"gpt-5.2":["copilot/gpt-5.2*","openai/gpt-5.2*"],"gpt-5.3":["copilot/gpt-5.3*","openai/gpt-5.3*"],"gpt-5.4":["copilot/gpt-5.4*","openai/gpt-5.4*"],"gpt-5.5":["copilot/gpt-5.5*","openai/gpt-5.5*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"opusplan":["opus?effort=high"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"robotics":["copilot/*robotics*","google/*robotics*","gemini/*robotics*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4-5-*","anthropic/*sonnet-4-5-*","copilot/*sonnet-4-6*","anthropic/*sonnet-4-6*"],"summarization":["haiku","gpt-5-mini","gemini-flash-lite","mini"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-tool github --allow-tool safeoutputs --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(cat:*)'\'' --allow-tool '\''shell(date)'\'' --allow-tool '\''shell(echo)'\'' --allow-tool '\''shell(find:*)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(grep:*)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(head:*)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(ls:*)'\'' --allow-tool '\''shell(printf)'\'' --allow-tool '\''shell(pwd)'\'' --allow-tool '\''shell(safeoutputs:*)'\'' --allow-tool '\''shell(sort)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(tail:*)'\'' --allow-tool '\''shell(uniq)'\'' --allow-tool '\''shell(wc)'\'' --allow-tool '\''shell(wc:*)'\'' --allow-tool '\''shell(yq)'\'' --allow-tool write --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-tool github --allow-tool safeoutputs --allow-tool '\''shell(cat)'\'' --allow-tool '\''shell(cat:*)'\'' --allow-tool '\''shell(date)'\'' --allow-tool '\''shell(echo)'\'' --allow-tool '\''shell(find:*)'\'' --allow-tool '\''shell(grep)'\'' --allow-tool '\''shell(grep:*)'\'' --allow-tool '\''shell(head)'\'' --allow-tool '\''shell(head:*)'\'' --allow-tool '\''shell(ls)'\'' --allow-tool '\''shell(ls:*)'\'' --allow-tool '\''shell(printf)'\'' --allow-tool '\''shell(pwd)'\'' --allow-tool '\''shell(safeoutputs:*)'\'' --allow-tool '\''shell(sort)'\'' --allow-tool '\''shell(tail)'\'' --allow-tool '\''shell(tail:*)'\'' --allow-tool '\''shell(uniq)'\'' --allow-tool '\''shell(wc)'\'' --allow-tool '\''shell(wc:*)'\'' --allow-tool '\''shell(yq)'\'' --allow-tool write --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json
GH_AW_PHASE: agent
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -836,12 +861,13 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- - name: Detect Copilot errors
- id: detect-copilot-errors
+ - name: Detect agent errors
if: always()
+ id: detect-agent-errors
continue-on-error: true
- run: node "${RUNNER_TEMP}/gh-aw/actions/detect_copilot_errors.cjs"
+ run: node "${RUNNER_TEMP}/gh-aw/actions/detect_agent_errors.cjs"
- name: Configure Git credentials
env:
REPO_NAME: ${{ github.repository }}
@@ -1023,7 +1049,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1032,7 +1058,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "SDK Runtime Triage"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/cross-repo-issue-analysis.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
id: download-agent-output
@@ -1055,6 +1082,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_NOOP_MAX: "1"
GH_AW_WORKFLOW_NAME: "SDK Runtime Triage"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/cross-repo-issue-analysis.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_NOOP_REPORT_AS_ISSUE: "true"
@@ -1071,6 +1099,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "SDK Runtime Triage"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/cross-repo-issue-analysis.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
@@ -1088,6 +1117,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_MISSING_TOOL_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "SDK Runtime Triage"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/cross-repo-issue-analysis.md"
with:
github-token: ${{ secrets.RUNTIME_TRIAGE_TOKEN }}
script: |
@@ -1102,6 +1132,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "SDK Runtime Triage"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/cross-repo-issue-analysis.md"
with:
github-token: ${{ secrets.RUNTIME_TRIAGE_TOKEN }}
script: |
@@ -1116,6 +1147,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "SDK Runtime Triage"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/cross-repo-issue-analysis.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_WORKFLOW_ID: "cross-repo-issue-analysis"
@@ -1162,7 +1194,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1171,7 +1203,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "SDK Runtime Triage"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/cross-repo-issue-analysis.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
id: download-agent-output
@@ -1198,7 +1231,7 @@ jobs:
rm -rf /tmp/gh-aw/sandbox/firewall/logs
rm -rf /tmp/gh-aw/sandbox/firewall/audit
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58
- name: Check if detection needed
id: detection_guard
if: always()
@@ -1224,6 +1257,9 @@ jobs:
run: |
mkdir -p /tmp/gh-aw/threat-detection/aw-prompts
cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true
+ if [ ! -s /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt ]; then
+ echo "::warning::ERR_VALIDATION: Missing or empty detection context prompt at /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt. Ensure the agent artifact includes /tmp/gh-aw/aw-prompts/prompt.txt. Detection will continue with fallback workflow context."
+ fi
cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true
for f in /tmp/gh-aw/aw-*.patch; do
[ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
@@ -1257,11 +1293,11 @@ jobs:
node-version: '24'
package-manager-cache: false
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Execute GitHub Copilot CLI
if: always() && steps.detection_guard.outputs.run_detection == 'true'
continue-on-error: true
@@ -1274,24 +1310,36 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/threat-detection/detection.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","registry.npmjs.org","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_PHASE: detection
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -1304,6 +1352,7 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- name: Upload threat detection log
if: always() && steps.detection_guard.outputs.run_detection == 'true'
@@ -1357,14 +1406,15 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
env:
GH_AW_SETUP_WORKFLOW_NAME: "SDK Runtime Triage"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/cross-repo-issue-analysis.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Check team membership for workflow
id: check_membership
@@ -1398,9 +1448,10 @@ jobs:
GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }}
GH_AW_ENGINE_ID: "copilot"
GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
- GH_AW_ENGINE_VERSION: "1.0.48"
+ GH_AW_ENGINE_VERSION: "1.0.55"
GH_AW_WORKFLOW_ID: "cross-repo-issue-analysis"
GH_AW_WORKFLOW_NAME: "SDK Runtime Triage"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/cross-repo-issue-analysis.md"
outputs:
code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}
code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}
@@ -1413,7 +1464,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1422,7 +1473,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "SDK Runtime Triage"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/cross-repo-issue-analysis.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
id: download-agent-output
@@ -1452,6 +1504,7 @@ jobs:
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
+ GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }}
GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_API_URL: ${{ github.api_url }}
diff --git a/.github/workflows/handle-bug.lock.yml b/.github/workflows/handle-bug.lock.yml
index 038b965d6..014ed4b68 100644
--- a/.github/workflows/handle-bug.lock.yml
+++ b/.github/workflows/handle-bug.lock.yml
@@ -1,5 +1,5 @@
-# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"a473a22cd67feb7f8f5225639fd989cf71705f78c9fe11c3fc757168e1672b0e","compiler_version":"v0.74.4","strict":true,"agent_id":"copilot"}
-# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"d3abfe96a194bce3a523ed2093ddedd5704cdf62","version":"v0.74.4"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.46"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.9","digest":"sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388"},{"image":"ghcr.io/github/github-mcp-server:v1.0.4"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]}
+# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"a473a22cd67feb7f8f5225639fd989cf71705f78c9fe11c3fc757168e1672b0e","body_hash":"376c982b907760113954510ef1aff70d22dcb172c7bb851b2fa3d82121bdbc1c","compiler_version":"v0.77.5","strict":true,"agent_id":"copilot"}
+# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"3ea13c02d765410340d533515cb31a7eef2baaf0","version":"v0.77.5"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.58"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.22"},{"image":"ghcr.io/github/github-mcp-server:v1.1.0"},{"image":"node:lts-alpine","digest":"sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14","pinned_image":"node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14"}]}
# ___ _ _
# / _ \ | | (_)
# | |_| | __ _ ___ _ __ | |_ _ ___
@@ -14,7 +14,7 @@
# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
#
-# This file was automatically generated by gh-aw (v0.74.4). DO NOT EDIT.
+# This file was automatically generated by gh-aw (v0.77.5). DO NOT EDIT.
#
# To update this file, edit the corresponding .md file and run:
# gh aw compile
@@ -36,15 +36,15 @@
# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
# - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
-# - github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+# - github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
#
# Container images used:
-# - ghcr.io/github/gh-aw-firewall/agent:0.25.46
-# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46
-# - ghcr.io/github/gh-aw-firewall/squid:0.25.46
-# - ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388
-# - ghcr.io/github/github-mcp-server:v1.0.4
-# - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+# - ghcr.io/github/gh-aw-firewall/agent:0.25.58
+# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58
+# - ghcr.io/github/gh-aw-firewall/squid:0.25.58
+# - ghcr.io/github/gh-aw-mcpg:v0.3.22
+# - ghcr.io/github/github-mcp-server:v1.1.0
+# - node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
name: "Bug Handler"
on:
@@ -52,7 +52,7 @@ on:
inputs:
aw_context:
default: ""
- description: Agent caller context (used internally by Agentic Workflows).
+ description: "Agent caller context (used internally by Agentic Workflows)."
required: false
type: string
issue_number:
@@ -108,14 +108,15 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
env:
GH_AW_SETUP_WORKFLOW_NAME: "Bug Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-bug.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Resolve host repo for activation checkout
@@ -142,17 +143,17 @@ jobs:
env:
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI"
- GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
- GH_AW_INFO_VERSION: "1.0.48"
- GH_AW_INFO_AGENT_VERSION: "1.0.48"
- GH_AW_INFO_CLI_VERSION: "v0.74.4"
+ GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AGENT_VERSION: "1.0.55"
+ GH_AW_INFO_CLI_VERSION: "v0.77.5"
GH_AW_INFO_WORKFLOW_NAME: "Bug Handler"
GH_AW_INFO_EXPERIMENTAL: "false"
GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
GH_AW_INFO_STAGED: "false"
GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]'
GH_AW_INFO_FIREWALL_ENABLED: "true"
- GH_AW_INFO_AWF_VERSION: "v0.25.46"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_AWMG_VERSION: ""
GH_AW_INFO_FIREWALL_TYPE: "squid"
GH_AW_COMPILED_STRICT: "true"
@@ -185,6 +186,7 @@ jobs:
sparse-checkout: |
.github
.agents
+ .antigravity
.claude
.codex
.crush
@@ -195,8 +197,8 @@ jobs:
fetch-depth: 1
- name: Save agent config folders for base branch restoration
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
# poutine:ignore untrusted_checkout_exec
run: bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh"
- name: Check workflow lock file
@@ -214,7 +216,7 @@ jobs:
- name: Check compile-agentic version
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
- GH_AW_COMPILED_VERSION: "v0.74.4"
+ GH_AW_COMPILED_VERSION: "v0.77.5"
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@@ -354,12 +356,14 @@ jobs:
include-hidden-files: true
path: |
/tmp/gh-aw/aw_info.json
+ /tmp/gh-aw/model_multipliers.json
/tmp/gh-aw/aw-prompts/prompt.txt
/tmp/gh-aw/aw-prompts/prompt-template.txt
/tmp/gh-aw/aw-prompts/prompt-import-tree.json
/tmp/gh-aw/github_rate_limits.jsonl
/tmp/gh-aw/base
/tmp/gh-aw/.github/agents
+ /tmp/gh-aw/.github/skills
if-no-files-found: ignore
retention-days: 1
@@ -371,7 +375,8 @@ jobs:
issues: read
pull-requests: read
concurrency:
- group: "gh-aw-copilot-${{ github.workflow }}-${{ inputs.issue_number }}"
+ group: "gh-aw-copilot-handle-bug-${{ inputs.issue_number }}"
+ queue: max
env:
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
GH_AW_ASSETS_ALLOWED_EXTS: ""
@@ -380,16 +385,16 @@ jobs:
GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
GH_AW_WORKFLOW_ID_SANITIZED: handlebug
outputs:
- agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }}
+ agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }}
artifact_prefix: ${{ needs.activation.outputs.artifact_prefix }}
checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }}
effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }}
has_patch: ${{ steps.collect_output.outputs.has_patch }}
- inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }}
- mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }}
+ inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }}
+ mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }}
model: ${{ needs.activation.outputs.model }}
- model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }}
+ model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }}
output: ${{ steps.collect_output.outputs.output }}
output_types: ${{ steps.collect_output.outputs.output_types }}
setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
@@ -398,7 +403,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -407,7 +412,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Bug Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-bug.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Set runtime paths
@@ -456,11 +462,11 @@ jobs:
const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs');
await main();
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Parse integrity filter lists
id: parse-guard-vars
env:
@@ -476,16 +482,20 @@ jobs:
- name: Restore agent config folders from base branch
if: steps.checkout-pr.outcome == 'success'
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh"
- name: Restore inline sub-agents from activation artifact
env:
GH_AW_SUB_AGENT_DIR: ".github/agents"
GH_AW_SUB_AGENT_EXT: ".agent.md"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh"
+ - name: Restore inline skills from activation artifact
+ env:
+ GH_AW_SKILL_DIR: ".github/skills"
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh"
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46 ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388 ghcr.io/github/github-mcp-server:v1.0.4 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58 ghcr.io/github/gh-aw-mcpg:v0.3.22 ghcr.io/github/github-mcp-server:v1.1.0 node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
- name: Generate Safe Outputs Config
run: |
mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
@@ -701,7 +711,7 @@ jobs:
* ) DOCKER_SOCK_PATH=/var/run/docker.sock ;;
esac
DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0')
- export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.9'
+ export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.22'
mkdir -p /home/runner/.copilot
GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node)
@@ -710,7 +720,7 @@ jobs:
"mcpServers": {
"github": {
"type": "stdio",
- "container": "ghcr.io/github/github-mcp-server:v1.0.4",
+ "container": "ghcr.io/github/github-mcp-server:v1.1.0",
"env": {
"GITHUB_HOST": "\${GITHUB_SERVER_URL}",
"GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
@@ -781,26 +791,38 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/agent-stdio.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"auto":["large"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5.3","gemini-pro","any"],"antigravity":["copilot/antigravity*","google/antigravity*","gemini/antigravity*"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"claude":["agent"],"codex":["agent"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"computer-use":["copilot/*computer-use*","google/*computer-use*","gemini/*computer-use*","openai/*computer-use*"],"copilot":["agent"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent"],"gemini-3-flash":["copilot/gemini-3*flash*","google/gemini-3*flash*","gemini/gemini-3*flash*"],"gemini-3-pro":["copilot/gemini-3*pro*","google/gemini-3*pro*","gemini/gemini-3*pro*"],"gemini-3.1-flash":["copilot/gemini-3.1*flash*","google/gemini-3.1*flash*","gemini/gemini-3.1*flash*"],"gemini-3.1-pro":["copilot/gemini-3.1*pro*","google/gemini-3.1*pro*","gemini/gemini-3.1*pro*"],"gemini-3.5-flash":["copilot/gemini-3.5*flash*","google/gemini-3.5*flash*","gemini/gemini-3.5*flash*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"gpt-5.2":["copilot/gpt-5.2*","openai/gpt-5.2*"],"gpt-5.3":["copilot/gpt-5.3*","openai/gpt-5.3*"],"gpt-5.4":["copilot/gpt-5.4*","openai/gpt-5.4*"],"gpt-5.5":["copilot/gpt-5.5*","openai/gpt-5.5*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"opusplan":["opus?effort=high"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"robotics":["copilot/*robotics*","google/*robotics*","gemini/*robotics*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4-5-*","anthropic/*sonnet-4-5-*","copilot/*sonnet-4-6*","anthropic/*sonnet-4-6*"],"summarization":["haiku","gpt-5-mini","gemini-flash-lite","mini"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json
GH_AW_PHASE: agent
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -814,12 +836,13 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- - name: Detect Copilot errors
- id: detect-copilot-errors
+ - name: Detect agent errors
if: always()
+ id: detect-agent-errors
continue-on-error: true
- run: node "${RUNNER_TEMP}/gh-aw/actions/detect_copilot_errors.cjs"
+ run: node "${RUNNER_TEMP}/gh-aw/actions/detect_agent_errors.cjs"
- name: Configure Git credentials
env:
REPO_NAME: ${{ github.repository }}
@@ -1003,7 +1026,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1012,7 +1035,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Bug Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-bug.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Download agent output artifact
@@ -1036,6 +1060,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_NOOP_MAX: "1"
GH_AW_WORKFLOW_NAME: "Bug Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-bug.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_NOOP_REPORT_AS_ISSUE: "true"
@@ -1052,6 +1077,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Bug Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-bug.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
@@ -1069,6 +1095,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_MISSING_TOOL_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "Bug Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-bug.md"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1083,6 +1110,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "Bug Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-bug.md"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1097,6 +1125,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Bug Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-bug.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_WORKFLOW_ID: "handle-bug"
@@ -1143,7 +1172,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1152,7 +1181,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Bug Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-bug.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Download agent output artifact
@@ -1180,7 +1210,7 @@ jobs:
rm -rf /tmp/gh-aw/sandbox/firewall/logs
rm -rf /tmp/gh-aw/sandbox/firewall/audit
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58
- name: Check if detection needed
id: detection_guard
if: always()
@@ -1206,6 +1236,9 @@ jobs:
run: |
mkdir -p /tmp/gh-aw/threat-detection/aw-prompts
cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true
+ if [ ! -s /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt ]; then
+ echo "::warning::ERR_VALIDATION: Missing or empty detection context prompt at /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt. Ensure the agent artifact includes /tmp/gh-aw/aw-prompts/prompt.txt. Detection will continue with fallback workflow context."
+ fi
cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true
for f in /tmp/gh-aw/aw-*.patch; do
[ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
@@ -1239,11 +1272,11 @@ jobs:
node-version: '24'
package-manager-cache: false
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Execute GitHub Copilot CLI
if: always() && steps.detection_guard.outputs.run_detection == 'true'
continue-on-error: true
@@ -1256,24 +1289,36 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/threat-detection/detection.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","registry.npmjs.org","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_PHASE: detection
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -1286,6 +1331,7 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- name: Upload threat detection log
if: always() && steps.detection_guard.outputs.run_detection == 'true'
@@ -1347,9 +1393,10 @@ jobs:
GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }}
GH_AW_ENGINE_ID: "copilot"
GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
- GH_AW_ENGINE_VERSION: "1.0.48"
+ GH_AW_ENGINE_VERSION: "1.0.55"
GH_AW_WORKFLOW_ID: "handle-bug"
GH_AW_WORKFLOW_NAME: "Bug Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-bug.md"
outputs:
code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}
code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}
@@ -1362,7 +1409,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1371,7 +1418,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Bug Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-bug.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Download agent output artifact
@@ -1402,6 +1450,7 @@ jobs:
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
+ GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }}
GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_API_URL: ${{ github.api_url }}
diff --git a/.github/workflows/handle-documentation.lock.yml b/.github/workflows/handle-documentation.lock.yml
index 3d8c9e05e..92a284669 100644
--- a/.github/workflows/handle-documentation.lock.yml
+++ b/.github/workflows/handle-documentation.lock.yml
@@ -1,5 +1,5 @@
-# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"258058e9a5e3bb707bbcfc9157b7b69f64c06547642da2526a1ff441e3a358dd","compiler_version":"v0.74.4","strict":true,"agent_id":"copilot"}
-# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"d3abfe96a194bce3a523ed2093ddedd5704cdf62","version":"v0.74.4"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.46"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.9","digest":"sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388"},{"image":"ghcr.io/github/github-mcp-server:v1.0.4"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]}
+# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"258058e9a5e3bb707bbcfc9157b7b69f64c06547642da2526a1ff441e3a358dd","body_hash":"81c8287f5691cdc10ae8f60c004bb671d9b4942740d73fcc9646e28fbcd8790e","compiler_version":"v0.77.5","strict":true,"agent_id":"copilot"}
+# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"3ea13c02d765410340d533515cb31a7eef2baaf0","version":"v0.77.5"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.58"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.22"},{"image":"ghcr.io/github/github-mcp-server:v1.1.0"},{"image":"node:lts-alpine","digest":"sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14","pinned_image":"node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14"}]}
# ___ _ _
# / _ \ | | (_)
# | |_| | __ _ ___ _ __ | |_ _ ___
@@ -14,7 +14,7 @@
# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
#
-# This file was automatically generated by gh-aw (v0.74.4). DO NOT EDIT.
+# This file was automatically generated by gh-aw (v0.77.5). DO NOT EDIT.
#
# To update this file, edit the corresponding .md file and run:
# gh aw compile
@@ -36,15 +36,15 @@
# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
# - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
-# - github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+# - github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
#
# Container images used:
-# - ghcr.io/github/gh-aw-firewall/agent:0.25.46
-# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46
-# - ghcr.io/github/gh-aw-firewall/squid:0.25.46
-# - ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388
-# - ghcr.io/github/github-mcp-server:v1.0.4
-# - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+# - ghcr.io/github/gh-aw-firewall/agent:0.25.58
+# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58
+# - ghcr.io/github/gh-aw-firewall/squid:0.25.58
+# - ghcr.io/github/gh-aw-mcpg:v0.3.22
+# - ghcr.io/github/github-mcp-server:v1.1.0
+# - node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
name: "Documentation Handler"
on:
@@ -52,7 +52,7 @@ on:
inputs:
aw_context:
default: ""
- description: Agent caller context (used internally by Agentic Workflows).
+ description: "Agent caller context (used internally by Agentic Workflows)."
required: false
type: string
issue_number:
@@ -108,14 +108,15 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
env:
GH_AW_SETUP_WORKFLOW_NAME: "Documentation Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-documentation.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Resolve host repo for activation checkout
@@ -142,17 +143,17 @@ jobs:
env:
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI"
- GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
- GH_AW_INFO_VERSION: "1.0.48"
- GH_AW_INFO_AGENT_VERSION: "1.0.48"
- GH_AW_INFO_CLI_VERSION: "v0.74.4"
+ GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AGENT_VERSION: "1.0.55"
+ GH_AW_INFO_CLI_VERSION: "v0.77.5"
GH_AW_INFO_WORKFLOW_NAME: "Documentation Handler"
GH_AW_INFO_EXPERIMENTAL: "false"
GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
GH_AW_INFO_STAGED: "false"
GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]'
GH_AW_INFO_FIREWALL_ENABLED: "true"
- GH_AW_INFO_AWF_VERSION: "v0.25.46"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_AWMG_VERSION: ""
GH_AW_INFO_FIREWALL_TYPE: "squid"
GH_AW_COMPILED_STRICT: "true"
@@ -185,6 +186,7 @@ jobs:
sparse-checkout: |
.github
.agents
+ .antigravity
.claude
.codex
.crush
@@ -195,8 +197,8 @@ jobs:
fetch-depth: 1
- name: Save agent config folders for base branch restoration
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
# poutine:ignore untrusted_checkout_exec
run: bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh"
- name: Check workflow lock file
@@ -214,7 +216,7 @@ jobs:
- name: Check compile-agentic version
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
- GH_AW_COMPILED_VERSION: "v0.74.4"
+ GH_AW_COMPILED_VERSION: "v0.77.5"
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@@ -354,12 +356,14 @@ jobs:
include-hidden-files: true
path: |
/tmp/gh-aw/aw_info.json
+ /tmp/gh-aw/model_multipliers.json
/tmp/gh-aw/aw-prompts/prompt.txt
/tmp/gh-aw/aw-prompts/prompt-template.txt
/tmp/gh-aw/aw-prompts/prompt-import-tree.json
/tmp/gh-aw/github_rate_limits.jsonl
/tmp/gh-aw/base
/tmp/gh-aw/.github/agents
+ /tmp/gh-aw/.github/skills
if-no-files-found: ignore
retention-days: 1
@@ -371,7 +375,8 @@ jobs:
issues: read
pull-requests: read
concurrency:
- group: "gh-aw-copilot-${{ github.workflow }}-${{ inputs.issue_number }}"
+ group: "gh-aw-copilot-handle-documentation-${{ inputs.issue_number }}"
+ queue: max
env:
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
GH_AW_ASSETS_ALLOWED_EXTS: ""
@@ -380,16 +385,16 @@ jobs:
GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
GH_AW_WORKFLOW_ID_SANITIZED: handledocumentation
outputs:
- agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }}
+ agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }}
artifact_prefix: ${{ needs.activation.outputs.artifact_prefix }}
checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }}
effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }}
has_patch: ${{ steps.collect_output.outputs.has_patch }}
- inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }}
- mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }}
+ inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }}
+ mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }}
model: ${{ needs.activation.outputs.model }}
- model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }}
+ model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }}
output: ${{ steps.collect_output.outputs.output }}
output_types: ${{ steps.collect_output.outputs.output_types }}
setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
@@ -398,7 +403,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -407,7 +412,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Documentation Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-documentation.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Set runtime paths
@@ -456,11 +462,11 @@ jobs:
const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs');
await main();
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Parse integrity filter lists
id: parse-guard-vars
env:
@@ -476,16 +482,20 @@ jobs:
- name: Restore agent config folders from base branch
if: steps.checkout-pr.outcome == 'success'
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh"
- name: Restore inline sub-agents from activation artifact
env:
GH_AW_SUB_AGENT_DIR: ".github/agents"
GH_AW_SUB_AGENT_EXT: ".agent.md"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh"
+ - name: Restore inline skills from activation artifact
+ env:
+ GH_AW_SKILL_DIR: ".github/skills"
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh"
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46 ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388 ghcr.io/github/github-mcp-server:v1.0.4 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58 ghcr.io/github/gh-aw-mcpg:v0.3.22 ghcr.io/github/github-mcp-server:v1.1.0 node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
- name: Generate Safe Outputs Config
run: |
mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
@@ -701,7 +711,7 @@ jobs:
* ) DOCKER_SOCK_PATH=/var/run/docker.sock ;;
esac
DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0')
- export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.9'
+ export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.22'
mkdir -p /home/runner/.copilot
GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node)
@@ -710,7 +720,7 @@ jobs:
"mcpServers": {
"github": {
"type": "stdio",
- "container": "ghcr.io/github/github-mcp-server:v1.0.4",
+ "container": "ghcr.io/github/github-mcp-server:v1.1.0",
"env": {
"GITHUB_HOST": "\${GITHUB_SERVER_URL}",
"GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
@@ -781,26 +791,38 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/agent-stdio.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"auto":["large"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5.3","gemini-pro","any"],"antigravity":["copilot/antigravity*","google/antigravity*","gemini/antigravity*"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"claude":["agent"],"codex":["agent"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"computer-use":["copilot/*computer-use*","google/*computer-use*","gemini/*computer-use*","openai/*computer-use*"],"copilot":["agent"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent"],"gemini-3-flash":["copilot/gemini-3*flash*","google/gemini-3*flash*","gemini/gemini-3*flash*"],"gemini-3-pro":["copilot/gemini-3*pro*","google/gemini-3*pro*","gemini/gemini-3*pro*"],"gemini-3.1-flash":["copilot/gemini-3.1*flash*","google/gemini-3.1*flash*","gemini/gemini-3.1*flash*"],"gemini-3.1-pro":["copilot/gemini-3.1*pro*","google/gemini-3.1*pro*","gemini/gemini-3.1*pro*"],"gemini-3.5-flash":["copilot/gemini-3.5*flash*","google/gemini-3.5*flash*","gemini/gemini-3.5*flash*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"gpt-5.2":["copilot/gpt-5.2*","openai/gpt-5.2*"],"gpt-5.3":["copilot/gpt-5.3*","openai/gpt-5.3*"],"gpt-5.4":["copilot/gpt-5.4*","openai/gpt-5.4*"],"gpt-5.5":["copilot/gpt-5.5*","openai/gpt-5.5*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"opusplan":["opus?effort=high"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"robotics":["copilot/*robotics*","google/*robotics*","gemini/*robotics*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4-5-*","anthropic/*sonnet-4-5-*","copilot/*sonnet-4-6*","anthropic/*sonnet-4-6*"],"summarization":["haiku","gpt-5-mini","gemini-flash-lite","mini"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json
GH_AW_PHASE: agent
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -814,12 +836,13 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- - name: Detect Copilot errors
- id: detect-copilot-errors
+ - name: Detect agent errors
if: always()
+ id: detect-agent-errors
continue-on-error: true
- run: node "${RUNNER_TEMP}/gh-aw/actions/detect_copilot_errors.cjs"
+ run: node "${RUNNER_TEMP}/gh-aw/actions/detect_agent_errors.cjs"
- name: Configure Git credentials
env:
REPO_NAME: ${{ github.repository }}
@@ -1003,7 +1026,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1012,7 +1035,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Documentation Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-documentation.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Download agent output artifact
@@ -1036,6 +1060,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_NOOP_MAX: "1"
GH_AW_WORKFLOW_NAME: "Documentation Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-documentation.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_NOOP_REPORT_AS_ISSUE: "true"
@@ -1052,6 +1077,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Documentation Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-documentation.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
@@ -1069,6 +1095,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_MISSING_TOOL_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "Documentation Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-documentation.md"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1083,6 +1110,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "Documentation Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-documentation.md"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1097,6 +1125,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Documentation Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-documentation.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_WORKFLOW_ID: "handle-documentation"
@@ -1143,7 +1172,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1152,7 +1181,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Documentation Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-documentation.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Download agent output artifact
@@ -1180,7 +1210,7 @@ jobs:
rm -rf /tmp/gh-aw/sandbox/firewall/logs
rm -rf /tmp/gh-aw/sandbox/firewall/audit
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58
- name: Check if detection needed
id: detection_guard
if: always()
@@ -1206,6 +1236,9 @@ jobs:
run: |
mkdir -p /tmp/gh-aw/threat-detection/aw-prompts
cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true
+ if [ ! -s /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt ]; then
+ echo "::warning::ERR_VALIDATION: Missing or empty detection context prompt at /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt. Ensure the agent artifact includes /tmp/gh-aw/aw-prompts/prompt.txt. Detection will continue with fallback workflow context."
+ fi
cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true
for f in /tmp/gh-aw/aw-*.patch; do
[ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
@@ -1239,11 +1272,11 @@ jobs:
node-version: '24'
package-manager-cache: false
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Execute GitHub Copilot CLI
if: always() && steps.detection_guard.outputs.run_detection == 'true'
continue-on-error: true
@@ -1256,24 +1289,36 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/threat-detection/detection.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","registry.npmjs.org","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_PHASE: detection
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -1286,6 +1331,7 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- name: Upload threat detection log
if: always() && steps.detection_guard.outputs.run_detection == 'true'
@@ -1347,9 +1393,10 @@ jobs:
GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }}
GH_AW_ENGINE_ID: "copilot"
GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
- GH_AW_ENGINE_VERSION: "1.0.48"
+ GH_AW_ENGINE_VERSION: "1.0.55"
GH_AW_WORKFLOW_ID: "handle-documentation"
GH_AW_WORKFLOW_NAME: "Documentation Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-documentation.md"
outputs:
code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}
code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}
@@ -1362,7 +1409,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1371,7 +1418,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Documentation Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-documentation.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Download agent output artifact
@@ -1402,6 +1450,7 @@ jobs:
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
+ GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }}
GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_API_URL: ${{ github.api_url }}
diff --git a/.github/workflows/handle-enhancement.lock.yml b/.github/workflows/handle-enhancement.lock.yml
index 1255d9369..de163e4e3 100644
--- a/.github/workflows/handle-enhancement.lock.yml
+++ b/.github/workflows/handle-enhancement.lock.yml
@@ -1,5 +1,5 @@
-# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"0a1cd53da97b1be36f489e58d1153583dc96c9b436fab3392437a8d498d4d8fb","compiler_version":"v0.74.4","strict":true,"agent_id":"copilot"}
-# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"d3abfe96a194bce3a523ed2093ddedd5704cdf62","version":"v0.74.4"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.46"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.9","digest":"sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388"},{"image":"ghcr.io/github/github-mcp-server:v1.0.4"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]}
+# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"0a1cd53da97b1be36f489e58d1153583dc96c9b436fab3392437a8d498d4d8fb","body_hash":"624219976b9b7078c6bb11c4177925478cfd8316fe8de535a581bdd176eda825","compiler_version":"v0.77.5","strict":true,"agent_id":"copilot"}
+# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"3ea13c02d765410340d533515cb31a7eef2baaf0","version":"v0.77.5"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.58"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.22"},{"image":"ghcr.io/github/github-mcp-server:v1.1.0"},{"image":"node:lts-alpine","digest":"sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14","pinned_image":"node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14"}]}
# ___ _ _
# / _ \ | | (_)
# | |_| | __ _ ___ _ __ | |_ _ ___
@@ -14,7 +14,7 @@
# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
#
-# This file was automatically generated by gh-aw (v0.74.4). DO NOT EDIT.
+# This file was automatically generated by gh-aw (v0.77.5). DO NOT EDIT.
#
# To update this file, edit the corresponding .md file and run:
# gh aw compile
@@ -36,15 +36,15 @@
# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
# - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
-# - github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+# - github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
#
# Container images used:
-# - ghcr.io/github/gh-aw-firewall/agent:0.25.46
-# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46
-# - ghcr.io/github/gh-aw-firewall/squid:0.25.46
-# - ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388
-# - ghcr.io/github/github-mcp-server:v1.0.4
-# - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+# - ghcr.io/github/gh-aw-firewall/agent:0.25.58
+# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58
+# - ghcr.io/github/gh-aw-firewall/squid:0.25.58
+# - ghcr.io/github/gh-aw-mcpg:v0.3.22
+# - ghcr.io/github/github-mcp-server:v1.1.0
+# - node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
name: "Enhancement Handler"
on:
@@ -52,7 +52,7 @@ on:
inputs:
aw_context:
default: ""
- description: Agent caller context (used internally by Agentic Workflows).
+ description: "Agent caller context (used internally by Agentic Workflows)."
required: false
type: string
issue_number:
@@ -108,14 +108,15 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
env:
GH_AW_SETUP_WORKFLOW_NAME: "Enhancement Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-enhancement.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Resolve host repo for activation checkout
@@ -142,17 +143,17 @@ jobs:
env:
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI"
- GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
- GH_AW_INFO_VERSION: "1.0.48"
- GH_AW_INFO_AGENT_VERSION: "1.0.48"
- GH_AW_INFO_CLI_VERSION: "v0.74.4"
+ GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AGENT_VERSION: "1.0.55"
+ GH_AW_INFO_CLI_VERSION: "v0.77.5"
GH_AW_INFO_WORKFLOW_NAME: "Enhancement Handler"
GH_AW_INFO_EXPERIMENTAL: "false"
GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
GH_AW_INFO_STAGED: "false"
GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]'
GH_AW_INFO_FIREWALL_ENABLED: "true"
- GH_AW_INFO_AWF_VERSION: "v0.25.46"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_AWMG_VERSION: ""
GH_AW_INFO_FIREWALL_TYPE: "squid"
GH_AW_COMPILED_STRICT: "true"
@@ -185,6 +186,7 @@ jobs:
sparse-checkout: |
.github
.agents
+ .antigravity
.claude
.codex
.crush
@@ -195,8 +197,8 @@ jobs:
fetch-depth: 1
- name: Save agent config folders for base branch restoration
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
# poutine:ignore untrusted_checkout_exec
run: bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh"
- name: Check workflow lock file
@@ -214,7 +216,7 @@ jobs:
- name: Check compile-agentic version
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
- GH_AW_COMPILED_VERSION: "v0.74.4"
+ GH_AW_COMPILED_VERSION: "v0.77.5"
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@@ -354,12 +356,14 @@ jobs:
include-hidden-files: true
path: |
/tmp/gh-aw/aw_info.json
+ /tmp/gh-aw/model_multipliers.json
/tmp/gh-aw/aw-prompts/prompt.txt
/tmp/gh-aw/aw-prompts/prompt-template.txt
/tmp/gh-aw/aw-prompts/prompt-import-tree.json
/tmp/gh-aw/github_rate_limits.jsonl
/tmp/gh-aw/base
/tmp/gh-aw/.github/agents
+ /tmp/gh-aw/.github/skills
if-no-files-found: ignore
retention-days: 1
@@ -371,7 +375,8 @@ jobs:
issues: read
pull-requests: read
concurrency:
- group: "gh-aw-copilot-${{ github.workflow }}-${{ inputs.issue_number }}"
+ group: "gh-aw-copilot-handle-enhancement-${{ inputs.issue_number }}"
+ queue: max
env:
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
GH_AW_ASSETS_ALLOWED_EXTS: ""
@@ -380,16 +385,16 @@ jobs:
GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
GH_AW_WORKFLOW_ID_SANITIZED: handleenhancement
outputs:
- agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }}
+ agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }}
artifact_prefix: ${{ needs.activation.outputs.artifact_prefix }}
checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }}
effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }}
has_patch: ${{ steps.collect_output.outputs.has_patch }}
- inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }}
- mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }}
+ inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }}
+ mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }}
model: ${{ needs.activation.outputs.model }}
- model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }}
+ model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }}
output: ${{ steps.collect_output.outputs.output }}
output_types: ${{ steps.collect_output.outputs.output_types }}
setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
@@ -398,7 +403,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -407,7 +412,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Enhancement Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-enhancement.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Set runtime paths
@@ -456,11 +462,11 @@ jobs:
const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs');
await main();
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Parse integrity filter lists
id: parse-guard-vars
env:
@@ -476,16 +482,20 @@ jobs:
- name: Restore agent config folders from base branch
if: steps.checkout-pr.outcome == 'success'
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh"
- name: Restore inline sub-agents from activation artifact
env:
GH_AW_SUB_AGENT_DIR: ".github/agents"
GH_AW_SUB_AGENT_EXT: ".agent.md"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh"
+ - name: Restore inline skills from activation artifact
+ env:
+ GH_AW_SKILL_DIR: ".github/skills"
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh"
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46 ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388 ghcr.io/github/github-mcp-server:v1.0.4 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58 ghcr.io/github/gh-aw-mcpg:v0.3.22 ghcr.io/github/github-mcp-server:v1.1.0 node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
- name: Generate Safe Outputs Config
run: |
mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
@@ -701,7 +711,7 @@ jobs:
* ) DOCKER_SOCK_PATH=/var/run/docker.sock ;;
esac
DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0')
- export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.9'
+ export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.22'
mkdir -p /home/runner/.copilot
GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node)
@@ -710,7 +720,7 @@ jobs:
"mcpServers": {
"github": {
"type": "stdio",
- "container": "ghcr.io/github/github-mcp-server:v1.0.4",
+ "container": "ghcr.io/github/github-mcp-server:v1.1.0",
"env": {
"GITHUB_HOST": "\${GITHUB_SERVER_URL}",
"GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
@@ -781,26 +791,38 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/agent-stdio.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"auto":["large"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5.3","gemini-pro","any"],"antigravity":["copilot/antigravity*","google/antigravity*","gemini/antigravity*"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"claude":["agent"],"codex":["agent"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"computer-use":["copilot/*computer-use*","google/*computer-use*","gemini/*computer-use*","openai/*computer-use*"],"copilot":["agent"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent"],"gemini-3-flash":["copilot/gemini-3*flash*","google/gemini-3*flash*","gemini/gemini-3*flash*"],"gemini-3-pro":["copilot/gemini-3*pro*","google/gemini-3*pro*","gemini/gemini-3*pro*"],"gemini-3.1-flash":["copilot/gemini-3.1*flash*","google/gemini-3.1*flash*","gemini/gemini-3.1*flash*"],"gemini-3.1-pro":["copilot/gemini-3.1*pro*","google/gemini-3.1*pro*","gemini/gemini-3.1*pro*"],"gemini-3.5-flash":["copilot/gemini-3.5*flash*","google/gemini-3.5*flash*","gemini/gemini-3.5*flash*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"gpt-5.2":["copilot/gpt-5.2*","openai/gpt-5.2*"],"gpt-5.3":["copilot/gpt-5.3*","openai/gpt-5.3*"],"gpt-5.4":["copilot/gpt-5.4*","openai/gpt-5.4*"],"gpt-5.5":["copilot/gpt-5.5*","openai/gpt-5.5*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"opusplan":["opus?effort=high"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"robotics":["copilot/*robotics*","google/*robotics*","gemini/*robotics*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4-5-*","anthropic/*sonnet-4-5-*","copilot/*sonnet-4-6*","anthropic/*sonnet-4-6*"],"summarization":["haiku","gpt-5-mini","gemini-flash-lite","mini"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json
GH_AW_PHASE: agent
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -814,12 +836,13 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- - name: Detect Copilot errors
- id: detect-copilot-errors
+ - name: Detect agent errors
if: always()
+ id: detect-agent-errors
continue-on-error: true
- run: node "${RUNNER_TEMP}/gh-aw/actions/detect_copilot_errors.cjs"
+ run: node "${RUNNER_TEMP}/gh-aw/actions/detect_agent_errors.cjs"
- name: Configure Git credentials
env:
REPO_NAME: ${{ github.repository }}
@@ -1003,7 +1026,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1012,7 +1035,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Enhancement Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-enhancement.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Download agent output artifact
@@ -1036,6 +1060,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_NOOP_MAX: "1"
GH_AW_WORKFLOW_NAME: "Enhancement Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-enhancement.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_NOOP_REPORT_AS_ISSUE: "true"
@@ -1052,6 +1077,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Enhancement Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-enhancement.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
@@ -1069,6 +1095,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_MISSING_TOOL_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "Enhancement Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-enhancement.md"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1083,6 +1110,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "Enhancement Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-enhancement.md"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1097,6 +1125,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Enhancement Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-enhancement.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_WORKFLOW_ID: "handle-enhancement"
@@ -1143,7 +1172,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1152,7 +1181,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Enhancement Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-enhancement.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Download agent output artifact
@@ -1180,7 +1210,7 @@ jobs:
rm -rf /tmp/gh-aw/sandbox/firewall/logs
rm -rf /tmp/gh-aw/sandbox/firewall/audit
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58
- name: Check if detection needed
id: detection_guard
if: always()
@@ -1206,6 +1236,9 @@ jobs:
run: |
mkdir -p /tmp/gh-aw/threat-detection/aw-prompts
cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true
+ if [ ! -s /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt ]; then
+ echo "::warning::ERR_VALIDATION: Missing or empty detection context prompt at /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt. Ensure the agent artifact includes /tmp/gh-aw/aw-prompts/prompt.txt. Detection will continue with fallback workflow context."
+ fi
cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true
for f in /tmp/gh-aw/aw-*.patch; do
[ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
@@ -1239,11 +1272,11 @@ jobs:
node-version: '24'
package-manager-cache: false
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Execute GitHub Copilot CLI
if: always() && steps.detection_guard.outputs.run_detection == 'true'
continue-on-error: true
@@ -1256,24 +1289,36 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/threat-detection/detection.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","registry.npmjs.org","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_PHASE: detection
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -1286,6 +1331,7 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- name: Upload threat detection log
if: always() && steps.detection_guard.outputs.run_detection == 'true'
@@ -1347,9 +1393,10 @@ jobs:
GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }}
GH_AW_ENGINE_ID: "copilot"
GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
- GH_AW_ENGINE_VERSION: "1.0.48"
+ GH_AW_ENGINE_VERSION: "1.0.55"
GH_AW_WORKFLOW_ID: "handle-enhancement"
GH_AW_WORKFLOW_NAME: "Enhancement Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-enhancement.md"
outputs:
code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}
code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}
@@ -1362,7 +1409,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1371,7 +1418,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Enhancement Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-enhancement.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Download agent output artifact
@@ -1402,6 +1450,7 @@ jobs:
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
+ GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }}
GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_API_URL: ${{ github.api_url }}
diff --git a/.github/workflows/handle-question.lock.yml b/.github/workflows/handle-question.lock.yml
index af8052999..14f7fe199 100644
--- a/.github/workflows/handle-question.lock.yml
+++ b/.github/workflows/handle-question.lock.yml
@@ -1,5 +1,5 @@
-# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"fb6cc48845814496ea0da474d3030f9e02e7d38b5bb346b70ca525c06c271cb1","compiler_version":"v0.74.4","strict":true,"agent_id":"copilot"}
-# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"d3abfe96a194bce3a523ed2093ddedd5704cdf62","version":"v0.74.4"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.46"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.9","digest":"sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388"},{"image":"ghcr.io/github/github-mcp-server:v1.0.4"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]}
+# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"fb6cc48845814496ea0da474d3030f9e02e7d38b5bb346b70ca525c06c271cb1","body_hash":"1bdd19aae2095beb6e3fcf7af755cd102d424de3a8727ef6e4674815950c7e8b","compiler_version":"v0.77.5","strict":true,"agent_id":"copilot"}
+# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"3ea13c02d765410340d533515cb31a7eef2baaf0","version":"v0.77.5"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.58"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.22"},{"image":"ghcr.io/github/github-mcp-server:v1.1.0"},{"image":"node:lts-alpine","digest":"sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14","pinned_image":"node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14"}]}
# ___ _ _
# / _ \ | | (_)
# | |_| | __ _ ___ _ __ | |_ _ ___
@@ -14,7 +14,7 @@
# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
#
-# This file was automatically generated by gh-aw (v0.74.4). DO NOT EDIT.
+# This file was automatically generated by gh-aw (v0.77.5). DO NOT EDIT.
#
# To update this file, edit the corresponding .md file and run:
# gh aw compile
@@ -36,15 +36,15 @@
# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
# - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
-# - github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+# - github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
#
# Container images used:
-# - ghcr.io/github/gh-aw-firewall/agent:0.25.46
-# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46
-# - ghcr.io/github/gh-aw-firewall/squid:0.25.46
-# - ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388
-# - ghcr.io/github/github-mcp-server:v1.0.4
-# - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+# - ghcr.io/github/gh-aw-firewall/agent:0.25.58
+# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58
+# - ghcr.io/github/gh-aw-firewall/squid:0.25.58
+# - ghcr.io/github/gh-aw-mcpg:v0.3.22
+# - ghcr.io/github/github-mcp-server:v1.1.0
+# - node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
name: "Question Handler"
on:
@@ -52,7 +52,7 @@ on:
inputs:
aw_context:
default: ""
- description: Agent caller context (used internally by Agentic Workflows).
+ description: "Agent caller context (used internally by Agentic Workflows)."
required: false
type: string
issue_number:
@@ -108,14 +108,15 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
env:
GH_AW_SETUP_WORKFLOW_NAME: "Question Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-question.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Resolve host repo for activation checkout
@@ -142,17 +143,17 @@ jobs:
env:
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI"
- GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
- GH_AW_INFO_VERSION: "1.0.48"
- GH_AW_INFO_AGENT_VERSION: "1.0.48"
- GH_AW_INFO_CLI_VERSION: "v0.74.4"
+ GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AGENT_VERSION: "1.0.55"
+ GH_AW_INFO_CLI_VERSION: "v0.77.5"
GH_AW_INFO_WORKFLOW_NAME: "Question Handler"
GH_AW_INFO_EXPERIMENTAL: "false"
GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
GH_AW_INFO_STAGED: "false"
GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]'
GH_AW_INFO_FIREWALL_ENABLED: "true"
- GH_AW_INFO_AWF_VERSION: "v0.25.46"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_AWMG_VERSION: ""
GH_AW_INFO_FIREWALL_TYPE: "squid"
GH_AW_COMPILED_STRICT: "true"
@@ -185,6 +186,7 @@ jobs:
sparse-checkout: |
.github
.agents
+ .antigravity
.claude
.codex
.crush
@@ -195,8 +197,8 @@ jobs:
fetch-depth: 1
- name: Save agent config folders for base branch restoration
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
# poutine:ignore untrusted_checkout_exec
run: bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh"
- name: Check workflow lock file
@@ -214,7 +216,7 @@ jobs:
- name: Check compile-agentic version
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
- GH_AW_COMPILED_VERSION: "v0.74.4"
+ GH_AW_COMPILED_VERSION: "v0.77.5"
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@@ -354,12 +356,14 @@ jobs:
include-hidden-files: true
path: |
/tmp/gh-aw/aw_info.json
+ /tmp/gh-aw/model_multipliers.json
/tmp/gh-aw/aw-prompts/prompt.txt
/tmp/gh-aw/aw-prompts/prompt-template.txt
/tmp/gh-aw/aw-prompts/prompt-import-tree.json
/tmp/gh-aw/github_rate_limits.jsonl
/tmp/gh-aw/base
/tmp/gh-aw/.github/agents
+ /tmp/gh-aw/.github/skills
if-no-files-found: ignore
retention-days: 1
@@ -371,7 +375,8 @@ jobs:
issues: read
pull-requests: read
concurrency:
- group: "gh-aw-copilot-${{ github.workflow }}-${{ inputs.issue_number }}"
+ group: "gh-aw-copilot-handle-question-${{ inputs.issue_number }}"
+ queue: max
env:
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
GH_AW_ASSETS_ALLOWED_EXTS: ""
@@ -380,16 +385,16 @@ jobs:
GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
GH_AW_WORKFLOW_ID_SANITIZED: handlequestion
outputs:
- agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }}
+ agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }}
artifact_prefix: ${{ needs.activation.outputs.artifact_prefix }}
checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }}
effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }}
has_patch: ${{ steps.collect_output.outputs.has_patch }}
- inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }}
- mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }}
+ inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }}
+ mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }}
model: ${{ needs.activation.outputs.model }}
- model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }}
+ model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }}
output: ${{ steps.collect_output.outputs.output }}
output_types: ${{ steps.collect_output.outputs.output_types }}
setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
@@ -398,7 +403,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -407,7 +412,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Question Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-question.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Set runtime paths
@@ -456,11 +462,11 @@ jobs:
const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs');
await main();
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Parse integrity filter lists
id: parse-guard-vars
env:
@@ -476,16 +482,20 @@ jobs:
- name: Restore agent config folders from base branch
if: steps.checkout-pr.outcome == 'success'
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh"
- name: Restore inline sub-agents from activation artifact
env:
GH_AW_SUB_AGENT_DIR: ".github/agents"
GH_AW_SUB_AGENT_EXT: ".agent.md"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh"
+ - name: Restore inline skills from activation artifact
+ env:
+ GH_AW_SKILL_DIR: ".github/skills"
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh"
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46 ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388 ghcr.io/github/github-mcp-server:v1.0.4 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58 ghcr.io/github/gh-aw-mcpg:v0.3.22 ghcr.io/github/github-mcp-server:v1.1.0 node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
- name: Generate Safe Outputs Config
run: |
mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
@@ -701,7 +711,7 @@ jobs:
* ) DOCKER_SOCK_PATH=/var/run/docker.sock ;;
esac
DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0')
- export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.9'
+ export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.22'
mkdir -p /home/runner/.copilot
GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node)
@@ -710,7 +720,7 @@ jobs:
"mcpServers": {
"github": {
"type": "stdio",
- "container": "ghcr.io/github/github-mcp-server:v1.0.4",
+ "container": "ghcr.io/github/github-mcp-server:v1.1.0",
"env": {
"GITHUB_HOST": "\${GITHUB_SERVER_URL}",
"GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
@@ -781,26 +791,38 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/agent-stdio.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"auto":["large"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5.3","gemini-pro","any"],"antigravity":["copilot/antigravity*","google/antigravity*","gemini/antigravity*"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"claude":["agent"],"codex":["agent"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"computer-use":["copilot/*computer-use*","google/*computer-use*","gemini/*computer-use*","openai/*computer-use*"],"copilot":["agent"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent"],"gemini-3-flash":["copilot/gemini-3*flash*","google/gemini-3*flash*","gemini/gemini-3*flash*"],"gemini-3-pro":["copilot/gemini-3*pro*","google/gemini-3*pro*","gemini/gemini-3*pro*"],"gemini-3.1-flash":["copilot/gemini-3.1*flash*","google/gemini-3.1*flash*","gemini/gemini-3.1*flash*"],"gemini-3.1-pro":["copilot/gemini-3.1*pro*","google/gemini-3.1*pro*","gemini/gemini-3.1*pro*"],"gemini-3.5-flash":["copilot/gemini-3.5*flash*","google/gemini-3.5*flash*","gemini/gemini-3.5*flash*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"gpt-5.2":["copilot/gpt-5.2*","openai/gpt-5.2*"],"gpt-5.3":["copilot/gpt-5.3*","openai/gpt-5.3*"],"gpt-5.4":["copilot/gpt-5.4*","openai/gpt-5.4*"],"gpt-5.5":["copilot/gpt-5.5*","openai/gpt-5.5*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"opusplan":["opus?effort=high"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"robotics":["copilot/*robotics*","google/*robotics*","gemini/*robotics*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4-5-*","anthropic/*sonnet-4-5-*","copilot/*sonnet-4-6*","anthropic/*sonnet-4-6*"],"summarization":["haiku","gpt-5-mini","gemini-flash-lite","mini"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json
GH_AW_PHASE: agent
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -814,12 +836,13 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- - name: Detect Copilot errors
- id: detect-copilot-errors
+ - name: Detect agent errors
if: always()
+ id: detect-agent-errors
continue-on-error: true
- run: node "${RUNNER_TEMP}/gh-aw/actions/detect_copilot_errors.cjs"
+ run: node "${RUNNER_TEMP}/gh-aw/actions/detect_agent_errors.cjs"
- name: Configure Git credentials
env:
REPO_NAME: ${{ github.repository }}
@@ -1003,7 +1026,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1012,7 +1035,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Question Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-question.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Download agent output artifact
@@ -1036,6 +1060,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_NOOP_MAX: "1"
GH_AW_WORKFLOW_NAME: "Question Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-question.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_NOOP_REPORT_AS_ISSUE: "true"
@@ -1052,6 +1077,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Question Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-question.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
@@ -1069,6 +1095,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_MISSING_TOOL_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "Question Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-question.md"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1083,6 +1110,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "Question Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-question.md"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1097,6 +1125,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Question Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-question.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_WORKFLOW_ID: "handle-question"
@@ -1143,7 +1172,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1152,7 +1181,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Question Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-question.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Download agent output artifact
@@ -1180,7 +1210,7 @@ jobs:
rm -rf /tmp/gh-aw/sandbox/firewall/logs
rm -rf /tmp/gh-aw/sandbox/firewall/audit
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58
- name: Check if detection needed
id: detection_guard
if: always()
@@ -1206,6 +1236,9 @@ jobs:
run: |
mkdir -p /tmp/gh-aw/threat-detection/aw-prompts
cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true
+ if [ ! -s /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt ]; then
+ echo "::warning::ERR_VALIDATION: Missing or empty detection context prompt at /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt. Ensure the agent artifact includes /tmp/gh-aw/aw-prompts/prompt.txt. Detection will continue with fallback workflow context."
+ fi
cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true
for f in /tmp/gh-aw/aw-*.patch; do
[ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
@@ -1239,11 +1272,11 @@ jobs:
node-version: '24'
package-manager-cache: false
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Execute GitHub Copilot CLI
if: always() && steps.detection_guard.outputs.run_detection == 'true'
continue-on-error: true
@@ -1256,24 +1289,36 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/threat-detection/detection.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","registry.npmjs.org","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_PHASE: detection
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -1286,6 +1331,7 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- name: Upload threat detection log
if: always() && steps.detection_guard.outputs.run_detection == 'true'
@@ -1347,9 +1393,10 @@ jobs:
GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }}
GH_AW_ENGINE_ID: "copilot"
GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
- GH_AW_ENGINE_VERSION: "1.0.48"
+ GH_AW_ENGINE_VERSION: "1.0.55"
GH_AW_WORKFLOW_ID: "handle-question"
GH_AW_WORKFLOW_NAME: "Question Handler"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/handle-question.md"
outputs:
code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}
code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}
@@ -1362,7 +1409,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1371,7 +1418,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Question Handler"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/handle-question.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_SETUP_AW_CONTEXT: ${{ inputs.aw_context }}
- name: Download agent output artifact
@@ -1402,6 +1450,7 @@ jobs:
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
+ GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }}
GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_API_URL: ${{ github.api_url }}
diff --git a/.github/workflows/issue-classification.lock.yml b/.github/workflows/issue-classification.lock.yml
index 45c944c7b..0fd635914 100644
--- a/.github/workflows/issue-classification.lock.yml
+++ b/.github/workflows/issue-classification.lock.yml
@@ -1,5 +1,5 @@
-# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"1c9f9a62a510a7796b96187fbe0537fd05da1c082d8fab86cd7b99bf001aee01","compiler_version":"v0.74.4","strict":true,"agent_id":"copilot"}
-# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"d3abfe96a194bce3a523ed2093ddedd5704cdf62","version":"v0.74.4"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.46"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.9","digest":"sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388"},{"image":"ghcr.io/github/github-mcp-server:v1.0.4"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]}
+# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"1c9f9a62a510a7796b96187fbe0537fd05da1c082d8fab86cd7b99bf001aee01","body_hash":"8e7ac9b7bb6ab07630a10a4a016108ba59f70feadf82a7391ca0ba5504e14bff","compiler_version":"v0.77.5","strict":true,"agent_id":"copilot"}
+# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"3ea13c02d765410340d533515cb31a7eef2baaf0","version":"v0.77.5"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.58"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.22"},{"image":"ghcr.io/github/github-mcp-server:v1.1.0"},{"image":"node:lts-alpine","digest":"sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14","pinned_image":"node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14"}]}
# ___ _ _
# / _ \ | | (_)
# | |_| | __ _ ___ _ __ | |_ _ ___
@@ -14,7 +14,7 @@
# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
#
-# This file was automatically generated by gh-aw (v0.74.4). DO NOT EDIT.
+# This file was automatically generated by gh-aw (v0.77.5). DO NOT EDIT.
#
# To update this file, edit the corresponding .md file and run:
# gh aw compile
@@ -36,15 +36,15 @@
# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
# - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
-# - github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+# - github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
#
# Container images used:
-# - ghcr.io/github/gh-aw-firewall/agent:0.25.46
-# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46
-# - ghcr.io/github/gh-aw-firewall/squid:0.25.46
-# - ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388
-# - ghcr.io/github/github-mcp-server:v1.0.4
-# - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+# - ghcr.io/github/gh-aw-firewall/agent:0.25.58
+# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58
+# - ghcr.io/github/gh-aw-firewall/squid:0.25.58
+# - ghcr.io/github/gh-aw-mcpg:v0.3.22
+# - ghcr.io/github/github-mcp-server:v1.1.0
+# - node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
name: "Issue Classification Agent"
on:
@@ -56,7 +56,7 @@ on:
inputs:
aw_context:
default: ""
- description: Agent caller context (used internally by Agentic Workflows).
+ description: "Agent caller context (used internally by Agentic Workflows)."
required: false
type: string
issue_number:
@@ -94,31 +94,32 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
env:
GH_AW_SETUP_WORKFLOW_NAME: "Issue Classification Agent"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/issue-classification.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Generate agentic run info
id: generate_aw_info
env:
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI"
- GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
- GH_AW_INFO_VERSION: "1.0.48"
- GH_AW_INFO_AGENT_VERSION: "1.0.48"
- GH_AW_INFO_CLI_VERSION: "v0.74.4"
+ GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AGENT_VERSION: "1.0.55"
+ GH_AW_INFO_CLI_VERSION: "v0.77.5"
GH_AW_INFO_WORKFLOW_NAME: "Issue Classification Agent"
GH_AW_INFO_EXPERIMENTAL: "false"
GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
GH_AW_INFO_STAGED: "false"
GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]'
GH_AW_INFO_FIREWALL_ENABLED: "true"
- GH_AW_INFO_AWF_VERSION: "v0.25.46"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_AWMG_VERSION: ""
GH_AW_INFO_FIREWALL_TYPE: "squid"
GH_AW_COMPILED_STRICT: "true"
@@ -141,6 +142,7 @@ jobs:
sparse-checkout: |
.github
.agents
+ .antigravity
.claude
.codex
.crush
@@ -151,8 +153,8 @@ jobs:
fetch-depth: 1
- name: Save agent config folders for base branch restoration
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
# poutine:ignore untrusted_checkout_exec
run: bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh"
- name: Check workflow lock file
@@ -170,7 +172,7 @@ jobs:
- name: Check compile-agentic version
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
- GH_AW_COMPILED_VERSION: "v0.74.4"
+ GH_AW_COMPILED_VERSION: "v0.77.5"
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@@ -202,6 +204,7 @@ jobs:
GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
+ GH_AW_INPUTS_ISSUE_NUMBER: ${{ inputs.issue_number }}
# poutine:ignore untrusted_checkout_exec
run: |
bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh"
@@ -263,6 +266,7 @@ jobs:
GH_AW_EXPR_54492A5B: ${{ github.event.issue.number || inputs.issue_number }}
GH_AW_GITHUB_EVENT_ISSUE_TITLE: ${{ github.event.issue.title }}
GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
+ GH_AW_INPUTS_ISSUE_NUMBER: ${{ inputs.issue_number }}
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@@ -283,6 +287,7 @@ jobs:
GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
+ GH_AW_INPUTS_ISSUE_NUMBER: ${{ inputs.issue_number }}
GH_AW_MCP_CLI_SERVERS_LIST: '- `safeoutputs` — run `safeoutputs --help` to see available tools'
with:
script: |
@@ -305,6 +310,7 @@ jobs:
GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY,
GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID,
GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE,
+ GH_AW_INPUTS_ISSUE_NUMBER: process.env.GH_AW_INPUTS_ISSUE_NUMBER,
GH_AW_MCP_CLI_SERVERS_LIST: process.env.GH_AW_MCP_CLI_SERVERS_LIST
}
});
@@ -326,12 +332,14 @@ jobs:
include-hidden-files: true
path: |
/tmp/gh-aw/aw_info.json
+ /tmp/gh-aw/model_multipliers.json
/tmp/gh-aw/aw-prompts/prompt.txt
/tmp/gh-aw/aw-prompts/prompt-template.txt
/tmp/gh-aw/aw-prompts/prompt-import-tree.json
/tmp/gh-aw/github_rate_limits.jsonl
/tmp/gh-aw/base
/tmp/gh-aw/.github/agents
+ /tmp/gh-aw/.github/skills
if-no-files-found: ignore
retention-days: 1
@@ -350,15 +358,15 @@ jobs:
GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
GH_AW_WORKFLOW_ID_SANITIZED: issueclassification
outputs:
- agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }}
+ agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }}
checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }}
effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }}
has_patch: ${{ steps.collect_output.outputs.has_patch }}
- inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }}
- mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }}
+ inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }}
+ mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }}
model: ${{ needs.activation.outputs.model }}
- model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }}
+ model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }}
output: ${{ steps.collect_output.outputs.output }}
output_types: ${{ steps.collect_output.outputs.output_types }}
setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
@@ -367,7 +375,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -376,7 +384,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Issue Classification Agent"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/issue-classification.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Set runtime paths
id: set-runtime-paths
@@ -424,11 +433,11 @@ jobs:
const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs');
await main();
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Parse integrity filter lists
id: parse-guard-vars
env:
@@ -444,16 +453,20 @@ jobs:
- name: Restore agent config folders from base branch
if: steps.checkout-pr.outcome == 'success'
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh"
- name: Restore inline sub-agents from activation artifact
env:
GH_AW_SUB_AGENT_DIR: ".github/agents"
GH_AW_SUB_AGENT_EXT: ".agent.md"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh"
+ - name: Restore inline skills from activation artifact
+ env:
+ GH_AW_SKILL_DIR: ".github/skills"
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh"
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46 ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388 ghcr.io/github/github-mcp-server:v1.0.4 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58 ghcr.io/github/gh-aw-mcpg:v0.3.22 ghcr.io/github/github-mcp-server:v1.1.0 node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
- name: Generate Safe Outputs Config
run: |
mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
@@ -758,7 +771,7 @@ jobs:
* ) DOCKER_SOCK_PATH=/var/run/docker.sock ;;
esac
DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0')
- export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.9'
+ export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.22'
mkdir -p /home/runner/.copilot
GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node)
@@ -767,7 +780,7 @@ jobs:
"mcpServers": {
"github": {
"type": "stdio",
- "container": "ghcr.io/github/github-mcp-server:v1.0.4",
+ "container": "ghcr.io/github/github-mcp-server:v1.1.0",
"env": {
"GITHUB_HOST": "\${GITHUB_SERVER_URL}",
"GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
@@ -838,26 +851,38 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/agent-stdio.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"auto":["large"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5.3","gemini-pro","any"],"antigravity":["copilot/antigravity*","google/antigravity*","gemini/antigravity*"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"claude":["agent"],"codex":["agent"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"computer-use":["copilot/*computer-use*","google/*computer-use*","gemini/*computer-use*","openai/*computer-use*"],"copilot":["agent"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent"],"gemini-3-flash":["copilot/gemini-3*flash*","google/gemini-3*flash*","gemini/gemini-3*flash*"],"gemini-3-pro":["copilot/gemini-3*pro*","google/gemini-3*pro*","gemini/gemini-3*pro*"],"gemini-3.1-flash":["copilot/gemini-3.1*flash*","google/gemini-3.1*flash*","gemini/gemini-3.1*flash*"],"gemini-3.1-pro":["copilot/gemini-3.1*pro*","google/gemini-3.1*pro*","gemini/gemini-3.1*pro*"],"gemini-3.5-flash":["copilot/gemini-3.5*flash*","google/gemini-3.5*flash*","gemini/gemini-3.5*flash*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"gpt-5.2":["copilot/gpt-5.2*","openai/gpt-5.2*"],"gpt-5.3":["copilot/gpt-5.3*","openai/gpt-5.3*"],"gpt-5.4":["copilot/gpt-5.4*","openai/gpt-5.4*"],"gpt-5.5":["copilot/gpt-5.5*","openai/gpt-5.5*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"opusplan":["opus?effort=high"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"robotics":["copilot/*robotics*","google/*robotics*","gemini/*robotics*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4-5-*","anthropic/*sonnet-4-5-*","copilot/*sonnet-4-6*","anthropic/*sonnet-4-6*"],"summarization":["haiku","gpt-5-mini","gemini-flash-lite","mini"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json
GH_AW_PHASE: agent
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -871,12 +896,13 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- - name: Detect Copilot errors
- id: detect-copilot-errors
+ - name: Detect agent errors
if: always()
+ id: detect-agent-errors
continue-on-error: true
- run: node "${RUNNER_TEMP}/gh-aw/actions/detect_copilot_errors.cjs"
+ run: node "${RUNNER_TEMP}/gh-aw/actions/detect_agent_errors.cjs"
- name: Configure Git credentials
env:
REPO_NAME: ${{ github.repository }}
@@ -1140,7 +1166,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1149,7 +1175,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Issue Classification Agent"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/issue-classification.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
id: download-agent-output
@@ -1172,6 +1199,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_NOOP_MAX: "1"
GH_AW_WORKFLOW_NAME: "Issue Classification Agent"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/issue-classification.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_NOOP_REPORT_AS_ISSUE: "true"
@@ -1188,6 +1216,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Issue Classification Agent"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/issue-classification.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
@@ -1205,6 +1234,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_MISSING_TOOL_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "Issue Classification Agent"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/issue-classification.md"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1219,6 +1249,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "Issue Classification Agent"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/issue-classification.md"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1233,6 +1264,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Issue Classification Agent"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/issue-classification.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_WORKFLOW_ID: "issue-classification"
@@ -1279,7 +1311,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1288,7 +1320,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Issue Classification Agent"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/issue-classification.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
id: download-agent-output
@@ -1315,7 +1348,7 @@ jobs:
rm -rf /tmp/gh-aw/sandbox/firewall/logs
rm -rf /tmp/gh-aw/sandbox/firewall/audit
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58
- name: Check if detection needed
id: detection_guard
if: always()
@@ -1341,6 +1374,9 @@ jobs:
run: |
mkdir -p /tmp/gh-aw/threat-detection/aw-prompts
cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true
+ if [ ! -s /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt ]; then
+ echo "::warning::ERR_VALIDATION: Missing or empty detection context prompt at /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt. Ensure the agent artifact includes /tmp/gh-aw/aw-prompts/prompt.txt. Detection will continue with fallback workflow context."
+ fi
cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true
for f in /tmp/gh-aw/aw-*.patch; do
[ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
@@ -1374,11 +1410,11 @@ jobs:
node-version: '24'
package-manager-cache: false
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Execute GitHub Copilot CLI
if: always() && steps.detection_guard.outputs.run_detection == 'true'
continue-on-error: true
@@ -1391,24 +1427,36 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/threat-detection/detection.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","registry.npmjs.org","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_PHASE: detection
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -1421,6 +1469,7 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- name: Upload threat detection log
if: always() && steps.detection_guard.outputs.run_detection == 'true'
@@ -1482,9 +1531,10 @@ jobs:
GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }}
GH_AW_ENGINE_ID: "copilot"
GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
- GH_AW_ENGINE_VERSION: "1.0.48"
+ GH_AW_ENGINE_VERSION: "1.0.55"
GH_AW_WORKFLOW_ID: "issue-classification"
GH_AW_WORKFLOW_NAME: "Issue Classification Agent"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/issue-classification.md"
outputs:
call_workflow_name: ${{ steps.process_safe_outputs.outputs.call_workflow_name }}
call_workflow_payload: ${{ steps.process_safe_outputs.outputs.call_workflow_payload }}
@@ -1499,7 +1549,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1508,7 +1558,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Issue Classification Agent"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/issue-classification.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
id: download-agent-output
@@ -1538,6 +1589,7 @@ jobs:
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
+ GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }}
GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_API_URL: ${{ github.api_url }}
diff --git a/.github/workflows/issue-triage.lock.yml b/.github/workflows/issue-triage.lock.yml
index 6e08aa042..dce3e9171 100644
--- a/.github/workflows/issue-triage.lock.yml
+++ b/.github/workflows/issue-triage.lock.yml
@@ -1,5 +1,5 @@
-# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"22ed351fca21814391eea23a7470028e8321a9e2fe21fb95e31b13d0353aee4b","compiler_version":"v0.74.4","strict":true,"agent_id":"copilot"}
-# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"d3abfe96a194bce3a523ed2093ddedd5704cdf62","version":"v0.74.4"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.46"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.9","digest":"sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388"},{"image":"ghcr.io/github/github-mcp-server:v1.0.4"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]}
+# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"4472ef96371b3dbbd8e7b52b2612d552047d519ba61344a9b2a92e663fee87ed","body_hash":"30994be7c5c23b102c12a56a325ac313e413a2507dff11d0dc695899379bfbd0","compiler_version":"v0.77.5","strict":true,"agent_id":"copilot"}
+# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"3ea13c02d765410340d533515cb31a7eef2baaf0","version":"v0.77.5"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.58"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.22"},{"image":"ghcr.io/github/github-mcp-server:v1.1.0"},{"image":"node:lts-alpine","digest":"sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14","pinned_image":"node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14"}]}
# ___ _ _
# / _ \ | | (_)
# | |_| | __ _ ___ _ __ | |_ _ ___
@@ -14,7 +14,7 @@
# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
#
-# This file was automatically generated by gh-aw (v0.74.4). DO NOT EDIT.
+# This file was automatically generated by gh-aw (v0.77.5). DO NOT EDIT.
#
# To update this file, edit the corresponding .md file and run:
# gh aw compile
@@ -37,15 +37,15 @@
# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9)
# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
# - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
-# - github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+# - github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
#
# Container images used:
-# - ghcr.io/github/gh-aw-firewall/agent:0.25.46
-# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46
-# - ghcr.io/github/gh-aw-firewall/squid:0.25.46
-# - ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388
-# - ghcr.io/github/github-mcp-server:v1.0.4
-# - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+# - ghcr.io/github/gh-aw-firewall/agent:0.25.58
+# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58
+# - ghcr.io/github/gh-aw-firewall/squid:0.25.58
+# - ghcr.io/github/gh-aw-mcpg:v0.3.22
+# - ghcr.io/github/github-mcp-server:v1.1.0
+# - node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
name: "Issue Triage Agent"
on:
@@ -57,7 +57,7 @@ on:
inputs:
aw_context:
default: ""
- description: Agent caller context (used internally by Agentic Workflows).
+ description: "Agent caller context (used internally by Agentic Workflows)."
required: false
type: string
issue_number:
@@ -95,31 +95,32 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
env:
GH_AW_SETUP_WORKFLOW_NAME: "Issue Triage Agent"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/issue-triage.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Generate agentic run info
id: generate_aw_info
env:
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI"
- GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
- GH_AW_INFO_VERSION: "1.0.48"
- GH_AW_INFO_AGENT_VERSION: "1.0.48"
- GH_AW_INFO_CLI_VERSION: "v0.74.4"
+ GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AGENT_VERSION: "1.0.55"
+ GH_AW_INFO_CLI_VERSION: "v0.77.5"
GH_AW_INFO_WORKFLOW_NAME: "Issue Triage Agent"
GH_AW_INFO_EXPERIMENTAL: "false"
GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
GH_AW_INFO_STAGED: "false"
GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]'
GH_AW_INFO_FIREWALL_ENABLED: "true"
- GH_AW_INFO_AWF_VERSION: "v0.25.46"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_AWMG_VERSION: ""
GH_AW_INFO_FIREWALL_TYPE: "squid"
GH_AW_COMPILED_STRICT: "true"
@@ -142,6 +143,7 @@ jobs:
sparse-checkout: |
.github
.agents
+ .antigravity
.claude
.codex
.crush
@@ -152,8 +154,8 @@ jobs:
fetch-depth: 1
- name: Save agent config folders for base branch restoration
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
# poutine:ignore untrusted_checkout_exec
run: bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh"
- name: Check workflow lock file
@@ -171,7 +173,7 @@ jobs:
- name: Check compile-agentic version
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
- GH_AW_COMPILED_VERSION: "v0.74.4"
+ GH_AW_COMPILED_VERSION: "v0.77.5"
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@@ -203,24 +205,25 @@ jobs:
GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
+ GH_AW_INPUTS_ISSUE_NUMBER: ${{ inputs.issue_number }}
# poutine:ignore untrusted_checkout_exec
run: |
bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh"
{
- cat << 'GH_AW_PROMPT_e74a3944dc48d8ab_EOF'
+ cat << 'GH_AW_PROMPT_294c35176923eb24_EOF'
- GH_AW_PROMPT_e74a3944dc48d8ab_EOF
+ GH_AW_PROMPT_294c35176923eb24_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md"
- cat << 'GH_AW_PROMPT_e74a3944dc48d8ab_EOF'
+ cat << 'GH_AW_PROMPT_294c35176923eb24_EOF'
Tools: add_comment(max:2), close_issue, update_issue, add_labels(max:10), missing_tool, missing_data, noop
- GH_AW_PROMPT_e74a3944dc48d8ab_EOF
+ GH_AW_PROMPT_294c35176923eb24_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md"
- cat << 'GH_AW_PROMPT_e74a3944dc48d8ab_EOF'
+ cat << 'GH_AW_PROMPT_294c35176923eb24_EOF'
The following GitHub context information is available for this workflow:
{{#if github.actor}}
@@ -249,12 +252,12 @@ jobs:
{{/if}}
- GH_AW_PROMPT_e74a3944dc48d8ab_EOF
+ GH_AW_PROMPT_294c35176923eb24_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md"
- cat << 'GH_AW_PROMPT_e74a3944dc48d8ab_EOF'
+ cat << 'GH_AW_PROMPT_294c35176923eb24_EOF'
{{#runtime-import .github/workflows/issue-triage.md}}
- GH_AW_PROMPT_e74a3944dc48d8ab_EOF
+ GH_AW_PROMPT_294c35176923eb24_EOF
} > "$GH_AW_PROMPT"
- name: Interpolate variables and render templates
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
@@ -264,6 +267,7 @@ jobs:
GH_AW_EXPR_54492A5B: ${{ github.event.issue.number || inputs.issue_number }}
GH_AW_GITHUB_EVENT_ISSUE_TITLE: ${{ github.event.issue.title }}
GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
+ GH_AW_INPUTS_ISSUE_NUMBER: ${{ inputs.issue_number }}
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@@ -284,6 +288,7 @@ jobs:
GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
+ GH_AW_INPUTS_ISSUE_NUMBER: ${{ inputs.issue_number }}
GH_AW_MCP_CLI_SERVERS_LIST: '- `safeoutputs` — run `safeoutputs --help` to see available tools'
with:
script: |
@@ -306,6 +311,7 @@ jobs:
GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY,
GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID,
GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE,
+ GH_AW_INPUTS_ISSUE_NUMBER: process.env.GH_AW_INPUTS_ISSUE_NUMBER,
GH_AW_MCP_CLI_SERVERS_LIST: process.env.GH_AW_MCP_CLI_SERVERS_LIST
}
});
@@ -327,12 +333,14 @@ jobs:
include-hidden-files: true
path: |
/tmp/gh-aw/aw_info.json
+ /tmp/gh-aw/model_multipliers.json
/tmp/gh-aw/aw-prompts/prompt.txt
/tmp/gh-aw/aw-prompts/prompt-template.txt
/tmp/gh-aw/aw-prompts/prompt-import-tree.json
/tmp/gh-aw/github_rate_limits.jsonl
/tmp/gh-aw/base
/tmp/gh-aw/.github/agents
+ /tmp/gh-aw/.github/skills
if-no-files-found: ignore
retention-days: 1
@@ -351,15 +359,15 @@ jobs:
GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
GH_AW_WORKFLOW_ID_SANITIZED: issuetriage
outputs:
- agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }}
+ agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }}
checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }}
effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }}
has_patch: ${{ steps.collect_output.outputs.has_patch }}
- inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }}
- mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }}
+ inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }}
+ mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }}
model: ${{ needs.activation.outputs.model }}
- model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }}
+ model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }}
output: ${{ steps.collect_output.outputs.output }}
output_types: ${{ steps.collect_output.outputs.output_types }}
setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
@@ -368,7 +376,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -377,7 +385,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Issue Triage Agent"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/issue-triage.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Set runtime paths
id: set-runtime-paths
@@ -425,11 +434,11 @@ jobs:
const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs');
await main();
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Determine automatic lockdown mode for GitHub MCP Server
id: determine-automatic-lockdown
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9)
@@ -448,31 +457,35 @@ jobs:
- name: Restore agent config folders from base branch
if: steps.checkout-pr.outcome == 'success'
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh"
- name: Restore inline sub-agents from activation artifact
env:
GH_AW_SUB_AGENT_DIR: ".github/agents"
GH_AW_SUB_AGENT_EXT: ".agent.md"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh"
+ - name: Restore inline skills from activation artifact
+ env:
+ GH_AW_SKILL_DIR: ".github/skills"
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh"
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46 ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388 ghcr.io/github/github-mcp-server:v1.0.4 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58 ghcr.io/github/gh-aw-mcpg:v0.3.22 ghcr.io/github/github-mcp-server:v1.1.0 node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
- name: Generate Safe Outputs Config
run: |
mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
mkdir -p /tmp/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
- cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_6607c9cdef4a0243_EOF'
- {"add_comment":{"max":2},"add_labels":{"allowed":["bug","enhancement","question","documentation","sdk/dotnet","sdk/go","sdk/nodejs","sdk/python","priority/high","priority/low","testing","security","needs-info","duplicate"],"max":10,"target":"triggering"},"close_issue":{"max":1,"target":"triggering"},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{},"update_issue":{"allow_body":true,"max":1,"target":"triggering"}}
- GH_AW_SAFE_OUTPUTS_CONFIG_6607c9cdef4a0243_EOF
+ cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_90ffae57d01667f3_EOF'
+ {"add_comment":{"max":2},"add_labels":{"allowed":["bug","enhancement","question","documentation","sdk/dotnet","sdk/go","sdk/java","sdk/nodejs","sdk/python","priority/high","priority/low","testing","security","needs-info","duplicate"],"max":10,"target":"triggering"},"close_issue":{"max":1,"target":"triggering"},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{},"update_issue":{"allow_body":true,"max":1,"target":"triggering"}}
+ GH_AW_SAFE_OUTPUTS_CONFIG_90ffae57d01667f3_EOF
- name: Generate Safe Outputs Tools
env:
GH_AW_TOOLS_META_JSON: |
{
"description_suffixes": {
"add_comment": " CONSTRAINTS: Maximum 2 comment(s) can be added. Supports reply_to_id for discussion threading.",
- "add_labels": " CONSTRAINTS: Maximum 10 label(s) can be added. Only these labels are allowed: [\"bug\" \"enhancement\" \"question\" \"documentation\" \"sdk/dotnet\" \"sdk/go\" \"sdk/nodejs\" \"sdk/python\" \"priority/high\" \"priority/low\" \"testing\" \"security\" \"needs-info\" \"duplicate\"]. Target: triggering.",
+ "add_labels": " CONSTRAINTS: Maximum 10 label(s) can be added. Only these labels are allowed: [\"bug\" \"enhancement\" \"question\" \"documentation\" \"sdk/dotnet\" \"sdk/go\" \"sdk/java\" \"sdk/nodejs\" \"sdk/python\" \"priority/high\" \"priority/low\" \"testing\" \"security\" \"needs-info\" \"duplicate\"]. Target: triggering.",
"close_issue": " CONSTRAINTS: Maximum 1 issue(s) can be closed. Target: triggering.",
"update_issue": " CONSTRAINTS: Maximum 1 issue(s) can be updated. Target: triggering."
},
@@ -526,7 +539,6 @@ jobs:
"defaultMax": 1,
"fields": {
"body": {
- "required": true,
"type": "string",
"sanitize": true,
"maxLength": 65000
@@ -749,16 +761,16 @@ jobs:
* ) DOCKER_SOCK_PATH=/var/run/docker.sock ;;
esac
DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0')
- export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.9'
+ export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.22'
mkdir -p /home/runner/.copilot
GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node)
- cat << GH_AW_MCP_CONFIG_b6b29985f1ee0a9c_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs"
+ cat << GH_AW_MCP_CONFIG_90b7530930d86f98_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs"
{
"mcpServers": {
"github": {
"type": "stdio",
- "container": "ghcr.io/github/github-mcp-server:v1.0.4",
+ "container": "ghcr.io/github/github-mcp-server:v1.1.0",
"env": {
"GITHUB_HOST": "\${GITHUB_SERVER_URL}",
"GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
@@ -794,7 +806,7 @@ jobs:
"payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
}
}
- GH_AW_MCP_CONFIG_b6b29985f1ee0a9c_EOF
+ GH_AW_MCP_CONFIG_90b7530930d86f98_EOF
- name: Mount MCP servers as CLIs
id: mount-mcp-clis
continue-on-error: true
@@ -826,26 +838,38 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/agent-stdio.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"auto":["large"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5.3","gemini-pro","any"],"antigravity":["copilot/antigravity*","google/antigravity*","gemini/antigravity*"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"claude":["agent"],"codex":["agent"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"computer-use":["copilot/*computer-use*","google/*computer-use*","gemini/*computer-use*","openai/*computer-use*"],"copilot":["agent"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent"],"gemini-3-flash":["copilot/gemini-3*flash*","google/gemini-3*flash*","gemini/gemini-3*flash*"],"gemini-3-pro":["copilot/gemini-3*pro*","google/gemini-3*pro*","gemini/gemini-3*pro*"],"gemini-3.1-flash":["copilot/gemini-3.1*flash*","google/gemini-3.1*flash*","gemini/gemini-3.1*flash*"],"gemini-3.1-pro":["copilot/gemini-3.1*pro*","google/gemini-3.1*pro*","gemini/gemini-3.1*pro*"],"gemini-3.5-flash":["copilot/gemini-3.5*flash*","google/gemini-3.5*flash*","gemini/gemini-3.5*flash*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"gpt-5.2":["copilot/gpt-5.2*","openai/gpt-5.2*"],"gpt-5.3":["copilot/gpt-5.3*","openai/gpt-5.3*"],"gpt-5.4":["copilot/gpt-5.4*","openai/gpt-5.4*"],"gpt-5.5":["copilot/gpt-5.5*","openai/gpt-5.5*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"opusplan":["opus?effort=high"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"robotics":["copilot/*robotics*","google/*robotics*","gemini/*robotics*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4-5-*","anthropic/*sonnet-4-5-*","copilot/*sonnet-4-6*","anthropic/*sonnet-4-6*"],"summarization":["haiku","gpt-5-mini","gemini-flash-lite","mini"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json
GH_AW_PHASE: agent
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -859,12 +883,13 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- - name: Detect Copilot errors
- id: detect-copilot-errors
+ - name: Detect agent errors
if: always()
+ id: detect-agent-errors
continue-on-error: true
- run: node "${RUNNER_TEMP}/gh-aw/actions/detect_copilot_errors.cjs"
+ run: node "${RUNNER_TEMP}/gh-aw/actions/detect_agent_errors.cjs"
- name: Configure Git credentials
env:
REPO_NAME: ${{ github.repository }}
@@ -1046,7 +1071,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1055,7 +1080,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Issue Triage Agent"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/issue-triage.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
id: download-agent-output
@@ -1078,6 +1104,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_NOOP_MAX: "1"
GH_AW_WORKFLOW_NAME: "Issue Triage Agent"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/issue-triage.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_NOOP_REPORT_AS_ISSUE: "true"
@@ -1094,6 +1121,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Issue Triage Agent"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/issue-triage.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
@@ -1111,6 +1139,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_MISSING_TOOL_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "Issue Triage Agent"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/issue-triage.md"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1125,6 +1154,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "Issue Triage Agent"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/issue-triage.md"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1139,6 +1169,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Issue Triage Agent"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/issue-triage.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_WORKFLOW_ID: "issue-triage"
@@ -1185,7 +1216,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1194,7 +1225,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Issue Triage Agent"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/issue-triage.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
id: download-agent-output
@@ -1221,7 +1253,7 @@ jobs:
rm -rf /tmp/gh-aw/sandbox/firewall/logs
rm -rf /tmp/gh-aw/sandbox/firewall/audit
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58
- name: Check if detection needed
id: detection_guard
if: always()
@@ -1247,6 +1279,9 @@ jobs:
run: |
mkdir -p /tmp/gh-aw/threat-detection/aw-prompts
cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true
+ if [ ! -s /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt ]; then
+ echo "::warning::ERR_VALIDATION: Missing or empty detection context prompt at /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt. Ensure the agent artifact includes /tmp/gh-aw/aw-prompts/prompt.txt. Detection will continue with fallback workflow context."
+ fi
cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true
for f in /tmp/gh-aw/aw-*.patch; do
[ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
@@ -1280,11 +1315,11 @@ jobs:
node-version: '24'
package-manager-cache: false
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Execute GitHub Copilot CLI
if: always() && steps.detection_guard.outputs.run_detection == 'true'
continue-on-error: true
@@ -1297,24 +1332,36 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/threat-detection/detection.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","registry.npmjs.org","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_PHASE: detection
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -1327,6 +1374,7 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- name: Upload threat detection log
if: always() && steps.detection_guard.outputs.run_detection == 'true'
@@ -1388,9 +1436,10 @@ jobs:
GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }}
GH_AW_ENGINE_ID: "copilot"
GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
- GH_AW_ENGINE_VERSION: "1.0.48"
+ GH_AW_ENGINE_VERSION: "1.0.55"
GH_AW_WORKFLOW_ID: "issue-triage"
GH_AW_WORKFLOW_NAME: "Issue Triage Agent"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/issue-triage.md"
outputs:
code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}
code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}
@@ -1403,7 +1452,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1412,7 +1461,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Issue Triage Agent"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/issue-triage.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
id: download-agent-output
@@ -1442,10 +1492,11 @@ jobs:
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
+ GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }}
GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_API_URL: ${{ github.api_url }}
- GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":2},\"add_labels\":{\"allowed\":[\"bug\",\"enhancement\",\"question\",\"documentation\",\"sdk/dotnet\",\"sdk/go\",\"sdk/nodejs\",\"sdk/python\",\"priority/high\",\"priority/low\",\"testing\",\"security\",\"needs-info\",\"duplicate\"],\"max\":10,\"target\":\"triggering\"},\"close_issue\":{\"max\":1,\"target\":\"triggering\"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{},\"update_issue\":{\"allow_body\":true,\"max\":1,\"target\":\"triggering\"}}"
+ GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":2},\"add_labels\":{\"allowed\":[\"bug\",\"enhancement\",\"question\",\"documentation\",\"sdk/dotnet\",\"sdk/go\",\"sdk/java\",\"sdk/nodejs\",\"sdk/python\",\"priority/high\",\"priority/low\",\"testing\",\"security\",\"needs-info\",\"duplicate\"],\"max\":10,\"target\":\"triggering\"},\"close_issue\":{\"max\":1,\"target\":\"triggering\"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{},\"update_issue\":{\"allow_body\":true,\"max\":1,\"target\":\"triggering\"}}"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
diff --git a/.github/workflows/issue-triage.md b/.github/workflows/issue-triage.md
index 006b8a644..72f2042dc 100644
--- a/.github/workflows/issue-triage.md
+++ b/.github/workflows/issue-triage.md
@@ -21,7 +21,7 @@ safe-outputs:
add-comment:
max: 2
add-labels:
- allowed: [bug, enhancement, question, documentation, sdk/dotnet, sdk/go, sdk/nodejs, sdk/python, priority/high, priority/low, testing, security, needs-info, duplicate]
+ allowed: [bug, enhancement, question, documentation, sdk/dotnet, sdk/go, sdk/java, sdk/nodejs, sdk/python, priority/high, priority/low, testing, security, needs-info, duplicate]
max: 10
target: triggering
update-issue:
@@ -33,7 +33,7 @@ timeout-minutes: 10
# Issue Triage Agent
-You are an AI agent that triages newly opened issues in the copilot-sdk repository — a multi-language SDK with implementations in .NET, Go, Node.js, and Python.
+You are an AI agent that triages newly opened issues in the copilot-sdk repository — a multi-language SDK with implementations in .NET, Go, Java, Node.js, and Python.
## Your Task
@@ -48,7 +48,8 @@ When a new issue is opened, analyze it and perform the following actions:
### SDK/Language Labels (apply one or more if the issue relates to specific SDKs):
- `sdk/dotnet` — .NET SDK issues
-- `sdk/go` — Go SDK issues
+- `sdk/go` — Go SDK issues
+- `sdk/java` — Java SDK issues
- `sdk/nodejs` — Node.js SDK issues
- `sdk/python` — Python SDK issues
diff --git a/.github/workflows/java-adapt-handwritten-code-to-accept-upgrade-changes.lock.yml b/.github/workflows/java-adapt-handwritten-code-to-accept-upgrade-changes.lock.yml
new file mode 100644
index 000000000..90a08df7f
--- /dev/null
+++ b/.github/workflows/java-adapt-handwritten-code-to-accept-upgrade-changes.lock.yml
@@ -0,0 +1,1480 @@
+# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"3eae016f8d014497b4ae30ea62a2fa1906140d2a01b90c98b64970a9f1b55316","body_hash":"261128483856c9b8dd35d3377cc6a6e20dd9aad4442c64dbf6be7d27c2dbcd5a","compiler_version":"v0.77.5","strict":true,"agent_id":"copilot"}
+# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"3ea13c02d765410340d533515cb31a7eef2baaf0","version":"v0.77.5"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.58"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.22"},{"image":"ghcr.io/github/github-mcp-server:v1.1.0"},{"image":"node:lts-alpine","digest":"sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14","pinned_image":"node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14"}]}
+# ___ _ _
+# / _ \ | | (_)
+# | |_| | __ _ ___ _ __ | |_ _ ___
+# | _ |/ _` |/ _ \ '_ \| __| |/ __|
+# | | | | (_| | __/ | | | |_| | (__
+# \_| |_/\__, |\___|_| |_|\__|_|\___|
+# __/ |
+# _ _ |___/
+# | | | | / _| |
+# | | | | ___ _ __ _ __| |_| | _____ ____
+# | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___|
+# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
+# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
+#
+# This file was automatically generated by gh-aw (v0.77.5). DO NOT EDIT.
+#
+# To update this file, edit the corresponding .md file and run:
+# gh aw compile
+# Not all edits will cause changes to this file.
+#
+# For more information: https://github.github.com/gh-aw/introduction/overview/
+#
+# Adapt handwritten Java SDK code to work with regenerated types after a
+# @github/copilot version bump. Assumes codegen succeeded and generated code
+# compiles. Fixes handwritten source and tests only.
+#
+# Secrets used:
+# - COPILOT_GITHUB_TOKEN
+# - GH_AW_CI_TRIGGER_TOKEN
+# - GH_AW_GITHUB_MCP_SERVER_TOKEN
+# - GH_AW_GITHUB_TOKEN
+# - GITHUB_TOKEN
+#
+# Custom actions used:
+# - actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+# - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9)
+# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
+# - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+# - github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
+#
+# Container images used:
+# - ghcr.io/github/gh-aw-firewall/agent:0.25.58
+# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58
+# - ghcr.io/github/gh-aw-firewall/squid:0.25.58
+# - ghcr.io/github/gh-aw-mcpg:v0.3.22
+# - ghcr.io/github/github-mcp-server:v1.1.0
+# - node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
+
+name: "Java Handwritten Code Adaptation After CLI Upgrade"
+on:
+ workflow_dispatch:
+ inputs:
+ aw_context:
+ default: ""
+ description: "Agent caller context (used internally by Agentic Workflows)."
+ required: false
+ type: string
+ branch:
+ description: Branch containing the upgrade PR
+ required: true
+ type: string
+ pr_number:
+ description: PR number to push fixes to
+ required: true
+ type: string
+
+permissions: {}
+
+concurrency:
+ group: "gh-aw-${{ github.workflow }}-${{ github.ref || github.run_id }}"
+
+run-name: "Java Handwritten Code Adaptation After CLI Upgrade"
+
+jobs:
+ activation:
+ runs-on: ubuntu-slim
+ permissions:
+ actions: read
+ contents: read
+ outputs:
+ comment_id: ""
+ comment_repo: ""
+ engine_id: ${{ steps.generate_aw_info.outputs.engine_id }}
+ lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }}
+ model: ${{ steps.generate_aw_info.outputs.model }}
+ secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }}
+ setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
+ setup-span-id: ${{ steps.setup.outputs.span-id }}
+ setup-trace-id: ${{ steps.setup.outputs.trace-id }}
+ stale_lock_file_failed: ${{ steps.check-lock-file.outputs.stale_lock_file_failed == 'true' }}
+ steps:
+ - name: Setup Scripts
+ id: setup
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
+ with:
+ destination: ${{ runner.temp }}/gh-aw/actions
+ job-name: ${{ github.job }}
+ env:
+ GH_AW_SETUP_WORKFLOW_NAME: "Java Handwritten Code Adaptation After CLI Upgrade"
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/java-adapt-handwritten-code-to-accept-upgrade-changes.lock.yml@${{ github.ref }}
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
+ GH_AW_INFO_ENGINE_ID: "copilot"
+ - name: Generate agentic run info
+ id: generate_aw_info
+ env:
+ GH_AW_INFO_ENGINE_ID: "copilot"
+ GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI"
+ GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AGENT_VERSION: "1.0.55"
+ GH_AW_INFO_CLI_VERSION: "v0.77.5"
+ GH_AW_INFO_WORKFLOW_NAME: "Java Handwritten Code Adaptation After CLI Upgrade"
+ GH_AW_INFO_EXPERIMENTAL: "false"
+ GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
+ GH_AW_INFO_STAGED: "false"
+ GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","github"]'
+ GH_AW_INFO_FIREWALL_ENABLED: "true"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
+ GH_AW_INFO_AWMG_VERSION: ""
+ GH_AW_INFO_FIREWALL_TYPE: "squid"
+ GH_AW_COMPILED_STRICT: "true"
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ with:
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_aw_info.cjs');
+ await main(core, context);
+ - name: Validate COPILOT_GITHUB_TOKEN secret
+ id: validate-secret
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/validate_multi_secret.sh" COPILOT_GITHUB_TOKEN 'GitHub Copilot CLI' https://github.github.com/gh-aw/reference/engines/#github-copilot-default
+ env:
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
+ - name: Checkout .github and .agents folders
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ sparse-checkout: |
+ .github
+ .agents
+ .antigravity
+ .claude
+ .codex
+ .crush
+ .gemini
+ .opencode
+ .pi
+ sparse-checkout-cone-mode: true
+ fetch-depth: 1
+ - name: Save agent config folders for base branch restoration
+ env:
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ # poutine:ignore untrusted_checkout_exec
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh"
+ - name: Check workflow lock file
+ id: check-lock-file
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ GH_AW_WORKFLOW_FILE: "java-adapt-handwritten-code-to-accept-upgrade-changes.lock.yml"
+ GH_AW_CONTEXT_WORKFLOW_REF: "${{ github.workflow_ref }}"
+ with:
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/check_workflow_timestamp_api.cjs');
+ await main();
+ - name: Check compile-agentic version
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ GH_AW_COMPILED_VERSION: "v0.77.5"
+ with:
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/check_version_updates.cjs');
+ await main();
+ - name: Create prompt with built-in context
+ env:
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl
+ GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }}
+ GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }}
+ GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }}
+ GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }}
+ GH_AW_GITHUB_ACTOR: ${{ github.actor }}
+ GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
+ GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
+ GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
+ GH_AW_INPUTS_BRANCH: ${{ inputs.branch }}
+ GH_AW_INPUTS_PR_NUMBER: ${{ inputs.pr_number }}
+ # poutine:ignore untrusted_checkout_exec
+ run: |
+ bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh"
+ {
+ cat << 'GH_AW_PROMPT_3ae477de969fafa9_EOF'
+
+ GH_AW_PROMPT_3ae477de969fafa9_EOF
+ cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md"
+ cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md"
+ cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md"
+ cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md"
+ cat << 'GH_AW_PROMPT_3ae477de969fafa9_EOF'
+
+ Tools: add_comment(max:10), push_to_pull_request_branch, missing_tool, missing_data, noop
+ GH_AW_PROMPT_3ae477de969fafa9_EOF
+ cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_push_to_pr_branch.md"
+ cat << 'GH_AW_PROMPT_3ae477de969fafa9_EOF'
+
+ GH_AW_PROMPT_3ae477de969fafa9_EOF
+ cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md"
+ cat << 'GH_AW_PROMPT_3ae477de969fafa9_EOF'
+
+ The following GitHub context information is available for this workflow:
+ {{#if github.actor}}
+ - **actor**: __GH_AW_GITHUB_ACTOR__
+ {{/if}}
+ {{#if github.repository}}
+ - **repository**: __GH_AW_GITHUB_REPOSITORY__
+ {{/if}}
+ {{#if github.workspace}}
+ - **workspace**: __GH_AW_GITHUB_WORKSPACE__
+ {{/if}}
+ {{#if github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)}}
+ - **issue-number**: #__GH_AW_EXPR_802A9F6A__
+ {{/if}}
+ {{#if github.event.discussion.number || (github.aw.context.item_type == 'discussion' && github.aw.context.item_number)}}
+ - **discussion-number**: #__GH_AW_EXPR_1A3A194A__
+ {{/if}}
+ {{#if github.event.pull_request.number || (github.aw.context.item_type == 'pull_request' && github.aw.context.item_number)}}
+ - **pull-request-number**: #__GH_AW_EXPR_463A214A__
+ {{/if}}
+ {{#if github.event.comment.id || github.aw.context.comment_id}}
+ - **comment-id**: __GH_AW_EXPR_FF1D34CE__
+ {{/if}}
+ {{#if github.run_id}}
+ - **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__
+ {{/if}}
+
+
+ GH_AW_PROMPT_3ae477de969fafa9_EOF
+ cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md"
+ cat << 'GH_AW_PROMPT_3ae477de969fafa9_EOF'
+
+ {{#runtime-import .github/workflows/java-adapt-handwritten-code-to-accept-upgrade-changes.md}}
+ GH_AW_PROMPT_3ae477de969fafa9_EOF
+ } > "$GH_AW_PROMPT"
+ - name: Interpolate variables and render templates
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ GH_AW_ENGINE_ID: "copilot"
+ GH_AW_INPUTS_BRANCH: ${{ inputs.branch }}
+ GH_AW_INPUTS_PR_NUMBER: ${{ inputs.pr_number }}
+ with:
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/interpolate_prompt.cjs');
+ await main();
+ - name: Substitute placeholders
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }}
+ GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }}
+ GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }}
+ GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }}
+ GH_AW_GITHUB_ACTOR: ${{ github.actor }}
+ GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
+ GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
+ GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
+ GH_AW_INPUTS_BRANCH: ${{ inputs.branch }}
+ GH_AW_INPUTS_PR_NUMBER: ${{ inputs.pr_number }}
+ GH_AW_MCP_CLI_SERVERS_LIST: '- `safeoutputs` — run `safeoutputs --help` to see available tools'
+ with:
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+
+ const substitutePlaceholders = require('${{ runner.temp }}/gh-aw/actions/substitute_placeholders.cjs');
+
+ // Call the substitution function
+ return await substitutePlaceholders({
+ file: process.env.GH_AW_PROMPT,
+ substitutions: {
+ GH_AW_EXPR_1A3A194A: process.env.GH_AW_EXPR_1A3A194A,
+ GH_AW_EXPR_463A214A: process.env.GH_AW_EXPR_463A214A,
+ GH_AW_EXPR_802A9F6A: process.env.GH_AW_EXPR_802A9F6A,
+ GH_AW_EXPR_FF1D34CE: process.env.GH_AW_EXPR_FF1D34CE,
+ GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR,
+ GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY,
+ GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID,
+ GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE,
+ GH_AW_INPUTS_BRANCH: process.env.GH_AW_INPUTS_BRANCH,
+ GH_AW_INPUTS_PR_NUMBER: process.env.GH_AW_INPUTS_PR_NUMBER,
+ GH_AW_MCP_CLI_SERVERS_LIST: process.env.GH_AW_MCP_CLI_SERVERS_LIST
+ }
+ });
+ - name: Validate prompt placeholders
+ env:
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ # poutine:ignore untrusted_checkout_exec
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh"
+ - name: Print prompt
+ env:
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ # poutine:ignore untrusted_checkout_exec
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh"
+ - name: Upload activation artifact
+ if: success()
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ with:
+ name: activation
+ include-hidden-files: true
+ path: |
+ /tmp/gh-aw/aw_info.json
+ /tmp/gh-aw/model_multipliers.json
+ /tmp/gh-aw/aw-prompts/prompt.txt
+ /tmp/gh-aw/aw-prompts/prompt-template.txt
+ /tmp/gh-aw/aw-prompts/prompt-import-tree.json
+ /tmp/gh-aw/github_rate_limits.jsonl
+ /tmp/gh-aw/base
+ /tmp/gh-aw/.github/agents
+ /tmp/gh-aw/.github/skills
+ if-no-files-found: ignore
+ retention-days: 1
+
+ agent:
+ needs: activation
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ contents: read
+ env:
+ DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
+ GH_AW_ASSETS_ALLOWED_EXTS: ""
+ GH_AW_ASSETS_BRANCH: ""
+ GH_AW_ASSETS_MAX_SIZE_KB: 0
+ GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
+ GH_AW_WORKFLOW_ID_SANITIZED: javaadapthandwrittencodetoacceptupgradechanges
+ outputs:
+ agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }}
+ checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
+ effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }}
+ effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }}
+ has_patch: ${{ steps.collect_output.outputs.has_patch }}
+ inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }}
+ mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }}
+ model: ${{ needs.activation.outputs.model }}
+ model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }}
+ output: ${{ steps.collect_output.outputs.output }}
+ output_types: ${{ steps.collect_output.outputs.output_types }}
+ setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
+ setup-span-id: ${{ steps.setup.outputs.span-id }}
+ setup-trace-id: ${{ steps.setup.outputs.trace-id }}
+ steps:
+ - name: Setup Scripts
+ id: setup
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
+ with:
+ destination: ${{ runner.temp }}/gh-aw/actions
+ job-name: ${{ github.job }}
+ trace-id: ${{ needs.activation.outputs.setup-trace-id }}
+ parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }}
+ env:
+ GH_AW_SETUP_WORKFLOW_NAME: "Java Handwritten Code Adaptation After CLI Upgrade"
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/java-adapt-handwritten-code-to-accept-upgrade-changes.lock.yml@${{ github.ref }}
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
+ GH_AW_INFO_ENGINE_ID: "copilot"
+ - name: Set runtime paths
+ id: set-runtime-paths
+ run: |
+ {
+ echo "GH_AW_SAFE_OUTPUTS=${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl"
+ echo "GH_AW_SAFE_OUTPUTS_CONFIG_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/config.json"
+ echo "GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json"
+ } >> "$GITHUB_OUTPUT"
+ - name: Checkout repository
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ - name: Create gh-aw temp directory
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh"
+ - name: Configure gh CLI for GitHub Enterprise
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh"
+ env:
+ GH_TOKEN: ${{ github.token }}
+ - name: Configure Git credentials
+ env:
+ REPO_NAME: ${{ github.repository }}
+ SERVER_URL: ${{ github.server_url }}
+ GITHUB_TOKEN: ${{ github.token }}
+ run: |
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
+ git config --global user.name "github-actions[bot]"
+ git config --global am.keepcr true
+ # Re-authenticate git with GitHub token
+ SERVER_URL_STRIPPED="${SERVER_URL#https://}"
+ git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
+ echo "Git configured with standard GitHub Actions identity"
+ - name: Checkout PR branch
+ id: checkout-pr
+ if: |
+ github.event.pull_request || github.event.issue.pull_request
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs');
+ await main();
+ - name: Install GitHub Copilot CLI
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
+ env:
+ GH_HOST: github.com
+ - name: Install AWF binary
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
+ - name: Determine automatic lockdown mode for GitHub MCP Server
+ id: determine-automatic-lockdown
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9)
+ env:
+ GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
+ GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
+ with:
+ script: |
+ const determineAutomaticLockdown = require('${{ runner.temp }}/gh-aw/actions/determine_automatic_lockdown.cjs');
+ await determineAutomaticLockdown(github, context, core);
+ - name: Download activation artifact
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ name: activation
+ path: /tmp/gh-aw
+ - name: Restore agent config folders from base branch
+ if: steps.checkout-pr.outcome == 'success'
+ env:
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh"
+ - name: Restore inline sub-agents from activation artifact
+ env:
+ GH_AW_SUB_AGENT_DIR: ".github/agents"
+ GH_AW_SUB_AGENT_EXT: ".agent.md"
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh"
+ - name: Restore inline skills from activation artifact
+ env:
+ GH_AW_SKILL_DIR: ".github/skills"
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh"
+ - name: Download container images
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58 ghcr.io/github/gh-aw-mcpg:v0.3.22 ghcr.io/github/github-mcp-server:v1.1.0 node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
+ - name: Generate Safe Outputs Config
+ run: |
+ mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
+ mkdir -p /tmp/gh-aw/safeoutputs
+ mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
+ cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_4ab337cddbf20b67_EOF'
+ {"add_comment":{"max":10,"target":"*"},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"false"},"push_to_pull_request_branch":{"if_no_changes":"warn","max_patch_size":1024,"protect_top_level_dot_folders":true,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","DESIGN.md","README.md","CONTRIBUTING.md","CHANGELOG.md","SECURITY.md","CODE_OF_CONDUCT.md","AGENTS.md","CLAUDE.md","GEMINI.md"],"required_labels":["dependencies","sdk/java"],"target":"*"},"report_incomplete":{}}
+ GH_AW_SAFE_OUTPUTS_CONFIG_4ab337cddbf20b67_EOF
+ - name: Generate Safe Outputs Tools
+ env:
+ GH_AW_TOOLS_META_JSON: |
+ {
+ "description_suffixes": {
+ "add_comment": " CONSTRAINTS: Maximum 10 comment(s) can be added. Target: *. Supports reply_to_id for discussion threading."
+ },
+ "repo_params": {},
+ "dynamic_tools": []
+ }
+ GH_AW_VALIDATION_JSON: |
+ {
+ "add_comment": {
+ "defaultMax": 1,
+ "fields": {
+ "body": {
+ "required": true,
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 65000
+ },
+ "item_number": {
+ "issueOrPRNumber": true
+ },
+ "reply_to_id": {
+ "type": "string",
+ "maxLength": 256
+ },
+ "repo": {
+ "type": "string",
+ "maxLength": 256
+ }
+ }
+ },
+ "missing_data": {
+ "defaultMax": 20,
+ "fields": {
+ "alternatives": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 256
+ },
+ "context": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 256
+ },
+ "data_type": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 128
+ },
+ "reason": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 256
+ }
+ }
+ },
+ "missing_tool": {
+ "defaultMax": 20,
+ "fields": {
+ "alternatives": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 512
+ },
+ "reason": {
+ "required": true,
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 256
+ },
+ "tool": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 128
+ }
+ }
+ },
+ "noop": {
+ "defaultMax": 1,
+ "fields": {
+ "message": {
+ "required": true,
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 65000
+ }
+ }
+ },
+ "push_to_pull_request_branch": {
+ "defaultMax": 1,
+ "fields": {
+ "branch": {
+ "required": true,
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 256
+ },
+ "message": {
+ "required": true,
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 65000
+ },
+ "pull_request_number": {
+ "issueOrPRNumber": true
+ }
+ }
+ },
+ "report_incomplete": {
+ "defaultMax": 5,
+ "fields": {
+ "details": {
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 65000
+ },
+ "reason": {
+ "required": true,
+ "type": "string",
+ "sanitize": true,
+ "maxLength": 1024
+ }
+ }
+ }
+ }
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ with:
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/generate_safe_outputs_tools.cjs');
+ await main();
+ - name: Generate Safe Outputs MCP Server Config
+ id: safe-outputs-config
+ run: |
+ # Generate a secure random API key (360 bits of entropy, 40+ chars)
+ # Mask immediately to prevent timing vulnerabilities
+ API_KEY=$(openssl rand -base64 45 | tr -d '/+=')
+ echo "::add-mask::${API_KEY}"
+
+ PORT=3001
+
+ # Set outputs for next steps
+ {
+ echo "safe_outputs_api_key=${API_KEY}"
+ echo "safe_outputs_port=${PORT}"
+ } >> "$GITHUB_OUTPUT"
+
+ echo "Safe Outputs MCP server will run on port ${PORT}"
+
+ - name: Start Safe Outputs MCP HTTP Server
+ id: safe-outputs-start
+ env:
+ DEBUG: '*'
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
+ GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-config.outputs.safe_outputs_port }}
+ GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-config.outputs.safe_outputs_api_key }}
+ GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/tools.json
+ GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ runner.temp }}/gh-aw/safeoutputs/config.json
+ GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
+ run: |
+ # Environment variables are set above to prevent template injection
+ export DEBUG
+ export GH_AW_SAFE_OUTPUTS
+ export GH_AW_SAFE_OUTPUTS_PORT
+ export GH_AW_SAFE_OUTPUTS_API_KEY
+ export GH_AW_SAFE_OUTPUTS_TOOLS_PATH
+ export GH_AW_SAFE_OUTPUTS_CONFIG_PATH
+ export GH_AW_MCP_LOG_DIR
+
+ bash "${RUNNER_TEMP}/gh-aw/actions/start_safe_outputs_server.sh"
+
+ - name: Start MCP Gateway
+ id: start-mcp-gateway
+ env:
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
+ GH_AW_SAFE_OUTPUTS_API_KEY: ${{ steps.safe-outputs-start.outputs.api_key }}
+ GH_AW_SAFE_OUTPUTS_PORT: ${{ steps.safe-outputs-start.outputs.port }}
+ GITHUB_MCP_GUARD_MIN_INTEGRITY: ${{ steps.determine-automatic-lockdown.outputs.min_integrity }}
+ GITHUB_MCP_GUARD_REPOS: ${{ steps.determine-automatic-lockdown.outputs.repos }}
+ GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ run: |
+ set -eo pipefail
+ mkdir -p "${RUNNER_TEMP}/gh-aw/mcp-config"
+
+ # Export gateway environment variables for MCP config and gateway script
+ export MCP_GATEWAY_PORT="8080"
+ export MCP_GATEWAY_DOMAIN="host.docker.internal"
+ export MCP_GATEWAY_HOST_DOMAIN="localhost"
+ MCP_GATEWAY_API_KEY=$(openssl rand -base64 45 | tr -d '/+=')
+ echo "::add-mask::${MCP_GATEWAY_API_KEY}"
+ export MCP_GATEWAY_API_KEY
+ export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads"
+ mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}"
+ export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288"
+ export DEBUG="*"
+
+ export GH_AW_ENGINE="copilot"
+ MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0')
+ MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0')
+ case "${DOCKER_HOST:-}" in
+ unix://* ) DOCKER_SOCK_PATH="${DOCKER_HOST#unix://}" ;;
+ /* ) DOCKER_SOCK_PATH="$DOCKER_HOST" ;;
+ * ) DOCKER_SOCK_PATH=/var/run/docker.sock ;;
+ esac
+ DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0')
+ export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.22'
+
+ mkdir -p /home/runner/.copilot
+ GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node)
+ cat << GH_AW_MCP_CONFIG_8329361e2cf909e5_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs"
+ {
+ "mcpServers": {
+ "github": {
+ "type": "stdio",
+ "container": "ghcr.io/github/github-mcp-server:v1.1.0",
+ "env": {
+ "GITHUB_HOST": "\${GITHUB_SERVER_URL}",
+ "GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
+ "GITHUB_READ_ONLY": "1",
+ "GITHUB_TOOLSETS": "context,repos"
+ },
+ "guard-policies": {
+ "allow-only": {
+ "min-integrity": "$GITHUB_MCP_GUARD_MIN_INTEGRITY",
+ "repos": "$GITHUB_MCP_GUARD_REPOS"
+ }
+ }
+ },
+ "safeoutputs": {
+ "type": "http",
+ "url": "http://host.docker.internal:$GH_AW_SAFE_OUTPUTS_PORT",
+ "headers": {
+ "Authorization": "\${GH_AW_SAFE_OUTPUTS_API_KEY}"
+ },
+ "guard-policies": {
+ "write-sink": {
+ "accept": [
+ "*"
+ ]
+ }
+ }
+ }
+ },
+ "gateway": {
+ "port": $MCP_GATEWAY_PORT,
+ "domain": "${MCP_GATEWAY_DOMAIN}",
+ "apiKey": "${MCP_GATEWAY_API_KEY}",
+ "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
+ }
+ }
+ GH_AW_MCP_CONFIG_8329361e2cf909e5_EOF
+ - name: Mount MCP servers as CLIs
+ id: mount-mcp-clis
+ continue-on-error: true
+ env:
+ MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }}
+ MCP_GATEWAY_DOMAIN: ${{ steps.start-mcp-gateway.outputs.gateway-domain }}
+ MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ with:
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/mount_mcp_as_cli.cjs');
+ await main();
+ - name: Clean credentials
+ continue-on-error: true
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/clean_git_credentials.sh"
+ - name: Audit pre-agent workspace
+ id: pre_agent_audit
+ continue-on-error: true
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/audit_pre_agent_workspace.sh"
+ - name: Execute GitHub Copilot CLI
+ id: agentic_execution
+ # Copilot CLI tool arguments (sorted):
+ timeout-minutes: 60
+ run: |
+ set -o pipefail
+ printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt
+ touch /tmp/gh-aw/agent-step-summary.md
+ GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
+ export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
+ (umask 177 && touch /tmp/gh-aw/agent-stdio.log)
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["*.githubusercontent.com","api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","codeload.github.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","docs.github.com","github-cloud.githubusercontent.com","github-cloud.s3.amazonaws.com","github.blog","github.com","github.githubassets.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","lfs.github.com","objects.githubusercontent.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","patch-diff.githubusercontent.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5.3","gemini-pro","any"],"antigravity":["copilot/antigravity*","google/antigravity*","gemini/antigravity*"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"claude":["agent"],"codex":["agent"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"computer-use":["copilot/*computer-use*","google/*computer-use*","gemini/*computer-use*","openai/*computer-use*"],"copilot":["agent"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent"],"gemini-3-flash":["copilot/gemini-3*flash*","google/gemini-3*flash*","gemini/gemini-3*flash*"],"gemini-3-pro":["copilot/gemini-3*pro*","google/gemini-3*pro*","gemini/gemini-3*pro*"],"gemini-3.1-flash":["copilot/gemini-3.1*flash*","google/gemini-3.1*flash*","gemini/gemini-3.1*flash*"],"gemini-3.1-pro":["copilot/gemini-3.1*pro*","google/gemini-3.1*pro*","gemini/gemini-3.1*pro*"],"gemini-3.5-flash":["copilot/gemini-3.5*flash*","google/gemini-3.5*flash*","gemini/gemini-3.5*flash*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"gpt-5.2":["copilot/gpt-5.2*","openai/gpt-5.2*"],"gpt-5.3":["copilot/gpt-5.3*","openai/gpt-5.3*"],"gpt-5.4":["copilot/gpt-5.4*","openai/gpt-5.4*"],"gpt-5.5":["copilot/gpt-5.5*","openai/gpt-5.5*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"opusplan":["opus?effort=high"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"robotics":["copilot/*robotics*","google/*robotics*","gemini/*robotics*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4-5-*","anthropic/*sonnet-4-5-*","copilot/*sonnet-4-6*","anthropic/*sonnet-4-6*"],"summarization":["haiku","gpt-5-mini","gemini-flash-lite","mini"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
+ if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
+ GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
+ fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
+ # shellcheck disable=SC1003
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
+ env:
+ AWF_REFLECT_ENABLED: 1
+ COPILOT_AGENT_RUNNER_TYPE: STANDALONE
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
+ GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json
+ GH_AW_PHASE: agent
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
+ GH_AW_VERSION: v0.77.5
+ GITHUB_API_URL: ${{ github.api_url }}
+ GITHUB_AW: true
+ GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
+ GITHUB_HEAD_REF: ${{ github.head_ref }}
+ GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ GITHUB_REF_NAME: ${{ github.ref_name }}
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md
+ GITHUB_WORKSPACE: ${{ github.workspace }}
+ GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
+ GIT_AUTHOR_NAME: github-actions[bot]
+ GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
+ GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
+ XDG_CONFIG_HOME: /home/runner
+ - name: Detect agent errors
+ if: always()
+ id: detect-agent-errors
+ continue-on-error: true
+ run: node "${RUNNER_TEMP}/gh-aw/actions/detect_agent_errors.cjs"
+ - name: Configure Git credentials
+ env:
+ REPO_NAME: ${{ github.repository }}
+ SERVER_URL: ${{ github.server_url }}
+ GITHUB_TOKEN: ${{ github.token }}
+ run: |
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
+ git config --global user.name "github-actions[bot]"
+ git config --global am.keepcr true
+ # Re-authenticate git with GitHub token
+ SERVER_URL_STRIPPED="${SERVER_URL#https://}"
+ git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
+ echo "Git configured with standard GitHub Actions identity"
+ - name: Copy Copilot session state files to logs
+ if: always()
+ continue-on-error: true
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/copy_copilot_session_state.sh"
+ - name: Stop MCP Gateway
+ if: always()
+ continue-on-error: true
+ env:
+ MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }}
+ MCP_GATEWAY_API_KEY: ${{ steps.start-mcp-gateway.outputs.gateway-api-key }}
+ GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }}
+ run: |
+ bash "${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh" "$GATEWAY_PID"
+ - name: Redact secrets in logs
+ if: always()
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ with:
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/redact_secrets.cjs');
+ await main();
+ env:
+ GH_AW_SECRET_NAMES: 'COPILOT_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN'
+ SECRET_COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
+ SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }}
+ SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }}
+ SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: Append agent step summary
+ if: always()
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/append_agent_step_summary.sh"
+ - name: Copy Safe Outputs
+ if: always()
+ env:
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
+ run: |
+ mkdir -p /tmp/gh-aw
+ cp "$GH_AW_SAFE_OUTPUTS" /tmp/gh-aw/safeoutputs.jsonl 2>/dev/null || true
+ - name: Ingest agent output
+ id: collect_output
+ if: always()
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
+ GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_API_URL: ${{ github.api_url }}
+ with:
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/collect_ndjson_output.cjs');
+ await main();
+ - name: Parse agent logs for step summary
+ if: always()
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ GH_AW_AGENT_OUTPUT: /tmp/gh-aw/sandbox/agent/logs/
+ with:
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_copilot_log.cjs');
+ await main();
+ - name: Parse MCP Gateway logs for step summary
+ if: always()
+ id: parse-mcp-gateway
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ with:
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_mcp_gateway_log.cjs');
+ await main();
+ - name: Print firewall logs
+ if: always()
+ continue-on-error: true
+ env:
+ AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs
+ run: |
+ # Fix permissions on firewall logs/audit dirs so they can be uploaded as artifacts
+ # AWF runs with sudo, creating files owned by root
+ sudo chmod -R a+rX /tmp/gh-aw/sandbox/firewall 2>/dev/null || true
+ # Only run awf logs summary if awf command exists (it may not be installed if workflow failed before install step)
+ if command -v awf &> /dev/null; then
+ awf logs summary | tee -a "$GITHUB_STEP_SUMMARY"
+ else
+ echo 'AWF binary not installed, skipping firewall log summary'
+ fi
+ - name: Parse token usage for step summary
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ with:
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_token_usage.cjs');
+ await main();
+ - name: Print AWF reflect summary
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ with:
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/awf_reflect_summary.cjs');
+ await main();
+ - name: Write agent output placeholder if missing
+ if: always()
+ run: |
+ if [ ! -f /tmp/gh-aw/agent_output.json ]; then
+ echo '{"items":[]}' > /tmp/gh-aw/agent_output.json
+ fi
+ - name: Upload agent artifacts
+ if: always()
+ continue-on-error: true
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ with:
+ name: agent
+ path: |
+ /tmp/gh-aw/aw-prompts/prompt.txt
+ /tmp/gh-aw/sandbox/agent/logs/
+ /tmp/gh-aw/redacted-urls.log
+ /tmp/gh-aw/mcp-logs/
+ /tmp/gh-aw/agent_usage.json
+ /tmp/gh-aw/agent-stdio.log
+ /tmp/gh-aw/pre-agent-audit.txt
+ /tmp/gh-aw/agent/
+ /tmp/gh-aw/github_rate_limits.jsonl
+ /tmp/gh-aw/safeoutputs.jsonl
+ /tmp/gh-aw/agent_output.json
+ /tmp/gh-aw/aw-*.patch
+ /tmp/gh-aw/aw-*.bundle
+ /tmp/gh-aw/awf-config.json
+ /tmp/gh-aw/sandbox/firewall/logs/
+ /tmp/gh-aw/sandbox/firewall/audit/
+ /tmp/gh-aw/sandbox/firewall/awf-reflect.json
+ if-no-files-found: ignore
+
+ conclusion:
+ needs:
+ - activation
+ - agent
+ - detection
+ - safe_outputs
+ if: >
+ always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true' ||
+ needs.activation.outputs.stale_lock_file_failed == 'true')
+ runs-on: ubuntu-slim
+ permissions:
+ contents: write
+ discussions: write
+ issues: write
+ pull-requests: write
+ concurrency:
+ group: "gh-aw-conclusion-java-adapt-handwritten-code-to-accept-upgrade-changes"
+ cancel-in-progress: false
+ queue: max
+ outputs:
+ incomplete_count: ${{ steps.report_incomplete.outputs.incomplete_count }}
+ noop_message: ${{ steps.noop.outputs.noop_message }}
+ tools_reported: ${{ steps.missing_tool.outputs.tools_reported }}
+ total_count: ${{ steps.missing_tool.outputs.total_count }}
+ steps:
+ - name: Setup Scripts
+ id: setup
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
+ with:
+ destination: ${{ runner.temp }}/gh-aw/actions
+ job-name: ${{ github.job }}
+ trace-id: ${{ needs.activation.outputs.setup-trace-id }}
+ parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }}
+ env:
+ GH_AW_SETUP_WORKFLOW_NAME: "Java Handwritten Code Adaptation After CLI Upgrade"
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/java-adapt-handwritten-code-to-accept-upgrade-changes.lock.yml@${{ github.ref }}
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
+ GH_AW_INFO_ENGINE_ID: "copilot"
+ - name: Download agent output artifact
+ id: download-agent-output
+ continue-on-error: true
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ name: agent
+ path: /tmp/gh-aw/
+ - name: Setup agent output environment variable
+ id: setup-agent-output-env
+ if: steps.download-agent-output.outcome == 'success'
+ run: |
+ mkdir -p /tmp/gh-aw/
+ find "/tmp/gh-aw/" -type f -print
+ echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
+ - name: Process no-op messages
+ id: noop
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
+ GH_AW_NOOP_MAX: "1"
+ GH_AW_WORKFLOW_NAME: "Java Handwritten Code Adaptation After CLI Upgrade"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/java-adapt-handwritten-code-to-accept-upgrade-changes.md"
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
+ GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
+ GH_AW_NOOP_REPORT_AS_ISSUE: "false"
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_noop_message.cjs');
+ await main();
+ - name: Log detection run
+ id: detection_runs
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
+ GH_AW_WORKFLOW_NAME: "Java Handwritten Code Adaptation After CLI Upgrade"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/java-adapt-handwritten-code-to-accept-upgrade-changes.md"
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
+ GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
+ GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_detection_runs.cjs');
+ await main();
+ - name: Record missing tool
+ id: missing_tool
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
+ GH_AW_MISSING_TOOL_CREATE_ISSUE: "true"
+ GH_AW_WORKFLOW_NAME: "Java Handwritten Code Adaptation After CLI Upgrade"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/java-adapt-handwritten-code-to-accept-upgrade-changes.md"
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/missing_tool.cjs');
+ await main();
+ - name: Record incomplete
+ id: report_incomplete
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
+ GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true"
+ GH_AW_WORKFLOW_NAME: "Java Handwritten Code Adaptation After CLI Upgrade"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/java-adapt-handwritten-code-to-accept-upgrade-changes.md"
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/report_incomplete_handler.cjs');
+ await main();
+ - name: Handle agent failure
+ id: handle_agent_failure
+ if: always()
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
+ GH_AW_WORKFLOW_NAME: "Java Handwritten Code Adaptation After CLI Upgrade"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/java-adapt-handwritten-code-to-accept-upgrade-changes.md"
+ GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
+ GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
+ GH_AW_WORKFLOW_ID: "java-adapt-handwritten-code-to-accept-upgrade-changes"
+ GH_AW_ACTION_FAILURE_ISSUE_EXPIRES_HOURS: "168"
+ GH_AW_ENGINE_ID: "copilot"
+ GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }}
+ GH_AW_CHECKOUT_PR_SUCCESS: ${{ needs.agent.outputs.checkout_pr_success }}
+ GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens || '' }}
+ GH_AW_EFFECTIVE_TOKENS_RATE_LIMIT_ERROR: ${{ needs.agent.outputs.effective_tokens_rate_limit_error || 'false' }}
+ GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }}
+ GH_AW_MCP_POLICY_ERROR: ${{ needs.agent.outputs.mcp_policy_error }}
+ GH_AW_AGENTIC_ENGINE_TIMEOUT: ${{ needs.agent.outputs.agentic_engine_timeout }}
+ GH_AW_MODEL_NOT_SUPPORTED_ERROR: ${{ needs.agent.outputs.model_not_supported_error }}
+ GH_AW_ENGINE_API_HOSTS: "api.enterprise.githubcopilot.com,api.githubcopilot.com,api.business.githubcopilot.com,api.individual.githubcopilot.com"
+ GH_AW_CODE_PUSH_FAILURE_ERRORS: ${{ needs.safe_outputs.outputs.code_push_failure_errors }}
+ GH_AW_CODE_PUSH_FAILURE_COUNT: ${{ needs.safe_outputs.outputs.code_push_failure_count }}
+ GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }}
+ GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }}
+ GH_AW_GROUP_REPORTS: "false"
+ GH_AW_FAILURE_REPORT_AS_ISSUE: "true"
+ GH_AW_MISSING_TOOL_REPORT_AS_FAILURE: "true"
+ GH_AW_MISSING_DATA_REPORT_AS_FAILURE: "true"
+ GH_AW_TIMEOUT_MINUTES: "60"
+ GH_AW_MAX_EFFECTIVE_TOKENS: "25000000"
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/handle_agent_failure.cjs');
+ await main();
+
+ detection:
+ needs:
+ - activation
+ - agent
+ if: >
+ always() && needs.agent.result != 'skipped' && (needs.agent.outputs.output_types != '' || needs.agent.outputs.has_patch == 'true')
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ outputs:
+ detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }}
+ detection_reason: ${{ steps.detection_conclusion.outputs.reason }}
+ detection_success: ${{ steps.detection_conclusion.outputs.success }}
+ steps:
+ - name: Setup Scripts
+ id: setup
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
+ with:
+ destination: ${{ runner.temp }}/gh-aw/actions
+ job-name: ${{ github.job }}
+ trace-id: ${{ needs.activation.outputs.setup-trace-id }}
+ parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }}
+ env:
+ GH_AW_SETUP_WORKFLOW_NAME: "Java Handwritten Code Adaptation After CLI Upgrade"
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/java-adapt-handwritten-code-to-accept-upgrade-changes.lock.yml@${{ github.ref }}
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
+ GH_AW_INFO_ENGINE_ID: "copilot"
+ - name: Download agent output artifact
+ id: download-agent-output
+ continue-on-error: true
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ name: agent
+ path: /tmp/gh-aw/
+ - name: Setup agent output environment variable
+ id: setup-agent-output-env
+ if: steps.download-agent-output.outcome == 'success'
+ run: |
+ mkdir -p /tmp/gh-aw/
+ find "/tmp/gh-aw/" -type f -print
+ echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
+ - name: Checkout repository for patch context
+ if: needs.agent.outputs.has_patch == 'true'
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ # --- Threat Detection ---
+ - name: Clean stale firewall files from agent artifact
+ run: |
+ rm -rf /tmp/gh-aw/sandbox/firewall/logs
+ rm -rf /tmp/gh-aw/sandbox/firewall/audit
+ - name: Download container images
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58
+ - name: Check if detection needed
+ id: detection_guard
+ if: always()
+ env:
+ OUTPUT_TYPES: ${{ needs.agent.outputs.output_types }}
+ HAS_PATCH: ${{ needs.agent.outputs.has_patch }}
+ run: |
+ if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then
+ echo "run_detection=true" >> "$GITHUB_OUTPUT"
+ echo "Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH"
+ else
+ echo "run_detection=false" >> "$GITHUB_OUTPUT"
+ echo "Detection skipped: no agent outputs or patches to analyze"
+ fi
+ - name: Clear MCP Config for detection
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
+ run: |
+ rm -f "${RUNNER_TEMP}/gh-aw/mcp-config/mcp-servers.json"
+ rm -f /home/runner/.copilot/mcp-config.json
+ rm -f "$GITHUB_WORKSPACE/.gemini/settings.json"
+ - name: Prepare threat detection files
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
+ run: |
+ mkdir -p /tmp/gh-aw/threat-detection/aw-prompts
+ cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true
+ if [ ! -s /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt ]; then
+ echo "::warning::ERR_VALIDATION: Missing or empty detection context prompt at /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt. Ensure the agent artifact includes /tmp/gh-aw/aw-prompts/prompt.txt. Detection will continue with fallback workflow context."
+ fi
+ cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true
+ for f in /tmp/gh-aw/aw-*.patch; do
+ [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
+ done
+ for f in /tmp/gh-aw/aw-*.bundle; do
+ [ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
+ done
+ echo "Prepared threat detection files:"
+ ls -la /tmp/gh-aw/threat-detection/ 2>/dev/null || true
+ - name: Setup threat detection
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ WORKFLOW_NAME: "Java Handwritten Code Adaptation After CLI Upgrade"
+ WORKFLOW_DESCRIPTION: "Adapt handwritten Java SDK code to work with regenerated types after a\n@github/copilot version bump. Assumes codegen succeeded and generated code\ncompiles. Fixes handwritten source and tests only."
+ HAS_PATCH: ${{ needs.agent.outputs.has_patch }}
+ with:
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/setup_threat_detection.cjs');
+ await main();
+ - name: Ensure threat-detection directory and log
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
+ run: |
+ mkdir -p /tmp/gh-aw/threat-detection
+ touch /tmp/gh-aw/threat-detection/detection.log
+ - name: Setup Node.js
+ uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
+ with:
+ node-version: '24'
+ package-manager-cache: false
+ - name: Install GitHub Copilot CLI
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
+ env:
+ GH_HOST: github.com
+ - name: Install AWF binary
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
+ - name: Execute GitHub Copilot CLI
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
+ continue-on-error: true
+ id: detection_agentic_execution
+ # Copilot CLI tool arguments (sorted):
+ timeout-minutes: 20
+ run: |
+ set -o pipefail
+ printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt
+ touch /tmp/gh-aw/agent-step-summary.md
+ GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
+ export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
+ (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log)
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","registry.npmjs.org","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
+ if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
+ GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
+ fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
+ # shellcheck disable=SC1003
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
+ env:
+ AWF_REFLECT_ENABLED: 1
+ COPILOT_AGENT_RUNNER_TYPE: STANDALONE
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
+ COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
+ GH_AW_PHASE: detection
+ GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
+ GH_AW_VERSION: v0.77.5
+ GITHUB_API_URL: ${{ github.api_url }}
+ GITHUB_AW: true
+ GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
+ GITHUB_HEAD_REF: ${{ github.head_ref }}
+ GITHUB_REF_NAME: ${{ github.ref_name }}
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md
+ GITHUB_WORKSPACE: ${{ github.workspace }}
+ GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com
+ GIT_AUTHOR_NAME: github-actions[bot]
+ GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
+ GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
+ XDG_CONFIG_HOME: /home/runner
+ - name: Upload threat detection log
+ if: always() && steps.detection_guard.outputs.run_detection == 'true'
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ with:
+ name: detection
+ path: /tmp/gh-aw/threat-detection/detection.log
+ if-no-files-found: ignore
+ - name: Parse and conclude threat detection
+ id: detection_conclusion
+ if: always()
+ continue-on-error: true
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }}
+ DETECTION_AGENTIC_EXECUTION_OUTCOME: ${{ steps.detection_agentic_execution.outcome }}
+ GH_AW_DETECTION_CONTINUE_ON_ERROR: "true"
+ with:
+ script: |
+ try {
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/parse_threat_detection_results.cjs');
+ await main();
+ } catch (loadErr) {
+ const continueOnError = process.env.GH_AW_DETECTION_CONTINUE_ON_ERROR !== 'false';
+ const detectionExecutionFailed = process.env.DETECTION_AGENTIC_EXECUTION_OUTCOME === 'failure';
+ const msg = 'ERR_SYSTEM: \u274C Unexpected error loading threat detection module: ' + (loadErr && loadErr.message ? loadErr.message : String(loadErr));
+ core.error(msg);
+ core.setOutput('reason', 'parse_error');
+ if (continueOnError && !detectionExecutionFailed) {
+ core.warning('\u26A0\uFE0F ' + msg);
+ core.setOutput('conclusion', 'warning');
+ core.setOutput('success', 'false');
+ } else {
+ core.setOutput('conclusion', 'failure');
+ core.setOutput('success', 'false');
+ core.setFailed(msg);
+ }
+ }
+
+ safe_outputs:
+ needs:
+ - activation
+ - agent
+ - detection
+ if: (!cancelled()) && needs.agent.result != 'skipped' && needs.detection.result == 'success'
+ runs-on: ubuntu-slim
+ permissions:
+ contents: write
+ discussions: write
+ issues: write
+ pull-requests: write
+ timeout-minutes: 15
+ env:
+ GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/java-adapt-handwritten-code-to-accept-upgrade-changes"
+ GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
+ GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
+ GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }}
+ GH_AW_ENGINE_ID: "copilot"
+ GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
+ GH_AW_ENGINE_VERSION: "1.0.55"
+ GH_AW_WORKFLOW_ID: "java-adapt-handwritten-code-to-accept-upgrade-changes"
+ GH_AW_WORKFLOW_NAME: "Java Handwritten Code Adaptation After CLI Upgrade"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/java-adapt-handwritten-code-to-accept-upgrade-changes.md"
+ outputs:
+ code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}
+ code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}
+ comment_id: ${{ steps.process_safe_outputs.outputs.comment_id }}
+ comment_url: ${{ steps.process_safe_outputs.outputs.comment_url }}
+ create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }}
+ create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }}
+ process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }}
+ process_safe_outputs_temporary_id_map: ${{ steps.process_safe_outputs.outputs.temporary_id_map }}
+ push_commit_sha: ${{ steps.process_safe_outputs.outputs.push_commit_sha }}
+ push_commit_url: ${{ steps.process_safe_outputs.outputs.push_commit_url }}
+ steps:
+ - name: Setup Scripts
+ id: setup
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
+ with:
+ destination: ${{ runner.temp }}/gh-aw/actions
+ job-name: ${{ github.job }}
+ trace-id: ${{ needs.activation.outputs.setup-trace-id }}
+ parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }}
+ env:
+ GH_AW_SETUP_WORKFLOW_NAME: "Java Handwritten Code Adaptation After CLI Upgrade"
+ GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/java-adapt-handwritten-code-to-accept-upgrade-changes.lock.yml@${{ github.ref }}
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
+ GH_AW_INFO_ENGINE_ID: "copilot"
+ - name: Download agent output artifact
+ id: download-agent-output
+ continue-on-error: true
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ name: agent
+ path: /tmp/gh-aw/
+ - name: Setup agent output environment variable
+ id: setup-agent-output-env
+ if: steps.download-agent-output.outcome == 'success'
+ run: |
+ mkdir -p /tmp/gh-aw/
+ find "/tmp/gh-aw/" -type f -print
+ echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT"
+ - name: Download patch artifact
+ continue-on-error: true
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ name: agent
+ path: /tmp/gh-aw/
+ - name: Extract base branch from agent output
+ id: extract-base-branch
+ if: steps.download-agent-output.outcome == 'success'
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ with:
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/extract_base_branch_from_agent_output.cjs');
+ await main();
+ - name: Checkout repository (trusted default branch for comment events)
+ if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') && (github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment')
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ ref: ${{ github.event.repository.default_branch }}
+ token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ persist-credentials: false
+ fetch-depth: 1
+ - name: Checkout repository
+ if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') && github.event_name != 'issue_comment' && github.event_name != 'pull_request_review_comment'
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ ref: ${{ steps.extract-base-branch.outputs.base-branch || github.base_ref || github.event.pull_request.base.ref || github.ref_name || github.event.repository.default_branch }}
+ token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ persist-credentials: false
+ fetch-depth: 1
+ - name: Configure Git credentials
+ if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')
+ env:
+ REPO_NAME: ${{ github.repository }}
+ SERVER_URL: ${{ github.server_url }}
+ GIT_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ run: |
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
+ git config --global user.name "github-actions[bot]"
+ git config --global am.keepcr true
+ # Re-authenticate git with GitHub token
+ SERVER_URL_STRIPPED="${SERVER_URL#https://}"
+ git remote set-url origin "https://x-access-token:${GIT_TOKEN}@${SERVER_URL_STRIPPED}/${REPO_NAME}.git"
+ echo "Git configured with standard GitHub Actions identity"
+ - name: Configure GH_HOST for enterprise compatibility
+ id: ghes-host-config
+ shell: bash
+ run: |
+ # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct
+ # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op.
+ GH_HOST="${GITHUB_SERVER_URL#https://}"
+ GH_HOST="${GH_HOST#http://}"
+ echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV"
+ - name: Process Safe Outputs
+ id: process_safe_outputs
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
+ GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }}
+ GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
+ GITHUB_SERVER_URL: ${{ github.server_url }}
+ GITHUB_API_URL: ${{ github.api_url }}
+ GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":10,\"target\":\"*\"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"false\"},\"push_to_pull_request_branch\":{\"if_no_changes\":\"warn\",\"max_patch_size\":1024,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"required_labels\":[\"dependencies\",\"sdk/java\"],\"target\":\"*\"},\"report_incomplete\":{}}"
+ GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }}
+ with:
+ github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/safe_output_handler_manager.cjs');
+ await main();
+ - name: Upload Safe Outputs Items
+ if: always()
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ with:
+ name: safe-outputs-items
+ path: |
+ /tmp/gh-aw/safe-output-items.jsonl
+ /tmp/gh-aw/temporary-id-map.json
+ if-no-files-found: ignore
+
diff --git a/.github/workflows/java-adapt-handwritten-code-to-accept-upgrade-changes.md b/.github/workflows/java-adapt-handwritten-code-to-accept-upgrade-changes.md
new file mode 100644
index 000000000..dfd6eb3fa
--- /dev/null
+++ b/.github/workflows/java-adapt-handwritten-code-to-accept-upgrade-changes.md
@@ -0,0 +1,151 @@
+---
+description: |
+ Adapt handwritten Java SDK code to work with regenerated types after a
+ @github/copilot version bump. Assumes codegen succeeded and generated code
+ compiles. Fixes handwritten source and tests only.
+
+on:
+ workflow_dispatch:
+ inputs:
+ branch:
+ description: 'Branch containing the upgrade PR'
+ required: true
+ type: string
+ pr_number:
+ description: 'PR number to push fixes to'
+ required: true
+ type: string
+
+permissions:
+ contents: read
+ actions: read
+
+timeout-minutes: 60
+
+network:
+ allowed:
+ - defaults
+ - github
+
+tools:
+ github:
+ toolsets: [context, repos]
+
+safe-outputs:
+ push-to-pull-request-branch:
+ target: "*"
+ labels: [dependencies, sdk/java]
+ add-comment:
+ target: "*"
+ max: 10
+ noop:
+ report-as-issue: false
+---
+# Java Handwritten Code Adaptation After CLI Upgrade
+
+You are an automation agent that fixes handwritten Java SDK source and test code after a `@github/copilot` version bump has regenerated the typed schemas.
+
+## Assumptions
+
+- The branch `${{ inputs.branch }}` already has:
+ - Updated `java/scripts/codegen/package.json` with the new version
+ - Regenerated `java/src/generated/java/` code that compiles successfully
+ - Updated `java/.lastmerge` and POM property
+- Your job is ONLY to fix **handwritten** code, NOT generated code.
+
+## Boundaries
+
+- ❌ Do NOT edit anything under `java/src/generated/java/`
+- ❌ Do NOT edit `java/scripts/codegen/java.ts`
+- ❌ Do NOT create or modify tests in the `com.github.copilot.generated` test package (`java/src/test/java/com/github/copilot/sdk/generated/`)
+- ✅ DO edit `java/src/main/java/com/github/copilot/sdk/**`
+- ✅ DO edit `java/src/test/java/com/github/copilot/sdk/**` (excluding the `generated` subpackage)
+- ✅ DO add new test methods or test classes if new user-facing API surface is introduced
+
+## Instructions
+
+### Step 0: Setup
+
+```bash
+git checkout "${{ inputs.branch }}"
+git pull origin "${{ inputs.branch }}"
+```
+
+Verify Java environment:
+```bash
+java -version
+mvn --version
+node --version
+```
+
+### Step 1: Reproduce failures
+
+```bash
+cd java
+mvn clean test-compile jar:jar
+mvn verify -Dskip.test.harness=true 2>&1 | tee /tmp/mvn-verify.log
+```
+
+If `mvn verify` succeeds (exit code 0), call `noop` with message "All tests pass on branch ${{ inputs.branch }}. No handwritten fixes needed." and stop.
+
+### Step 2: Analyze compilation errors
+
+Read the build output. Common patterns after a schema bump:
+
+1. **Constructor arity mismatch** — A generated Java record gained new fields, changing its constructor signature. Fix: add `null` (or appropriate default) for new parameters at every call site.
+2. **Missing enum constants** — A generated enum gained new values that existing switch/if-else does not cover. Fix: add cases or ensure default handling.
+3. **Type changes** — A field type changed (e.g., `String` → enum, `double` → `Long`). Fix: update usages.
+4. **New event types** — New session event classes were generated. If `CopilotSession.java` or event handlers reference events by explicit type listing, add the new types.
+
+### Step 3: Fix compilation errors
+
+Apply minimal targeted fixes:
+- Search for compilation errors referencing generated type names.
+- Update constructor calls to match new arity.
+- Update type references if renamed/moved.
+- Do NOT over-engineer — just make it compile.
+
+After each fix round, verify:
+```bash
+cd java && mvn compile -Pskip-test-harness
+```
+
+### Step 4: Fix test failures
+
+Once compilation passes, run tests:
+```bash
+cd java && mvn verify -Dskip.test.harness=true 2>&1 | tee /tmp/mvn-test.log
+```
+
+Fix failing assertions:
+- Update expected constructor arg counts in test utility calls.
+- Update expected enum values in assertions.
+- Add coverage for new public API if introduced (new getters, new config options).
+
+### Step 5: Format
+
+```bash
+cd java && mvn spotless:apply
+```
+
+### Step 6: Final validation
+
+```bash
+cd java
+mvn clean test-compile jar:jar
+mvn verify -Dskip.test.harness=true
+```
+
+If this passes, commit and push:
+```bash
+git add java/src/main/java java/src/test/java
+git commit -m "Fix handwritten Java code for @github/copilot schema changes
+
+Adapt constructor calls, enum references, and test assertions to match
+regenerated types after CLI version bump."
+git push origin "${{ inputs.branch }}"
+```
+
+Then add a comment to PR #${{ inputs.pr_number }} summarizing what was fixed.
+
+If after 3 full fix-compile-test cycles the build still fails, add a comment to the PR describing the remaining failures and stop.
diff --git a/.github/workflows/java-codegen-fix.lock.yml b/.github/workflows/java-codegen-fix.lock.yml
index 8c650044f..79d9505ec 100644
--- a/.github/workflows/java-codegen-fix.lock.yml
+++ b/.github/workflows/java-codegen-fix.lock.yml
@@ -1,5 +1,5 @@
-# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"af13eefc935af6393de806a9a4307707d3b51a8c0d96992a84383cd9be790d52","compiler_version":"v0.74.4","strict":true,"agent_id":"copilot"}
-# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"d3abfe96a194bce3a523ed2093ddedd5704cdf62","version":"v0.74.4"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.46"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.9","digest":"sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388"},{"image":"ghcr.io/github/github-mcp-server:v1.0.4"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]}
+# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"af13eefc935af6393de806a9a4307707d3b51a8c0d96992a84383cd9be790d52","body_hash":"fe41f8fe1c12cb585cfaefdd755f58d2a84410d9d819cd706a3192ce052e2545","compiler_version":"v0.77.5","strict":true,"agent_id":"copilot"}
+# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"3ea13c02d765410340d533515cb31a7eef2baaf0","version":"v0.77.5"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.58"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.22"},{"image":"ghcr.io/github/github-mcp-server:v1.1.0"},{"image":"node:lts-alpine","digest":"sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14","pinned_image":"node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14"}]}
# ___ _ _
# / _ \ | | (_)
# | |_| | __ _ ___ _ __ | |_ _ ___
@@ -14,7 +14,7 @@
# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
#
-# This file was automatically generated by gh-aw (v0.74.4). DO NOT EDIT.
+# This file was automatically generated by gh-aw (v0.77.5). DO NOT EDIT.
#
# To update this file, edit the corresponding .md file and run:
# gh aw compile
@@ -39,15 +39,15 @@
# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9)
# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
# - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
-# - github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+# - github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
#
# Container images used:
-# - ghcr.io/github/gh-aw-firewall/agent:0.25.46
-# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46
-# - ghcr.io/github/gh-aw-firewall/squid:0.25.46
-# - ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388
-# - ghcr.io/github/github-mcp-server:v1.0.4
-# - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+# - ghcr.io/github/gh-aw-firewall/agent:0.25.58
+# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58
+# - ghcr.io/github/gh-aw-firewall/squid:0.25.58
+# - ghcr.io/github/gh-aw-mcpg:v0.3.22
+# - ghcr.io/github/github-mcp-server:v1.1.0
+# - node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
name: "Java Codegen Agentic Fix"
on:
@@ -55,7 +55,7 @@ on:
inputs:
aw_context:
default: ""
- description: Agent caller context (used internally by Agentic Workflows).
+ description: "Agent caller context (used internally by Agentic Workflows)."
required: false
type: string
branch:
@@ -98,31 +98,32 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
env:
GH_AW_SETUP_WORKFLOW_NAME: "Java Codegen Agentic Fix"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/java-codegen-fix.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Generate agentic run info
id: generate_aw_info
env:
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI"
- GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
- GH_AW_INFO_VERSION: "1.0.48"
- GH_AW_INFO_AGENT_VERSION: "1.0.48"
- GH_AW_INFO_CLI_VERSION: "v0.74.4"
+ GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AGENT_VERSION: "1.0.55"
+ GH_AW_INFO_CLI_VERSION: "v0.77.5"
GH_AW_INFO_WORKFLOW_NAME: "Java Codegen Agentic Fix"
GH_AW_INFO_EXPERIMENTAL: "false"
GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
GH_AW_INFO_STAGED: "false"
GH_AW_INFO_ALLOWED_DOMAINS: '["defaults","github"]'
GH_AW_INFO_FIREWALL_ENABLED: "true"
- GH_AW_INFO_AWF_VERSION: "v0.25.46"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_AWMG_VERSION: ""
GH_AW_INFO_FIREWALL_TYPE: "squid"
GH_AW_COMPILED_STRICT: "true"
@@ -145,6 +146,7 @@ jobs:
sparse-checkout: |
.github
.agents
+ .antigravity
.claude
.codex
.crush
@@ -155,8 +157,8 @@ jobs:
fetch-depth: 1
- name: Save agent config folders for base branch restoration
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
# poutine:ignore untrusted_checkout_exec
run: bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh"
- name: Check workflow lock file
@@ -174,7 +176,7 @@ jobs:
- name: Check compile-agentic version
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
- GH_AW_COMPILED_VERSION: "v0.74.4"
+ GH_AW_COMPILED_VERSION: "v0.77.5"
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@@ -325,12 +327,14 @@ jobs:
include-hidden-files: true
path: |
/tmp/gh-aw/aw_info.json
+ /tmp/gh-aw/model_multipliers.json
/tmp/gh-aw/aw-prompts/prompt.txt
/tmp/gh-aw/aw-prompts/prompt-template.txt
/tmp/gh-aw/aw-prompts/prompt-import-tree.json
/tmp/gh-aw/github_rate_limits.jsonl
/tmp/gh-aw/base
/tmp/gh-aw/.github/agents
+ /tmp/gh-aw/.github/skills
if-no-files-found: ignore
retention-days: 1
@@ -348,15 +352,15 @@ jobs:
GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
GH_AW_WORKFLOW_ID_SANITIZED: javacodegenfix
outputs:
- agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }}
+ agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }}
checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }}
effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }}
has_patch: ${{ steps.collect_output.outputs.has_patch }}
- inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }}
- mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }}
+ inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }}
+ mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }}
model: ${{ needs.activation.outputs.model }}
- model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }}
+ model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }}
output: ${{ steps.collect_output.outputs.output }}
output_types: ${{ steps.collect_output.outputs.output_types }}
setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
@@ -365,7 +369,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -374,7 +378,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Java Codegen Agentic Fix"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/java-codegen-fix.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Set runtime paths
id: set-runtime-paths
@@ -422,11 +427,11 @@ jobs:
const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs');
await main();
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Determine automatic lockdown mode for GitHub MCP Server
id: determine-automatic-lockdown
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9)
@@ -445,23 +450,27 @@ jobs:
- name: Restore agent config folders from base branch
if: steps.checkout-pr.outcome == 'success'
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh"
- name: Restore inline sub-agents from activation artifact
env:
GH_AW_SUB_AGENT_DIR: ".github/agents"
GH_AW_SUB_AGENT_EXT: ".agent.md"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh"
+ - name: Restore inline skills from activation artifact
+ env:
+ GH_AW_SKILL_DIR: ".github/skills"
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh"
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46 ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388 ghcr.io/github/github-mcp-server:v1.0.4 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58 ghcr.io/github/gh-aw-mcpg:v0.3.22 ghcr.io/github/github-mcp-server:v1.1.0 node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
- name: Generate Safe Outputs Config
run: |
mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
mkdir -p /tmp/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_9547b36a6c2ad8b6_EOF'
- {"add_comment":{"max":5,"target":"*"},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"false"},"push_to_pull_request_branch":{"if_no_changes":"warn","labels":["dependencies"],"max_patch_size":1024,"protect_top_level_dot_folders":true,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","DESIGN.md","README.md","CONTRIBUTING.md","CHANGELOG.md","SECURITY.md","CODE_OF_CONDUCT.md","AGENTS.md","CLAUDE.md","GEMINI.md"],"target":"*"},"report_incomplete":{}}
+ {"add_comment":{"max":5,"target":"*"},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"false"},"push_to_pull_request_branch":{"if_no_changes":"warn","max_patch_size":1024,"protect_top_level_dot_folders":true,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","DESIGN.md","README.md","CONTRIBUTING.md","CHANGELOG.md","SECURITY.md","CODE_OF_CONDUCT.md","AGENTS.md","CLAUDE.md","GEMINI.md"],"required_labels":["dependencies"],"target":"*"},"report_incomplete":{}}
GH_AW_SAFE_OUTPUTS_CONFIG_9547b36a6c2ad8b6_EOF
- name: Generate Safe Outputs Tools
env:
@@ -672,7 +681,7 @@ jobs:
* ) DOCKER_SOCK_PATH=/var/run/docker.sock ;;
esac
DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0')
- export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.9'
+ export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.22'
mkdir -p /home/runner/.copilot
GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node)
@@ -681,7 +690,7 @@ jobs:
"mcpServers": {
"github": {
"type": "stdio",
- "container": "ghcr.io/github/github-mcp-server:v1.0.4",
+ "container": "ghcr.io/github/github-mcp-server:v1.1.0",
"env": {
"GITHUB_HOST": "\${GITHUB_SERVER_URL}",
"GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
@@ -749,26 +758,38 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/agent-stdio.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["*.githubusercontent.com","api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","codeload.github.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","docs.github.com","github-cloud.githubusercontent.com","github-cloud.s3.amazonaws.com","github.blog","github.com","github.githubassets.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","lfs.github.com","objects.githubusercontent.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"auto":["large"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["*.githubusercontent.com","api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","codeload.github.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","docs.github.com","github-cloud.githubusercontent.com","github-cloud.s3.amazonaws.com","github.blog","github.com","github.githubassets.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","lfs.github.com","objects.githubusercontent.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","patch-diff.githubusercontent.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5.3","gemini-pro","any"],"antigravity":["copilot/antigravity*","google/antigravity*","gemini/antigravity*"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"claude":["agent"],"codex":["agent"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"computer-use":["copilot/*computer-use*","google/*computer-use*","gemini/*computer-use*","openai/*computer-use*"],"copilot":["agent"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent"],"gemini-3-flash":["copilot/gemini-3*flash*","google/gemini-3*flash*","gemini/gemini-3*flash*"],"gemini-3-pro":["copilot/gemini-3*pro*","google/gemini-3*pro*","gemini/gemini-3*pro*"],"gemini-3.1-flash":["copilot/gemini-3.1*flash*","google/gemini-3.1*flash*","gemini/gemini-3.1*flash*"],"gemini-3.1-pro":["copilot/gemini-3.1*pro*","google/gemini-3.1*pro*","gemini/gemini-3.1*pro*"],"gemini-3.5-flash":["copilot/gemini-3.5*flash*","google/gemini-3.5*flash*","gemini/gemini-3.5*flash*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"gpt-5.2":["copilot/gpt-5.2*","openai/gpt-5.2*"],"gpt-5.3":["copilot/gpt-5.3*","openai/gpt-5.3*"],"gpt-5.4":["copilot/gpt-5.4*","openai/gpt-5.4*"],"gpt-5.5":["copilot/gpt-5.5*","openai/gpt-5.5*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"opusplan":["opus?effort=high"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"robotics":["copilot/*robotics*","google/*robotics*","gemini/*robotics*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4-5-*","anthropic/*sonnet-4-5-*","copilot/*sonnet-4-6*","anthropic/*sonnet-4-6*"],"summarization":["haiku","gpt-5-mini","gemini-flash-lite","mini"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json
GH_AW_PHASE: agent
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -782,12 +803,13 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- - name: Detect Copilot errors
- id: detect-copilot-errors
+ - name: Detect agent errors
if: always()
+ id: detect-agent-errors
continue-on-error: true
- run: node "${RUNNER_TEMP}/gh-aw/actions/detect_copilot_errors.cjs"
+ run: node "${RUNNER_TEMP}/gh-aw/actions/detect_agent_errors.cjs"
- name: Configure Git credentials
env:
REPO_NAME: ${{ github.repository }}
@@ -845,7 +867,7 @@ jobs:
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
- GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
+ GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_API_URL: ${{ github.api_url }}
with:
@@ -969,7 +991,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -978,7 +1000,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Java Codegen Agentic Fix"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/java-codegen-fix.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
id: download-agent-output
@@ -1001,6 +1024,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_NOOP_MAX: "1"
GH_AW_WORKFLOW_NAME: "Java Codegen Agentic Fix"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/java-codegen-fix.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_NOOP_REPORT_AS_ISSUE: "false"
@@ -1017,6 +1041,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Java Codegen Agentic Fix"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/java-codegen-fix.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
@@ -1034,6 +1059,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_MISSING_TOOL_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "Java Codegen Agentic Fix"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/java-codegen-fix.md"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1048,6 +1074,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "Java Codegen Agentic Fix"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/java-codegen-fix.md"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1062,6 +1089,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Java Codegen Agentic Fix"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/java-codegen-fix.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_WORKFLOW_ID: "java-codegen-fix"
@@ -1110,7 +1138,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1119,7 +1147,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Java Codegen Agentic Fix"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/java-codegen-fix.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
id: download-agent-output
@@ -1146,7 +1175,7 @@ jobs:
rm -rf /tmp/gh-aw/sandbox/firewall/logs
rm -rf /tmp/gh-aw/sandbox/firewall/audit
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58
- name: Check if detection needed
id: detection_guard
if: always()
@@ -1172,6 +1201,9 @@ jobs:
run: |
mkdir -p /tmp/gh-aw/threat-detection/aw-prompts
cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true
+ if [ ! -s /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt ]; then
+ echo "::warning::ERR_VALIDATION: Missing or empty detection context prompt at /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt. Ensure the agent artifact includes /tmp/gh-aw/aw-prompts/prompt.txt. Detection will continue with fallback workflow context."
+ fi
cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true
for f in /tmp/gh-aw/aw-*.patch; do
[ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
@@ -1205,11 +1237,11 @@ jobs:
node-version: '24'
package-manager-cache: false
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Execute GitHub Copilot CLI
if: always() && steps.detection_guard.outputs.run_detection == 'true'
continue-on-error: true
@@ -1222,24 +1254,36 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/threat-detection/detection.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","registry.npmjs.org","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_PHASE: detection
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -1252,6 +1296,7 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- name: Upload threat detection log
if: always() && steps.detection_guard.outputs.run_detection == 'true'
@@ -1313,9 +1358,10 @@ jobs:
GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }}
GH_AW_ENGINE_ID: "copilot"
GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
- GH_AW_ENGINE_VERSION: "1.0.48"
+ GH_AW_ENGINE_VERSION: "1.0.55"
GH_AW_WORKFLOW_ID: "java-codegen-fix"
GH_AW_WORKFLOW_NAME: "Java Codegen Agentic Fix"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/java-codegen-fix.md"
outputs:
code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}
code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}
@@ -1330,7 +1376,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1339,7 +1385,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Java Codegen Agentic Fix"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/java-codegen-fix.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
id: download-agent-output
@@ -1364,28 +1411,23 @@ jobs:
- name: Extract base branch from agent output
id: extract-base-branch
if: steps.download-agent-output.outcome == 'success'
- shell: bash
- run: |
- if [ -f "/tmp/gh-aw/agent_output.json" ]; then
- GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node)
- BASE_BRANCH=$("$GH_AW_NODE" -e "
- try {
- const data = JSON.parse(require('fs').readFileSync('/tmp/gh-aw/agent_output.json', 'utf8'));
- const item = (data.items || []).find(i =>
- (i.type === 'create_pull_request' || i.type === 'push_to_pull_request_branch') &&
- i.base_branch
- );
- if (item) process.stdout.write(item.base_branch);
- } catch(e) {}
- " 2>/dev/null || true)
- # Validate: only allow safe git branch name characters
- if [[ "$BASE_BRANCH" =~ ^[a-zA-Z0-9/_.-]+$ ]] && [ ${#BASE_BRANCH} -le 255 ]; then
- printf 'base-branch=%s\n' "$BASE_BRANCH" >> "$GITHUB_OUTPUT"
- echo "Extracted base branch from safe output: $BASE_BRANCH"
- fi
- fi
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ with:
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/extract_base_branch_from_agent_output.cjs');
+ await main();
+ - name: Checkout repository (trusted default branch for comment events)
+ if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') && (github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment')
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ ref: ${{ github.event.repository.default_branch }}
+ token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ persist-credentials: false
+ fetch-depth: 1
- name: Checkout repository
- if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch')
+ if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'push_to_pull_request_branch') && github.event_name != 'issue_comment' && github.event_name != 'pull_request_review_comment'
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ steps.extract-base-branch.outputs.base-branch || github.base_ref || github.event.pull_request.base.ref || github.ref_name || github.event.repository.default_branch }}
@@ -1420,10 +1462,11 @@ jobs:
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
- GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
+ GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }}
+ GH_AW_ALLOWED_DOMAINS: "*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,patch-diff.githubusercontent.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_API_URL: ${{ github.api_url }}
- GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":5,\"target\":\"*\"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"false\"},\"push_to_pull_request_branch\":{\"if_no_changes\":\"warn\",\"labels\":[\"dependencies\"],\"max_patch_size\":1024,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"target\":\"*\"},\"report_incomplete\":{}}"
+ GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":5,\"target\":\"*\"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"false\"},\"push_to_pull_request_branch\":{\"if_no_changes\":\"warn\",\"max_patch_size\":1024,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"required_labels\":[\"dependencies\"],\"target\":\"*\"},\"report_incomplete\":{}}"
GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }}
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/java-publish-maven.yml b/.github/workflows/java-publish-maven.yml
index 03c9136ab..e22cd05a5 100644
--- a/.github/workflows/java-publish-maven.yml
+++ b/.github/workflows/java-publish-maven.yml
@@ -32,8 +32,62 @@ concurrency:
cancel-in-progress: false
jobs:
+ preflight:
+ name: Preflight checks
+ runs-on: ubuntu-latest
+ steps:
+ - name: Verify JAVA_RELEASE_TOKEN can push to repository
+ run: |
+ # JAVA_RELEASE_TOKEN is used by actions/checkout and for:
+ # - git push origin main (doc updates)
+ # - mvn release:prepare -DpushChanges=true (release commits + tags)
+ # - git revert + push (rollback on failure)
+ # It must have push (contents:write) permission on this repo.
+ PUSH=$(gh api repos/${{ github.repository }} --jq '.permissions.push // false')
+ if [ "$PUSH" != "true" ]; then
+ echo "::error::JAVA_RELEASE_TOKEN lacks push permission on ${{ github.repository }}. It is required for pushing release commits and tags to main."
+ exit 1
+ fi
+ echo "JAVA_RELEASE_TOKEN push access OK"
+ env:
+ GITHUB_TOKEN: ${{ secrets.JAVA_RELEASE_TOKEN }}
+
+ - name: Verify JAVA_RELEASE_GITHUB_TOKEN can trigger workflows
+ run: |
+ # JAVA_RELEASE_GITHUB_TOKEN is used for:
+ # - gh workflow run release-changelog.lock.yml (requires actions:write)
+ # Check the token's OAuth scopes for 'workflow' (classic PAT) or
+ # attempt a workflow dispatch with a non-existent ref to verify write access
+ # (fine-grained PAT — these don't expose scopes via X-OAuth-Scopes).
+ SCOPES=$(gh api -i user 2>&1 | grep -i '^x-oauth-scopes:' | tr '[:upper:]' '[:lower:]' || true)
+ if echo "$SCOPES" | grep -q 'workflow'; then
+ echo "JAVA_RELEASE_GITHUB_TOKEN has 'workflow' scope (classic PAT)"
+ elif [ -z "$SCOPES" ]; then
+ # Fine-grained PAT: no X-OAuth-Scopes header returned.
+ # Attempt a workflow dispatch against a non-existent ref. If the token
+ # has actions:write, the API returns 422 (validation failed on ref).
+ # If it lacks the permission, the API returns 403.
+ HTTP_CODE=$(gh api -X POST \
+ "repos/${{ github.repository }}/actions/workflows/release-changelog.lock.yml/dispatches" \
+ -f ref="preflight-check-nonexistent-ref" \
+ -f 'inputs[tag]=preflight-check' \
+ --silent -i 2>&1 | head -1 | grep -oE '[0-9]{3}' || echo "000")
+ if [ "$HTTP_CODE" = "403" ] || [ "$HTTP_CODE" = "000" ]; then
+ echo "::error::JAVA_RELEASE_GITHUB_TOKEN lacks actions:write permission on ${{ github.repository }}. It cannot trigger the changelog generation workflow."
+ exit 1
+ fi
+ # 422 = has write access but ref doesn't exist (expected), 204 would mean it dispatched (shouldn't happen with fake ref)
+ echo "JAVA_RELEASE_GITHUB_TOKEN actions:write access OK (fine-grained PAT, dispatch returned HTTP ${HTTP_CODE})"
+ else
+ echo "::error::JAVA_RELEASE_GITHUB_TOKEN lacks 'workflow' scope. Found scopes: ${SCOPES}. It needs this scope to trigger changelog generation via gh workflow run."
+ exit 1
+ fi
+ env:
+ GITHUB_TOKEN: ${{ secrets.JAVA_RELEASE_GITHUB_TOKEN }}
+
publish-maven:
name: Publish Java SDK to Maven Central
+ needs: preflight
runs-on: ubuntu-latest
defaults:
run:
@@ -118,13 +172,16 @@ jobs:
run: |
VERSION="${{ steps.versions.outputs.release_version }}"
- # Update version in README.md (supports any version qualifier like -java.N, -java-preview.N, -beta-java.N)
+ # Update release version in README.md (supports any version qualifier like -java.N, -java-preview.N, -beta-java.N)
sed -i "s|[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\(-[a-z][a-z0-9-]*\.[0-9][0-9]*\)*|${VERSION}|g" README.md
sed -i "s|copilot-sdk-java:[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\(-[a-z][a-z0-9-]*\.[0-9][0-9]*\)*|copilot-sdk-java:${VERSION}|g" README.md
- # Update snapshot version in README.md
+ # Update snapshot versions in README.md (must run AFTER release version seds
+ # because the release copilot-sdk-java: pattern partially matches inside snapshot
+ # strings — the snapshot-specific seds override with the correct DEV_VERSION)
DEV_VERSION="${{ steps.versions.outputs.dev_version }}"
sed -i "s|[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\(-[a-z][a-z0-9-]*\.[0-9][0-9]*\)*-SNAPSHOT|${DEV_VERSION}|g" README.md
+ sed -i "s|copilot-sdk-java:[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\(-[a-z][a-z0-9-]*\.[0-9][0-9]*\)*-SNAPSHOT|copilot-sdk-java:${DEV_VERSION}|g" README.md
# Update version in jbang-example.java
sed -i "s|copilot-sdk-java:[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\(-[a-z][a-z0-9-]*\.[0-9][0-9]*\)*|copilot-sdk-java:${VERSION}|g" jbang-example.java
@@ -177,7 +234,7 @@ jobs:
github-release:
name: Create GitHub Release
- needs: publish-maven
+ needs: [preflight, publish-maven]
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
defaults:
@@ -233,3 +290,28 @@ jobs:
run: gh workflow run release-changelog.lock.yml -f tag="java/v${{ needs.publish-maven.outputs.version }}"
env:
GITHUB_TOKEN: ${{ secrets.JAVA_RELEASE_GITHUB_TOKEN }}
+
+ deploy-site:
+ name: Deploy Documentation Site
+ needs: [preflight, publish-maven, github-release]
+ if: github.ref == 'refs/heads/main'
+ runs-on: ubuntu-latest
+ steps:
+ - name: Trigger site deployment on standalone repo
+ run: |
+ VERSION="${{ needs.publish-maven.outputs.version }}"
+ TAG="java/v${VERSION}"
+ PUBLISH_AS_LATEST=true
+ if [ "${{ inputs.prerelease }}" = "true" ]; then
+ PUBLISH_AS_LATEST=false
+ fi
+ echo "Triggering site deployment for version ${VERSION} (tag: ${TAG})"
+ gh workflow run deploy-site.yml \
+ --repo github/copilot-sdk-java \
+ -f version="${VERSION}" \
+ -f publish_as_latest="${PUBLISH_AS_LATEST}" \
+ -f monorepo_tag="${TAG}"
+ echo "### Site Deployment" >> $GITHUB_STEP_SUMMARY
+ echo "Triggered deploy-site.yml on github/copilot-sdk-java for version ${VERSION}" >> $GITHUB_STEP_SUMMARY
+ env:
+ GITHUB_TOKEN: ${{ secrets.JAVA_RELEASE_GITHUB_TOKEN }}
diff --git a/.github/workflows/java-sdk-tests.yml b/.github/workflows/java-sdk-tests.yml
index f005226dc..20e66b41c 100644
--- a/.github/workflows/java-sdk-tests.yml
+++ b/.github/workflows/java-sdk-tests.yml
@@ -120,7 +120,7 @@ jobs:
- name: Generate JaCoCo badge
if: success() && github.ref == 'refs/heads/main' && matrix.test-jdk == '25'
working-directory: .
- run: .github/scripts/generate-java-coverage-badge.sh java/target/site/jacoco-coverage/jacoco.csv .github/badges
+ run: bash .github/scripts/generate-java-coverage-badge.sh java/target/site/jacoco-coverage/jacoco.csv .github/badges
- name: Create PR for JaCoCo badge update
if: success() && github.ref == 'refs/heads/main' && matrix.test-jdk == '25'
diff --git a/.github/workflows/java.notes.template b/.github/workflows/java.notes.template
index bec50a91b..e209a110b 100644
--- a/.github/workflows/java.notes.template
+++ b/.github/workflows/java.notes.template
@@ -1,11 +1,14 @@
+
+
# Installation
-ℹ️ **Public Preview:** This is the official Java SDK for GitHub Copilot. This repository treats the official .NET and Node.js SDKs for GitHub Copilot as reference implementations. These SDKs are all officially supported as GitHub open source projects. The Java implementation follows the backward compatibility guarantees offered by the reference implementations.
-
⚠️ **Artifact versioning plan:** Releases of this implementation track releases of the reference implementation. For each release of the reference implementation, there may follow a corresponding release of this implementation with the same number as the reference implementation. Release identifiers of the reference implementation are in the form `vMaj.Min.Micro`. For example v0.1.32. The corresponding maven version for the release will be `Maj.Min.Micro-java.N`, where `Maj`, `Min` and `Micro` are the corresponding numbers for the reference implementation release, and `N` is a monotonically increasing sequence number starting with 0 for each release. See the corresponding architectural decision record for more information in the `docs/adr` directory of the source code.
-
+
📦 [View on Maven Central](https://central.sonatype.com/artifact/${GROUP_ID}/${ARTIFACT_ID}/${VERSION})
+📖 [Documentation](https://github.github.io/copilot-sdk-java/${VERSION}/) · [Javadoc](https://github.github.io/copilot-sdk-java/${VERSION}/apidocs/index.html)
+
+
## Maven
```xml
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index a93bec32f..6a92a112f 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -59,10 +59,13 @@ jobs:
if [ -n "${{ github.event.inputs.version }}" ]; then
VERSION="${{ github.event.inputs.version }}"
# Validate version format matches dist-tag
- # TEMPORARY: skips validation for "latest" so prerelease versions
- # can be published under that tag. To ship stable 1.0.0, revert the
- # commit that introduced this temporary change.
- if [ "${{ github.event.inputs.dist-tag }}" != "latest" ]; then
+ if [ "${{ github.event.inputs.dist-tag }}" = "latest" ]; then
+ if [[ "$VERSION" == *-* ]]; then
+ echo "❌ Error: Version '$VERSION' has a prerelease suffix but dist-tag is 'latest'" >> $GITHUB_STEP_SUMMARY
+ echo "Use a version without suffix (e.g., '1.0.0') for latest releases"
+ exit 1
+ fi
+ else
if [[ "$VERSION" != *-* ]]; then
echo "❌ Error: Version '$VERSION' has no prerelease suffix but dist-tag is '${{ github.event.inputs.dist-tag }}'" >> $GITHUB_STEP_SUMMARY
echo "Use a version with suffix (e.g., '1.0.0-preview.0') for prerelease/unstable"
@@ -231,11 +234,21 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
- # TEMPORARY: both "latest" and "prerelease" create GitHub pre-releases
- # since "latest" publishes beta versions. To ship stable 1.0.0, revert
- # the commit that introduced this temporary change.
- name: Create GitHub Release
- if: github.event.inputs.dist-tag == 'latest' || github.event.inputs.dist-tag == 'prerelease'
+ if: github.event.inputs.dist-tag == 'latest'
+ run: |
+ NOTES_FLAG=""
+ if git rev-parse "v${{ needs.version.outputs.current }}" >/dev/null 2>&1; then
+ NOTES_FLAG="--notes-start-tag v${{ needs.version.outputs.current }}"
+ fi
+ gh release create "v${{ needs.version.outputs.version }}" \
+ --title "v${{ needs.version.outputs.version }}" \
+ --generate-notes $NOTES_FLAG \
+ --target ${{ github.sha }}
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: Create GitHub Pre-Release
+ if: github.event.inputs.dist-tag == 'prerelease'
run: |
NOTES_FLAG=""
if git rev-parse "v${{ needs.version.outputs.current-prerelease }}" >/dev/null 2>&1; then
diff --git a/.github/workflows/release-changelog.lock.yml b/.github/workflows/release-changelog.lock.yml
index 98cf18dc3..4e8adbc0c 100644
--- a/.github/workflows/release-changelog.lock.yml
+++ b/.github/workflows/release-changelog.lock.yml
@@ -1,5 +1,5 @@
-# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"f56148e477b1349cf894dd5ee148dae8af3a90ab64cf708a41697d2c13b2da4b","compiler_version":"v0.74.4","strict":true,"agent_id":"copilot"}
-# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"d3abfe96a194bce3a523ed2093ddedd5704cdf62","version":"v0.74.4"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.46"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.9","digest":"sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388"},{"image":"ghcr.io/github/github-mcp-server:v1.0.4"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]}
+# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"f56148e477b1349cf894dd5ee148dae8af3a90ab64cf708a41697d2c13b2da4b","body_hash":"89e26ed929f440bd6af57d1da92b06dbf1739b4a1d34b9923286919d00f272d1","compiler_version":"v0.77.5","strict":true,"agent_id":"copilot"}
+# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"3ea13c02d765410340d533515cb31a7eef2baaf0","version":"v0.77.5"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.58"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.22"},{"image":"ghcr.io/github/github-mcp-server:v1.1.0"},{"image":"node:lts-alpine","digest":"sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14","pinned_image":"node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14"}]}
# ___ _ _
# / _ \ | | (_)
# | |_| | __ _ ___ _ __ | |_ _ ___
@@ -14,7 +14,7 @@
# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
#
-# This file was automatically generated by gh-aw (v0.74.4). DO NOT EDIT.
+# This file was automatically generated by gh-aw (v0.77.5). DO NOT EDIT.
#
# To update this file, edit the corresponding .md file and run:
# gh aw compile
@@ -38,15 +38,15 @@
# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9)
# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
# - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
-# - github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+# - github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
#
# Container images used:
-# - ghcr.io/github/gh-aw-firewall/agent:0.25.46
-# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46
-# - ghcr.io/github/gh-aw-firewall/squid:0.25.46
-# - ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388
-# - ghcr.io/github/github-mcp-server:v1.0.4
-# - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+# - ghcr.io/github/gh-aw-firewall/agent:0.25.58
+# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58
+# - ghcr.io/github/gh-aw-firewall/squid:0.25.58
+# - ghcr.io/github/gh-aw-mcpg:v0.3.22
+# - ghcr.io/github/github-mcp-server:v1.1.0
+# - node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
name: "Release Changelog Generator"
on:
@@ -54,7 +54,7 @@ on:
inputs:
aw_context:
default: ""
- description: Agent caller context (used internally by Agentic Workflows).
+ description: "Agent caller context (used internally by Agentic Workflows)."
required: false
type: string
tag:
@@ -89,31 +89,32 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
env:
GH_AW_SETUP_WORKFLOW_NAME: "Release Changelog Generator"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/release-changelog.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Generate agentic run info
id: generate_aw_info
env:
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI"
- GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
- GH_AW_INFO_VERSION: "1.0.48"
- GH_AW_INFO_AGENT_VERSION: "1.0.48"
- GH_AW_INFO_CLI_VERSION: "v0.74.4"
+ GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AGENT_VERSION: "1.0.55"
+ GH_AW_INFO_CLI_VERSION: "v0.77.5"
GH_AW_INFO_WORKFLOW_NAME: "Release Changelog Generator"
GH_AW_INFO_EXPERIMENTAL: "false"
GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
GH_AW_INFO_STAGED: "false"
GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]'
GH_AW_INFO_FIREWALL_ENABLED: "true"
- GH_AW_INFO_AWF_VERSION: "v0.25.46"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_AWMG_VERSION: ""
GH_AW_INFO_FIREWALL_TYPE: "squid"
GH_AW_COMPILED_STRICT: "true"
@@ -136,6 +137,7 @@ jobs:
sparse-checkout: |
.github
.agents
+ .antigravity
.claude
.codex
.crush
@@ -146,8 +148,8 @@ jobs:
fetch-depth: 1
- name: Save agent config folders for base branch restoration
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
# poutine:ignore untrusted_checkout_exec
run: bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh"
- name: Check workflow lock file
@@ -165,7 +167,7 @@ jobs:
- name: Check compile-agentic version
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
- GH_AW_COMPILED_VERSION: "v0.74.4"
+ GH_AW_COMPILED_VERSION: "v0.77.5"
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@@ -309,12 +311,14 @@ jobs:
include-hidden-files: true
path: |
/tmp/gh-aw/aw_info.json
+ /tmp/gh-aw/model_multipliers.json
/tmp/gh-aw/aw-prompts/prompt.txt
/tmp/gh-aw/aw-prompts/prompt-template.txt
/tmp/gh-aw/aw-prompts/prompt-import-tree.json
/tmp/gh-aw/github_rate_limits.jsonl
/tmp/gh-aw/base
/tmp/gh-aw/.github/agents
+ /tmp/gh-aw/.github/skills
if-no-files-found: ignore
retention-days: 1
@@ -334,15 +338,15 @@ jobs:
GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
GH_AW_WORKFLOW_ID_SANITIZED: releasechangelog
outputs:
- agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }}
+ agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }}
checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }}
effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }}
has_patch: ${{ steps.collect_output.outputs.has_patch }}
- inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }}
- mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }}
+ inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }}
+ mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }}
model: ${{ needs.activation.outputs.model }}
- model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }}
+ model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }}
output: ${{ steps.collect_output.outputs.output }}
output_types: ${{ steps.collect_output.outputs.output_types }}
setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
@@ -351,7 +355,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -360,7 +364,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Release Changelog Generator"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/release-changelog.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Set runtime paths
id: set-runtime-paths
@@ -408,11 +413,11 @@ jobs:
const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs');
await main();
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Determine automatic lockdown mode for GitHub MCP Server
id: determine-automatic-lockdown
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9)
@@ -431,23 +436,27 @@ jobs:
- name: Restore agent config folders from base branch
if: steps.checkout-pr.outcome == 'success'
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh"
- name: Restore inline sub-agents from activation artifact
env:
GH_AW_SUB_AGENT_DIR: ".github/agents"
GH_AW_SUB_AGENT_EXT: ".agent.md"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh"
+ - name: Restore inline skills from activation artifact
+ env:
+ GH_AW_SKILL_DIR: ".github/skills"
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh"
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46 ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388 ghcr.io/github/github-mcp-server:v1.0.4 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58 ghcr.io/github/gh-aw-mcpg:v0.3.22 ghcr.io/github/github-mcp-server:v1.1.0 node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
- name: Generate Safe Outputs Config
run: |
mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
mkdir -p /tmp/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_6e92a7a47fdc567f_EOF'
- {"create_pull_request":{"draft":false,"labels":["automation","changelog"],"max":1,"max_patch_files":100,"max_patch_size":1024,"protect_top_level_dot_folders":true,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","DESIGN.md","README.md","CONTRIBUTING.md","CHANGELOG.md","SECURITY.md","CODE_OF_CONDUCT.md","AGENTS.md","CLAUDE.md","GEMINI.md"],"title_prefix":"[changelog] "},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{},"update_release":{"max":1}}
+ {"create_pull_request":{"draft":false,"labels":["automation","changelog"],"max":1,"max_patch_files":100,"max_patch_size":1024,"protect_top_level_dot_folders":true,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","DESIGN.md","README.md","CONTRIBUTING.md","CHANGELOG.md","SECURITY.md","CODE_OF_CONDUCT.md","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_files_policy":"request_review","title_prefix":"[changelog] "},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{},"update_release":{"max":1}}
GH_AW_SAFE_OUTPUTS_CONFIG_6e92a7a47fdc567f_EOF
- name: Generate Safe Outputs Tools
env:
@@ -683,7 +692,7 @@ jobs:
* ) DOCKER_SOCK_PATH=/var/run/docker.sock ;;
esac
DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0')
- export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.9'
+ export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.22'
mkdir -p /home/runner/.copilot
GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node)
@@ -692,7 +701,7 @@ jobs:
"mcpServers": {
"github": {
"type": "stdio",
- "container": "ghcr.io/github/github-mcp-server:v1.0.4",
+ "container": "ghcr.io/github/github-mcp-server:v1.1.0",
"env": {
"GITHUB_HOST": "\${GITHUB_SERVER_URL}",
"GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
@@ -760,26 +769,38 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/agent-stdio.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"auto":["large"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5.3","gemini-pro","any"],"antigravity":["copilot/antigravity*","google/antigravity*","gemini/antigravity*"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"claude":["agent"],"codex":["agent"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"computer-use":["copilot/*computer-use*","google/*computer-use*","gemini/*computer-use*","openai/*computer-use*"],"copilot":["agent"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent"],"gemini-3-flash":["copilot/gemini-3*flash*","google/gemini-3*flash*","gemini/gemini-3*flash*"],"gemini-3-pro":["copilot/gemini-3*pro*","google/gemini-3*pro*","gemini/gemini-3*pro*"],"gemini-3.1-flash":["copilot/gemini-3.1*flash*","google/gemini-3.1*flash*","gemini/gemini-3.1*flash*"],"gemini-3.1-pro":["copilot/gemini-3.1*pro*","google/gemini-3.1*pro*","gemini/gemini-3.1*pro*"],"gemini-3.5-flash":["copilot/gemini-3.5*flash*","google/gemini-3.5*flash*","gemini/gemini-3.5*flash*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"gpt-5.2":["copilot/gpt-5.2*","openai/gpt-5.2*"],"gpt-5.3":["copilot/gpt-5.3*","openai/gpt-5.3*"],"gpt-5.4":["copilot/gpt-5.4*","openai/gpt-5.4*"],"gpt-5.5":["copilot/gpt-5.5*","openai/gpt-5.5*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"opusplan":["opus?effort=high"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"robotics":["copilot/*robotics*","google/*robotics*","gemini/*robotics*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4-5-*","anthropic/*sonnet-4-5-*","copilot/*sonnet-4-6*","anthropic/*sonnet-4-6*"],"summarization":["haiku","gpt-5-mini","gemini-flash-lite","mini"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json
GH_AW_PHASE: agent
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -793,12 +814,13 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- - name: Detect Copilot errors
- id: detect-copilot-errors
+ - name: Detect agent errors
if: always()
+ id: detect-agent-errors
continue-on-error: true
- run: node "${RUNNER_TEMP}/gh-aw/actions/detect_copilot_errors.cjs"
+ run: node "${RUNNER_TEMP}/gh-aw/actions/detect_agent_errors.cjs"
- name: Configure Git credentials
env:
REPO_NAME: ${{ github.repository }}
@@ -979,7 +1001,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -988,7 +1010,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Release Changelog Generator"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/release-changelog.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
id: download-agent-output
@@ -1011,6 +1034,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_NOOP_MAX: "1"
GH_AW_WORKFLOW_NAME: "Release Changelog Generator"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/release-changelog.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_NOOP_REPORT_AS_ISSUE: "true"
@@ -1027,6 +1051,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Release Changelog Generator"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/release-changelog.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }}
@@ -1044,6 +1069,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_MISSING_TOOL_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "Release Changelog Generator"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/release-changelog.md"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1058,6 +1084,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "Release Changelog Generator"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/release-changelog.md"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
script: |
@@ -1072,6 +1099,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "Release Changelog Generator"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/release-changelog.md"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
GH_AW_WORKFLOW_ID: "release-changelog"
@@ -1120,7 +1148,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1129,7 +1157,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Release Changelog Generator"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/release-changelog.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
id: download-agent-output
@@ -1156,7 +1185,7 @@ jobs:
rm -rf /tmp/gh-aw/sandbox/firewall/logs
rm -rf /tmp/gh-aw/sandbox/firewall/audit
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58
- name: Check if detection needed
id: detection_guard
if: always()
@@ -1182,6 +1211,9 @@ jobs:
run: |
mkdir -p /tmp/gh-aw/threat-detection/aw-prompts
cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true
+ if [ ! -s /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt ]; then
+ echo "::warning::ERR_VALIDATION: Missing or empty detection context prompt at /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt. Ensure the agent artifact includes /tmp/gh-aw/aw-prompts/prompt.txt. Detection will continue with fallback workflow context."
+ fi
cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true
for f in /tmp/gh-aw/aw-*.patch; do
[ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
@@ -1215,11 +1247,11 @@ jobs:
node-version: '24'
package-manager-cache: false
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Execute GitHub Copilot CLI
if: always() && steps.detection_guard.outputs.run_detection == 'true'
continue-on-error: true
@@ -1232,24 +1264,36 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/threat-detection/detection.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","registry.npmjs.org","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_PHASE: detection
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -1262,6 +1306,7 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- name: Upload threat detection log
if: always() && steps.detection_guard.outputs.run_detection == 'true'
@@ -1322,9 +1367,10 @@ jobs:
GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }}
GH_AW_ENGINE_ID: "copilot"
GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
- GH_AW_ENGINE_VERSION: "1.0.48"
+ GH_AW_ENGINE_VERSION: "1.0.55"
GH_AW_WORKFLOW_ID: "release-changelog"
GH_AW_WORKFLOW_NAME: "Release Changelog Generator"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/release-changelog.md"
outputs:
code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}
code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}
@@ -1337,7 +1383,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1346,7 +1392,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "Release Changelog Generator"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/release-changelog.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
id: download-agent-output
@@ -1371,28 +1418,23 @@ jobs:
- name: Extract base branch from agent output
id: extract-base-branch
if: steps.download-agent-output.outcome == 'success'
- shell: bash
- run: |
- if [ -f "/tmp/gh-aw/agent_output.json" ]; then
- GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node)
- BASE_BRANCH=$("$GH_AW_NODE" -e "
- try {
- const data = JSON.parse(require('fs').readFileSync('/tmp/gh-aw/agent_output.json', 'utf8'));
- const item = (data.items || []).find(i =>
- (i.type === 'create_pull_request' || i.type === 'push_to_pull_request_branch') &&
- i.base_branch
- );
- if (item) process.stdout.write(item.base_branch);
- } catch(e) {}
- " 2>/dev/null || true)
- # Validate: only allow safe git branch name characters
- if [[ "$BASE_BRANCH" =~ ^[a-zA-Z0-9/_.-]+$ ]] && [ ${#BASE_BRANCH} -le 255 ]; then
- printf 'base-branch=%s\n' "$BASE_BRANCH" >> "$GITHUB_OUTPUT"
- echo "Extracted base branch from safe output: $BASE_BRANCH"
- fi
- fi
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ with:
+ script: |
+ const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
+ setupGlobals(core, github, context, exec, io, getOctokit);
+ const { main } = require('${{ runner.temp }}/gh-aw/actions/extract_base_branch_from_agent_output.cjs');
+ await main();
+ - name: Checkout repository (trusted default branch for comment events)
+ if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') && (github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment')
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ ref: ${{ github.event.repository.default_branch }}
+ token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
+ persist-credentials: false
+ fetch-depth: 1
- name: Checkout repository
- if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request')
+ if: (!cancelled()) && needs.agent.result != 'skipped' && contains(needs.agent.outputs.output_types, 'create_pull_request') && github.event_name != 'issue_comment' && github.event_name != 'pull_request_review_comment'
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ steps.extract-base-branch.outputs.base-branch || github.base_ref || github.event.pull_request.base.ref || github.ref_name || github.event.repository.default_branch }}
@@ -1427,10 +1469,11 @@ jobs:
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
+ GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }}
GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_API_URL: ${{ github.api_url }}
- GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_pull_request\":{\"draft\":false,\"labels\":[\"automation\",\"changelog\"],\"max\":1,\"max_patch_files\":100,\"max_patch_size\":1024,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"title_prefix\":\"[changelog] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{},\"update_release\":{\"max\":1}}"
+ GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"create_pull_request\":{\"draft\":false,\"labels\":[\"automation\",\"changelog\"],\"max\":1,\"max_patch_files\":100,\"max_patch_size\":1024,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[changelog] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"report_incomplete\":{},\"update_release\":{\"max\":1}}"
GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }}
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/release-changelog.md b/.github/workflows/release-changelog.md
index d82365ac5..52af777cd 100644
--- a/.github/workflows/release-changelog.md
+++ b/.github/workflows/release-changelog.md
@@ -117,6 +117,11 @@ Use the `create-pull-request` output to submit your changes. The PR should:
Use the `update-release` output to replace the auto-generated release notes with your nicely formatted changelog. **Do not include the version heading** (`## [vX.Y.Z](...) (date)`) in the release notes — the release already has a title showing the version. Start directly with the feature sections or other changes list.
+**IMPORTANT — Preserving the Installation section:**
+The release body may contain an Installation section delimited by `` and `` HTML comments. In the case of Java, this section includes Maven/Gradle dependency snippets and a "View on Maven Central" link. You **MUST** preserve this entire section (from the opening comment through the closing comment, inclusive) exactly as it appears in the existing release body. Place your generated changelog content **after** the Installation section.
+
+**URL reconstruction:** If the Maven Central URL in the Installation section appears corrupted or contains the word "redacted", reconstruct it. Extract the version from the release tag (e.g., `java/v1.0.0` → `1.0.0`), and rebuild the URL as: `https://central.sonatype.com/artifact/com.github/copilot-sdk-java/{VERSION}`. The `` HTML comment in the section contains the intended URL pattern.
+
## Example Output
Here is an example of what a changelog entry should look like, based on real commits from this repo. **Follow this style exactly.**
diff --git a/.github/workflows/rust-sdk-tests.yml b/.github/workflows/rust-sdk-tests.yml
index 23e686eb7..f75a5d6a2 100644
--- a/.github/workflows/rust-sdk-tests.yml
+++ b/.github/workflows/rust-sdk-tests.yml
@@ -159,6 +159,9 @@ jobs:
toolchain: "1.94.0"
- uses: Swatinem/rust-cache@v2
+ # Cache is only an optimization; the Windows bundled smoke test should
+ # not fail when rust-cache's post-job save flakes after a successful build.
+ continue-on-error: ${{ runner.os == 'Windows' }}
with:
workspaces: "rust"
key: bundled-cli
diff --git a/.github/workflows/sdk-consistency-review.lock.yml b/.github/workflows/sdk-consistency-review.lock.yml
index 4aebf32ed..3cffd9d38 100644
--- a/.github/workflows/sdk-consistency-review.lock.yml
+++ b/.github/workflows/sdk-consistency-review.lock.yml
@@ -1,5 +1,5 @@
-# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"b1f707a5df4bab2e9be118c097a5767ac0b909cf3ee1547f71895c5b33ca342d","compiler_version":"v0.74.4","strict":true,"agent_id":"copilot"}
-# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"d3abfe96a194bce3a523ed2093ddedd5704cdf62","version":"v0.74.4"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.46"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.9","digest":"sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388"},{"image":"ghcr.io/github/github-mcp-server:v1.0.4"},{"image":"node:lts-alpine","digest":"sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f","pinned_image":"node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f"}]}
+# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"7705f1f36359046432427c7379dff5ce45f49f1d69e23433af41c1234042e51b","body_hash":"97333b6724b46fcc7c9d59c1eec7c424d3a2005fab0e52e2520c97a02021426b","compiler_version":"v0.77.5","strict":true,"agent_id":"copilot"}
+# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"3ea13c02d765410340d533515cb31a7eef2baaf0","version":"v0.77.5"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.58"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.22"},{"image":"ghcr.io/github/github-mcp-server:v1.1.0"},{"image":"node:lts-alpine","digest":"sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14","pinned_image":"node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14"}]}
# ___ _ _
# / _ \ | | (_)
# | |_| | __ _ ___ _ __ | |_ _ ___
@@ -14,7 +14,7 @@
# \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \
# \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/
#
-# This file was automatically generated by gh-aw (v0.74.4). DO NOT EDIT.
+# This file was automatically generated by gh-aw (v0.77.5). DO NOT EDIT.
#
# To update this file, edit the corresponding .md file and run:
# gh aw compile
@@ -37,15 +37,15 @@
# - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9)
# - actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
# - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
-# - github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+# - github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
#
# Container images used:
-# - ghcr.io/github/gh-aw-firewall/agent:0.25.46
-# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46
-# - ghcr.io/github/gh-aw-firewall/squid:0.25.46
-# - ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388
-# - ghcr.io/github/github-mcp-server:v1.0.4
-# - node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+# - ghcr.io/github/gh-aw-firewall/agent:0.25.58
+# - ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58
+# - ghcr.io/github/gh-aw-firewall/squid:0.25.58
+# - ghcr.io/github/gh-aw-mcpg:v0.3.22
+# - ghcr.io/github/github-mcp-server:v1.1.0
+# - node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
name: "SDK Consistency Review Agent"
on:
@@ -55,6 +55,10 @@ on:
- python/**
- go/**
- dotnet/**
+ - java/**
+ - "!java/docs/**"
+ - "!java/*.txt"
+ - "!java/*.md"
types:
- opened
- synchronize
@@ -64,7 +68,7 @@ on:
inputs:
aw_context:
default: ""
- description: Agent caller context (used internally by Agentic Workflows).
+ description: "Agent caller context (used internally by Agentic Workflows)."
required: false
type: string
pr_number:
@@ -104,31 +108,32 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
env:
GH_AW_SETUP_WORKFLOW_NAME: "SDK Consistency Review Agent"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/sdk-consistency-review.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Generate agentic run info
id: generate_aw_info
env:
GH_AW_INFO_ENGINE_ID: "copilot"
GH_AW_INFO_ENGINE_NAME: "GitHub Copilot CLI"
- GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
- GH_AW_INFO_VERSION: "1.0.48"
- GH_AW_INFO_AGENT_VERSION: "1.0.48"
- GH_AW_INFO_CLI_VERSION: "v0.74.4"
+ GH_AW_INFO_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AGENT_VERSION: "1.0.55"
+ GH_AW_INFO_CLI_VERSION: "v0.77.5"
GH_AW_INFO_WORKFLOW_NAME: "SDK Consistency Review Agent"
GH_AW_INFO_EXPERIMENTAL: "false"
GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true"
GH_AW_INFO_STAGED: "false"
GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]'
GH_AW_INFO_FIREWALL_ENABLED: "true"
- GH_AW_INFO_AWF_VERSION: "v0.25.46"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_AWMG_VERSION: ""
GH_AW_INFO_FIREWALL_TYPE: "squid"
GH_AW_COMPILED_STRICT: "true"
@@ -151,6 +156,7 @@ jobs:
sparse-checkout: |
.github
.agents
+ .antigravity
.claude
.codex
.crush
@@ -161,8 +167,8 @@ jobs:
fetch-depth: 1
- name: Save agent config folders for base branch restoration
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
# poutine:ignore untrusted_checkout_exec
run: bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh"
- name: Check workflow lock file
@@ -180,7 +186,7 @@ jobs:
- name: Check compile-agentic version
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
- GH_AW_COMPILED_VERSION: "v0.74.4"
+ GH_AW_COMPILED_VERSION: "v0.77.5"
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@@ -211,24 +217,25 @@ jobs:
GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
+ GH_AW_INPUTS_PR_NUMBER: ${{ inputs.pr_number }}
# poutine:ignore untrusted_checkout_exec
run: |
bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh"
{
- cat << 'GH_AW_PROMPT_ba8cce6b4497d40e_EOF'
+ cat << 'GH_AW_PROMPT_cf79d4d226819b37_EOF'
- GH_AW_PROMPT_ba8cce6b4497d40e_EOF
+ GH_AW_PROMPT_cf79d4d226819b37_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md"
- cat << 'GH_AW_PROMPT_ba8cce6b4497d40e_EOF'
+ cat << 'GH_AW_PROMPT_cf79d4d226819b37_EOF'
Tools: add_comment, create_pull_request_review_comment(max:10), missing_tool, missing_data, noop
- GH_AW_PROMPT_ba8cce6b4497d40e_EOF
+ GH_AW_PROMPT_cf79d4d226819b37_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md"
- cat << 'GH_AW_PROMPT_ba8cce6b4497d40e_EOF'
+ cat << 'GH_AW_PROMPT_cf79d4d226819b37_EOF'
The following GitHub context information is available for this workflow:
{{#if github.actor}}
@@ -257,12 +264,12 @@ jobs:
{{/if}}
- GH_AW_PROMPT_ba8cce6b4497d40e_EOF
+ GH_AW_PROMPT_cf79d4d226819b37_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md"
- cat << 'GH_AW_PROMPT_ba8cce6b4497d40e_EOF'
+ cat << 'GH_AW_PROMPT_cf79d4d226819b37_EOF'
{{#runtime-import .github/workflows/sdk-consistency-review.md}}
- GH_AW_PROMPT_ba8cce6b4497d40e_EOF
+ GH_AW_PROMPT_cf79d4d226819b37_EOF
} > "$GH_AW_PROMPT"
- name: Interpolate variables and render templates
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
@@ -271,6 +278,7 @@ jobs:
GH_AW_ENGINE_ID: "copilot"
GH_AW_EXPR_A0E5D436: ${{ github.event.pull_request.number || inputs.pr_number }}
GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
+ GH_AW_INPUTS_PR_NUMBER: ${{ inputs.pr_number }}
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
@@ -290,6 +298,7 @@ jobs:
GH_AW_GITHUB_REPOSITORY: ${{ github.repository }}
GH_AW_GITHUB_RUN_ID: ${{ github.run_id }}
GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }}
+ GH_AW_INPUTS_PR_NUMBER: ${{ inputs.pr_number }}
GH_AW_MCP_CLI_SERVERS_LIST: '- `safeoutputs` — run `safeoutputs --help` to see available tools'
with:
script: |
@@ -311,6 +320,7 @@ jobs:
GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY,
GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID,
GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE,
+ GH_AW_INPUTS_PR_NUMBER: process.env.GH_AW_INPUTS_PR_NUMBER,
GH_AW_MCP_CLI_SERVERS_LIST: process.env.GH_AW_MCP_CLI_SERVERS_LIST
}
});
@@ -332,12 +342,14 @@ jobs:
include-hidden-files: true
path: |
/tmp/gh-aw/aw_info.json
+ /tmp/gh-aw/model_multipliers.json
/tmp/gh-aw/aw-prompts/prompt.txt
/tmp/gh-aw/aw-prompts/prompt-template.txt
/tmp/gh-aw/aw-prompts/prompt-import-tree.json
/tmp/gh-aw/github_rate_limits.jsonl
/tmp/gh-aw/base
/tmp/gh-aw/.github/agents
+ /tmp/gh-aw/.github/skills
if-no-files-found: ignore
retention-days: 1
@@ -356,15 +368,15 @@ jobs:
GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs
GH_AW_WORKFLOW_ID_SANITIZED: sdkconsistencyreview
outputs:
- agentic_engine_timeout: ${{ steps.detect-copilot-errors.outputs.agentic_engine_timeout || 'false' }}
+ agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }}
checkout_pr_success: ${{ steps.checkout-pr.outputs.checkout_pr_success || 'true' }}
effective_tokens: ${{ steps.parse-mcp-gateway.outputs.effective_tokens }}
effective_tokens_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.effective_tokens_rate_limit_error || 'false' }}
has_patch: ${{ steps.collect_output.outputs.has_patch }}
- inference_access_error: ${{ steps.detect-copilot-errors.outputs.inference_access_error || 'false' }}
- mcp_policy_error: ${{ steps.detect-copilot-errors.outputs.mcp_policy_error || 'false' }}
+ inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }}
+ mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }}
model: ${{ needs.activation.outputs.model }}
- model_not_supported_error: ${{ steps.detect-copilot-errors.outputs.model_not_supported_error || 'false' }}
+ model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }}
output: ${{ steps.collect_output.outputs.output }}
output_types: ${{ steps.collect_output.outputs.output_types }}
setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }}
@@ -373,7 +385,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -382,7 +394,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "SDK Consistency Review Agent"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/sdk-consistency-review.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Set runtime paths
id: set-runtime-paths
@@ -430,11 +443,11 @@ jobs:
const { main } = require('${{ runner.temp }}/gh-aw/actions/checkout_pr_branch.cjs');
await main();
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Determine automatic lockdown mode for GitHub MCP Server
id: determine-automatic-lockdown
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9)
@@ -453,24 +466,28 @@ jobs:
- name: Restore agent config folders from base branch
if: steps.checkout-pr.outcome == 'success'
env:
- GH_AW_AGENT_FOLDERS: ".agents .claude .codex .crush .gemini .github .opencode .pi"
- GH_AW_AGENT_FILES: ".crush.json AGENTS.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
+ GH_AW_AGENT_FOLDERS: ".agents .antigravity .claude .codex .crush .gemini .github .opencode .pi"
+ GH_AW_AGENT_FILES: ".crush.json AGENTS.md ANTIGRAVITY.md CLAUDE.md GEMINI.md PI.md opencode.jsonc"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_base_github_folders.sh"
- name: Restore inline sub-agents from activation artifact
env:
GH_AW_SUB_AGENT_DIR: ".github/agents"
GH_AW_SUB_AGENT_EXT: ".agent.md"
run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh"
+ - name: Restore inline skills from activation artifact
+ env:
+ GH_AW_SKILL_DIR: ".github/skills"
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh"
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46 ghcr.io/github/gh-aw-mcpg:v0.3.9@sha256:64828b42a4482f58fab16509d7f8f495a6d97c972a98a68aff20543531ac0388 ghcr.io/github/github-mcp-server:v1.0.4 node:lts-alpine@sha256:d1b3b4da11eefd5941e7f0b9cf17783fc99d9c6fc34884a665f40a06dbdfc94f
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58 ghcr.io/github/gh-aw-mcpg:v0.3.22 ghcr.io/github/github-mcp-server:v1.1.0 node:lts-alpine@sha256:2bdb65ed1dab192432bc31c95f94155ca5ad7fc1392fb7eb7526ab682fa5bf14
- name: Generate Safe Outputs Config
run: |
mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
mkdir -p /tmp/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
- cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_8507857a3b512809_EOF'
+ cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_ee26456e9d33cb21_EOF'
{"add_comment":{"hide_older_comments":true,"max":1},"create_pull_request_review_comment":{"max":10,"side":"RIGHT"},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{}}
- GH_AW_SAFE_OUTPUTS_CONFIG_8507857a3b512809_EOF
+ GH_AW_SAFE_OUTPUTS_CONFIG_ee26456e9d33cb21_EOF
- name: Generate Safe Outputs Tools
env:
GH_AW_TOOLS_META_JSON: |
@@ -698,16 +715,16 @@ jobs:
* ) DOCKER_SOCK_PATH=/var/run/docker.sock ;;
esac
DOCKER_SOCK_GID=$(stat -c '%g' "$DOCKER_SOCK_PATH" 2>/dev/null || echo '0')
- export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.9'
+ export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host --add-host host.docker.internal:127.0.0.1 --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.3.22'
mkdir -p /home/runner/.copilot
GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node)
- cat << GH_AW_MCP_CONFIG_73099b6c804f5a74_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs"
+ cat << GH_AW_MCP_CONFIG_f1f5e8d8750acfbe_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs"
{
"mcpServers": {
"github": {
"type": "stdio",
- "container": "ghcr.io/github/github-mcp-server:v1.0.4",
+ "container": "ghcr.io/github/github-mcp-server:v1.1.0",
"env": {
"GITHUB_HOST": "\${GITHUB_SERVER_URL}",
"GITHUB_PERSONAL_ACCESS_TOKEN": "\${GITHUB_MCP_SERVER_TOKEN}",
@@ -743,7 +760,7 @@ jobs:
"payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
}
}
- GH_AW_MCP_CONFIG_73099b6c804f5a74_EOF
+ GH_AW_MCP_CONFIG_f1f5e8d8750acfbe_EOF
- name: Mount MCP servers as CLIs
id: mount-mcp-clis
continue-on-error: true
@@ -775,26 +792,38 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/agent-stdio.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"auto":["large"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-4.1":["copilot/gpt-4.1*","openai/gpt-4.1*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","api.snapcraft.io","archive.ubuntu.com","azure.archive.ubuntu.com","crl.geotrust.com","crl.globalsign.com","crl.identrust.com","crl.sectigo.com","crl.thawte.com","crl.usertrust.com","crl.verisign.com","crl3.digicert.com","crl4.digicert.com","crls.ssl.com","github.com","host.docker.internal","json-schema.org","json.schemastore.org","keyserver.ubuntu.com","ocsp.digicert.com","ocsp.geotrust.com","ocsp.globalsign.com","ocsp.identrust.com","ocsp.sectigo.com","ocsp.ssl.com","ocsp.thawte.com","ocsp.usertrust.com","ocsp.verisign.com","packagecloud.io","packages.cloud.google.com","packages.microsoft.com","ppa.launchpad.net","raw.githubusercontent.com","registry.npmjs.org","s.symcb.com","s.symcd.com","security.ubuntu.com","telemetry.enterprise.githubcopilot.com","ts-crl.ws.symantec.com","ts-ocsp.ws.symantec.com","www.googleapis.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000,"models":{"agent":["sonnet-6x","gpt-5.4","gpt-5.3","gemini-pro","any"],"antigravity":["copilot/antigravity*","google/antigravity*","gemini/antigravity*"],"any":["copilot/*","anthropic/*","openai/*","google/*","gemini/*"],"claude":["agent"],"codex":["agent"],"coding":["copilot/gpt-5*codex*","openai/gpt-5*codex*","gpt-5-codex"],"computer-use":["copilot/*computer-use*","google/*computer-use*","gemini/*computer-use*","openai/*computer-use*"],"copilot":["agent"],"deep-research":["copilot/deep-research*","copilot/o3-deep-research*","copilot/o4-mini-deep-research*","google/deep-research*","gemini/deep-research*","openai/o3-deep-research*","openai/o4-mini-deep-research*"],"gemini":["agent"],"gemini-3-flash":["copilot/gemini-3*flash*","google/gemini-3*flash*","gemini/gemini-3*flash*"],"gemini-3-pro":["copilot/gemini-3*pro*","google/gemini-3*pro*","gemini/gemini-3*pro*"],"gemini-3.1-flash":["copilot/gemini-3.1*flash*","google/gemini-3.1*flash*","gemini/gemini-3.1*flash*"],"gemini-3.1-pro":["copilot/gemini-3.1*pro*","google/gemini-3.1*pro*","gemini/gemini-3.1*pro*"],"gemini-3.5-flash":["copilot/gemini-3.5*flash*","google/gemini-3.5*flash*","gemini/gemini-3.5*flash*"],"gemini-flash":["copilot/gemini-*flash*","google/gemini-*flash*","gemini/gemini-*flash*"],"gemini-flash-lite":["copilot/gemini-*flash*lite*","google/gemini-*flash*lite*","gemini/gemini-*flash*lite*"],"gemini-pro":["copilot/gemini-*pro*","google/gemini-*pro*","gemini/gemini-*pro*"],"gemma":["copilot/gemma*","google/gemma*","gemini/gemma*"],"gpt-5":["copilot/gpt-5*","openai/gpt-5*"],"gpt-5-codex":["copilot/gpt-5*codex*","openai/gpt-5*codex*"],"gpt-5-mini":["copilot/gpt-5*mini*","openai/gpt-5*mini*"],"gpt-5-nano":["copilot/gpt-5*nano*","openai/gpt-5*nano*"],"gpt-5-pro":["copilot/gpt-5*pro*","openai/gpt-5*pro*"],"gpt-5.2":["copilot/gpt-5.2*","openai/gpt-5.2*"],"gpt-5.3":["copilot/gpt-5.3*","openai/gpt-5.3*"],"gpt-5.4":["copilot/gpt-5.4*","openai/gpt-5.4*"],"gpt-5.5":["copilot/gpt-5.5*","openai/gpt-5.5*"],"haiku":["copilot/*haiku*","anthropic/*haiku*"],"large":["sonnet","gpt-5-pro","gpt-5","gemini-pro"],"mini":["haiku","gpt-5-mini","gpt-5-nano","gemini-flash-lite"],"opus":["copilot/*opus*","anthropic/*opus*"],"opusplan":["opus?effort=high"],"reasoning":["copilot/o1*","copilot/o3*","copilot/o4*","openai/o1*","openai/o3*","openai/o4*"],"robotics":["copilot/*robotics*","google/*robotics*","gemini/*robotics*"],"small":["mini"],"sonnet":["copilot/*sonnet*","anthropic/*sonnet*"],"sonnet-6x":["copilot/*sonnet-4-5-*","anthropic/*sonnet-4-5-*","copilot/*sonnet-4-6*","anthropic/*sonnet-4-6*"],"summarization":["haiku","gpt-5-mini","gemini-flash-lite","mini"],"vision":["copilot/gemini-*image*","gemini/gemini-*image*","copilot/gemini-*flash*","gemini/gemini-*flash*"]}},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_API_KEY --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --allow-all-paths --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/agent-stdio.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_AGENT_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_MCP_CONFIG: /home/runner/.copilot/mcp-config.json
GH_AW_PHASE: agent
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }}
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -808,12 +837,13 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- - name: Detect Copilot errors
- id: detect-copilot-errors
+ - name: Detect agent errors
if: always()
+ id: detect-agent-errors
continue-on-error: true
- run: node "${RUNNER_TEMP}/gh-aw/actions/detect_copilot_errors.cjs"
+ run: node "${RUNNER_TEMP}/gh-aw/actions/detect_agent_errors.cjs"
- name: Configure Git credentials
env:
REPO_NAME: ${{ github.repository }}
@@ -995,7 +1025,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1004,7 +1034,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "SDK Consistency Review Agent"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/sdk-consistency-review.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
id: download-agent-output
@@ -1027,6 +1058,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_NOOP_MAX: "1"
GH_AW_WORKFLOW_NAME: "SDK Consistency Review Agent"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/sdk-consistency-review.md"
GH_AW_TRACKER_ID: "sdk-consistency-review"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
@@ -1044,6 +1076,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "SDK Consistency Review Agent"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/sdk-consistency-review.md"
GH_AW_TRACKER_ID: "sdk-consistency-review"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }}
@@ -1062,6 +1095,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_MISSING_TOOL_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "SDK Consistency Review Agent"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/sdk-consistency-review.md"
GH_AW_TRACKER_ID: "sdk-consistency-review"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
@@ -1077,6 +1111,7 @@ jobs:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true"
GH_AW_WORKFLOW_NAME: "SDK Consistency Review Agent"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/sdk-consistency-review.md"
GH_AW_TRACKER_ID: "sdk-consistency-review"
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
@@ -1092,6 +1127,7 @@ jobs:
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
GH_AW_WORKFLOW_NAME: "SDK Consistency Review Agent"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/sdk-consistency-review.md"
GH_AW_TRACKER_ID: "sdk-consistency-review"
GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }}
@@ -1139,7 +1175,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1148,7 +1184,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "SDK Consistency Review Agent"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/sdk-consistency-review.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
id: download-agent-output
@@ -1175,7 +1212,7 @@ jobs:
rm -rf /tmp/gh-aw/sandbox/firewall/logs
rm -rf /tmp/gh-aw/sandbox/firewall/audit
- name: Download container images
- run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.46 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.46 ghcr.io/github/gh-aw-firewall/squid:0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.25.58 ghcr.io/github/gh-aw-firewall/api-proxy:0.25.58 ghcr.io/github/gh-aw-firewall/squid:0.25.58
- name: Check if detection needed
id: detection_guard
if: always()
@@ -1201,6 +1238,9 @@ jobs:
run: |
mkdir -p /tmp/gh-aw/threat-detection/aw-prompts
cp /tmp/gh-aw/aw-prompts/prompt.txt /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt 2>/dev/null || true
+ if [ ! -s /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt ]; then
+ echo "::warning::ERR_VALIDATION: Missing or empty detection context prompt at /tmp/gh-aw/threat-detection/aw-prompts/prompt.txt. Ensure the agent artifact includes /tmp/gh-aw/aw-prompts/prompt.txt. Detection will continue with fallback workflow context."
+ fi
cp /tmp/gh-aw/agent_output.json /tmp/gh-aw/threat-detection/agent_output.json 2>/dev/null || true
for f in /tmp/gh-aw/aw-*.patch; do
[ -f "$f" ] && cp "$f" /tmp/gh-aw/threat-detection/ 2>/dev/null || true
@@ -1234,11 +1274,11 @@ jobs:
node-version: '24'
package-manager-cache: false
- name: Install GitHub Copilot CLI
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.48
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_copilot_cli.sh" 1.0.55
env:
GH_HOST: github.com
- name: Install AWF binary
- run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.46
+ run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.25.58
- name: Execute GitHub Copilot CLI
if: always() && steps.detection_guard.outputs.run_detection == 'true'
continue-on-error: true
@@ -1251,24 +1291,36 @@ jobs:
touch /tmp/gh-aw/agent-step-summary.md
GH_AW_NODE_BIN=$(command -v node 2>/dev/null || true)
export GH_AW_NODE_BIN
+ export COPILOT_API_KEY="$COPILOT_DUMMY_BYOK"
(umask 177 && touch /tmp/gh-aw/threat-detection/detection.log)
- printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.46/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.46"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json" && cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
+ printf '%s\n' '{"$schema":"https://github.com/github/gh-aw-firewall/releases/download/v0.25.58/awf-config.schema.json","network":{"allowDomains":["api.business.githubcopilot.com","api.enterprise.githubcopilot.com","api.github.com","api.githubcopilot.com","api.individual.githubcopilot.com","github.com","host.docker.internal","registry.npmjs.org","telemetry.enterprise.githubcopilot.com"]},"apiProxy":{"enabled":true,"enableTokenSteering":true,"maxRuns":500,"maxEffectiveTokens":25000000},"container":{"imageTag":"0.25.58"}}' > "${RUNNER_TEMP}/gh-aw/awf-config.json"
+ GH_AW_MODEL_MULTIPLIERS_PATH="/tmp/gh-aw/model_multipliers.json" node "${RUNNER_TEMP}/gh-aw/actions/merge_awf_model_multipliers.cjs"
+ cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS=""
if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then
GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS="--docker-host-path-prefix /tmp/gh-aw"
fi
+ GH_AW_TOOL_CACHE_MOUNT=""
+ GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"
+ if [ -d "$GH_AW_TOOL_CACHE" ]; then
+ if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then
+ GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro"
+ fi
+ elif [ -d "/home/runner/work/_tool" ]; then
+ GH_AW_TOOL_CACHE_MOUNT="/home/runner/work/_tool:/home/runner/work/_tool:ro"
+ fi
# shellcheck disable=SC1003
- sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
- -- /bin/bash -c 'export PATH="$(find /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
+ sudo -E awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST_PATH_PREFIX_ARGS} --env-all --exclude-env COPILOT_GITHUB_TOKEN --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --audit-dir /tmp/gh-aw/sandbox/firewall/audit --enable-host-access --allow-host-ports 80,443,8080 --skip-pull \
+ -- /bin/bash -c 'set +o histexpand; GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}"; export PATH="$(find "$GH_AW_TOOL_CACHE" /opt/hostedtoolcache /home/runner/work/_tool -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/copilot_harness.cjs /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --disable-builtin-mcps --no-ask-user --allow-all-tools --add-dir "${GITHUB_WORKSPACE}" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log
env:
AWF_REFLECT_ENABLED: 1
COPILOT_AGENT_RUNNER_TYPE: STANDALONE
- COPILOT_API_KEY: dummy-byok-key-for-offline-mode
+ COPILOT_DUMMY_BYOK: dummy-byok-key-for-offline-mode
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || 'claude-sonnet-4.6' }}
+ COPILOT_MODEL: ${{ vars.GH_AW_MODEL_DETECTION_COPILOT || vars.GH_AW_DEFAULT_MODEL_COPILOT || 'claude-sonnet-4.6' }}
GH_AW_PHASE: detection
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
- GH_AW_VERSION: v0.74.4
+ GH_AW_VERSION: v0.77.5
GITHUB_API_URL: ${{ github.api_url }}
GITHUB_AW: true
GITHUB_COPILOT_INTEGRATION_ID: agentic-workflows
@@ -1281,6 +1333,7 @@ jobs:
GIT_AUTHOR_NAME: github-actions[bot]
GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com
GIT_COMMITTER_NAME: github-actions[bot]
+ RUNNER_TEMP: ${{ runner.temp }}
XDG_CONFIG_HOME: /home/runner
- name: Upload threat detection log
if: always() && steps.detection_guard.outputs.run_detection == 'true'
@@ -1342,10 +1395,11 @@ jobs:
GH_AW_EFFECTIVE_TOKENS: ${{ needs.agent.outputs.effective_tokens }}
GH_AW_ENGINE_ID: "copilot"
GH_AW_ENGINE_MODEL: ${{ needs.agent.outputs.model }}
- GH_AW_ENGINE_VERSION: "1.0.48"
+ GH_AW_ENGINE_VERSION: "1.0.55"
GH_AW_TRACKER_ID: "sdk-consistency-review"
GH_AW_WORKFLOW_ID: "sdk-consistency-review"
GH_AW_WORKFLOW_NAME: "SDK Consistency Review Agent"
+ GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/sdk-consistency-review.md"
outputs:
code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }}
code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }}
@@ -1358,7 +1412,7 @@ jobs:
steps:
- name: Setup Scripts
id: setup
- uses: github/gh-aw-actions/setup@d3abfe96a194bce3a523ed2093ddedd5704cdf62 # v0.74.4
+ uses: github/gh-aw-actions/setup@3ea13c02d765410340d533515cb31a7eef2baaf0 # v0.77.5
with:
destination: ${{ runner.temp }}/gh-aw/actions
job-name: ${{ github.job }}
@@ -1367,7 +1421,8 @@ jobs:
env:
GH_AW_SETUP_WORKFLOW_NAME: "SDK Consistency Review Agent"
GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/sdk-consistency-review.lock.yml@${{ github.ref }}
- GH_AW_INFO_VERSION: "1.0.48"
+ GH_AW_INFO_VERSION: "1.0.55"
+ GH_AW_INFO_AWF_VERSION: "v0.25.58"
GH_AW_INFO_ENGINE_ID: "copilot"
- name: Download agent output artifact
id: download-agent-output
@@ -1397,6 +1452,7 @@ jobs:
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }}
+ GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }}
GH_AW_ALLOWED_DOMAINS: "api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_API_URL: ${{ github.api_url }}
diff --git a/.github/workflows/sdk-consistency-review.md b/.github/workflows/sdk-consistency-review.md
index bff588f38..4111015ba 100644
--- a/.github/workflows/sdk-consistency-review.md
+++ b/.github/workflows/sdk-consistency-review.md
@@ -10,6 +10,10 @@ on:
- 'python/**'
- 'go/**'
- 'dotnet/**'
+ - 'java/**'
+ - '!java/docs/**'
+ - '!java/*.txt'
+ - '!java/*.md'
workflow_dispatch:
inputs:
pr_number:
@@ -35,7 +39,7 @@ timeout-minutes: 15
# SDK Consistency Review Agent
-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.
+You are an AI code reviewer specialized in ensuring consistency across multi-language SDK implementations. This repository contains six SDK implementations (Node.js/TypeScript, Python, Go, .NET, Java, and Rust) that should maintain feature parity and consistent API design.
## Your Task
@@ -69,6 +73,8 @@ When a pull request modifies any SDK client code, review it to ensure:
- **Python**: `python/copilot/`
- **Go**: `go/`
- **.NET**: `dotnet/src/`
+- **Java**: `java/src/main/java/`
+- **Rust**: `rust/src/`
## Review Process
@@ -90,6 +96,8 @@ When a pull request modifies any SDK client code, review it to ensure:
- Python uses snake_case (e.g., `create_session`)
- Go uses PascalCase for exported/public functions (e.g., `CreateSession`) and camelCase for unexported/private functions
- .NET uses PascalCase (e.g., `CreateSession`)
+ - Java uses camelCase for methods (e.g., `createSession`) and PascalCase for classes
+ - Rust uses snake_case for functions and methods (e.g., `create_session`) and PascalCase for types
- Focus on public API methods when comparing across languages
3. **Focus on API surface**: Prioritize public APIs over internal implementation details
4. **Distinguish between bugs and features**:
@@ -102,7 +110,7 @@ When a pull request modifies any SDK client code, review it to ensure:
## Example Scenarios
### Good: Consistent feature addition
-If a PR adds a new `setTimeout` option to the Node.js SDK and the equivalent feature already exists or is added to Python, Go, and .NET in the same PR.
+If a PR adds a new `setTimeout` option to the Node.js SDK and the equivalent feature already exists or is added to Python, Go, .NET, Java, and Rust in the same PR.
### Bad: Inconsistent feature
If a PR adds a `withRetry` method to only the Python SDK, but this functionality doesn't exist in other SDKs and would be useful everywhere.
diff --git a/.github/workflows/update-copilot-dependency.yml b/.github/workflows/update-copilot-dependency.yml
index 05833bf73..5d39d3bb2 100644
--- a/.github/workflows/update-copilot-dependency.yml
+++ b/.github/workflows/update-copilot-dependency.yml
@@ -4,7 +4,7 @@ on:
workflow_dispatch:
inputs:
version:
- description: 'Target version of @github/copilot (e.g. 0.0.420)'
+ description: "Target version of @github/copilot (e.g. 0.0.420)"
required: true
type: string
@@ -34,7 +34,7 @@ jobs:
- uses: actions/setup-go@v5
with:
- go-version: '1.22'
+ go-version: "1.22"
- uses: actions/setup-dotnet@v5
with:
@@ -86,6 +86,38 @@ jobs:
cd ../dotnet && dotnet format src/GitHub.Copilot.SDK.csproj
cd ../rust && cargo +nightly-2026-04-14 fmt --all -- --config-path .rustfmt.nightly.toml
+ - uses: actions/setup-java@v5
+ with:
+ java-version: "25"
+ distribution: "microsoft"
+
+ - name: Update @github/copilot in Java codegen
+ env:
+ VERSION: ${{ inputs.version }}
+ working-directory: ./java/scripts/codegen
+ run: npm install "@github/copilot@$VERSION"
+
+ - name: Update Java POM CLI version property
+ env:
+ VERSION: ${{ inputs.version }}
+ working-directory: ./java
+ run: |
+ PROP="readonly-copilot-sdk-ref-impl-version-from-lastmerge-file-updated-by-reference-impl-sync"
+ sed -i -E "s|(<${PROP}>)[^<]*(${PROP}>)|\1^${VERSION}\2|" pom.xml
+ # Use fixed-string matching (-F) because npm versions contain regex
+ # metacharacters: '^' (caret ranges) and '.' (dots in semver) would
+ # otherwise be interpreted as start-of-line and any-char respectively,
+ # causing false negatives or spurious matches.
+ grep -qF "<${PROP}>^${VERSION}${PROP}>" pom.xml
+
+ - name: Run Java codegen
+ working-directory: ./java
+ run: mvn generate-sources -Pcodegen
+
+ - name: Compile Java SDK (validate generated code)
+ working-directory: ./java
+ run: mvn compile -Pskip-test-harness
+
- name: Create pull request
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -95,15 +127,45 @@ jobs:
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
+ # Fetch the PR branch if it exists remotely (shallow clones may not have it)
+ git fetch origin "$BRANCH" 2>/dev/null || true
+
if git rev-parse --verify "origin/$BRANCH" >/dev/null 2>&1; then
- git fetch origin "$BRANCH"
+ # We need to switch to the existing PR branch, but earlier workflow
+ # steps (dependency bumps, codegen) may have left uncommitted changes
+ # in the working tree. We must stash those changes before checkout,
+ # then re-apply them on the PR branch.
+ #
+ # HOWEVER: `git stash` is a no-op when the working tree is clean —
+ # it exits 0 but creates NO refs/stash entry. If we then blindly run
+ # `git stash pop`, it fails with "No stash entries found" and, under
+ # the shell's `set -e` (GitHub Actions default), aborts the entire
+ # step. This happens when the requested version is already current or
+ # earlier steps produced no file changes.
+ #
+ # Fix: only stash/pop when there are actual uncommitted changes.
+ STASHED=false
+ if ! git diff --quiet || ! git diff --cached --quiet; then
+ git stash --include-untracked
+ STASHED=true
+ fi
+
git checkout "$BRANCH"
git reset --hard "origin/$BRANCH"
+
+ # Re-apply the dependency/codegen changes on top of the PR branch,
+ # but only if we actually stashed something above.
+ if [ "$STASHED" = "true" ]; then
+ git stash pop
+ fi
else
git checkout -b "$BRANCH"
fi
- git add -A
+ # Stage everything except java/.lastmerge so it doesn't create a
+ # spurious diff in the no-changes check below. The ':!...' pathspec
+ # (exclude magic) tells git to skip that one file.
+ git add -A -- ':!java/.lastmerge'
if git diff --cached --quiet; then
echo "No changes detected; skipping commit and PR creation."
@@ -115,8 +177,59 @@ jobs:
- Updated nodejs and test harness dependencies
- Re-ran code generators
- Formatted generated code"
+
+ # Record the sync point AFTER the commit so that .lastmerge contains
+ # the SHA of the commit that actually includes the bumped
+ # nodejs/package.json. Java's build reads .lastmerge to clone the
+ # monorepo at that commit and extract the test harness + CLI version
+ # from nodejs/package.json. If we wrote .lastmerge BEFORE committing,
+ # it would point to the parent commit which still has the OLD version,
+ # causing Java tests to run against a stale CLI.
+ git rev-parse HEAD > java/.lastmerge
+ git add java/.lastmerge
+ git commit --amend --no-edit
git push origin "$BRANCH" --force-with-lease
+ PR_BODY=$(cat <<'BODY_EOF'
+ Automated update of `@github/copilot` to version `PLACEHOLDER_VERSION`.
+
+ ### Changes
+ - Updated `@github/copilot` in `nodejs/package.json` and `test/harness/package.json`
+ - Re-ran all code generators (`scripts/codegen`)
+ - Formatted generated output
+ - Updated Java codegen dependency, `.lastmerge`, POM property, and regenerated Java types
+
+ ### Java Handwritten Code Adaptation Plan
+
+ If `java-sdk-tests` CI fails on this PR, follow these steps:
+
+ 1. **Identify failures**: Run `mvn clean`, `mvn verify` from `java/` locally or check the `java-sdk-tests` workflow run logs.
+ 2. **Categorize errors**:
+ - Constructor signature changes (new fields added to generated records)
+ - Enum value additions/renames in generated types
+ - New event types requiring handler registration
+ - Removed or renamed generated types
+ 3. **Fix handwritten source** (`java/src/main/java/com/github/copilot/sdk/`):
+ - Update call sites passing positional constructor args to include new fields (typically `null` for optional new fields).
+ - Update switch/if-else over enum values to handle new cases.
+ - Register handlers for new event types in `CopilotSession.java` if applicable.
+ 4. **Fix handwritten tests** (`java/src/test/java/com/github/copilot/sdk/`):
+ - Same constructor/enum fixes as above.
+ - Add new test methods for new functionality if the change adds user-facing API surface.
+ 5. **Validate**: `cd java && mvn clean test-compile jar:jar && mvn verify -Dskip.test.harness=true`
+ 6. **Format**: `cd java && mvn spotless:apply`
+ 7. Push fixes to this PR branch.
+
+ > To automate this, trigger the `java-adapt-handwritten-code-to-accept-upgrade-changes` agentic workflow instead.
+
+ ### Next steps
+ When ready, click **Ready for review** to trigger CI checks.
+
+ > Created by the **Update @github/copilot Dependency** workflow.
+ BODY_EOF
+ )
+ PR_BODY="${PR_BODY//PLACEHOLDER_VERSION/$VERSION}"
+
PR_STATE="$(gh pr view "$BRANCH" --json state --jq '.state' 2>/dev/null || echo "")"
if [ "$PR_STATE" = "OPEN" ]; then
if [ "$(gh pr view "$BRANCH" --json isDraft --jq '.isDraft')" = "false" ]; then
@@ -129,17 +242,7 @@ jobs:
gh pr create \
--draft \
--title "Update @github/copilot to $VERSION" \
- --body "Automated update of \`@github/copilot\` to version \`$VERSION\`.
-
- ### Changes
- - Updated \`@github/copilot\` in \`nodejs/package.json\` and \`test/harness/package.json\`
- - Re-ran all code generators (\`scripts/codegen\`)
- - Formatted generated output
-
- ### Next steps
- When ready, click **Ready for review** to trigger CI checks.
-
- > Created by the **Update @github/copilot Dependency** workflow." \
+ --body "$PR_BODY" \
--base main \
--head "$BRANCH"
fi
diff --git a/.github/workflows/verify-compiled.yml b/.github/workflows/verify-compiled.yml
index 7e5ba0ee4..2e3eee554 100644
--- a/.github/workflows/verify-compiled.yml
+++ b/.github/workflows/verify-compiled.yml
@@ -19,7 +19,7 @@ jobs:
- name: Install gh-aw CLI
uses: github/gh-aw/actions/setup-cli@main
with:
- version: v0.74.4
+ version: v0.77.5
- name: Recompile workflows
run: gh aw compile
- name: Check for uncommitted changes
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 2fa57dbe6..041fc6865 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,7 +2,7 @@
Thanks for your interest in contributing!
-This repository contains the Copilot SDK, a set of multi-language SDKs (Node/TypeScript, Python, Go, .NET, Rust) for building applications with the GitHub Copilot agent, maintained by the GitHub Copilot team.
+This repository contains the Copilot SDK, a set of multi-language SDKs (Node/TypeScript, Python, Go, .NET, Java, and Rust) for building applications with the GitHub Copilot agent, maintained by the GitHub Copilot team.
Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) to the public under the [project's open source license](LICENSE).
diff --git a/README.md b/README.md
index ceb7a5b35..19e92e16b 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@
Agents for every app.
-Embed Copilot's agentic workflows in your application—now available in public preview as a programmable SDK for Python, TypeScript, Go, .NET, and Java. A Rust SDK is also available in technical preview.
+Embed Copilot's agentic workflows in your application with the GitHub Copilot SDK for Python, TypeScript, Go, .NET, Java, and Rust.
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.
@@ -37,7 +37,7 @@ Quick steps:
1. **(Optional) Install the Copilot CLI**
For Node.js, Python, and .NET SDKs, the Copilot CLI is bundled automatically and no separate installation is required.
-For the Go, Java and Rust SDKs, [install the CLI manually](https://github.com/features/copilot/cli) or ensure `copilot` is available in your PATH unless you opt into their application-level CLI bundling features.
+For Go, Java, and Rust, [install the CLI manually](https://github.com/features/copilot/cli) or ensure `copilot` is available in your PATH. Go and Rust also expose application-level CLI bundling features.
2. **Install your preferred SDK** using the commands above.
@@ -88,7 +88,7 @@ See the **[Authentication documentation](./docs/auth/index.md)** for details on
No — for Node.js, Python, and .NET SDKs, the Copilot CLI is bundled automatically as a dependency. You do not need to install it separately.
-For Go, Java and Rust SDKs, the CLI is **not** bundled by default. Install the CLI manually, ensure `copilot` is available in your PATH, or opt into their application-level CLI bundling features.
+For Go, Java, and Rust SDKs, the CLI is **not** bundled by default. Install the CLI manually or ensure `copilot` is available in your PATH. Go and Rust also expose application-level CLI bundling features.
Advanced: You can override the CLI binary or connect to an external server. See the individual SDK README for language-specific options.
@@ -117,7 +117,7 @@ All models available via Copilot CLI are supported in the SDK. The SDK also expo
### Is the SDK production-ready?
-The GitHub Copilot SDK is currently in Public Preview. While it is functional and can be used for development and testing, it may not yet be suitable for production use.
+The GitHub Copilot SDK is generally available and follows semantic versioning. See [CHANGELOG.md](./CHANGELOG.md) for release notes.
### How do I report issues or request features?
diff --git a/docs/auth/authenticate.md b/docs/auth/authenticate.md
index 36bc855f5..0c4d70699 100644
--- a/docs/auth/authenticate.md
+++ b/docs/auth/authenticate.md
@@ -167,7 +167,7 @@ func main() {
import copilot "github.com/github/copilot-sdk/go"
client := copilot.NewClient(&copilot.ClientOptions{
- GithubToken: userAccessToken, // Token from OAuth flow
+ GitHubToken: userAccessToken, // Token from OAuth flow
UseLoggedInUser: copilot.Bool(false), // Don't use stored CLI credentials
})
```
@@ -300,13 +300,15 @@ BYOK allows you to use your own API keys from model providers like Azure AI Foun
When multiple authentication methods are available, the SDK uses them in this priority order:
-1. **Explicit `gitHubToken`** - Token passed directly to SDK constructor
+1. **Explicit `gitHubToken`** - Token passed directly to the SDK client or session configuration
1. **HMAC key** - `CAPI_HMAC_KEY` or `COPILOT_HMAC_KEY` environment variables
1. **Direct API token** - `GITHUB_COPILOT_API_TOKEN` with `COPILOT_API_URL`
1. **Environment variable tokens** - `COPILOT_GITHUB_TOKEN` → `GH_TOKEN` → `GITHUB_TOKEN`
1. **Stored OAuth credentials** - From previous `copilot` CLI login
1. **GitHub CLI** - `gh auth` credentials
+For multi-user server mode, pass a per-session `gitHubToken` so each session runs with the correct GitHub identity; see [Multi-user and server deployments](../setup/multi-tenancy.md).
+
## Disabling auto-login
To prevent the SDK from automatically using stored credentials or `gh` CLI auth, use the `useLoggedInUser: false` option:
diff --git a/docs/auth/byok.md b/docs/auth/byok.md
index 8bfc5d50c..6f2d20633 100644
--- a/docs/auth/byok.md
+++ b/docs/auth/byok.md
@@ -115,7 +115,7 @@ func main() {
Provider: &copilot.ProviderConfig{
Type: "openai",
BaseURL: "https://your-resource.openai.azure.com/openai/v1/",
- WireApi: "responses", // Use "completions" for older models
+ WireAPI: "responses", // Use "completions" for older models
APIKey: os.Getenv("FOUNDRY_API_KEY"),
},
})
@@ -205,15 +205,17 @@ client.stop().get();
| `baseUrl` / `base_url` | string | **Required.** API endpoint URL |
| `apiKey` / `api_key` | string | API key (optional for local providers like Ollama) |
| `bearerToken` / `bearer_token` | string | Bearer token auth (takes precedence over apiKey) |
-| `wireApi` / `wire_api` | `"completions"` \| `"responses"` | API format (default: `"completions"`) |
+| `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 (default: `"2024-10-21"`) |
### Wire API format
The `wireApi` setting determines which OpenAI API format to use:
-* **`"completions"`** (default) - Chat Completions API (`/chat/completions`). Use for most models.
-* **`"responses"`** - Responses API. Use for GPT-5 series models that support the newer responses format.
+* **`"completions"`** (default) - Chat Completions API (`/chat/completions`) for broad model compatibility.
+* **`"responses"`** - Responses API for multi-turn state management, tool namespacing, and reasoning support.
+
+Anthropic models always use the Anthropic Messages API regardless of this setting.
### Type-specific notes
@@ -407,7 +409,7 @@ func main() {
Name: "My Custom Model",
Capabilities: copilot.ModelCapabilities{
Supports: copilot.ModelSupports{Vision: false, ReasoningEffort: false},
- Limits: copilot.ModelLimits{MaxContextWindowTokens: 128000},
+ Limits: copilot.ModelLimits{MaxContextWindowTokens: copilot.Int(128000)},
},
},
}, nil
@@ -476,7 +478,7 @@ When using BYOK, be aware of these limitations:
### Identity limitations
-BYOK authentication uses **static credentials only**.
+BYOK authentication uses **static credentials only**.
You must use an API key or static bearer token that you manage yourself.
diff --git a/docs/auth/index.md b/docs/auth/index.md
index 2d5a3914a..b09646d5d 100644
--- a/docs/auth/index.md
+++ b/docs/auth/index.md
@@ -4,3 +4,9 @@ Choose the authentication method that best fits your deployment scenario for the
* [Authenticate Copilot SDK](authenticate.md): methods, priority order, and examples
* [Bring your own key (BYOK)](./byok.md): use your own API keys from OpenAI, Azure, Anthropic, and more
+
+## Authentication priority
+
+When multiple credentials are configured, an explicit SDK token takes priority, followed by HMAC or direct Copilot API environment authentication, environment variable GitHub tokens, stored Copilot CLI credentials, and then GitHub CLI credentials. See [Authenticate Copilot SDK](authenticate.md#authentication-priority) for details.
+
+For multi-user server mode, pass a per-session `gitHubToken` so each session runs with the correct GitHub identity; see [Multi-user and server deployments](../setup/multi-tenancy.md).
diff --git a/docs/features/cloud-sessions.md b/docs/features/cloud-sessions.md
new file mode 100644
index 000000000..6f9564911
--- /dev/null
+++ b/docs/features/cloud-sessions.md
@@ -0,0 +1,384 @@
+# Cloud sessions
+
+Cloud sessions run Copilot work on GitHub-hosted compute through Mission Control. Use them when your app should create a session that executes remotely instead of starting a local Copilot CLI session on the user's machine or your server.
+
+## Prerequisites
+
+Before creating a cloud session, make sure:
+
+* The user has Copilot access with cloud-agent entitlement.
+* The session can authenticate to GitHub, either with a user token or a logged-in Copilot CLI identity.
+* You can associate the session with a GitHub repository. This is optional in the SDK type, but recommended so Mission Control and the cloud agent have repository context.
+* Organization policies allow remote control and viewing sessions from cloud surfaces.
+
+## Creating a cloud session
+
+Set the create-session `cloud` option to create a cloud session. You can include repository metadata to associate the cloud session with a GitHub repository.
+
+
+
+### TypeScript
+
+```typescript
+import { CopilotClient } from "@github/copilot-sdk";
+
+const client = new CopilotClient();
+await client.start();
+
+const session = await client.createSession({
+ onPermissionRequest: async () => ({ kind: "approve-once" }),
+ cloud: {
+ repository: {
+ owner: "github",
+ name: "copilot-sdk",
+ branch: "main",
+ },
+ },
+});
+```
+
+### Python
+
+```python
+from copilot import (
+ CloudSessionOptions,
+ CloudSessionRepository,
+ CopilotClient,
+ PermissionHandler,
+)
+
+client = CopilotClient()
+await client.start()
+
+session = await client.create_session(
+ on_permission_request=PermissionHandler.approve_all,
+ cloud=CloudSessionOptions(
+ repository=CloudSessionRepository(
+ owner="github",
+ name="copilot-sdk",
+ branch="main",
+ )
+ ),
+)
+```
+
+### Go
+
+
+```go
+package main
+
+import (
+ "context"
+
+ copilot "github.com/github/copilot-sdk/go"
+ "github.com/github/copilot-sdk/go/rpc"
+)
+
+func main() {
+ _ = run(context.Background())
+}
+
+func run(ctx context.Context) error {
+ client := copilot.NewClient(nil)
+ if err := client.Start(ctx); err != nil {
+ return err
+ }
+
+ session, err := client.CreateSession(ctx, &copilot.SessionConfig{
+ Cloud: &copilot.CloudSessionOptions{
+ Repository: &copilot.CloudSessionRepository{
+ Owner: "github",
+ Name: "copilot-sdk",
+ Branch: "main",
+ },
+ },
+ OnPermissionRequest: func(_ copilot.PermissionRequest, _ copilot.PermissionInvocation) (rpc.PermissionDecision, error) {
+ return &rpc.PermissionDecisionApproveOnce{}, nil
+ },
+ })
+ _ = session
+ return err
+}
+```
+
+
+```go
+client := copilot.NewClient(nil)
+if err := client.Start(ctx); err != nil {
+ return err
+}
+
+session, err := client.CreateSession(ctx, &copilot.SessionConfig{
+ Cloud: &copilot.CloudSessionOptions{
+ Repository: &copilot.CloudSessionRepository{
+ Owner: "github",
+ Name: "copilot-sdk",
+ Branch: "main",
+ },
+ },
+ OnPermissionRequest: func(req copilot.PermissionRequest, inv copilot.PermissionInvocation) (rpc.PermissionDecision, error) {
+ return &rpc.PermissionDecisionApproveOnce{}, nil
+ },
+})
+_ = session
+```
+
+### .NET
+
+```csharp
+await using var client = new CopilotClient();
+
+var session = await client.CreateSessionAsync(new SessionConfig
+{
+ Cloud = new CloudSessionOptions
+ {
+ Repository = new CloudSessionRepository
+ {
+ Owner = "github",
+ Name = "copilot-sdk",
+ Branch = "main",
+ },
+ },
+ OnPermissionRequest = (req, inv) =>
+ Task.FromResult(PermissionDecision.ApproveOnce()),
+});
+```
+
+### Java
+
+```java
+import com.github.copilot.CopilotClient;
+import com.github.copilot.rpc.*;
+
+try (var client = new CopilotClient()) {
+ client.start().get();
+
+ var session = client.createSession(
+ new SessionConfig()
+ .setCloud(new CloudSessionOptions()
+ .setRepository(new CloudSessionRepository()
+ .setOwner("github")
+ .setName("copilot-sdk")
+ .setBranch("main")))
+ .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
+ ).get();
+}
+```
+
+### Rust
+
+```rust
+use std::sync::Arc;
+use github_copilot_sdk::{CloudSessionOptions, CloudSessionRepository, SessionConfig};
+use github_copilot_sdk::handler::ApproveAllHandler;
+
+let session = client.create_session(
+ SessionConfig::default()
+ .with_cloud(CloudSessionOptions::with_repository(
+ CloudSessionRepository::new("github", "copilot-sdk").with_branch("main"),
+ ))
+ .with_permission_handler(Arc::new(ApproveAllHandler)),
+).await?;
+```
+
+
+
+## Sending the first prompt
+
+Cloud sessions initialize in two phases: `createSession` resolves as soon as Mission Control has reserved a task, but the remote `copilot-agent` worker takes another second or two to connect and emit `session.start`. If you call `session.send` before that, the runtime's `RemoteSession.send` throws `"Remote session is still starting"` — but the schema wrapper is fire-and-forget and **silently swallows the error** while still returning a fresh `messageId` to your code. The prompt is dropped on the server and never reaches the worker.
+
+To send reliably, subscribe to events **before** sending and await the first `session.start` event whose `producer` is `"copilot-agent"`:
+
+
+```typescript
+import { CopilotClient, type CopilotSession } from "@github/copilot-sdk";
+
+const client = new CopilotClient();
+await client.start();
+
+const session: CopilotSession = await client.createSession({
+ streaming: true, // required for assistant.message_delta to fire
+ cloud: { repository: { owner: "github", name: "copilot-sdk" } },
+ onPermissionRequest: async () => ({ kind: "approve-once" }),
+});
+
+// Subscribe BEFORE sending so you don't miss the start event.
+const ready = new Promise((resolve) => {
+ const off = session.on("session.start", (event) => {
+ if (event.data?.producer === "copilot-agent") {
+ off();
+ resolve();
+ }
+ });
+});
+
+await ready;
+await session.send({ prompt: "Summarize the README" });
+```
+
+A few notes:
+
+* Set `streaming: true` on `createSession` so the runtime emits `assistant.message_delta` events. Without it, the only assistant signal you get is the final `assistant.message` — fine for batch use, but the chat will look frozen if you're rendering a live UI. See [Streaming Events](./streaming-events.md).
+* Only the **first** `session.send` is sensitive to this race. Subsequent sends on the same session work normally because the runtime keeps `hasSessionStarted` set for the life of the session.
+* Apply a timeout (e.g. 60 s) around the `ready` promise so a stuck Mission Control provisioning doesn't hang your app forever.
+* The same pattern works in every SDK language — subscribe to `session.start`, check `producer === "copilot-agent"`, then call `send`.
+
+## Accessing the Mission Control URL
+
+Cloud sessions are inherently remote: once the worker connects, Mission Control publishes the session at `https://github.com/copilot/tasks/{sessionId}` and the runtime emits a `session.info` event with the URL. You do **not** need to call `remote.enable()` — that API is only for promoting a local session to Mission Control.
+
+Capture the URL by subscribing to `session.info` and filtering by `infoType: "remote"`:
+
+
+```typescript
+session.on("session.info", (event) => {
+ if (event.data?.infoType === "remote" && event.data.url) {
+ console.log("Open from web or mobile:", event.data.url);
+ // e.g. surface in your UI as a shareable link or QR code.
+ }
+});
+```
+
+The event fires shortly after `session.start`. If your renderer mounts after the event has already fired, persist the URL alongside the session record in your app's state and rehydrate on remount — the runtime does not re-emit `session.info` on its own.
+
+For the same wiring on local sessions promoted via `remote: true`, see [Remote Sessions](./remote-sessions.md).
+
+## Repository association
+
+The `cloud.repository` object associates the cloud session with a GitHub repository:
+
+| Field | Required | Description |
+|-------|----------|-------------|
+| `owner` | Yes | Repository owner or organization. |
+| `name` | Yes | Repository name. |
+| `branch` | No | Branch to use for repository context. Omit it to let the runtime choose the default branch or current repository context. |
+
+Repository association is optional in the SDK type, but include it whenever your app knows the target repository. It helps Mission Control display the session in the right context and gives the cloud agent a clearer starting point.
+
+Use `branch` when the work should start from a specific branch. If your app is creating sessions from pull requests, issue triage flows, or deployment workflows, pass the branch that matches the user-visible task.
+
+## Resuming a cloud session
+
+The `cloud` option only applies when creating a new session. To resume an existing cloud session, use the standard resume API for the SDK language:
+
+
+```typescript
+import { CopilotClient } from "@github/copilot-sdk";
+
+const client = new CopilotClient();
+await client.start();
+
+const session = await client.resumeSession("session-id", {
+ onPermissionRequest: async () => ({ kind: "approve-once" }),
+});
+void session;
+```
+
+
+```typescript
+const session = await client.resumeSession("session-id", {
+ onPermissionRequest: async () => ({ kind: "approve-once" }),
+});
+```
+
+Do not pass `cloud` again on resume. The saved session metadata determines that the session is cloud-backed, and resume follows the normal session resume path.
+
+## Org policies and entitlements
+
+Cloud session creation can fail when the user or organization is not entitled to cloud-agent execution or when organization-level policies block the flow. In particular, policies for cloud sandbox can prevent clients from creating the cloud task.
+
+When this happens, the runtime reports a `"policy_blocked"` failure reason for cloud task creation. Treat this as an authorization or policy outcome, not as a transient infrastructure failure.
+
+In TypeScript, check for the reason before retrying:
+
+
+```typescript
+import {
+ CopilotClient,
+ type CloudSessionRepository,
+} from "@github/copilot-sdk";
+
+const client = new CopilotClient();
+await client.start();
+
+const repository: CloudSessionRepository = {
+ owner: "github",
+ name: "copilot-sdk",
+};
+
+try {
+ await client.createSession({
+ cloud: { repository },
+ onPermissionRequest: async () => ({ kind: "approve-once" }),
+ });
+} catch (error) {
+ if ((error as { reason?: string }).reason === "policy_blocked") {
+ // Show an admin-facing message or link to org policy settings.
+ }
+ throw error;
+}
+```
+
+
+```typescript
+try {
+ await client.createSession({ cloud: { repository } });
+} catch (error) {
+ if ((error as { reason?: string }).reason === "policy_blocked") {
+ // Show an admin-facing message or link to org policy settings.
+ }
+ throw error;
+}
+```
+
+In languages where SDK errors are represented differently, inspect the surfaced error reason or code and handle `"policy_blocked"` explicitly. Retrying without a policy change is not expected to succeed.
+
+## Integration ID and routing
+
+Cloud sessions are stamped with a `Copilot-Integration-Id` header derived from the `GITHUB_COPILOT_INTEGRATION_ID` environment variable. This integration ID is used by Mission Control for routing, attribution, and integration-specific behavior.
+
+For multi-user server guidance and full integration ID details, see [Multi-tenancy](../setup/multi-tenancy.md).
+
+Mission Control routes SDK-created cloud sessions to the `copilot-developer-sandbox` agent slug. The name is an internal routing slug for the cloud agent and does not mean the session uses the local Windows sandbox.
+
+## Advanced: `COPILOT_MC_BASE_URL`
+
+By default, the runtime derives the Mission Control base URL from the configured Copilot API URL. Set `COPILOT_MC_BASE_URL` only when you need to override that Mission Control endpoint.
+
+This may be required for GitHub Enterprise Server deployments. Confirm the correct value and support status with your GitHub representative before relying on it in production.
+
+```shell
+COPILOT_MC_BASE_URL="https://example.com/agents"
+```
+
+## Cloud sessions vs. remote sessions
+
+| Capability | Remote sessions | Cloud sessions |
+|------------|-----------------|----------------|
+| Execution location | Local machine or your server | GitHub-hosted compute |
+| Mission Control role | Shares a local session to GitHub web/mobile | Creates and routes the hosted session |
+| SDK option | `remote: true` on the client or session | `cloud: { ... }` on create session |
+| Resume path | Standard resume | Standard resume |
+| Windows sandbox relation | Unrelated | Unrelated |
+
+Use remote sessions when the session should execute where the SDK runtime is already running, but also be accessible from Mission Control. Use cloud sessions when the session should execute on GitHub-hosted compute.
+
+## Troubleshooting
+
+| Symptom | Likely cause | What to check |
+|---------|--------------|---------------|
+| Cloud session creation returns `"policy_blocked"` | Organization policy blocks remote control or view from cloud flows | Check org Copilot policies and user entitlement |
+| Session creates without repository context | `cloud.repository` was omitted | Pass `owner`, `name`, and optionally `branch` |
+| Resume ignores a new `cloud` option | `cloud` only applies to new sessions | Resume the existing session normally |
+| Confusion with sandbox settings | Windows sandbox and cloud sessions are separate | Do not use `SANDBOX=true` for cloud execution |
+| `session.send` resolves with a `messageId` but no `assistant.*` events fire and Mission Control shows no prompt | The session.send raced ahead of `session.start` from the remote worker; the runtime swallowed the prompt | Await the first `session.start` event with `producer === "copilot-agent"` before sending. See [Sending the first prompt](#sending-the-first-prompt) |
+| Live UI never updates even though the cloud worker is processing | `streaming` was not set on `createSession`, so only the final `assistant.message` is emitted | Set `streaming: true` on `createSession` and re-launch |
+| Cloud session works but no shareable URL appears in your UI | App never subscribed to `session.info` for the URL | Subscribe to `session.info` and filter `infoType === "remote"`. See [Accessing the Mission Control URL](#accessing-the-mission-control-url) |
+
+## See also
+
+* [Remote Sessions](./remote-sessions.md): share locally hosted sessions through Mission Control
+* [Streaming Events](./streaming-events.md): subscribe to `assistant.*` deltas for live UI rendering
+* [Multi-tenancy](../setup/multi-tenancy.md): integration IDs and server deployment patterns
+* [Authentication](../auth/index.md): configure GitHub authentication for SDK sessions
diff --git a/docs/features/custom-agents.md b/docs/features/custom-agents.md
index d0f209649..fb2f81fd1 100644
--- a/docs/features/custom-agents.md
+++ b/docs/features/custom-agents.md
@@ -1,6 +1,6 @@
# Custom agents and sub-agent orchestration
-Define specialized agents with scoped tools and prompts, then let Copilot orchestrate them as sub-agents within a single session.
+Define specialized agents with scoped tools and prompts, then let Copilot orchestrate them as sub-agents within a single session. For dispatching multiple sub-agents in parallel, see [Fleet Mode](./fleet-mode.md).
## Overview
diff --git a/docs/features/fleet-mode.md b/docs/features/fleet-mode.md
new file mode 100644
index 000000000..a830f4931
--- /dev/null
+++ b/docs/features/fleet-mode.md
@@ -0,0 +1,349 @@
+# Fleet mode
+
+Fleet mode is Copilot's parallel orchestration pattern for work that can be split across independent sub-agents. In the runtime research notes, fleet mode is described as "the runtime's built-in pattern for dispatching multiple sub-agents in parallel via the `task` tool, with SQL todos as the shared coordination state." Use it when one parent session should coordinate several workers, collect their results, and continue the conversation with the combined context.
+
+## When to use fleet mode
+
+Fleet mode is useful when the work can be decomposed before execution and each unit can run without waiting for the others.
+
+Good fits include:
+
+- Multi-file refactors where each worker owns a file, package, or language SDK.
+- Batch reviews where each worker checks a separate diff, module, or alert group.
+- Parallel research across independent repositories, services, or feature areas.
+- Documentation refreshes where each worker owns a page or topic.
+- Migration tasks where each worker can validate its own slice and report back.
+
+Avoid fleet mode for:
+
+- Sequential tasks where step 2 needs the concrete output from step 1.
+- Tightly coupled edits where workers would contend for the same files.
+- Small tasks that one synchronous sub-agent or the parent agent can finish quickly.
+- Tasks that require continuous shared reasoning rather than clear ownership.
+
+Fleet mode works best when the parent session can create clear units of work, assign one owner per unit, and define what each worker must return.
+
+## Starting fleet mode
+
+The SDK exposes fleet mode through the session RPC namespace in several languages. The binding is experimental in the generated RPC surface; pin both the SDK and the Copilot CLI runtime if your application depends on it.
+
+### From within a session
+
+The wire method is `session.fleet.start`. The optional `prompt` is combined with the runtime's fleet orchestration instructions.
+
+
+Node.js / TypeScript
+
+```typescript
+const result = await session.rpc.fleet.start({
+ prompt: "Refactor each SDK package independently, then summarize the changes.",
+});
+
+if (result.started) {
+ console.log("Fleet mode started");
+}
+```
+
+
+
+
+Python
+
+```python
+from copilot.rpc import FleetStartRequest
+
+result = await session.rpc.fleet.start(
+ FleetStartRequest(
+ prompt="Review each service independently, then summarize the risks."
+ )
+)
+
+if result.started:
+ print("Fleet mode started")
+```
+
+
+
+
+Go
+
+
+```go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ copilot "github.com/github/copilot-sdk/go"
+ "github.com/github/copilot-sdk/go/rpc"
+)
+
+func main() {
+ ctx := context.Background()
+ client := copilot.NewClient(nil)
+ session, err := client.CreateSession(ctx, &copilot.SessionConfig{})
+ if err != nil {
+ return
+ }
+
+ prompt := "Update each package independently, then report validation results."
+ result, err := session.RPC.Fleet.Start(ctx, &rpc.FleetStartRequest{
+ Prompt: &prompt,
+ })
+ if err != nil {
+ return
+ }
+ if result.Started {
+ fmt.Println("Fleet mode started")
+ }
+}
+```
+
+
+```go
+prompt := "Update each package independently, then report validation results."
+result, err := session.RPC.Fleet.Start(ctx, &rpc.FleetStartRequest{
+ Prompt: &prompt,
+})
+if err != nil {
+ return err
+}
+if result.Started {
+ fmt.Println("Fleet mode started")
+}
+```
+
+
+
+
+.NET
+
+
+```csharp
+using GitHub.Copilot;
+
+await using var client = new CopilotClient();
+await using var session = await client.CreateSessionAsync(new SessionConfig());
+
+var result = await session.Rpc.Fleet.StartAsync(
+ "Audit each project independently, then summarize the findings.");
+
+if (result.Started)
+{
+ Console.WriteLine("Fleet mode started");
+}
+```
+
+
+```csharp
+var result = await session.Rpc.Fleet.StartAsync(
+ "Audit each project independently, then summarize the findings.");
+
+if (result.Started)
+{
+ Console.WriteLine("Fleet mode started");
+}
+```
+
+
+
+
+Rust
+
+```rust
+use github_copilot_sdk::rpc::FleetStartRequest;
+
+let result = session
+ .rpc()
+ .fleet()
+ .start(FleetStartRequest {
+ prompt: Some("Research each crate independently, then summarize the plan.".into()),
+ })
+ .await?;
+
+if result.started {
+ println!("Fleet mode started");
+}
+```
+
+
+
+Native typed bindings for fleet mode were verified in Node.js/TypeScript, Python, Go, .NET, and Rust. A Java binding was not found in `java/src/main/java` on this branch, so Java examples are omitted until that surface is available.
+
+### From plan mode
+
+Plan-mode UIs can start fleet deployment by returning the `autopilot_fleet` exit action. The generated session event types describe it as:
+
+```typescript
+type PlanModeExitAction =
+ | "exit_only"
+ | "interactive"
+ | "autopilot"
+ /** Exit plan mode and continue with parallel autonomous workers. */
+ | "autopilot_fleet";
+```
+
+Use this when a user approves a plan that already contains independent work items. Use `autopilot` for a single autonomous worker and `interactive` when the user should stay in the loop.
+
+## How sub-agents coordinate
+
+Fleet mode relies on explicit coordination state instead of implicit shared memory. The parent agent decomposes the work into todos, each sub-agent owns one todo, and the orchestrator dispatches workers whose dependencies are already complete.
+
+The canonical schema is:
+
+```sql
+CREATE TABLE todos (
+ id TEXT PRIMARY KEY,
+ title TEXT NOT NULL,
+ description TEXT,
+ status TEXT DEFAULT 'pending'
+);
+
+CREATE TABLE todo_deps (
+ todo_id TEXT,
+ depends_on TEXT,
+ PRIMARY KEY (todo_id, depends_on)
+);
+```
+
+Each todo moves through a small state machine:
+
+```text
+pending -> in_progress -> done
+ \-> blocked
+```
+
+A sub-agent should:
+
+1. Claim exactly one ready todo by setting `status = 'in_progress'`.
+1. Work only on that todo's scope.
+1. Store its result in the conversation or relevant task output.
+1. Set `status = 'done'` when complete.
+1. Set `status = 'blocked'` when it cannot proceed, and include the reason.
+
+The orchestrator can find work whose dependencies are satisfied with a query like:
+
+```sql
+SELECT t.*
+FROM todos t
+WHERE t.status = 'pending'
+ AND NOT EXISTS (
+ SELECT 1
+ FROM todo_deps td
+ JOIN todos dep ON td.depends_on = dep.id
+ WHERE td.todo_id = t.id
+ AND dep.status != 'done'
+ );
+```
+
+This pattern gives every worker a clear owner and lets the parent session reason about what is ready, running, complete, or blocked.
+
+## Lifecycle hooks
+
+Fleet mode invokes sub-agents through the runtime's task mechanism. The runtime emits hook activity for sub-agent tool calls: the runtime 1.0.52 changelog notes that `preToolUse`, `postToolUse`, `subagentStart`, and `subagentStop` fire correctly for sub-agent tool calls.
+
+A dedicated SDK hook callback for `subagentStart` or `subagentStop` was not found in the public SDK surface on this branch. SDK consumers can observe sub-agent activity through the generic session event stream, which includes events such as `subagent.started`, `subagent.completed`, `subagent.failed`, `subagent.selected`, and `subagent.deselected`.
+
+
+Node.js / TypeScript
+
+```typescript
+session.on((event) => {
+ if (event.type === "subagent.started") {
+ console.log(`Started ${event.data.agentDisplayName}`);
+ }
+
+ if (event.type === "subagent.completed") {
+ console.log(`Completed ${event.data.agentDisplayName}`);
+ }
+});
+```
+
+
+
+
+Python
+
+
+```python
+import asyncio
+from copilot import CopilotClient
+from copilot.session import PermissionHandler
+
+async def main():
+ client = CopilotClient()
+ await client.start()
+ session = await client.create_session(
+ on_permission_request=PermissionHandler.approve_all,
+ )
+
+ def handle_event(event):
+ if event.type == "subagent.started":
+ print(f"Started {event.data.agent_display_name}")
+ elif event.type == "subagent.completed":
+ print(f"Completed {event.data.agent_display_name}")
+
+ unsubscribe = session.on(handle_event)
+
+asyncio.run(main())
+```
+
+
+```python
+def handle_event(event):
+ if event.type == "subagent.started":
+ print(f"Started {event.data.agent_display_name}")
+ elif event.type == "subagent.completed":
+ print(f"Completed {event.data.agent_display_name}")
+
+unsubscribe = session.on(handle_event)
+```
+
+
+
+For hook configuration that is already exposed at the SDK layer, see [Hooks](hooks.md). For sub-agent event payloads, see [Custom agents and sub-agent orchestration](custom-agents.md).
+
+## Plugin sub-agents
+
+The runtime can load plugins with `--plugin-dir`. Plugins loaded this way can register their agents as available `task(agent_type=...)` sub-agent types in prompt mode, which means fleet mode can dispatch to those plugin-provided worker types.
+
+This is currently a runtime-level configuration pattern rather than a documented SDK-level registration API. Configure the Copilot CLI runtime with the plugin directory, then connect the SDK client to that runtime. Native SDK helpers for registering plugin sub-agent types may be added in the future.
+
+Conceptually, a fleet prompt can then ask for a specific worker type:
+
+```text
+Use task(agent_type="security-review") for each independent package.
+Run the workers in parallel and summarize only high-confidence findings.
+```
+
+Keep plugin-provided sub-agent types narrow and descriptive so the orchestrator can choose them reliably.
+
+## Best practices
+
+- Decompose the work into independent units before starting fleet mode.
+- Minimize dependencies between todos; dependencies reduce parallelism.
+- Give each todo a durable ID, a clear title, and a complete description.
+- Make each sub-agent own exactly one todo at a time.
+- Use background sub-agents for truly parallel work.
+- Use synchronous sub-agent calls for serialized steps or validation gates.
+- Provide each sub-agent with complete context; sub-agents are stateless across calls.
+- Include file paths, commands, expected outputs, and constraints in each worker prompt.
+- Do not dispatch a single background sub-agent; prefer a synchronous call or batch multiple workers in parallel.
+- Avoid assigning overlapping files to different workers unless the parent agent will reconcile conflicts explicitly.
+- Require every worker to report what it changed, how it validated the change, and what remains blocked.
+- Have the parent agent verify the combined result after workers finish.
+
+## Limitations and open questions
+
+- Fleet mode is exposed through generated session RPC bindings and is marked experimental in several SDKs.
+- The SQL todos pattern is the canonical coordination model in the runtime guidance, but whether it is a stable extensibility contract for SDK consumers is still an open question.
+- `subagentStart` and `subagentStop` are runtime hook names; this branch exposes sub-agent lifecycle to SDK consumers through the generic session event stream, not dedicated hook callbacks.
+- Plugin sub-agent registration is configured at the runtime layer through `--plugin-dir`; no SDK-level plugin registration helper was verified on this branch.
+- Java native typed bindings for `session.fleet.start` were not found in the Java SDK source on this branch.
+- Fleet mode does not remove the need for parent-agent review. Parallel workers can produce inconsistent assumptions that the orchestrator must reconcile.
+
+## See also
+
+- [Custom agents and sub-agent orchestration](custom-agents.md)
+- [Hooks](hooks.md)
diff --git a/docs/features/image-input.md b/docs/features/image-input.md
index b850a4c1b..db13973fc 100644
--- a/docs/features/image-input.md
+++ b/docs/features/image-input.md
@@ -120,7 +120,7 @@ func main() {
session.Send(ctx, copilot.MessageOptions{
Prompt: "Describe what you see in this image",
Attachments: []copilot.Attachment{
- &copilot.UserMessageAttachmentFile{
+ &copilot.AttachmentFile{
DisplayName: "screenshot.png",
Path: path,
},
@@ -146,7 +146,7 @@ path := "/absolute/path/to/screenshot.png"
session.Send(ctx, copilot.MessageOptions{
Prompt: "Describe what you see in this image",
Attachments: []copilot.Attachment{
- &copilot.UserMessageAttachmentFile{
+ &copilot.AttachmentFile{
DisplayName: "screenshot.png",
Path: path,
},
@@ -179,9 +179,9 @@ public static class ImageInputExample
await session.SendAsync(new MessageOptions
{
Prompt = "Describe what you see in this image",
- Attachments = new List
+ Attachments = new List
{
- new UserMessageAttachmentFile
+ new AttachmentFile
{
Path = "/absolute/path/to/screenshot.png",
DisplayName = "screenshot.png",
@@ -208,9 +208,9 @@ await using var session = await client.CreateSessionAsync(new SessionConfig
await session.SendAsync(new MessageOptions
{
Prompt = "Describe what you see in this image",
- Attachments = new List
+ Attachments = new List
{
- new UserMessageAttachmentFile
+ new AttachmentFile
{
Path = "/absolute/path/to/screenshot.png",
DisplayName = "screenshot.png",
@@ -344,7 +344,7 @@ func main() {
session.Send(ctx, copilot.MessageOptions{
Prompt: "Describe what you see in this image",
Attachments: []copilot.Attachment{
- &copilot.UserMessageAttachmentBlob{
+ &copilot.AttachmentBlob{
Data: base64ImageData,
MIMEType: mimeType,
DisplayName: &displayName,
@@ -361,7 +361,7 @@ displayName := "screenshot.png"
session.Send(ctx, copilot.MessageOptions{
Prompt: "Describe what you see in this image",
Attachments: []copilot.Attachment{
- &copilot.UserMessageAttachmentBlob{
+ &copilot.AttachmentBlob{
Data: base64ImageData, // base64-encoded string
MIMEType: mimeType,
DisplayName: &displayName,
@@ -396,9 +396,9 @@ public static class BlobAttachmentExample
await session.SendAsync(new MessageOptions
{
Prompt = "Describe what you see in this image",
- Attachments = new List
+ Attachments = new List
{
- new UserMessageAttachmentBlob
+ new AttachmentBlob
{
Data = base64ImageData,
MimeType = "image/png",
@@ -415,9 +415,9 @@ public static class BlobAttachmentExample
await session.SendAsync(new MessageOptions
{
Prompt = "Describe what you see in this image",
- Attachments = new List
+ Attachments = new List
{
- new UserMessageAttachmentBlob
+ new AttachmentBlob
{
Data = base64ImageData,
MimeType = "image/png",
diff --git a/docs/features/index.md b/docs/features/index.md
index 2fa11b76e..d6a560fc1 100644
--- a/docs/features/index.md
+++ b/docs/features/index.md
@@ -11,13 +11,16 @@ These guides cover the capabilities you can add to your Copilot SDK application.
| [The Agent Loop](./agent-loop.md) | How the CLI processes a prompt—the tool-use loop, turns, and completion signals |
| [Hooks](./hooks.md) | Intercept and customize session behavior—control tool execution, transform results, handle errors |
| [Custom Agents](./custom-agents.md) | Define specialized sub-agents with scoped tools and instructions |
+| [Fleet Mode](./fleet-mode.md) | Dispatch multiple sub-agents in parallel for large, independent workstreams |
| [MCP Servers](./mcp.md) | Integrate Model Context Protocol servers for external tool access |
| [Skills](./skills.md) | Load reusable prompt modules from directories |
+| [Plugin Directories](./plugin-directories.md) | Bundle skills, hooks, MCP servers, and agents as a single loadable plugin |
| [Image Input](./image-input.md) | Send images to sessions as attachments |
| [Streaming Events](./streaming-events.md) | Subscribe to real-time session events (40+ event types) |
| [Steering & Queueing](./steering-and-queueing.md) | Control message delivery—immediate steering vs. sequential queueing |
| [Session Persistence](./session-persistence.md) | Resume sessions across restarts, manage session storage |
-| [Remote Sessions](./remote-sessions.md) | Share sessions to GitHub web and mobile via Mission Control |
+| [Remote Sessions](./remote-sessions.md) | Share locally hosted sessions to GitHub web and mobile via Mission Control |
+| [Cloud Sessions](./cloud-sessions.md) | Run sessions on GitHub-hosted compute through Mission Control |
## Related
diff --git a/docs/features/mcp.md b/docs/features/mcp.md
index e974532b0..6f715bd2e 100644
--- a/docs/features/mcp.md
+++ b/docs/features/mcp.md
@@ -120,7 +120,7 @@ func main() {
"my-local-server": copilot.MCPStdioServerConfig{
Command: "node",
Args: []string{"./mcp-server.js"},
- Tools: &[]string{"*"},
+ Tools: []string{"*"},
},
},
})
diff --git a/docs/features/plugin-directories.md b/docs/features/plugin-directories.md
new file mode 100644
index 000000000..ccd95df95
--- /dev/null
+++ b/docs/features/plugin-directories.md
@@ -0,0 +1,358 @@
+# Plugin directories
+
+A **plugin** is a directory that bundles SDK extensions — skills, hooks, MCP servers, custom agents, and LSP configuration — behind a single manifest. Pointing the SDK at a plugin directory loads everything the plugin contributes, so you can ship reusable capability packs without writing per-extension wiring in every host application.
+
+This guide explains the plugin folder layout, how to load a plugin from a directory, when to use plugin directories vs. registering individual extensions, and how to make plugin sets deterministic.
+
+## When to use plugin directories
+
+Use a plugin directory when you want to:
+
+* **Distribute a bundle of capabilities** as one unit — e.g., a "TypeScript reviewer" pack with a skill, a `preToolUse` hook that enforces lint, and a custom agent that runs the reviewer.
+* **Vendor capability packs into a repository** so every clone of the host application loads the same extensions deterministically.
+* **Develop a plugin locally** before publishing it to a marketplace.
+* **Override or extend** a marketplace-installed plugin with a local checkout for testing.
+
+If you only need to add a single MCP server, a single hook, or a single custom agent, you can register it inline via the SDK config (`mcpServers`, `hooks`, `customAgents`). Plugin directories are most useful once you have three or more related extensions that ship together.
+
+## Plugin folder layout
+
+The Copilot CLI scans each plugin directory for a `plugin.json` manifest or a root-level `SKILL.md`. A minimal plugin looks like this:
+
+```
+my-plugin/
+├── plugin.json # manifest (required unless using SKILL.md only)
+├── SKILL.md # optional: top-level skill
+├── hooks.json # optional: hooks config
+├── .mcp.json # optional: MCP server config
+├── agents/ # optional: custom agents (one .md file per agent)
+│ └── code-reviewer.md
+└── skills/ # optional: additional skills
+ └── lint-fix/
+ └── SKILL.md
+```
+
+The manifest may also live at `.github/plugin.json` or `.github/plugin/plugin.json` so plugins can sit inside an existing repository without changing its root layout. Each subsystem (hooks, MCP, LSP, skills, agents) has its own loader and is optional — a plugin only needs the parts it contributes.
+
+For the full manifest schema, see the runtime documentation referenced from your CLI's `/plugin` slash command.
+
+## Loading a plugin directory from the SDK
+
+Plugin directories are loaded by passing `--plugin-dir ` to the Copilot CLI when the SDK spawns it. Each language exposes this through the runtime connection's extra-args option. The flag can be repeated to load multiple plugins.
+
+
+Node.js / TypeScript
+
+
+```typescript
+import { CopilotClient, RuntimeConnection } from "@github/copilot-sdk";
+
+async function main() {
+ const client = new CopilotClient({
+ connection: RuntimeConnection.forStdio({
+ args: [
+ "--plugin-dir", "./plugins/code-reviewer",
+ "--plugin-dir", "./plugins/lint-fix",
+ ],
+ }),
+ });
+
+ await client.start();
+}
+
+main();
+```
+
+
+```typescript
+import { CopilotClient, RuntimeConnection } from "@github/copilot-sdk";
+
+const client = new CopilotClient({
+ connection: RuntimeConnection.forStdio({
+ args: [
+ "--plugin-dir", "./plugins/code-reviewer",
+ "--plugin-dir", "./plugins/lint-fix",
+ ],
+ }),
+});
+
+await client.start();
+```
+
+
+
+
+Python
+
+
+```python
+from copilot import CopilotClient, StdioRuntimeConnection
+
+client = CopilotClient(
+ connection=StdioRuntimeConnection(
+ args=(
+ "--plugin-dir", "./plugins/code-reviewer",
+ "--plugin-dir", "./plugins/lint-fix",
+ ),
+ ),
+)
+await client.start()
+```
+
+
+
+
+Go
+
+
+```go
+package main
+
+import (
+ "context"
+
+ copilot "github.com/github/copilot-sdk/go"
+)
+
+func main() {
+ ctx := context.Background()
+ client := copilot.NewClient(&copilot.ClientOptions{
+ Connection: copilot.StdioConnection{
+ Args: []string{
+ "--plugin-dir", "./plugins/code-reviewer",
+ "--plugin-dir", "./plugins/lint-fix",
+ },
+ },
+ })
+ if err := client.Start(ctx); err != nil {
+ return
+ }
+}
+```
+
+
+```go
+client := copilot.NewClient(&copilot.ClientOptions{
+ Connection: copilot.StdioConnection{
+ Args: []string{
+ "--plugin-dir", "./plugins/code-reviewer",
+ "--plugin-dir", "./plugins/lint-fix",
+ },
+ },
+})
+if err := client.Start(ctx); err != nil {
+ return err
+}
+```
+
+
+
+
+.NET
+
+```csharp
+using GitHub.Copilot;
+
+await using var client = new CopilotClient(new CopilotClientOptions
+{
+ Connection = RuntimeConnection.ForStdio(args: new[]
+ {
+ "--plugin-dir", "./plugins/code-reviewer",
+ "--plugin-dir", "./plugins/lint-fix",
+ }),
+});
+
+await client.StartAsync();
+```
+
+
+
+
+Java
+
+
+```java
+import com.github.copilot.CopilotClient;
+import com.github.copilot.rpc.CopilotClientOptions;
+
+public class PluginDirectoriesExample {
+ public static void main(String[] args) throws Exception {
+ var options = new CopilotClientOptions()
+ .setCliArgs(new String[] {
+ "--plugin-dir", "./plugins/code-reviewer",
+ "--plugin-dir", "./plugins/lint-fix",
+ });
+
+ var client = new CopilotClient(options);
+ client.start().get();
+ }
+}
+```
+
+
+```java
+var options = new CopilotClientOptions()
+ .setCliArgs(new String[] {
+ "--plugin-dir", "./plugins/code-reviewer",
+ "--plugin-dir", "./plugins/lint-fix",
+ });
+
+var client = new CopilotClient(options);
+client.start().get();
+```
+
+
+
+
+Rust
+
+
+```rust
+use github_copilot_sdk::{Client, ClientOptions};
+
+#[tokio::main]
+async fn main() -> Result<(), Box> {
+ let _client = Client::start(
+ ClientOptions::new().with_extra_args([
+ "--plugin-dir", "./plugins/code-reviewer",
+ "--plugin-dir", "./plugins/lint-fix",
+ ]),
+ )
+ .await?;
+ Ok(())
+}
+```
+
+
+```rust
+use github_copilot_sdk::{Client, ClientOptions};
+
+let client = Client::start(
+ ClientOptions::new().with_extra_args([
+ "--plugin-dir", "./plugins/code-reviewer",
+ "--plugin-dir", "./plugins/lint-fix",
+ ]),
+)
+.await?;
+```
+
+
+
+> The example above uses an stdio runtime connection — the default when the SDK bundles the CLI. If you connect to an external runtime via a URL (`forUri` / `ForUri`), pass `--plugin-dir` to the long-running CLI server when you start it; the SDK does not forward `--plugin-dir` to runtimes it didn't spawn.
+
+## What a plugin can contribute
+
+Loading a plugin directory makes its extensions visible to every session created by the client. The runtime merges plugin-provided extensions with anything you register inline:
+
+| Plugin contributes | Visible to session as |
+|---|---|
+| Skills (`SKILL.md`, `skills/*/SKILL.md`) | Items in `session.skills.list()`; injectable by name |
+| Custom agents (`agents/*.md`) | Dispatchable via the `task(agent_type=...)` tool |
+| Hooks (`hooks.json`) | Fired alongside hooks registered via the SDK |
+| MCP servers (`.mcp.json`) | Tools and resources reachable through `session.mcp.*` |
+| LSP servers (`.lsp.json`) | Initialized via `session.lsp.initialize(...)` |
+
+Plugin agents are first-class sub-agents in [fleet mode](./fleet-mode.md): a parent agent can dispatch them by `agent_type`, and the runtime fires the `subagentStart` / `subagentStop` hooks for them like any other sub-agent.
+
+## Plugin-dir vs marketplace plugins
+
+The runtime has two ways to install plugins, and both end up looking the same to a session:
+
+* **Marketplace / direct-repo plugins** are installed persistently through the CLI's `/plugin` slash command or the underlying `installedPlugins` user setting. They are *ambient* — every session that runs against the same user config sees them, and they participate in plugin discovery rules.
+* **`--plugin-dir` plugins** are *explicit and ephemeral* — they only apply to the CLI process you launched with that flag. They take precedence over ambient discovery and are de-duplicated against marketplace entries with the same cache path, so the same plugin won't load twice when both surfaces reference it.
+
+For SDK-driven applications, `--plugin-dir` is usually the right choice: it keeps the plugin set under your application's control instead of depending on per-machine user state.
+
+## Making plugin sets deterministic
+
+When the host machine may have other plugins installed (marketplace or personal), set `COPILOT_PLUGIN_DIR_ONLY=true` in the runtime's environment to suppress automatic plugin discovery. Only the directories you pass via `--plugin-dir` will load.
+
+
+Node.js / TypeScript
+
+
+```typescript
+import { CopilotClient, RuntimeConnection } from "@github/copilot-sdk";
+
+async function main() {
+ process.env.COPILOT_PLUGIN_DIR_ONLY = "true";
+ const client = new CopilotClient({
+ connection: RuntimeConnection.forStdio({
+ args: ["--plugin-dir", "./plugins/code-reviewer"],
+ }),
+ });
+ await client.start();
+}
+
+main();
+```
+
+
+```typescript
+process.env.COPILOT_PLUGIN_DIR_ONLY = "true";
+
+const client = new CopilotClient({
+ connection: RuntimeConnection.forStdio({
+ args: ["--plugin-dir", "./plugins/code-reviewer"],
+ }),
+});
+await client.start();
+```
+
+
+
+Use this in CI, in headless server deployments, and anywhere you want a reproducible plugin set that doesn't depend on the host's user configuration.
+
+## Inspecting which plugins loaded
+
+Once a session is created, list the active plugins to confirm a directory was picked up correctly:
+
+
+Node.js / TypeScript
+
+
+```typescript
+import { CopilotClient } from "@github/copilot-sdk";
+
+async function main() {
+ const client = new CopilotClient();
+ await client.start();
+ const session = await client.createSession({
+ onPermissionRequest: async () => ({ kind: "approve-once" }),
+ });
+
+ const plugins = await session.rpc.plugins.list();
+ for (const plugin of plugins.plugins) {
+ console.log(`${plugin.name} (${plugin.enabled ? "enabled" : "disabled"})`);
+ }
+}
+
+main();
+```
+
+
+```typescript
+const plugins = await session.rpc.plugins.list();
+for (const plugin of plugins.plugins) {
+ console.log(`${plugin.name} (${plugin.enabled ? "enabled" : "disabled"})`);
+}
+```
+
+
+
+Plugins loaded via `--plugin-dir` appear in this list with their cache path set to the directory you provided. Marketplace installs are tagged with their registry source.
+
+## Troubleshooting
+
+* **"no plugin.json or SKILL.md found in <dir>"** — the directory exists but doesn't qualify as a plugin. Add a `plugin.json` manifest at the root (or under `.github/`), or include a top-level `SKILL.md`.
+* **Plugin loaded but agents/skills not visible** — make sure the plugin manifest declares the agents/skills it contributes, or use the implicit layout (`agents/*.md`, `skills/*/SKILL.md`). Then call `session.rpc.skills.reload()` to pick up changes without restarting.
+* **Duplicate hooks firing** — the runtime de-duplicates by `cache_path`, but only when the same directory is referenced both as a marketplace install and a `--plugin-dir`. If two different directories contain the same plugin, both will load. Remove one or use `COPILOT_PLUGIN_DIR_ONLY=true`.
+* **`--plugin-dir` ignored when connecting to an external runtime** — the SDK only forwards extra args when it spawns the CLI itself. For external runtimes (`forUri`/`ForUri`), pass `--plugin-dir` on the command line that starts the runtime server.
+
+## Related
+
+* [Custom Agents](./custom-agents.md): write agents that ship inside a plugin's `agents/` folder.
+* [Skills](./skills.md): how `SKILL.md` files are loaded, and the skill-tier ordering rules.
+* [Hooks](./hooks.md): hooks defined by a plugin fire alongside SDK-registered hooks.
+* [MCP Servers](./mcp.md): plugin-provided MCP servers integrate the same way as inline registrations.
+* [Fleet Mode](./fleet-mode.md): plugin-provided agents are dispatchable as sub-agents.
diff --git a/docs/features/remote-sessions.md b/docs/features/remote-sessions.md
index f58238eee..5a15ca825 100644
--- a/docs/features/remote-sessions.md
+++ b/docs/features/remote-sessions.md
@@ -2,6 +2,8 @@
Remote sessions let users access their Copilot session from GitHub web and mobile via [Mission Control](https://github.com). When enabled, the SDK connects each session to Mission Control, producing a URL that can be shared as a link or QR code.
+For running sessions on GitHub-hosted compute, see [Cloud Sessions](./cloud-sessions.md).
+
## Prerequisites
* The user must be authenticated (GitHub token or logged-in user)
@@ -120,92 +122,6 @@ while let Ok(event) = events.recv().await {
-### Cloud sessions
-
-Set the create-session `cloud` option to create a remote session in the cloud instead of a local session. You can include repository metadata to associate the cloud session with a GitHub repository.
-
-
-
-#### TypeScript
-
-
-```typescript
-const session = await client.createSession({
- onPermissionRequest: async () => ({ allowed: true }),
- cloud: {
- repository: { owner: "github", name: "copilot-sdk", branch: "main" },
- },
-});
-```
-
-#### Python
-
-
-```python
-from copilot import CloudSessionOptions, CloudSessionRepository
-
-session = await client.create_session(
- on_permission_request=PermissionHandler.approve_all,
- cloud=CloudSessionOptions(
- repository=CloudSessionRepository(
- owner="github",
- name="copilot-sdk",
- branch="main",
- )
- ),
-)
-```
-
-#### Go
-
-
-```go
-session, err := client.CreateSession(ctx, &copilot.SessionConfig{
- Cloud: &copilot.CloudSessionOptions{
- Repository: &copilot.CloudSessionRepository{
- Owner: "github",
- Name: "copilot-sdk",
- Branch: "main",
- },
- },
-})
-```
-
-#### C#
-
-
-```csharp
-var session = await client.CreateSessionAsync(new SessionConfig
-{
- Cloud = new CloudSessionOptions
- {
- Repository = new CloudSessionRepository
- {
- Owner = "github",
- Name = "copilot-sdk",
- Branch = "main"
- }
- }
-});
-```
-
-#### Rust
-
-
-```rust
-use github_copilot_sdk::{CloudSessionOptions, CloudSessionRepository, SessionConfig};
-
-let session = client.create_session(
- SessionConfig::default().with_cloud(
- CloudSessionOptions::with_repository(
- CloudSessionRepository::new("github", "copilot-sdk").with_branch("main"),
- ),
- ),
-).await?;
-```
-
-
-
### On-demand (per-session toggle)
Use `session.rpc.remote.enable()` to start remote access mid-session, and `session.rpc.remote.disable()` to stop it. This is equivalent to the CLI's `/remote on` and `/remote off` commands.
@@ -286,6 +202,5 @@ The remote URL can be rendered as a QR code for easy mobile access. The SDK prov
## Notes
* The `remote` client option only applies when the SDK spawns the CLI process. It is ignored when connecting to an external server via `cliUrl`.
-* The `cloud` session option applies only to new sessions created with `session.create`; it is not used when resuming an existing session.
* If the working directory is not a GitHub repository, remote setup is silently skipped (always-on mode) or returns an error (on-demand mode).
* Remote sessions require authentication. Ensure `gitHubToken` or `useLoggedInUser` is configured.
diff --git a/docs/features/streaming-events.md b/docs/features/streaming-events.md
index 3388d6a1a..423aa9e34 100644
--- a/docs/features/streaming-events.md
+++ b/docs/features/streaming-events.md
@@ -85,7 +85,7 @@ session.on("assistant.message_delta", (event) => {
```python
from copilot import CopilotClient
-from copilot.generated.session_events import SessionEventType
+from copilot.session_events import SessionEventType
client = CopilotClient()
@@ -100,7 +100,7 @@ def handle(event):
```python
-from copilot.generated.session_events import SessionEventType
+from copilot.session_events import SessionEventType
def handle(event):
if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA:
@@ -315,6 +315,7 @@ Ephemeral. Token usage and cost information for an individual API call.
| `duration` | `number` | | API call duration in milliseconds |
| `initiator` | `string` | | What triggered this call (e.g., `"sub-agent"`); absent for user-initiated |
| `apiCallId` | `string` | | Completion ID from the provider (e.g., `chatcmpl-abc123`) |
+| `apiEndpoint` | `"/chat/completions" \| "/v1/messages" \| "/responses" \| "ws:/responses"` | | API endpoint used for the model call; useful for observability and cost attribution. `ws:/responses` is the websocket variant of the responses API |
| `providerCallId` | `string` | | GitHub request tracing ID (`x-github-request-id`) |
| `parentToolCallId` | `string` | | Set when usage originates from a sub-agent |
| `quotaSnapshots` | `Record` | | Per-quota resource usage, keyed by quota identifier |
@@ -759,7 +760,7 @@ session.idle → Ready for next message (ephemeral)
| `assistant.message` | | Assistant | `messageId`, `content`, `toolRequests?`, `outputTokens?`, `phase?` |
| `assistant.message_delta` | ✅ | Assistant | `messageId`, `deltaContent`, `parentToolCallId?` |
| `assistant.turn_end` | | Assistant | `turnId` |
-| `assistant.usage` | ✅ | Assistant | `model`, `inputTokens?`, `outputTokens?`, `cost?`, `duration?` |
+| `assistant.usage` | ✅ | Assistant | `model`, `apiEndpoint?`, `inputTokens?`, `outputTokens?`, `cost?`, `duration?` |
| `tool.user_requested` | | Tool | `toolCallId`, `toolName`, `arguments?` |
| `tool.execution_start` | | Tool | `toolCallId`, `toolName`, `arguments?`, `mcpServerName?` |
| `tool.execution_partial_result` | ✅ | Tool | `toolCallId`, `partialOutput` |
diff --git a/docs/getting-started.md b/docs/getting-started.md
index 80c9541e4..f4e92f6fe 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -18,7 +18,7 @@ Copilot: In Tokyo it's 75°F and sunny. Great day to be outside!
Before you begin, make sure you have:
-* **GitHub Copilot CLI** installed and authenticated ([Installation guide](https://docs.github.com/en/copilot/how-tos/set-up/install-copilot-cli))
+* **GitHub Copilot CLI** installed and authenticated (the Node.js, Python, and .NET SDKs bundle the CLI automatically—see [Bundled CLI](./setup/bundled-cli.md). Required for Go, Java, and Rust unless using their application-level CLI bundling features.)
* Your preferred language runtime:
* **Node.js** 20+ or **Python** 3.11+ or **Go** 1.24+ or **Rust** 1.94+ or **Java** 17+ or **.NET** 8.0+
@@ -264,7 +264,7 @@ use github_copilot_sdk::{Client, ClientOptions, MessageOptions, SessionConfig};
async fn main() -> Result<(), Box> {
let client = Client::start(ClientOptions::default()).await?;
let session = client
- .create_session(SessionConfig::default().with_handler(Arc::new(ApproveAllHandler)))
+ .create_session(SessionConfig::default().with_permission_handler(Arc::new(ApproveAllHandler)))
.await?;
let response = session
@@ -413,7 +413,7 @@ import asyncio
import sys
from copilot import CopilotClient
from copilot.session import PermissionHandler
-from copilot.generated.session_events import SessionEventType
+from copilot.session_events import SessionEventType
async def main():
client = CopilotClient()
@@ -514,7 +514,7 @@ async fn main() -> Result<(), Box> {
let mut config = SessionConfig::default();
config.streaming = Some(true);
let session = client
- .create_session(config.with_handler(Arc::new(ApproveAllHandler)))
+ .create_session(config.with_permission_handler(Arc::new(ApproveAllHandler)))
.await?;
// Listen for response chunks
@@ -666,7 +666,7 @@ unsubscribeIdle();
```python
from copilot import CopilotClient, PermissionDecisionApproveOnce
-from copilot.generated.session_events import SessionEvent, SessionEventType
+from copilot.session_events import SessionEvent, SessionEventType
client = CopilotClient()
@@ -947,7 +947,7 @@ import sys
from copilot import CopilotClient
from copilot.session import PermissionHandler
from copilot.tools import define_tool
-from copilot.generated.session_events import SessionEventType
+from copilot.session_events import SessionEventType
from pydantic import BaseModel, Field
# Define the parameters for the tool using Pydantic
@@ -1086,7 +1086,7 @@ use std::sync::Arc;
use std::time::Duration;
use github_copilot_sdk::handler::ApproveAllHandler;
-use github_copilot_sdk::tool::{JsonSchema, ToolHandlerRouter, define_tool};
+use github_copilot_sdk::tool::{define_tool, JsonSchema};
use github_copilot_sdk::{Client, ClientOptions, MessageOptions, SessionConfig, ToolResult};
use serde::Deserialize;
@@ -1098,27 +1098,28 @@ struct GetWeatherParams {
#[tokio::main]
async fn main() -> Result<(), Box> {
// Define a tool that Copilot can call
- let router = ToolHandlerRouter::new(
- vec![define_tool(
- "get_weather",
- "Get the current weather for a city",
- |_inv, params: GetWeatherParams| async move {
- Ok(ToolResult::Text(format!(
- "{}: 62°F and sunny",
- params.city
- )))
- },
- )],
- Arc::new(ApproveAllHandler),
- );
- let tools = router.tools();
+ let tools = vec![define_tool(
+ "get_weather",
+ "Get the current weather for a city",
+ |_inv, params: GetWeatherParams| async move {
+ Ok(ToolResult::Text(format!(
+ "{}: 62°F and sunny",
+ params.city
+ )))
+ },
+ )];
let client = Client::start(ClientOptions::default()).await?;
let mut config = SessionConfig::default();
config.streaming = Some(true);
- config.tools = Some(tools);
- let session = client.create_session(config.with_handler(Arc::new(router))).await?;
+ let session = client
+ .create_session(
+ config
+ .with_tools(tools)
+ .with_permission_handler(Arc::new(ApproveAllHandler)),
+ )
+ .await?;
let mut events = session.subscribe();
tokio::spawn(async move {
@@ -1370,7 +1371,7 @@ import sys
from copilot import CopilotClient
from copilot.session import PermissionHandler
from copilot.tools import define_tool
-from copilot.generated.session_events import SessionEventType
+from copilot.session_events import SessionEventType
from pydantic import BaseModel, Field
class GetWeatherParams(BaseModel):
@@ -1546,7 +1547,7 @@ use std::sync::Arc;
use std::time::Duration;
use github_copilot_sdk::handler::ApproveAllHandler;
-use github_copilot_sdk::tool::{JsonSchema, ToolHandlerRouter, define_tool};
+use github_copilot_sdk::tool::{define_tool, JsonSchema};
use github_copilot_sdk::{Client, ClientOptions, MessageOptions, SessionConfig, ToolResult};
use serde::Deserialize;
@@ -1567,27 +1568,28 @@ fn read_line() -> Option {
#[tokio::main]
async fn main() -> Result<(), Box> {
- let router = ToolHandlerRouter::new(
- vec![define_tool(
- "get_weather",
- "Get the current weather for a city",
- |_inv, params: GetWeatherParams| async move {
- Ok(ToolResult::Text(format!(
- "{}: 62°F and sunny",
- params.city
- )))
- },
- )],
- Arc::new(ApproveAllHandler),
- );
- let tools = router.tools();
+ let tools = vec![define_tool(
+ "get_weather",
+ "Get the current weather for a city",
+ |_inv, params: GetWeatherParams| async move {
+ Ok(ToolResult::Text(format!(
+ "{}: 62°F and sunny",
+ params.city
+ )))
+ },
+ )];
let client = Client::start(ClientOptions::default()).await?;
let mut config = SessionConfig::default();
config.streaming = Some(true);
- config.tools = Some(tools);
- let session = client.create_session(config.with_handler(Arc::new(router))).await?;
+ let session = client
+ .create_session(
+ config
+ .with_tools(tools)
+ .with_permission_handler(Arc::new(ApproveAllHandler)),
+ )
+ .await?;
let mut events = session.subscribe();
tokio::spawn(async move {
@@ -1998,9 +2000,9 @@ import (
func main() {
ctx := context.Background()
- client := copilot.NewClient(&copilot.ClientOptions{
- Connection: copilot.UriConnection{URL: "localhost:4321"},
- })
+ client := copilot.NewClient(&copilot.ClientOptions{
+ Connection: copilot.URIConnection{URL: "localhost:4321"},
+ })
if err := client.Start(ctx); err != nil {
log.Fatal(err)
@@ -2019,7 +2021,7 @@ func main() {
import copilot "github.com/github/copilot-sdk/go"
client := copilot.NewClient(&copilot.ClientOptions{
- Connection: copilot.UriConnection{URL: "localhost:4321"},
+ Connection: copilot.URIConnection{URL: "localhost:4321"},
})
if err := client.Start(ctx); err != nil {
@@ -2054,7 +2056,7 @@ let client = Client::start(options).await?;
// Use the client normally
let session = client
- .create_session(SessionConfig::default().with_handler(Arc::new(ApproveAllHandler)))
+ .create_session(SessionConfig::default().with_permission_handler(Arc::new(ApproveAllHandler)))
.await?;
// ...
```
@@ -2103,7 +2105,7 @@ var session = client.createSession(
-**Note:** When `cli_url` / `cliUrl` / Go's `UriConnection` is provided, or Rust uses `Transport::External`, the SDK will not spawn or manage a CLI process - it will only connect to the existing server at the specified URL.
+**Note:** When `cli_url` / `cliUrl` / Go's `URIConnection` is provided, or Rust uses `Transport::External`, the SDK will not spawn or manage a CLI process - it will only connect to the existing server at the specified URL.
## Telemetry and observability
diff --git a/docs/hooks/pre-tool-use.md b/docs/hooks/pre-tool-use.md
index fe373cc2f..c2ab0b0ba 100644
--- a/docs/hooks/pre-tool-use.md
+++ b/docs/hooks/pre-tool-use.md
@@ -154,6 +154,23 @@ Return `null` or `undefined` to allow the tool to execute with no changes. Other
| `"deny"` | Tool is blocked, reason shown to user |
| `"ask"` | User is prompted to approve (interactive mode) |
+### Skipping permission prompts for trusted custom tools
+
+If you define a custom tool that is safe to run without prompting, set `skipPermission: true` on the tool definition. Use this for trusted, app-owned tools whose inputs are already constrained by your application; use `onPreToolUse` when you need per-call policy checks or argument validation.
+
+```typescript
+const getWeather = defineTool("get_weather", {
+ description: "Get weather for a location.",
+ parameters: {
+ type: "object",
+ properties: { location: { type: "string" } },
+ required: ["location"],
+ },
+ skipPermission: true,
+ handler: async ({ location }) => ({ forecast: `Sunny in ${location}` }),
+});
+```
+
## Examples
### Allow all tools (logging only)
diff --git a/docs/index.md b/docs/index.md
index 059b54b12..9abc943f5 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -28,6 +28,7 @@ How to configure and deploy the SDK for your use case.
* [GitHub OAuth](./setup/github-oauth.md): implement the OAuth flow
* [Azure Managed Identity](./setup/azure-managed-identity.md): BYOK with Azure AI Foundry
* [Scaling & Multi-Tenancy](./setup/scaling.md): horizontal scaling, isolation patterns
+* [Multi-Tenancy & Server Deployments](./setup/multi-tenancy.md): mode: "empty", session isolation, integration IDs, sessionFs
### [Authentication](./auth/index.md)
@@ -44,11 +45,14 @@ Guides for building with the SDK's capabilities.
* [Custom Agents](./features/custom-agents.md): define specialized sub-agents
* [MCP Servers](./features/mcp.md): integrate Model Context Protocol servers
* [Skills](./features/skills.md): load reusable prompt modules
+* [Plugin Directories](./features/plugin-directories.md): bundle skills, hooks, MCP servers, and agents as a single loadable plugin
* [Image Input](./features/image-input.md): send images as attachments
* [Streaming Events](./features/streaming-events.md): real-time event reference
* [Steering & Queueing](./features/steering-and-queueing.md): message delivery modes
* [Session Persistence](./features/session-persistence.md): resume sessions across restarts
-* [Remote Sessions](./features/remote-sessions.md): share sessions to GitHub web and mobile
+* [Remote Sessions](./features/remote-sessions.md): share sessions to GitHub web and mobile via Mission Control
+* [Cloud Sessions](./features/cloud-sessions.md): run sessions on GitHub-hosted compute with the cloud: option
+* [Fleet Mode](./features/fleet-mode.md): dispatch parallel sub-agents for parallelizable work
### [Hooks Reference](./hooks/index.md)
diff --git a/docs/observability/index.md b/docs/observability/index.md
index 9859cdffd..3f75e4658 100644
--- a/docs/observability/index.md
+++ b/docs/observability/index.md
@@ -3,3 +3,5 @@
Monitor and debug your GitHub Copilot SDK applications.
* [OpenTelemetry instrumentation](./opentelemetry.md): built-in TelemetryConfig and trace context propagation
+
+For cost attribution and endpoint-level analysis, subscribe to `assistant.usage` events and inspect `apiEndpoint` (`AssistantUsageApiEndpoint`); see [Streaming events](../features/streaming-events.md).
diff --git a/docs/observability/opentelemetry.md b/docs/observability/opentelemetry.md
index ee2014efb..d89f68ca9 100644
--- a/docs/observability/opentelemetry.md
+++ b/docs/observability/opentelemetry.md
@@ -115,6 +115,8 @@ let client = Client::start(ClientOptions::new()
The SDK can propagate W3C Trace Context (`traceparent`/`tracestate`) on JSON-RPC payloads so that your application's spans and the CLI's spans are linked in one distributed trace. This is useful when, for example, you want to see a "handle tool call" span in your app nested inside the CLI's "execute tool" span, or show the SDK call as a child of your request-handling span.
+For cost attribution alongside traces, subscribe to `assistant.usage` events and inspect `apiEndpoint` (`AssistantUsageApiEndpoint`) to see whether a turn used Chat Completions, Responses, or Anthropic Messages; see [Streaming events](../features/streaming-events.md).
+
#### SDK → CLI (outbound)
For **Node.js**, provide an `onGetTraceContext` callback on the client options. This is only needed if your application already uses `@opentelemetry/api` and you want to link your spans with the CLI's spans. The SDK calls this callback before `session.create`, `session.resume`, and `session.send` RPCs:
diff --git a/docs/setup/backend-services.md b/docs/setup/backend-services.md
index 2dc2c47d1..ca4a310b6 100644
--- a/docs/setup/backend-services.md
+++ b/docs/setup/backend-services.md
@@ -6,7 +6,7 @@ Run the Copilot SDK in server-side applications—APIs, web backends, microservi
## How it works
-Instead of the SDK spawning a CLI child process, you run the CLI independently in **headless server mode**. Your backend connects to it over TCP using the `Connection` option (`UriConnection`).
+Instead of the SDK spawning a CLI child process, you run the CLI independently in **headless server mode**. Your backend connects to it over TCP using the `Connection` option (`URIConnection`).
```mermaid
flowchart TB
@@ -36,6 +36,8 @@ flowchart TB
* Multiple SDK clients can share one CLI server
* Works with any auth method (GitHub tokens, env vars, BYOK)
+For multi-user server mode, configure SDK clients with `mode: "empty"`, pass user credentials per session, and explicitly allow tools for each session. See [Multi-Tenancy & Server Deployments](./multi-tenancy.md) for the full pattern.
+
## Architecture: auto-managed vs. external CLI
```mermaid
@@ -123,15 +125,18 @@ Restart=always
Node.js / TypeScript
```typescript
-import { CopilotClient } from "@github/copilot-sdk";
+import { CopilotClient, RuntimeConnection } from "@github/copilot-sdk";
const client = new CopilotClient({
- cliUrl: "localhost:4321",
+ connection: RuntimeConnection.forUri("localhost:4321"),
+ mode: "empty",
});
const session = await client.createSession({
sessionId: `user-${userId}-${Date.now()}`,
model: "gpt-4.1",
+ availableTools: ["custom:*"],
+ gitHubToken: user.githubToken,
});
const response = await session.sendAndWait({ prompt: req.body.message });
@@ -178,9 +183,9 @@ func main() {
userID := "user1"
message := "Hello"
- client := copilot.NewClient(&copilot.ClientOptions{
- Connection: copilot.UriConnection{URL: "localhost:4321"},
- })
+ client := copilot.NewClient(&copilot.ClientOptions{
+ Connection: copilot.URIConnection{URL: "localhost:4321"},
+ })
client.Start(ctx)
defer client.Stop()
@@ -197,7 +202,7 @@ func main() {
```go
client := copilot.NewClient(&copilot.ClientOptions{
- Connection: copilot.UriConnection{URL: "localhost:4321"},
+ Connection: copilot.URIConnection{URL: "localhost:4321"},
})
client.Start(ctx)
defer client.Stop()
@@ -318,17 +323,18 @@ copilot --headless --port 4321
Pass individual user tokens when creating sessions. See [GitHub OAuth](./github-oauth.md) for the full flow.
```typescript
+const client = new CopilotClient({
+ connection: RuntimeConnection.forUri("localhost:4321"),
+ mode: "empty",
+});
+
// Your API receives user tokens from your auth layer
app.post("/chat", authMiddleware, async (req, res) => {
- const client = new CopilotClient({
- cliUrl: "localhost:4321",
- gitHubToken: req.user.githubToken,
- useLoggedInUser: false,
- });
-
const session = await client.createSession({
sessionId: `user-${req.user.id}-chat`,
model: "gpt-4.1",
+ availableTools: ["custom:*"],
+ gitHubToken: req.user.githubToken,
});
const response = await session.sendAndWait({
@@ -345,7 +351,7 @@ Use your own API keys for the model provider. See [BYOK](../auth/byok.md) for de
```typescript
const client = new CopilotClient({
- cliUrl: "localhost:4321",
+ connection: RuntimeConnection.forUri("localhost:4321"),
});
const session = await client.createSession({
@@ -380,14 +386,15 @@ flowchart TB
```typescript
import express from "express";
-import { CopilotClient } from "@github/copilot-sdk";
+import { CopilotClient, RuntimeConnection } from "@github/copilot-sdk";
const app = express();
app.use(express.json());
-// Single shared CLI connection
+// Single shared CLI connection for multi-user server mode
const client = new CopilotClient({
- cliUrl: process.env.CLI_URL || "localhost:4321",
+ connection: RuntimeConnection.forUri(process.env.CLI_URL || "localhost:4321"),
+ mode: "empty",
});
app.post("/api/chat", async (req, res) => {
@@ -401,6 +408,8 @@ app.post("/api/chat", async (req, res) => {
session = await client.createSession({
sessionId,
model: "gpt-4.1",
+ availableTools: ["custom:*"],
+ gitHubToken: req.user.githubToken,
});
}
@@ -417,10 +426,10 @@ app.listen(3000);
### Background worker
```typescript
-import { CopilotClient } from "@github/copilot-sdk";
+import { CopilotClient, RuntimeConnection } from "@github/copilot-sdk";
const client = new CopilotClient({
- cliUrl: process.env.CLI_URL || "localhost:4321",
+ connection: RuntimeConnection.forUri(process.env.CLI_URL || "localhost:4321"),
});
// Process jobs from a queue
@@ -538,11 +547,13 @@ setInterval(() => cleanupSessions(24 * 60 * 60 * 1000), 60 * 60 * 1000);
| Need | Next Guide |
|------|-----------|
| Multiple CLI servers / high availability | [Scaling & Multi-Tenancy](./scaling.md) |
+| SDK isolation for concurrent users | [Multi-Tenancy & Server Deployments](./multi-tenancy.md) |
| GitHub account auth for users | [GitHub OAuth](./github-oauth.md) |
| Your own model keys | [BYOK](../auth/byok.md) |
## Next steps
+* **[Multi-Tenancy & Server Deployments](./multi-tenancy.md)**: Configure SDK isolation for concurrent users
* **[Scaling & Multi-Tenancy](./scaling.md)**: Handle more users, add redundancy
* **[Session Persistence](../features/session-persistence.md)**: Resume sessions across restarts
* **[GitHub OAuth](./github-oauth.md)**: Add user authentication
diff --git a/docs/setup/choosing-a-setup-path.md b/docs/setup/choosing-a-setup-path.md
index f1c4636c6..7fe28be8d 100644
--- a/docs/setup/choosing-a-setup-path.md
+++ b/docs/setup/choosing-a-setup-path.md
@@ -50,6 +50,7 @@ You're building tools for your team or company. Users are employees who need to
1. **[Backend Services](./backend-services.md)**—Run the SDK in your internal services
**If scaling beyond a single server:**
+1. **[Multi-tenancy and server deployments](./multi-tenancy.md)**—Configure SDK options for multi-user server mode
1. **[Scaling & Multi-Tenancy](./scaling.md)**—Handle multiple users and services
### 🚀 App developer (ISV)
@@ -62,6 +63,7 @@ You're building a product for customers. You need to handle authentication for y
1. **[Backend Services](./backend-services.md)**—Power your product from server-side code
**For production:**
+1. **[Multi-tenancy and server deployments](./multi-tenancy.md)**—Use `mode: "empty"`, per-session tokens, and isolated runtime state
1. **[Scaling & Multi-Tenancy](./scaling.md)**—Serve many customers reliably
### 🏗️ Platform developer
@@ -70,6 +72,7 @@ You're embedding Copilot into a platform—APIs, developer tools, or infrastruct
**Start with:**
1. **[Backend Services](./backend-services.md)**—Core server-side integration
+1. **[Multi-tenancy and server deployments](./multi-tenancy.md)**—SDK-level isolation, per-session auth, and shared runtime options
1. **[Scaling & Multi-Tenancy](./scaling.md)**—Session isolation, horizontal scaling, persistence
**Depending on your auth model:**
@@ -88,6 +91,7 @@ Use this table to find the right guides based on what you need to do:
| Use your own model keys (OpenAI, Azure, etc.) | [BYOK](../auth/byok.md) |
| Azure BYOK with Managed Identity (no API keys) | [Azure Managed Identity](./azure-managed-identity.md) |
| Run the SDK on a server | [Backend Services](./backend-services.md) |
+| Configure SDK options for concurrent users | [Multi-tenancy and server deployments](./multi-tenancy.md) |
| Serve multiple users / scale horizontally | [Scaling & Multi-Tenancy](./scaling.md) |
## Configuration comparison
diff --git a/docs/setup/github-oauth.md b/docs/setup/github-oauth.md
index aea6b22b9..25b6aa80e 100644
--- a/docs/setup/github-oauth.md
+++ b/docs/setup/github-oauth.md
@@ -206,7 +206,7 @@ func main() {
```go
func createClientForUser(userToken string) *copilot.Client {
return copilot.NewClient(&copilot.ClientOptions{
- GithubToken: userToken,
+ GitHubToken: userToken,
UseLoggedInUser: copilot.Bool(false),
})
}
diff --git a/docs/setup/index.md b/docs/setup/index.md
index d077cc6bb..cc4183ca7 100644
--- a/docs/setup/index.md
+++ b/docs/setup/index.md
@@ -6,6 +6,7 @@ Configure and deploy the GitHub Copilot SDK for your use case.
* [Default setup (bundled CLI)](./bundled-cli.md): the SDK includes the CLI automatically
* [Local CLI](./local-cli.md): use your own CLI binary or running instance
* [Backend services](./backend-services.md): server-side with headless CLI over TCP
+* [Multi-tenancy and server deployments](./multi-tenancy.md): SDK options for multi-user server mode
* [GitHub OAuth](./github-oauth.md): implement the OAuth flow
* [Azure managed identity](./azure-managed-identity.md): BYOK with Azure AI Foundry
* [Scaling and multi-tenancy](./scaling.md): horizontal scaling, isolation patterns
diff --git a/docs/setup/local-cli.md b/docs/setup/local-cli.md
index 4c7b5dced..12a66f155 100644
--- a/docs/setup/local-cli.md
+++ b/docs/setup/local-cli.md
@@ -54,7 +54,7 @@ await client.stop();
```python
from copilot import CopilotClient
-from copilot.generated.session_events import AssistantMessageData
+from copilot.session_events import AssistantMessageData
from copilot.session import PermissionHandler
client = CopilotClient({
diff --git a/docs/setup/multi-tenancy.md b/docs/setup/multi-tenancy.md
new file mode 100644
index 000000000..74e828ba7
--- /dev/null
+++ b/docs/setup/multi-tenancy.md
@@ -0,0 +1,457 @@
+# Multi-tenancy and server deployments
+
+Multi-user server mode means running the Copilot SDK from backend code that serves more than one human, tenant, workspace, or integration account. In this setup, the application owns request routing and authorization, while the SDK and runtime provide per-session state, per-session authentication, and explicit tool registration so one user's session does not inherit another user's tools or identity.
+
+**Best for:** SaaS products, partner integrations, internal platforms, and backend services that handle concurrent users.
+
+## Use this guide when
+
+Use this guide when you are building:
+
+* A multi-user SaaS product that embeds Copilot-powered agents
+* A backend for a partner integration, such as a Copilot Studio or Fabric-style pattern
+* Any server that handles concurrent users, workspaces, tenants, or requests
+* A shared runtime where multiple SDK clients connect to one Copilot runtime process
+
+This guide is a sister to [Scaling and multi-tenancy](./scaling.md). Use that guide for topology, load-balancing, and storage patterns. Use this guide for SDK-level options and runtime isolation choices.
+
+## Key SDK options
+
+| Option | Use it for | Notes |
+|--------|------------|-------|
+| `mode: "empty"` | Disabling ambient OS tools and CLI defaults | Required for multi-user or shared scenarios. |
+| `sessionIdleTimeoutSeconds` | Cleaning idle sessions | Set a server-side timeout for long-running processes. |
+| `baseDirectory` | Isolating `COPILOT_HOME` per runtime instance | Ignored when connecting to an existing runtime. |
+| `sessionFs` | Routing session filesystem storage off local disk | Pair with per-session filesystem providers. |
+| `RuntimeConnection.forUri(url)` | Sharing one already-running runtime | Language names vary; see samples below. |
+| Per-session `gitHubToken` | Scoping auth to the requesting user | Prefer this over a single shared user token. |
+
+### `mode: "empty"`
+
+`mode: "empty"` disables optional Copilot CLI behavior by default. In multi-user server mode, this is the safe baseline because your application must explicitly decide which tools, MCP servers, skills, and workspace paths a session can access.
+
+Do not use the default `mode: "copilot-cli"` for shared servers. That mode is intended for CLI-like coding agents and can expose ambient host filesystem capabilities.
+
+
+TypeScript
+
+```typescript
+import { CopilotClient, RuntimeConnection } from "@github/copilot-sdk";
+
+// baseDirectory and sessionIdleTimeoutSeconds apply when the SDK spawns the
+// runtime. With RuntimeConnection.forUri(...) configure COPILOT_HOME and the
+// idle timeout on the runtime process itself.
+const client = new CopilotClient({
+ mode: "empty",
+ connection: RuntimeConnection.forUri(process.env.COPILOT_RUNTIME_URL!),
+});
+
+const session = await client.createSession({
+ sessionId: `user-${user.id}-${crypto.randomUUID()}`,
+ model: "gpt-4.1",
+ availableTools: ["custom:lookupOrder", "custom:createTicket"],
+ gitHubToken: user.githubToken,
+});
+```
+
+
+
+
+Python
+
+```python
+from copilot import CopilotClient, RuntimeConnection
+from copilot.session import PermissionHandler
+
+client = CopilotClient(
+ mode="empty",
+ base_directory=f"/var/lib/my-app/copilot/{runtime_instance_id}",
+ session_idle_timeout_seconds=900,
+ connection=RuntimeConnection.for_uri(runtime_url),
+)
+await client.start()
+
+session = await client.create_session(
+ session_id=f"user-{user.id}-{request_id}",
+ model="gpt-4.1",
+ available_tools=["custom:lookupOrder", "custom:createTicket"],
+ github_token=user.github_token,
+ on_permission_request=PermissionHandler.approve_all,
+)
+```
+
+
+
+
+Go
+
+
+```go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ copilot "github.com/github/copilot-sdk/go"
+)
+
+type appUser struct {
+ ID string
+ GitHubToken string
+}
+
+func main() {
+ ctx := context.Background()
+ runtimeInstanceID := "instance-1"
+ runtimeURL := "http://127.0.0.1:8080"
+ requestID := "req-1"
+ user := appUser{ID: "alice", GitHubToken: "gho_xxx"}
+
+ client := copilot.NewClient(&copilot.ClientOptions{
+ Mode: copilot.ModeEmpty,
+ BaseDirectory: fmt.Sprintf("/var/lib/my-app/copilot/%s", runtimeInstanceID),
+ SessionIdleTimeoutSeconds: 900,
+ Connection: copilot.URIConnection{URL: runtimeURL},
+ })
+
+ session, err := client.CreateSession(ctx, &copilot.SessionConfig{
+ SessionID: fmt.Sprintf("user-%s-%s", user.ID, requestID),
+ Model: "gpt-4.1",
+ AvailableTools: []string{"custom:lookupOrder", "custom:createTicket"},
+ GitHubToken: user.GitHubToken,
+ })
+ _ = session
+ _ = err
+}
+```
+
+
+```go
+client := copilot.NewClient(&copilot.ClientOptions{
+ Mode: copilot.ModeEmpty,
+ BaseDirectory: fmt.Sprintf("/var/lib/my-app/copilot/%s", runtimeInstanceID),
+ SessionIdleTimeoutSeconds: 900,
+ Connection: copilot.URIConnection{URL: runtimeURL},
+})
+
+session, err := client.CreateSession(ctx, &copilot.SessionConfig{
+ SessionID: fmt.Sprintf("user-%s-%s", user.ID, requestID),
+ Model: "gpt-4.1",
+ AvailableTools: []string{"custom:lookupOrder", "custom:createTicket"},
+ GitHubToken: user.GitHubToken,
+})
+```
+
+
+
+
+.NET
+
+
+```csharp
+using GitHub.Copilot;
+
+var runtimeInstanceId = "instance-1";
+var runtimeUrl = "http://127.0.0.1:8080";
+var requestId = "req-1";
+var user = new { Id = "alice", GitHubToken = "gho_xxx" };
+
+var client = new CopilotClient(new CopilotClientOptions
+{
+ Mode = CopilotClientMode.Empty,
+ BaseDirectory = $"/var/lib/my-app/copilot/{runtimeInstanceId}",
+ SessionIdleTimeoutSeconds = 900,
+ Connection = RuntimeConnection.ForUri(runtimeUrl),
+});
+
+await using var session = await client.CreateSessionAsync(new SessionConfig
+{
+ SessionId = $"user-{user.Id}-{requestId}",
+ Model = "gpt-4.1",
+ AvailableTools = ["custom:lookupOrder", "custom:createTicket"],
+ GitHubToken = user.GitHubToken,
+});
+```
+
+
+```csharp
+var client = new CopilotClient(new CopilotClientOptions
+{
+ Mode = CopilotClientMode.Empty,
+ BaseDirectory = $"/var/lib/my-app/copilot/{runtimeInstanceId}",
+ SessionIdleTimeoutSeconds = 900,
+ Connection = RuntimeConnection.ForUri(runtimeUrl),
+});
+
+await using var session = await client.CreateSessionAsync(new SessionConfig
+{
+ SessionId = $"user-{user.Id}-{requestId}",
+ Model = "gpt-4.1",
+ AvailableTools = ["custom:lookupOrder", "custom:createTicket"],
+ GitHubToken = user.GitHubToken,
+});
+```
+
+
+
+
+Java
+
+
+```java
+import java.util.List;
+import com.github.copilot.CopilotClient;
+import com.github.copilot.rpc.CopilotClientOptions;
+import com.github.copilot.rpc.CopilotClientMode;
+import com.github.copilot.rpc.SessionConfig;
+
+public class MultiTenancyExample {
+ record User(String id, String gitHubToken) {}
+
+ public static void main(String[] args) throws Exception {
+ String runtimeUrl = "http://localhost:4321";
+ String requestId = "req-1";
+ User user = new User("u1", "ghu_token");
+
+ // setCopilotHome and setSessionIdleTimeoutSeconds are ignored when
+ // setCliUrl is used; configure those on the runtime process instead.
+ var client = new CopilotClient(new CopilotClientOptions()
+ .setMode(CopilotClientMode.EMPTY)
+ .setCliUrl(runtimeUrl)
+ );
+
+ var session = client.createSession(new SessionConfig()
+ .setSessionId("user-" + user.id() + "-" + requestId)
+ .setModel("gpt-4.1")
+ .setAvailableTools(List.of("custom:lookupOrder", "custom:createTicket"))
+ .setGitHubToken(user.gitHubToken())
+ ).get();
+ }
+}
+```
+
+
+```java
+// setCopilotHome and setSessionIdleTimeoutSeconds are ignored when
+// setCliUrl is used; configure those on the runtime process instead.
+var client = new CopilotClient(new CopilotClientOptions()
+ .setMode(CopilotClientMode.EMPTY)
+ .setCliUrl(runtimeUrl)
+);
+
+var session = client.createSession(new SessionConfig()
+ .setSessionId("user-" + user.id() + "-" + requestId)
+ .setModel("gpt-4.1")
+ .setAvailableTools(List.of("custom:lookupOrder", "custom:createTicket"))
+ .setGitHubToken(user.gitHubToken())
+).get();
+```
+
+
+
+
+Rust
+
+```rust
+use std::path::PathBuf;
+use github_copilot_sdk::{Client, ClientOptions, Transport};
+use github_copilot_sdk::mode::ClientMode;
+use github_copilot_sdk::types::SessionConfig;
+
+let client = Client::start(
+ ClientOptions::new()
+ .with_mode(ClientMode::Empty)
+ .with_base_directory(PathBuf::from(format!(
+ "/var/lib/my-app/copilot/{runtime_instance_id}"
+ )))
+ .with_session_idle_timeout_seconds(900)
+ .with_transport(Transport::External {
+ host: runtime_host.to_string(),
+ port: runtime_port,
+ connection_token: None,
+ }),
+).await?;
+
+let session = client.create_session(
+ SessionConfig::default()
+ .with_session_id(format!("user-{}-{request_id}", user.id))
+ .with_model("gpt-4.1")
+ .with_available_tools(["custom:lookupOrder", "custom:createTicket"])
+ .with_github_token(user.github_token),
+).await?;
+```
+
+
+
+### `sessionIdleTimeoutSeconds`
+
+Set `sessionIdleTimeoutSeconds` on servers so inactive sessions are cleaned up automatically. This prevents zombie sessions in long-running processes and reduces memory and filesystem pressure.
+
+| Language | Public option |
+|----------|---------------|
+| TypeScript | `sessionIdleTimeoutSeconds` |
+| Python | `session_idle_timeout_seconds` |
+| Go | `SessionIdleTimeoutSeconds` |
+| .NET | `SessionIdleTimeoutSeconds` |
+| Java | `setSessionIdleTimeoutSeconds(...)` |
+| Rust | `with_session_idle_timeout_seconds(...)` |
+
+Use a value that matches your product's conversation lifetime. For chat backends, 15 to 30 minutes is usually a good starting point. For workflow agents, use a longer timeout and explicit deletion when the workflow completes.
+
+### `baseDirectory`
+
+`baseDirectory` sets `COPILOT_HOME` for a runtime instance. Use it to isolate runtime state, credentials, and session data per process, pod, worker, or tenant boundary.
+
+```typescript
+const client = new CopilotClient({
+ mode: "empty",
+ baseDirectory: `/var/lib/my-app/copilot/runtime-${process.env.HOSTNAME}`,
+ sessionIdleTimeoutSeconds: 900,
+});
+```
+
+The runtime stores session state under the configured `COPILOT_HOME`, including `session-state/{sessionId}`. If your app runs multiple runtime instances, give each instance a distinct directory unless you intentionally use shared storage.
+
+When the SDK connects to an already-running runtime with `RuntimeConnection.forUri(url)`, `baseDirectory` is ignored by the SDK client. Configure `COPILOT_HOME` on the runtime process instead.
+
+### `sessionFs`
+
+`sessionFs` registers a custom session filesystem provider so session-scoped file I/O can be routed through application storage instead of the runtime's local disk. Use it when local disk is ephemeral, when session state needs to live in object storage, or when a platform needs to enforce tenant-aware storage paths.
+
+```typescript
+const client = new CopilotClient({
+ mode: "empty",
+ sessionFs: {
+ initialCwd: "/workspace",
+ sessionStatePath: "/session-state",
+ conventions: "posix",
+ },
+});
+```
+
+For languages that expose a provider callback, configure `sessionFs` at the client level and provide a per-session filesystem handler when creating or resuming a session. See [Session Persistence](../features/session-persistence.md) for persistence concepts and storage trade-offs.
+
+Verified public SDK surfaces:
+
+| Language | Client-level config | Per-session provider |
+|----------|---------------------|----------------------|
+| TypeScript | `sessionFs` | `createSessionFsAdapter` / provider callbacks |
+| Python | `session_fs` | `create_session_fs_handler` |
+| Go | `SessionFS` | `CreateSessionFSProvider` |
+| .NET | `SessionFs` | `CreateSessionFsProvider` |
+| Rust | `with_session_fs(...)` | `with_session_fs_provider(...)` |
+
+Java does not currently expose a verified public `sessionFs` option, so this guide does not show a Java `sessionFs` sample.
+
+### `RuntimeConnection.forUri(url)`
+
+Use an external runtime connection when multiple SDK clients should share one already-running runtime. This is common in backend services where the runtime process is managed separately from request handlers.
+
+| Language | External runtime connection |
+|----------|-----------------------------|
+| TypeScript | `RuntimeConnection.forUri(url)` |
+| Python | `RuntimeConnection.for_uri(url)` |
+| Go | `copilot.URIConnection{URL: url}` |
+| .NET | `RuntimeConnection.ForUri(url)` |
+| Java | `setCliUrl(url)` |
+| Rust | `Transport::External { host, port, connection_token }` |
+
+External runtimes manage their own process-level authentication and storage. Pass per-session tokens on `createSession` or `resumeSession` when you need user-specific auth.
+
+### Per-session `gitHubToken`
+
+Set `gitHubToken` on each session to scope GitHub auth to the requesting user. This is different from a client-level token, which authenticates the runtime process.
+
+```typescript
+const session = await client.createSession({
+ sessionId: `user-${user.id}-support`,
+ model: "gpt-4.1",
+ availableTools: ["custom:*"],
+ gitHubToken: user.githubToken,
+});
+```
+
+Use per-session tokens for content exclusion, model routing, quota checks, and user-specific Copilot access. Avoid sharing one service token across users unless your product intentionally uses service-account semantics.
+
+## Integration ID
+
+Partners building branded agents can set an integration ID for Mission Control requests. The runtime reads `GITHUB_COPILOT_INTEGRATION_ID` and stamps it as the `Copilot-Integration-Id` HTTP header on every Mission Control request.
+
+```bash
+GITHUB_COPILOT_INTEGRATION_ID=my-product-agent copilot --headless --port 4321
+```
+
+The default integration ID is `copilot-developer-cli`. Use a stable value such as `my-product-agent` for attribution and routing. The integration ID is currently configured by environment variable only; it is not a first-class SDK option.
+
+If the SDK spawns the runtime, pass the environment variable through the client environment option. If you connect with `RuntimeConnection.forUri(url)`, set the environment variable on the runtime process itself.
+
+## Session-level isolation guarantees
+
+Session-level isolation means the runtime keeps user-specific model and state information scoped to a session, not in global shared state.
+
+| Surface | Isolation behavior |
+|---------|--------------------|
+| Model list cache | Per-session. Model lookup uses the session's model list cache. |
+| Session state | Per session ID under `COPILOT_HOME/session-state/{sessionId}`. |
+| GitHub identity | Per-session when `gitHubToken` is set on the session. |
+| Tools | Explicit in `mode: "empty"`; ambient in `mode: "copilot-cli"`. |
+| Host filesystem | Shared by the runtime process if host tools are available. |
+
+`mode: "empty"` is what makes shared runtime patterns viable: no ambient OS tools are exposed unless your application registers or allows them. With `mode: "copilot-cli"`, OS filesystem access is shared through the host process, so do not use that mode for multi-user server mode.
+
+Session state is stored under `COPILOT_HOME/session-state/{sessionId}` unless you route it through `sessionFs`. Use unique session IDs that include your own tenant or user boundary, and enforce access control before resuming or deleting sessions.
+
+## Pattern comparison
+
+| Pattern | Use when | Trade-offs |
+|---------|----------|------------|
+| Pattern 1: isolated CLI per user | You need the strongest isolation boundary or separate process credentials per user. | Strong isolation; higher resource cost. See [Scaling and multi-tenancy](./scaling.md). |
+| Pattern 2: shared CLI with `mode: "empty"` | You want one runtime to serve many users while your app controls tools, auth, and session IDs. | Efficient; requires careful tool registration, per-session tokens, and application-level access checks. |
+| Pattern 3: hybrid | You route compute-heavy work to cloud sessions and light work to local sessions. | Flexible; requires workload routing and policy handling. See [Cloud Sessions](../features/cloud-sessions.md). |
+
+### Pattern 2: shared CLI with `mode: "empty"`
+
+In this pattern, all users connect through your backend to one runtime pool. The application performs user authentication, chooses a session ID, passes the user's GitHub token on the session, and provides an explicit tool allowlist.
+
+```mermaid
+flowchart TB
+ U1["User A"] --> API["Your backend"]
+ U2["User B"] --> API
+ API --> Runtime["Shared Copilot runtime"]
+ Runtime --> SA["session-state/user-a-..."]
+ Runtime --> SB["session-state/user-b-..."]
+
+ API -. "mode: empty" .-> Runtime
+ API -. "per-session gitHubToken" .-> Runtime
+
+ style API fill:#0d1117,stroke:#58a6ff,color:#c9d1d9
+ style Runtime fill:#0d1117,stroke:#3fb950,color:#c9d1d9
+```
+
+Use these rules:
+
+* Always start the client or runtime in `mode: "empty"`.
+* Use unique session IDs and store ownership metadata in your application database.
+* Check ownership before `resumeSession`, `deleteSession`, or any UI action that references a session ID.
+* Pass `gitHubToken` per session when requests should run as the user.
+* Register only the tools the session needs, and prefer source-qualified allowlists such as `custom:*` or `mcp:search_docs`.
+* Set `sessionIdleTimeoutSeconds` and delete completed workflow sessions explicitly.
+
+## Common pitfalls
+
+* Forgetting `mode: "empty"`. The default `copilot-cli` mode exposes CLI-style behavior and may expose the host filesystem through ambient tools.
+* Not setting `sessionIdleTimeoutSeconds`. Long-running servers can accumulate idle sessions if they do not clean them up.
+* Sharing one `gitHubToken` across users instead of passing a per-session token.
+* Trusting client-provided session IDs without checking ownership in your backend.
+* Setting `baseDirectory` on a client that connects to an existing runtime and expecting it to move runtime storage. Configure the runtime process instead.
+* Allowing broad tool patterns such as `builtin:*` without reviewing whether each tool is appropriate for your users.
+
+## See also
+
+* [Scaling and multi-tenancy](./scaling.md): deployment topologies, storage patterns, and isolation comparisons
+* [Backend services setup](./backend-services.md): running the runtime in headless server mode
+* [BYOK](../auth/byok.md): using your own model provider credentials
+* [Cloud Sessions](../features/cloud-sessions.md): routing selected work to cloud sessions
+* [Session Persistence](../features/session-persistence.md): managing resumable session state
+* [Features overview](../features/index.md): tools, events, hooks, and advanced SDK features
diff --git a/docs/setup/scaling.md b/docs/setup/scaling.md
index 371a402b3..d960eb94e 100644
--- a/docs/setup/scaling.md
+++ b/docs/setup/scaling.md
@@ -2,6 +2,8 @@
Design your Copilot SDK deployment to serve multiple users, handle concurrent sessions, and scale horizontally across infrastructure. This guide covers session isolation patterns, scaling topologies, and production best practices.
+For SDK-level options and patterns, see [Multi-Tenancy & Server Deployments](./multi-tenancy.md).
+
**Best for:** Platform developers, SaaS builders, any deployment serving more than a handful of concurrent users.
## Core concepts
diff --git a/docs/troubleshooting/compatibility.md b/docs/troubleshooting/compatibility.md
index 89476b26f..c68d59cc7 100644
--- a/docs/troubleshooting/compatibility.md
+++ b/docs/troubleshooting/compatibility.md
@@ -86,7 +86,7 @@ The Copilot SDK communicates with the CLI via JSON-RPC protocol. Features must b
| Working directory | `workingDirectory` config | Set session cwd |
| **Experimental** | | |
| Agent management | `session.rpc.agent.*` | List, select, deselect, get current agent |
-| Fleet mode | `session.rpc.fleet.start()` | Parallel sub-agent execution |
+| Fleet mode | `session.rpc.fleet.start()` | Parallel sub-agent execution; see [Fleet mode](../features/fleet-mode.md) |
| Manual compaction | `session.rpc.history.compact()` | Trigger compaction on demand |
| History truncation | `session.rpc.history.truncate()` | Remove events from a point onward |
| Session forking | `server.rpc.sessions.fork()` | Fork a session at a point in history |
@@ -170,6 +170,10 @@ The Copilot SDK communicates with the CLI via JSON-RPC protocol. Features must b
## Workarounds
+### Fleet mode
+
+Fleet mode is available through `session.rpc.fleet.start()` for SDK applications that want the runtime to dispatch parallel sub-agents for a larger objective. Use it when independent subtasks can run concurrently and then be summarized by the main session. For a full guide, see [Fleet mode](../features/fleet-mode.md).
+
### Session export
The `--share` option is not available via SDK. Workarounds:
diff --git a/docs/troubleshooting/debugging.md b/docs/troubleshooting/debugging.md
index 77f950552..588049f0d 100644
--- a/docs/troubleshooting/debugging.md
+++ b/docs/troubleshooting/debugging.md
@@ -292,7 +292,7 @@ var client = new CopilotClient(new CopilotClientOptions
```go
client := copilot.NewClient(&copilot.ClientOptions{
- GithubToken: os.Getenv("GITHUB_TOKEN"),
+ GitHubToken: os.Getenv("GITHUB_TOKEN"),
})
```
@@ -303,7 +303,7 @@ var client = new CopilotClient(new CopilotClientOptions
```csharp
var client = new CopilotClient(new CopilotClientOptions
{
- GithubToken = Environment.GetEnvironmentVariable("GITHUB_TOKEN")
+ GitHubToken = Environment.GetEnvironmentVariable("GITHUB_TOKEN")
});
```
diff --git a/docs/troubleshooting/mcp-debugging.md b/docs/troubleshooting/mcp-debugging.md
index 664826c6e..3447ed921 100644
--- a/docs/troubleshooting/mcp-debugging.md
+++ b/docs/troubleshooting/mcp-debugging.md
@@ -393,7 +393,7 @@ Create a wrapper script to log all communication:
#!/bin/bash
# mcp-debug-wrapper.sh
-LOG="/tmp/mcp-debug-$(date +%s).log"
+LOG="./mcp-debug-$(date +%s).log"
ACTUAL_SERVER="$1"
shift
diff --git a/dotnet/README.md b/dotnet/README.md
index 719c554f4..9b266421f 100644
--- a/dotnet/README.md
+++ b/dotnet/README.md
@@ -2,12 +2,10 @@
SDK for programmatic control of GitHub Copilot CLI.
-> **Note:** This SDK is in public preview and may change in breaking ways.
-
## Installation
```bash
-dotnet add package GitHub.Copilot
+dotnet add package GitHub.Copilot.SDK
```
## Run the Samples
diff --git a/dotnet/src/Client.cs b/dotnet/src/Client.cs
index 9608d98c3..4e8715bd5 100644
--- a/dotnet/src/Client.cs
+++ b/dotnet/src/Client.cs
@@ -57,6 +57,7 @@ public sealed partial class CopilotClient : IDisposable, IAsyncDisposable
/// Minimum protocol version this SDK can communicate with.
///
private const int MinProtocolVersion = 3;
+ private static readonly TimeSpan s_stderrPumpShutdownTimeout = TimeSpan.FromSeconds(5);
///
/// Provides a thread-safe collection of active Copilot sessions, indexed by session identifier.
@@ -235,6 +236,7 @@ async Task StartCoreAsync(CancellationToken ct)
var startTimestamp = Stopwatch.GetTimestamp();
Connection? connection = null;
Process? cliProcess = null;
+ ProcessStderrPump? stderrPump = null;
try
{
@@ -247,10 +249,11 @@ async Task StartCoreAsync(CancellationToken ct)
else
{
// Child process (stdio or TCP)
- var (startedProcess, portOrNull, stderrBuffer) = await StartCliServerAsync(ct);
+ var (startedProcess, portOrNull, startedStderrPump) = await StartCliServerAsync(ct);
cliProcess = startedProcess;
+ stderrPump = startedStderrPump;
_actualPort = portOrNull;
- connection = await ConnectToServerAsync(cliProcess, portOrNull is null ? null : "localhost", portOrNull, stderrBuffer, ct);
+ connection = await ConnectToServerAsync(cliProcess, portOrNull is null ? null : "localhost", portOrNull, stderrPump, ct);
}
LoggingHelpers.LogTiming(_logger, LogLevel.Debug, null,
@@ -292,7 +295,7 @@ async Task StartCoreAsync(CancellationToken ct)
}
else if (cliProcess is not null)
{
- await CleanupCliProcessAsync(cliProcess, errors: null, _logger);
+ await CleanupCliProcessAsync(cliProcess, stderrPump, errors: null, _logger);
}
throw;
@@ -436,31 +439,56 @@ private async Task CleanupConnectionAsync(Connection ctx, List? error
if (ctx.CliProcess is { } childProcess)
{
- await CleanupCliProcessAsync(childProcess, errors, _logger);
+ await CleanupCliProcessAsync(childProcess, ctx.StderrPump, errors, _logger);
}
}
- private static async Task CleanupCliProcessAsync(Process childProcess, List? errors, ILogger? logger)
+ private static async Task CleanupCliProcessAsync(Process childProcess, ProcessStderrPump? stderrPump, List? errors, ILogger? logger)
{
+ stderrPump?.Cancel();
+
try
{
+ if (!childProcess.HasExited)
+ {
+ childProcess.Kill(entireProcessTree: true);
+ // Kill is asynchronous; wait for the root CLI process to exit so cleanup callers
+ // do not observe StopAsync/DisposeAsync completion while it is still tearing down.
+ await childProcess.WaitForExitAsync();
+ }
+ }
+ catch (Exception ex)
+ {
+ AddCleanupError(errors, ex, logger);
+ }
+
+ if (stderrPump is not null)
+ {
+ var stderrPumpWaitTimestamp = Stopwatch.GetTimestamp();
try
{
- if (!childProcess.HasExited)
+ await stderrPump.Completion.WaitAsync(s_stderrPumpShutdownTimeout);
+ }
+ catch (TimeoutException ex)
+ {
+ if (logger is not null)
{
- childProcess.Kill(entireProcessTree: true);
- await childProcess.WaitForExitAsync();
+ LoggingHelpers.LogTiming(logger, LogLevel.Debug, ex,
+ "Timed out waiting for runtime stderr pump to stop. Elapsed={Elapsed}, Timeout={Timeout}",
+ stderrPumpWaitTimestamp,
+ s_stderrPumpShutdownTimeout);
}
+
+ AddCleanupError(errors, ex, logger);
}
- finally
+ catch (Exception ex)
{
- childProcess.Dispose();
+ AddCleanupError(errors, ex, logger);
}
}
- catch (Exception ex)
- {
- AddCleanupError(errors, ex, logger);
- }
+
+ try { childProcess.Dispose(); }
+ catch (Exception ex) { AddCleanupError(errors, ex, logger); }
}
private static void AddCleanupError(List? errors, Exception ex, ILogger? logger)
@@ -861,6 +889,7 @@ public async Task CreateSessionAsync(SessionConfig config, Cance
config.ClientName,
config.ReasoningEffort,
config.ReasoningSummary,
+ config.ContextTier,
config.Tools?.Select(ToolDefinition.FromAIFunction).ToList(),
wireSystemMessage,
toolFilter.AvailableTools,
@@ -909,6 +938,7 @@ public async Task CreateSessionAsync(SessionConfig config, Cance
Canvases: config.Canvases,
RequestCanvasRenderer: config.RequestCanvasRenderer,
RequestExtensions: config.RequestExtensions,
+ ExtensionSdkPath: config.ExtensionSdkPath,
ExtensionInfo: config.ExtensionInfo,
ToolFilterPrecedence: toolFilter.ToolFilterPrecedence);
@@ -1054,6 +1084,7 @@ public async Task ResumeSessionAsync(string sessionId, ResumeSes
config.Model,
config.ReasoningEffort,
config.ReasoningSummary,
+ config.ContextTier,
config.Tools?.Select(ToolDefinition.FromAIFunction).ToList(),
wireSystemMessage,
toolFilter.AvailableTools,
@@ -1103,6 +1134,7 @@ public async Task ResumeSessionAsync(string sessionId, ResumeSes
Canvases: config.Canvases,
RequestCanvasRenderer: config.RequestCanvasRenderer,
RequestExtensions: config.RequestExtensions,
+ ExtensionSdkPath: config.ExtensionSdkPath,
ExtensionInfo: config.ExtensionInfo,
OpenCanvases: config.OpenCanvases,
ToolFilterPrecedence: toolFilter.ToolFilterPrecedence);
@@ -1655,7 +1687,7 @@ private static bool IsUnsupportedConnectMethod(RemoteRpcException ex)
|| string.Equals(ex.Message, "Unhandled method connect", StringComparison.Ordinal);
}
- private async Task<(Process Process, int? DetectedLocalhostTcpPort, StringBuilder StderrBuffer)> StartCliServerAsync(CancellationToken cancellationToken)
+ private async Task<(Process Process, int? DetectedLocalhostTcpPort, ProcessStderrPump StderrPump)> StartCliServerAsync(CancellationToken cancellationToken)
{
var options = _options;
var logger = _logger;
@@ -1779,38 +1811,30 @@ private static bool IsUnsupportedConnectMethod(RemoteRpcException ex)
if (telemetry.CaptureContent is { } capture) startInfo.Environment["OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT"] = capture ? "true" : "false";
}
- Process? cliProcess = null;
+ var cliProcess = new Process { StartInfo = startInfo };
try
{
- cliProcess = new Process { StartInfo = startInfo };
var spawnTimestamp = Stopwatch.GetTimestamp();
cliProcess.Start();
LoggingHelpers.LogTiming(logger, LogLevel.Debug, null,
"CopilotClient.StartCliServerAsync subprocess spawned. Elapsed={Elapsed}",
spawnTimestamp);
+ }
+ catch
+ {
+ cliProcess.Dispose();
+ throw;
+ }
- // Capture stderr for error messages and forward to logger
- var stderrBuffer = new StringBuilder();
- var stderrReader = Task.Run(async () =>
- {
- while (true)
- {
- var line = await cliProcess.StandardError.ReadLineAsync(cancellationToken);
- if (line is null)
- {
- break;
- }
-
- lock (stderrBuffer)
- {
- stderrBuffer.AppendLine(line);
- }
-
- logger.LogWarning("[CLI] {Line}", line);
- }
- }, cancellationToken);
+ ProcessStderrPump? stderrPump = null;
+ int? detectedLocalhostTcpPort = null;
+ try
+ {
+ // Capture stderr for error messages and forward to logger.
+ // The pump has its own lifetime token and is later cancelled/observed
+ // by the owning Connection before the process is disposed.
+ stderrPump = ProcessStderrPump.Start(cliProcess, logger);
- var detectedLocalhostTcpPort = (int?)null;
if (!useStdio)
{
// Wait for port announcement
@@ -1818,40 +1842,48 @@ private static bool IsUnsupportedConnectMethod(RemoteRpcException ex)
using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
cts.CancelAfter(TimeSpan.FromSeconds(30));
- while (!cts.Token.IsCancellationRequested)
+ try
{
- var line = await cliProcess.StandardOutput.ReadLineAsync(cts.Token);
- if (line is null)
+ while (await cliProcess.StandardOutput.ReadLineAsync(cts.Token) is string line)
{
- await stderrReader;
- throw CreateCliExitedException("Runtime process exited unexpectedly", stderrBuffer);
+ if (logger.IsEnabled(LogLevel.Debug))
+ {
+ logger.LogDebug("[CLI] {Line}", line);
+ }
+
+ if (ListeningOnPortRegex().Match(line) is { Success: true } match)
+ {
+ detectedLocalhostTcpPort = int.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
+ LoggingHelpers.LogTiming(logger, LogLevel.Debug, null,
+ "CopilotClient.StartCliServerAsync TCP port wait complete. Elapsed={Elapsed}, Port={Port}",
+ portWaitTimestamp,
+ detectedLocalhostTcpPort.Value);
+ break;
+ }
}
- if (logger.IsEnabled(LogLevel.Debug))
+ if (detectedLocalhostTcpPort is null)
{
- logger.LogDebug("[CLI] {Line}", line);
- }
-
- if (ListeningOnPortRegex().Match(line) is { Success: true } match)
- {
- detectedLocalhostTcpPort = int.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
- LoggingHelpers.LogTiming(logger, LogLevel.Debug, null,
- "CopilotClient.StartCliServerAsync TCP port wait complete. Elapsed={Elapsed}, Port={Port}",
- portWaitTimestamp,
- detectedLocalhostTcpPort.Value);
- break;
+ // The CLI's stdout closed (process exited). Drain stderr
+ // before throwing so the surfaced exception includes the
+ // final diagnostic lines.
+ try { await stderrPump.Completion.WaitAsync(s_stderrPumpShutdownTimeout, CancellationToken.None); }
+ catch (TimeoutException) { /* best-effort: include whatever was captured */ }
+ catch (Exception ex) { logger.LogDebug(ex, "Runtime stderr pump faulted while draining"); }
+ throw CreateCliExitedException("Runtime process exited unexpectedly", stderrPump.Buffer);
}
}
+ catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested && cts.IsCancellationRequested)
+ {
+ throw CreateCliExitedException("Timed out waiting for Copilot CLI to report its TCP listening port.", stderrPump.Buffer);
+ }
}
- return (cliProcess, detectedLocalhostTcpPort, stderrBuffer);
+ return (cliProcess, detectedLocalhostTcpPort, stderrPump);
}
catch
{
- if (cliProcess is not null)
- {
- await CleanupCliProcessAsync(cliProcess, errors: null, logger);
- }
+ await CleanupCliProcessAsync(cliProcess, stderrPump, errors: null, logger);
throw;
}
@@ -1898,77 +1930,94 @@ private static (string FileName, IEnumerable Args) ResolveCliCommand(str
return (cliPath, args);
}
- private async Task ConnectToServerAsync(Process? cliProcess, string? tcpHost, int? tcpPort, StringBuilder? stderrBuffer, CancellationToken cancellationToken)
+ private async Task ConnectToServerAsync(Process? cliProcess, string? tcpHost, int? tcpPort, ProcessStderrPump? stderrPump, CancellationToken cancellationToken)
{
var setupTimestamp = Stopwatch.GetTimestamp();
- Stream inputStream, outputStream;
NetworkStream? networkStream = null;
+ JsonRpc? rpc = null;
- if (_connection is StdioRuntimeConnection)
+ try
{
- if (cliProcess == null)
- {
- throw new InvalidOperationException("Runtime process not started");
- }
+ Stream inputStream, outputStream;
- inputStream = cliProcess.StandardOutput.BaseStream;
- outputStream = cliProcess.StandardInput.BaseStream;
- }
- else
- {
- if (tcpHost is null || tcpPort is null)
+ if (_connection is StdioRuntimeConnection)
{
- throw new InvalidOperationException("Cannot connect because TCP host or port are not available");
- }
+ if (cliProcess == null)
+ {
+ throw new InvalidOperationException("Runtime process not started");
+ }
- var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
- try
- {
- var tcpConnectTimestamp = Stopwatch.GetTimestamp();
- LogConnectingToCliServer(_logger, tcpHost, tcpPort.Value);
- await socket.ConnectAsync(tcpHost, tcpPort.Value, cancellationToken);
- LoggingHelpers.LogTiming(_logger, LogLevel.Debug, null,
- "CopilotClient.ConnectToServerAsync TCP connect complete. Elapsed={Elapsed}, Host={Host}, Port={Port}",
- tcpConnectTimestamp,
- tcpHost,
- tcpPort.Value);
+ inputStream = cliProcess.StandardOutput.BaseStream;
+ outputStream = cliProcess.StandardInput.BaseStream;
}
- catch
+ else
{
- socket.Dispose();
- throw;
+ if (tcpHost is null || tcpPort is null)
+ {
+ throw new InvalidOperationException("Cannot connect because TCP host or port are not available");
+ }
+
+ var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
+ try
+ {
+ var tcpConnectTimestamp = Stopwatch.GetTimestamp();
+ LogConnectingToCliServer(_logger, tcpHost, tcpPort.Value);
+ await socket.ConnectAsync(tcpHost, tcpPort.Value, cancellationToken);
+ LoggingHelpers.LogTiming(_logger, LogLevel.Debug, null,
+ "CopilotClient.ConnectToServerAsync TCP connect complete. Elapsed={Elapsed}, Host={Host}, Port={Port}",
+ tcpConnectTimestamp,
+ tcpHost,
+ tcpPort.Value);
+ }
+ catch
+ {
+ socket.Dispose();
+ throw;
+ }
+
+ inputStream = outputStream = networkStream = new NetworkStream(socket, ownsSocket: true);
}
- inputStream = outputStream = networkStream = new NetworkStream(socket, ownsSocket: true);
- }
+ rpc = new JsonRpc(
+ outputStream,
+ inputStream,
+ SerializerOptionsForMessageFormatter,
+ _logger);
+
+ var handler = new RpcHandler(this);
+ rpc.SetLocalRpcMethod("session.event", handler.OnSessionEvent);
+ rpc.SetLocalRpcMethod("session.lifecycle", handler.OnSessionLifecycle);
+ rpc.SetLocalRpcMethod("userInput.request", handler.OnUserInputRequest);
+ rpc.SetLocalRpcMethod("exitPlanMode.request", handler.OnExitPlanModeRequest);
+ rpc.SetLocalRpcMethod("autoModeSwitch.request", handler.OnAutoModeSwitchRequest);
+ rpc.SetLocalRpcMethod("hooks.invoke", handler.OnHooksInvoke);
+ rpc.SetLocalRpcMethod("systemMessage.transform", handler.OnSystemMessageTransform);
+ ClientSessionApiRegistration.RegisterClientSessionApiHandlers(rpc, sessionId =>
+ {
+ var session = GetSession(sessionId) ?? throw new ArgumentException($"Unknown session {sessionId}");
+ return session.ClientSessionApis;
+ });
+ rpc.StartListening();
+ LoggingHelpers.LogTiming(_logger, LogLevel.Debug, null,
+ "CopilotClient.ConnectToServerAsync transport setup complete. Elapsed={Elapsed}",
+ setupTimestamp);
- var rpc = new JsonRpc(
- outputStream,
- inputStream,
- SerializerOptionsForMessageFormatter,
- _logger);
+ _serverRpc = new ServerRpc(rpc);
- var handler = new RpcHandler(this);
- rpc.SetLocalRpcMethod("session.event", handler.OnSessionEvent);
- rpc.SetLocalRpcMethod("session.lifecycle", handler.OnSessionLifecycle);
- rpc.SetLocalRpcMethod("userInput.request", handler.OnUserInputRequest);
- rpc.SetLocalRpcMethod("exitPlanMode.request", handler.OnExitPlanModeRequest);
- rpc.SetLocalRpcMethod("autoModeSwitch.request", handler.OnAutoModeSwitchRequest);
- rpc.SetLocalRpcMethod("hooks.invoke", handler.OnHooksInvoke);
- rpc.SetLocalRpcMethod("systemMessage.transform", handler.OnSystemMessageTransform);
- ClientSessionApiRegistration.RegisterClientSessionApiHandlers(rpc, sessionId =>
+ return new Connection(rpc, cliProcess, networkStream, stderrPump);
+ }
+ catch
{
- var session = GetSession(sessionId) ?? throw new ArgumentException($"Unknown session {sessionId}");
- return session.ClientSessionApis;
- });
- rpc.StartListening();
- LoggingHelpers.LogTiming(_logger, LogLevel.Debug, null,
- "CopilotClient.ConnectToServerAsync transport setup complete. Elapsed={Elapsed}",
- setupTimestamp);
-
- _serverRpc = new ServerRpc(rpc);
+ try { rpc?.Dispose(); }
+ catch (Exception ex) { _logger.LogDebug(ex, "Failed to dispose JSON-RPC connection after startup failure"); }
- return new Connection(rpc, cliProcess, networkStream, stderrBuffer);
+ if (networkStream is not null)
+ {
+ try { await networkStream.DisposeAsync(); }
+ catch (Exception ex) { _logger.LogDebug(ex, "Failed to dispose TCP stream after startup failure"); }
+ }
+ throw;
+ }
}
private static JsonSerializerOptions SerializerOptionsForMessageFormatter { get; } = CreateSerializerOptions();
@@ -2155,12 +2204,59 @@ private class Connection(
JsonRpc rpc,
Process? cliProcess, // Set if we created the child process
NetworkStream? networkStream, // Set if using TCP
- StringBuilder? stderrBuffer = null) // Captures stderr for error messages
+ ProcessStderrPump? stderrPump = null) // Captures stderr for error messages
{
public Process? CliProcess => cliProcess;
public JsonRpc Rpc => rpc;
public NetworkStream? NetworkStream => networkStream;
- public StringBuilder? StderrBuffer => stderrBuffer;
+ public ProcessStderrPump? StderrPump => stderrPump;
+ public StringBuilder? StderrBuffer => stderrPump?.Buffer;
+ }
+
+ private sealed class ProcessStderrPump
+ {
+ private readonly CancellationTokenSource _cancellationTokenSource = new();
+ private readonly Task _completion;
+
+ private ProcessStderrPump(Process process, ILogger logger)
+ {
+ _completion = Task.Run(() => PumpAsync(process, logger, _cancellationTokenSource.Token));
+ }
+
+ public StringBuilder Buffer { get; } = new();
+
+ public Task Completion => _completion;
+
+ public static ProcessStderrPump Start(Process process, ILogger logger)
+ {
+ return new ProcessStderrPump(process, logger);
+ }
+
+ public void Cancel() => _cancellationTokenSource.Cancel();
+
+ private async Task PumpAsync(Process process, ILogger logger, CancellationToken cancellationToken)
+ {
+ try
+ {
+ while (await process.StandardError.ReadLineAsync(cancellationToken) is string line)
+ {
+ lock (Buffer)
+ {
+ Buffer.AppendLine(line);
+ }
+
+ logger.LogWarning("[CLI] {Line}", line);
+ }
+ }
+ catch (Exception e) when (cancellationToken.IsCancellationRequested
+ && e is OperationCanceledException or InvalidOperationException or ObjectDisposedException or IOException)
+ {
+ }
+ catch (Exception ex)
+ {
+ logger.LogDebug(ex, "Runtime stderr pump stopped unexpectedly");
+ }
+ }
}
private static class ProcessArgumentEscaper
@@ -2180,6 +2276,7 @@ internal record CreateSessionRequest(
string? ClientName,
string? ReasoningEffort,
ReasoningSummary? ReasoningSummary,
+ ContextTier? ContextTier,
IList? Tools,
SystemMessageConfig? SystemMessage,
IList? AvailableTools,
@@ -2229,6 +2326,7 @@ internal record CreateSessionRequest(
IList? Canvases = null,
bool? RequestCanvasRenderer = null,
bool? RequestExtensions = null,
+ string? ExtensionSdkPath = null,
ExtensionInfo? ExtensionInfo = null,
OptionsUpdateToolFilterPrecedence? ToolFilterPrecedence = null);
#pragma warning restore GHCP001
@@ -2264,6 +2362,7 @@ internal record ResumeSessionRequest(
string? Model,
string? ReasoningEffort,
ReasoningSummary? ReasoningSummary,
+ ContextTier? ContextTier,
IList? Tools,
SystemMessageConfig? SystemMessage,
IList? AvailableTools,
@@ -2286,7 +2385,7 @@ internal record ResumeSessionRequest(
bool? EnableHostGitOperations,
bool? EnableSessionStore,
bool? EnableSkills,
- bool? SuppressResumeEvent,
+ [property: JsonPropertyName("disableResume")] bool? SuppressResumeEvent,
bool? Streaming,
bool? IncludeSubAgentStreamingEvents,
IDictionary? McpServers,
@@ -2314,6 +2413,7 @@ internal record ResumeSessionRequest(
IList? Canvases = null,
bool? RequestCanvasRenderer = null,
bool? RequestExtensions = null,
+ string? ExtensionSdkPath = null,
ExtensionInfo? ExtensionInfo = null,
IList? OpenCanvases = null,
OptionsUpdateToolFilterPrecedence? ToolFilterPrecedence = null);
diff --git a/dotnet/src/Generated/Rpc.cs b/dotnet/src/Generated/Rpc.cs
index b0453c8bb..72deafb8f 100644
--- a/dotnet/src/Generated/Rpc.cs
+++ b/dotnet/src/Generated/Rpc.cs
@@ -73,7 +73,7 @@ public sealed class ModelBillingTokenPricesLongContext
[JsonPropertyName("cachePrice")]
public double? CachePrice { get; set; }
- /// Maximum context window tokens for the long context tier.
+ /// Prompt token budget (max_prompt_tokens) for the long context tier. The total context window is this value plus the model's max_output_tokens.
[JsonPropertyName("contextMax")]
public long? ContextMax { get; set; }
@@ -97,7 +97,7 @@ public sealed class ModelBillingTokenPrices
[JsonPropertyName("cachePrice")]
public double? CachePrice { get; set; }
- /// Maximum context window tokens for the default tier.
+ /// Prompt token budget (max_prompt_tokens) for the default tier. The total context window is this value plus the model's max_output_tokens.
[JsonPropertyName("contextMax")]
public long? ContextMax { get; set; }
@@ -1384,198 +1384,6 @@ public sealed class SendResult
public string MessageId { get; set; } = string.Empty;
}
-/// A user message attachment — a file, directory, code selection, blob, or GitHub reference.
-/// Polymorphic base type discriminated by type.
-[Experimental(Diagnostics.Experimental)]
-[JsonPolymorphic(
- TypeDiscriminatorPropertyName = "type",
- UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)]
-[JsonDerivedType(typeof(SendAttachmentFile), "file")]
-[JsonDerivedType(typeof(SendAttachmentDirectory), "directory")]
-[JsonDerivedType(typeof(SendAttachmentSelection), "selection")]
-[JsonDerivedType(typeof(SendAttachmentGithubReference), "github_reference")]
-[JsonDerivedType(typeof(SendAttachmentBlob), "blob")]
-public partial class SendAttachment
-{
- /// The type discriminator.
- [JsonPropertyName("type")]
- public virtual string Type { get; set; } = string.Empty;
-}
-
-
-/// Optional line range to scope the attachment to a specific section of the file.
-[Experimental(Diagnostics.Experimental)]
-public sealed class SendAttachmentFileLineRange
-{
- /// End line number (1-based, inclusive).
- [JsonPropertyName("end")]
- public long End { get; set; }
-
- /// Start line number (1-based).
- [JsonPropertyName("start")]
- public long Start { get; set; }
-}
-
-/// File attachment.
-/// The file variant of .
-[Experimental(Diagnostics.Experimental)]
-public partial class SendAttachmentFile : SendAttachment
-{
- ///
- [JsonIgnore]
- public override string Type => "file";
-
- /// User-facing display name for the attachment.
- [JsonPropertyName("displayName")]
- public required string DisplayName { get; set; }
-
- /// Optional line range to scope the attachment to a specific section of the file.
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [JsonPropertyName("lineRange")]
- public SendAttachmentFileLineRange? LineRange { get; set; }
-
- /// Absolute file path.
- [JsonPropertyName("path")]
- public required string Path { get; set; }
-}
-
-/// Directory attachment.
-/// The directory variant of .
-[Experimental(Diagnostics.Experimental)]
-public partial class SendAttachmentDirectory : SendAttachment
-{
- ///
- [JsonIgnore]
- public override string Type => "directory";
-
- /// User-facing display name for the attachment.
- [JsonPropertyName("displayName")]
- public required string DisplayName { get; set; }
-
- /// Absolute directory path.
- [JsonPropertyName("path")]
- public required string Path { get; set; }
-}
-
-/// End position of the selection.
-[Experimental(Diagnostics.Experimental)]
-public sealed class SendAttachmentSelectionDetailsEnd
-{
- /// End character offset within the line (0-based).
- [JsonPropertyName("character")]
- public long Character { get; set; }
-
- /// End line number (0-based).
- [JsonPropertyName("line")]
- public long Line { get; set; }
-}
-
-/// Start position of the selection.
-[Experimental(Diagnostics.Experimental)]
-public sealed class SendAttachmentSelectionDetailsStart
-{
- /// Start character offset within the line (0-based).
- [JsonPropertyName("character")]
- public long Character { get; set; }
-
- /// Start line number (0-based).
- [JsonPropertyName("line")]
- public long Line { get; set; }
-}
-
-/// Position range of the selection within the file.
-[Experimental(Diagnostics.Experimental)]
-public sealed class SendAttachmentSelectionDetails
-{
- /// End position of the selection.
- [JsonPropertyName("end")]
- public SendAttachmentSelectionDetailsEnd End { get => field ??= new(); set; }
-
- /// Start position of the selection.
- [JsonPropertyName("start")]
- public SendAttachmentSelectionDetailsStart Start { get => field ??= new(); set; }
-}
-
-/// Code selection attachment from an editor.
-/// The selection variant of .
-[Experimental(Diagnostics.Experimental)]
-public partial class SendAttachmentSelection : SendAttachment
-{
- ///
- [JsonIgnore]
- public override string Type => "selection";
-
- /// User-facing display name for the selection.
- [JsonPropertyName("displayName")]
- public required string DisplayName { get; set; }
-
- /// Absolute path to the file containing the selection.
- [JsonPropertyName("filePath")]
- public required string FilePath { get; set; }
-
- /// Position range of the selection within the file.
- [JsonPropertyName("selection")]
- public required SendAttachmentSelectionDetails Selection { get; set; }
-
- /// The selected text content.
- [JsonPropertyName("text")]
- public required string Text { get; set; }
-}
-
-/// GitHub issue, pull request, or discussion reference.
-/// The github_reference variant of .
-[Experimental(Diagnostics.Experimental)]
-public partial class SendAttachmentGithubReference : SendAttachment
-{
- ///
- [JsonIgnore]
- public override string Type => "github_reference";
-
- /// Issue, pull request, or discussion number.
- [JsonPropertyName("number")]
- public required long Number { get; set; }
-
- /// Type of GitHub reference.
- [JsonPropertyName("referenceType")]
- public required SendAttachmentGithubReferenceType ReferenceType { get; set; }
-
- /// Current state of the referenced item (e.g., open, closed, merged).
- [JsonPropertyName("state")]
- public required string State { get; set; }
-
- /// Title of the referenced item.
- [JsonPropertyName("title")]
- public required string Title { get; set; }
-
- /// URL to the referenced item on GitHub.
- [JsonPropertyName("url")]
- public required string Url { get; set; }
-}
-
-/// Blob attachment with inline base64-encoded data.
-/// The blob variant of .
-[Experimental(Diagnostics.Experimental)]
-public partial class SendAttachmentBlob : SendAttachment
-{
- ///
- [JsonIgnore]
- public override string Type => "blob";
-
- /// Base64-encoded content.
- [Base64String]
- [JsonPropertyName("data")]
- public required string Data { get; set; }
-
- /// User-facing display name for the attachment.
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [JsonPropertyName("displayName")]
- public string? DisplayName { get; set; }
-
- /// MIME type of the inline data.
- [JsonPropertyName("mimeType")]
- public required string MimeType { get; set; }
-}
-
/// Parameters for sending a user message to the session.
[Experimental(Diagnostics.Experimental)]
internal sealed class SendRequest
@@ -1586,7 +1394,7 @@ internal sealed class SendRequest
/// Optional attachments (files, directories, selections, blobs, GitHub references) to include with the message.
[JsonPropertyName("attachments")]
- public IList? Attachments { get; set; }
+ public IList? Attachments { get; set; }
/// If false, this message will not trigger a Premium Request Unit charge. User messages default to billable.
[JsonPropertyName("billable")]
@@ -2485,10 +2293,14 @@ internal sealed class CanvasActionInvokeRequest
public string SessionId { get; set; } = string.Empty;
}
-/// The currently selected model and reasoning effort for the session.
+/// The currently selected model, reasoning effort, and context tier for the session. The context tier reflects `Session.getContextTier()`, restored from the session journal on resume.
[Experimental(Diagnostics.Experimental)]
public sealed class CurrentModel
{
+ /// Context tier for models that support multiple context-window sizes.
+ [JsonPropertyName("contextTier")]
+ public ContextTier? ContextTier { get; set; }
+
/// Currently active model identifier.
[JsonPropertyName("modelId")]
public string? ModelId { get; set; }
@@ -2584,9 +2396,9 @@ public sealed class ModelCapabilitiesOverride
[Experimental(Diagnostics.Experimental)]
internal sealed class ModelSwitchToRequest
{
- /// Explicit context tier for the selected model. `"default"` / `"long_context"` pin the tier; `null` clears any previous explicit choice; `undefined` leaves the existing tier untouched.
+ /// Explicit context tier for the selected model. `"default"` / `"long_context"` apply the requested tier; omit this field to use normal model behavior with no explicit tier.
[JsonPropertyName("contextTier")]
- public ModelSwitchToRequestContextTier? ContextTier { get; set; }
+ public ContextTier? ContextTier { get; set; }
/// Override individual model capabilities resolved by the runtime.
[JsonPropertyName("modelCapabilities")]
@@ -4712,6 +4524,10 @@ internal sealed class SessionUpdateOptionsParams
[JsonPropertyName("skipEmbeddingRetrieval")]
public bool? SkipEmbeddingRetrieval { get; set; }
+ /// When true, the selected custom agent's prompt is not injected into the user message (skill context is still injected). Used by automation triggers where the agent prompt is already in the problem statement.
+ [JsonPropertyName("suppressCustomAgentPrompt")]
+ public bool? SuppressCustomAgentPrompt { get; set; }
+
/// Controls how availableTools (allowlist) and excludedTools (denylist) combine when both are set.
[JsonPropertyName("toolFilterPrecedence")]
public OptionsUpdateToolFilterPrecedence? ToolFilterPrecedence { get; set; }
@@ -4789,36 +4605,266 @@ internal sealed class SessionExtensionsListRequest
public string SessionId { get; set; } = string.Empty;
}
-/// Source-qualified extension identifier to enable for the session.
+/// Source-qualified extension identifier to enable for the session.
+[Experimental(Diagnostics.Experimental)]
+internal sealed class ExtensionsEnableRequest
+{
+ /// Source-qualified extension ID to enable.
+ [JsonPropertyName("id")]
+ public string Id { get; set; } = string.Empty;
+
+ /// Target session identifier.
+ [JsonPropertyName("sessionId")]
+ public string SessionId { get; set; } = string.Empty;
+}
+
+/// Source-qualified extension identifier to disable for the session.
+[Experimental(Diagnostics.Experimental)]
+internal sealed class ExtensionsDisableRequest
+{
+ /// Source-qualified extension ID to disable.
+ [JsonPropertyName("id")]
+ public string Id { get; set; } = string.Empty;
+
+ /// Target session identifier.
+ [JsonPropertyName("sessionId")]
+ public string SessionId { get; set; } = string.Empty;
+}
+
+/// Identifies the target session.
+[Experimental(Diagnostics.Experimental)]
+internal sealed class SessionExtensionsReloadRequest
+{
+ /// Target session identifier.
+ [JsonPropertyName("sessionId")]
+ public string SessionId { get; set; } = string.Empty;
+}
+
+/// Schema for the `PushAttachment` type.
+/// Polymorphic base type discriminated by type.
+[Experimental(Diagnostics.Experimental)]
+[JsonPolymorphic(
+ TypeDiscriminatorPropertyName = "type",
+ UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)]
+[JsonDerivedType(typeof(PushAttachmentFile), "file")]
+[JsonDerivedType(typeof(PushAttachmentDirectory), "directory")]
+[JsonDerivedType(typeof(PushAttachmentSelection), "selection")]
+[JsonDerivedType(typeof(PushAttachmentGitHubReference), "github_reference")]
+[JsonDerivedType(typeof(PushAttachmentBlob), "blob")]
+[JsonDerivedType(typeof(PushAttachmentExtensionContext), "extension_context")]
+public partial class PushAttachment
+{
+ /// The type discriminator.
+ [JsonPropertyName("type")]
+ public virtual string Type { get; set; } = string.Empty;
+}
+
+
+/// Optional line range to scope the attachment to a specific section of the file.
+[Experimental(Diagnostics.Experimental)]
+public sealed class PushAttachmentFileLineRange
+{
+ /// End line number (1-based, inclusive).
+ [JsonPropertyName("end")]
+ public long End { get; set; }
+
+ /// Start line number (1-based).
+ [JsonPropertyName("start")]
+ public long Start { get; set; }
+}
+
+/// File attachment.
+/// The file variant of .
+[Experimental(Diagnostics.Experimental)]
+public partial class PushAttachmentFile : PushAttachment
+{
+ ///
+ [JsonIgnore]
+ public override string Type => "file";
+
+ /// User-facing display name for the attachment.
+ [JsonPropertyName("displayName")]
+ public required string DisplayName { get; set; }
+
+ /// Optional line range to scope the attachment to a specific section of the file.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("lineRange")]
+ public PushAttachmentFileLineRange? LineRange { get; set; }
+
+ /// Absolute file path.
+ [JsonPropertyName("path")]
+ public required string Path { get; set; }
+}
+
+/// Directory attachment.
+/// The directory variant of .
+[Experimental(Diagnostics.Experimental)]
+public partial class PushAttachmentDirectory : PushAttachment
+{
+ ///
+ [JsonIgnore]
+ public override string Type => "directory";
+
+ /// User-facing display name for the attachment.
+ [JsonPropertyName("displayName")]
+ public required string DisplayName { get; set; }
+
+ /// Absolute directory path.
+ [JsonPropertyName("path")]
+ public required string Path { get; set; }
+}
+
+/// End position of the selection.
+[Experimental(Diagnostics.Experimental)]
+public sealed class PushAttachmentSelectionDetailsEnd
+{
+ /// End character offset within the line (0-based).
+ [JsonPropertyName("character")]
+ public long Character { get; set; }
+
+ /// End line number (0-based).
+ [JsonPropertyName("line")]
+ public long Line { get; set; }
+}
+
+/// Start position of the selection.
+[Experimental(Diagnostics.Experimental)]
+public sealed class PushAttachmentSelectionDetailsStart
+{
+ /// Start character offset within the line (0-based).
+ [JsonPropertyName("character")]
+ public long Character { get; set; }
+
+ /// Start line number (0-based).
+ [JsonPropertyName("line")]
+ public long Line { get; set; }
+}
+
+/// Position range of the selection within the file.
+[Experimental(Diagnostics.Experimental)]
+public sealed class PushAttachmentSelectionDetails
+{
+ /// End position of the selection.
+ [JsonPropertyName("end")]
+ public PushAttachmentSelectionDetailsEnd End { get => field ??= new(); set; }
+
+ /// Start position of the selection.
+ [JsonPropertyName("start")]
+ public PushAttachmentSelectionDetailsStart Start { get => field ??= new(); set; }
+}
+
+/// Code selection attachment from an editor.
+/// The selection variant of .
+[Experimental(Diagnostics.Experimental)]
+public partial class PushAttachmentSelection : PushAttachment
+{
+ ///
+ [JsonIgnore]
+ public override string Type => "selection";
+
+ /// User-facing display name for the selection.
+ [JsonPropertyName("displayName")]
+ public required string DisplayName { get; set; }
+
+ /// Absolute path to the file containing the selection.
+ [JsonPropertyName("filePath")]
+ public required string FilePath { get; set; }
+
+ /// Position range of the selection within the file.
+ [JsonPropertyName("selection")]
+ public required PushAttachmentSelectionDetails Selection { get; set; }
+
+ /// The selected text content.
+ [JsonPropertyName("text")]
+ public required string Text { get; set; }
+}
+
+/// GitHub issue, pull request, or discussion reference.
+/// The github_reference variant of .
+[Experimental(Diagnostics.Experimental)]
+public partial class PushAttachmentGitHubReference : PushAttachment
+{
+ ///
+ [JsonIgnore]
+ public override string Type => "github_reference";
+
+ /// Issue, pull request, or discussion number.
+ [JsonPropertyName("number")]
+ public required long Number { get; set; }
+
+ /// Type of GitHub reference.
+ [JsonPropertyName("referenceType")]
+ public required PushAttachmentGitHubReferenceType ReferenceType { get; set; }
+
+ /// Current state of the referenced item (e.g., open, closed, merged).
+ [JsonPropertyName("state")]
+ public required string State { get; set; }
+
+ /// Title of the referenced item.
+ [JsonPropertyName("title")]
+ public required string Title { get; set; }
+
+ /// URL to the referenced item on GitHub.
+ [JsonPropertyName("url")]
+ public required string Url { get; set; }
+}
+
+/// Blob attachment with inline base64-encoded data.
+/// The blob variant of .
[Experimental(Diagnostics.Experimental)]
-internal sealed class ExtensionsEnableRequest
+public partial class PushAttachmentBlob : PushAttachment
{
- /// Source-qualified extension ID to enable.
- [JsonPropertyName("id")]
- public string Id { get; set; } = string.Empty;
+ ///
+ [JsonIgnore]
+ public override string Type => "blob";
- /// Target session identifier.
- [JsonPropertyName("sessionId")]
- public string SessionId { get; set; } = string.Empty;
+ /// Base64-encoded content.
+ [Base64String]
+ [JsonPropertyName("data")]
+ public required string Data { get; set; }
+
+ /// User-facing display name for the attachment.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("displayName")]
+ public string? DisplayName { get; set; }
+
+ /// MIME type of the inline data.
+ [JsonPropertyName("mimeType")]
+ public required string MimeType { get; set; }
}
-/// Source-qualified extension identifier to disable for the session.
+/// Slim input shape for extension_context attachments; identity fields are runtime-derived.
+/// The extension_context variant of .
[Experimental(Diagnostics.Experimental)]
-internal sealed class ExtensionsDisableRequest
+public partial class PushAttachmentExtensionContext : PushAttachment
{
- /// Source-qualified extension ID to disable.
- [JsonPropertyName("id")]
- public string Id { get; set; } = string.Empty;
+ ///
+ [JsonIgnore]
+ public override string Type => "extension_context";
- /// Target session identifier.
- [JsonPropertyName("sessionId")]
- public string SessionId { get; set; } = string.Empty;
+ /// Caller-supplied JSON payload (required, may be null but not undefined).
+ [JsonPropertyName("payload")]
+ public required JsonElement Payload { get; set; }
+
+ /// Human-readable composer pill label.
+ [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")]
+ [MinLength(1)]
+ [JsonPropertyName("title")]
+ public required string Title { get; set; }
}
-/// Identifies the target session.
+/// Parameters for session.extensions.sendAttachmentsToMessage.
[Experimental(Diagnostics.Experimental)]
-internal sealed class SessionExtensionsReloadRequest
+internal sealed class SendAttachmentsToMessageParams
{
+ /// Attachments to push into the next user-message turn. extension_context entries take the slim shape; standard variants take their full AttachmentSchema shape.
+ [JsonPropertyName("attachments")]
+ public IList Attachments { get => field ??= []; set; }
+
+ /// Optional canvas instance binding the push for provenance. When supplied, the runtime resolves the canvas, verifies it is owned by the calling extension, and stamps canvasId/instanceId onto each extension_context entry. When omitted, no resolution runs and those fields stay unset on the attachment.
+ [JsonPropertyName("instanceId")]
+ public string? InstanceId { get; set; }
+
/// Target session identifier.
[JsonPropertyName("sessionId")]
public string SessionId { get; set; } = string.Empty;
@@ -6321,6 +6367,10 @@ internal sealed class PermissionsSetAllowAllRequest
/// Target session identifier.
[JsonPropertyName("sessionId")]
public string SessionId { get; set; } = string.Empty;
+
+ /// Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers.
+ [JsonPropertyName("source")]
+ public PermissionsSetAllowAllSource? Source { get; set; }
}
/// Current full allow-all permission state.
@@ -7032,7 +7082,7 @@ public sealed class MetadataContextInfoResultContextInfo
[JsonPropertyName("conversationTokens")]
public long ConversationTokens { get; set; }
- /// Total context limit for /context display. promptTokenLimit + min(32k or 64k, outputTokenLimit) depending on model.
+ /// Total context limit for /context display: promptTokenLimit + outputTokenLimit (the model's full max_output_tokens reserved on top of the prompt budget).
[JsonPropertyName("limit")]
public long Limit { get; set; }
@@ -7509,7 +7559,7 @@ internal sealed class EventLogReadRequest
/// Maximum number of events to return in this batch (1–1000, default 200).
[JsonPropertyName("max")]
- public int? Max { get; set; }
+ public long? Max { get; set; }
/// Target session identifier.
[JsonPropertyName("sessionId")]
@@ -8743,7 +8793,7 @@ public SessionContextHostType(string value)
public string Value => _value ?? string.Empty;
/// Session repository is hosted on GitHub.
- public static SessionContextHostType Github { get; } = new("github");
+ public static SessionContextHostType GitHub { get; } = new("github");
/// Session repository is hosted on Azure DevOps.
public static SessionContextHostType Ado { get; } = new("ado");
@@ -9397,72 +9447,6 @@ public override void Write(Utf8JsonWriter writer, SendAgentMode value, JsonSeria
}
-/// Type of GitHub reference.
-[Experimental(Diagnostics.Experimental)]
-[JsonConverter(typeof(Converter))]
-[DebuggerDisplay("{Value,nq}")]
-public readonly struct SendAttachmentGithubReferenceType : IEquatable
-{
- private readonly string? _value;
-
- /// Initializes a new instance of the struct.
- /// The value to associate with this .
- [JsonConstructor]
- public SendAttachmentGithubReferenceType(string value)
- {
- ArgumentException.ThrowIfNullOrWhiteSpace(value);
- _value = value;
- }
-
- /// Gets the value associated with this .
- public string Value => _value ?? string.Empty;
-
- /// GitHub issue reference.
- public static SendAttachmentGithubReferenceType Issue { get; } = new("issue");
-
- /// GitHub pull request reference.
- public static SendAttachmentGithubReferenceType Pr { get; } = new("pr");
-
- /// GitHub discussion reference.
- public static SendAttachmentGithubReferenceType Discussion { get; } = new("discussion");
-
- /// Returns a value indicating whether two instances are equivalent.
- public static bool operator ==(SendAttachmentGithubReferenceType left, SendAttachmentGithubReferenceType right) => left.Equals(right);
-
- /// Returns a value indicating whether two instances are not equivalent.
- public static bool operator !=(SendAttachmentGithubReferenceType left, SendAttachmentGithubReferenceType right) => !(left == right);
-
- ///
- public override bool Equals(object? obj) => obj is SendAttachmentGithubReferenceType other && Equals(other);
-
- ///
- public bool Equals(SendAttachmentGithubReferenceType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase);
-
- ///
- public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value);
-
- ///
- public override string ToString() => Value;
-
- /// Provides a for serializing instances.
- [EditorBrowsable(EditorBrowsableState.Never)]
- public sealed class Converter : JsonConverter
- {
- ///
- public override SendAttachmentGithubReferenceType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- {
- return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
- }
-
- ///
- public override void Write(Utf8JsonWriter writer, SendAttachmentGithubReferenceType value, JsonSerializerOptions options)
- {
- GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SendAttachmentGithubReferenceType));
- }
- }
-}
-
-
/// How to deliver the message. `enqueue` (default) appends to the message queue. `immediate` interjects during an in-progress turn.
[Experimental(Diagnostics.Experimental)]
[JsonConverter(typeof(Converter))]
@@ -9733,68 +9717,6 @@ public override void Write(Utf8JsonWriter writer, CanvasInstanceAvailability val
}
-/// Defines the allowed values.
-[JsonConverter(typeof(Converter))]
-[DebuggerDisplay("{Value,nq}")]
-public readonly struct ModelSwitchToRequestContextTier : IEquatable
-{
- private readonly string? _value;
-
- /// Initializes a new instance of the struct.
- /// The value to associate with this .
- [JsonConstructor]
- public ModelSwitchToRequestContextTier(string value)
- {
- ArgumentException.ThrowIfNullOrWhiteSpace(value);
- _value = value;
- }
-
- /// Gets the value associated with this .
- public string Value => _value ?? string.Empty;
-
- /// Use the model's default context window.
- public static ModelSwitchToRequestContextTier Default { get; } = new("default");
-
- /// Pin the session to the long-context tier when supported.
- public static ModelSwitchToRequestContextTier LongContext { get; } = new("long_context");
-
- /// Returns a value indicating whether two instances are equivalent.
- public static bool operator ==(ModelSwitchToRequestContextTier left, ModelSwitchToRequestContextTier right) => left.Equals(right);
-
- /// Returns a value indicating whether two instances are not equivalent.
- public static bool operator !=(ModelSwitchToRequestContextTier left, ModelSwitchToRequestContextTier right) => !(left == right);
-
- ///
- public override bool Equals(object? obj) => obj is ModelSwitchToRequestContextTier other && Equals(other);
-
- ///
- public bool Equals(ModelSwitchToRequestContextTier other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase);
-
- ///
- public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value);
-
- ///
- public override string ToString() => Value;
-
- /// Provides a for serializing instances.
- [EditorBrowsable(EditorBrowsableState.Never)]
- public sealed class Converter : JsonConverter
- {
- ///
- public override ModelSwitchToRequestContextTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- {
- return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
- }
-
- ///
- public override void Write(Utf8JsonWriter writer, ModelSwitchToRequestContextTier value, JsonSerializerOptions options)
- {
- GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ModelSwitchToRequestContextTier));
- }
- }
-}
-
-
/// Allowed values for the `WorkspacesWorkspaceDetailsHostType` enumeration.
[Experimental(Diagnostics.Experimental)]
[JsonConverter(typeof(Converter))]
@@ -9816,7 +9738,7 @@ public WorkspacesWorkspaceDetailsHostType(string value)
public string Value => _value ?? string.Empty;
/// Workspace repository is hosted on GitHub.
- public static WorkspacesWorkspaceDetailsHostType Github { get; } = new("github");
+ public static WorkspacesWorkspaceDetailsHostType GitHub { get; } = new("github");
/// Workspace repository is hosted on Azure DevOps.
public static WorkspacesWorkspaceDetailsHostType Ado { get; } = new("ado");
@@ -11319,6 +11241,72 @@ public override void Write(Utf8JsonWriter writer, ExtensionStatus value, JsonSer
}
+/// Type of GitHub reference.
+[Experimental(Diagnostics.Experimental)]
+[JsonConverter(typeof(Converter))]
+[DebuggerDisplay("{Value,nq}")]
+public readonly struct PushAttachmentGitHubReferenceType : IEquatable
+{
+ private readonly string? _value;
+
+ /// Initializes a new instance of the struct.
+ /// The value to associate with this .
+ [JsonConstructor]
+ public PushAttachmentGitHubReferenceType(string value)
+ {
+ ArgumentException.ThrowIfNullOrWhiteSpace(value);
+ _value = value;
+ }
+
+ /// Gets the value associated with this .
+ public string Value => _value ?? string.Empty;
+
+ /// GitHub issue reference.
+ public static PushAttachmentGitHubReferenceType Issue { get; } = new("issue");
+
+ /// GitHub pull request reference.
+ public static PushAttachmentGitHubReferenceType Pr { get; } = new("pr");
+
+ /// GitHub discussion reference.
+ public static PushAttachmentGitHubReferenceType Discussion { get; } = new("discussion");
+
+ /// Returns a value indicating whether two instances are equivalent.
+ public static bool operator ==(PushAttachmentGitHubReferenceType left, PushAttachmentGitHubReferenceType right) => left.Equals(right);
+
+ /// Returns a value indicating whether two instances are not equivalent.
+ public static bool operator !=(PushAttachmentGitHubReferenceType left, PushAttachmentGitHubReferenceType right) => !(left == right);
+
+ ///
+ public override bool Equals(object? obj) => obj is PushAttachmentGitHubReferenceType other && Equals(other);
+
+ ///
+ public bool Equals(PushAttachmentGitHubReferenceType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase);
+
+ ///
+ public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value);
+
+ ///
+ public override string ToString() => Value;
+
+ /// Provides a for serializing instances.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public sealed class Converter : JsonConverter
+ {
+ ///
+ public override PushAttachmentGitHubReferenceType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
+ }
+
+ ///
+ public override void Write(Utf8JsonWriter writer, PushAttachmentGitHubReferenceType value, JsonSerializerOptions options)
+ {
+ GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PushAttachmentGitHubReferenceType));
+ }
+ }
+}
+
+
/// Optional completion hint for the input (e.g. 'directory' for filesystem path completion).
[Experimental(Diagnostics.Experimental)]
[JsonConverter(typeof(Converter))]
@@ -11778,6 +11766,75 @@ public override void Write(Utf8JsonWriter writer, PermissionsSetApproveAllSource
}
+/// Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers.
+[Experimental(Diagnostics.Experimental)]
+[JsonConverter(typeof(Converter))]
+[DebuggerDisplay("{Value,nq}")]
+public readonly struct PermissionsSetAllowAllSource : IEquatable
+{
+ private readonly string? _value;
+
+ /// Initializes a new instance of the struct.
+ /// The value to associate with this .
+ [JsonConstructor]
+ public PermissionsSetAllowAllSource(string value)
+ {
+ ArgumentException.ThrowIfNullOrWhiteSpace(value);
+ _value = value;
+ }
+
+ /// Gets the value associated with this .
+ public string Value => _value ?? string.Empty;
+
+ /// Allow-all was enabled from a CLI command-line flag.
+ public static PermissionsSetAllowAllSource CliFlag { get; } = new("cli_flag");
+
+ /// Allow-all was enabled by a slash command.
+ public static PermissionsSetAllowAllSource SlashCommand { get; } = new("slash_command");
+
+ /// Allow-all was enabled by confirming autopilot behavior.
+ public static PermissionsSetAllowAllSource AutopilotConfirmation { get; } = new("autopilot_confirmation");
+
+ /// Allow-all was enabled through an RPC caller.
+ public static PermissionsSetAllowAllSource Rpc { get; } = new("rpc");
+
+ /// Returns a value indicating whether two instances are equivalent.
+ public static bool operator ==(PermissionsSetAllowAllSource left, PermissionsSetAllowAllSource right) => left.Equals(right);
+
+ /// Returns a value indicating whether two instances are not equivalent.
+ public static bool operator !=(PermissionsSetAllowAllSource left, PermissionsSetAllowAllSource right) => !(left == right);
+
+ ///
+ public override bool Equals(object? obj) => obj is PermissionsSetAllowAllSource other && Equals(other);
+
+ ///
+ public bool Equals(PermissionsSetAllowAllSource other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase);
+
+ ///
+ public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value);
+
+ ///
+ public override string ToString() => Value;
+
+ /// Provides a for serializing instances.
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public sealed class Converter : JsonConverter
+ {
+ ///
+ public override PermissionsSetAllowAllSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
+ }
+
+ ///
+ public override void Write(Utf8JsonWriter writer, PermissionsSetAllowAllSource value, JsonSerializerOptions options)
+ {
+ GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(PermissionsSetAllowAllSource));
+ }
+ }
+}
+
+
/// Whether the change applies to ephemeral session-scoped rules (cleared at session end) or to location-scoped rules persisted via the location-permissions config file.
[Experimental(Diagnostics.Experimental)]
[JsonConverter(typeof(Converter))]
@@ -12054,7 +12111,7 @@ public WorkspaceSummaryHostType(string value)
public string Value => _value ?? string.Empty;
/// Workspace summary repository is hosted on GitHub.
- public static WorkspaceSummaryHostType Github { get; } = new("github");
+ public static WorkspaceSummaryHostType GitHub { get; } = new("github");
/// Workspace summary repository is hosted on Azure DevOps.
public static WorkspaceSummaryHostType Ado { get; } = new("ado");
@@ -12117,7 +12174,7 @@ public SessionWorkingDirectoryContextHostType(string value)
public string Value => _value ?? string.Empty;
/// The working directory repository is hosted on GitHub.
- public static SessionWorkingDirectoryContextHostType Github { get; } = new("github");
+ public static SessionWorkingDirectoryContextHostType GitHub { get; } = new("github");
/// The working directory repository is hosted on Azure DevOps.
public static SessionWorkingDirectoryContextHostType Ado { get; } = new("ado");
@@ -12744,6 +12801,12 @@ internal async Task ConnectAsync(string? token = null, Cancellati
Interlocked.CompareExchange(ref field, new(_rpc), null) ??
field;
+ /// Runtime APIs.
+ public ServerRuntimeApi Runtime =>
+ field ??
+ Interlocked.CompareExchange(ref field, new(_rpc), null) ??
+ field;
+
/// SessionFs APIs.
public ServerSessionFsApi SessionFs =>
field ??
@@ -13046,6 +13109,24 @@ public async Task ReloadAsync(CancellationToken cancellationToken = default)
}
}
+/// Provides server-scoped Runtime APIs.
+public sealed class ServerRuntimeApi
+{
+ private readonly JsonRpc _rpc;
+
+ internal ServerRuntimeApi(JsonRpc rpc)
+ {
+ _rpc = rpc;
+ }
+
+ /// Gracefully shuts down an SDK-owned runtime. The response is sent only after cleanup completes; callers may then terminate the owned runtime process.
+ /// The to monitor for cancellation requests. The default is .
+ public async Task ShutdownAsync(CancellationToken cancellationToken = default)
+ {
+ await CopilotClient.InvokeRpcAsync(_rpc, "runtime.shutdown", [], cancellationToken);
+ }
+}
+
/// Provides server-scoped SessionFs APIs.
public sealed class ServerSessionFsApi
{
@@ -13560,7 +13641,7 @@ public async Task SuspendAsync(CancellationToken cancellationToken = default)
/// The to monitor for cancellation requests. The default is .
/// Result of sending a user message.
[Experimental(Diagnostics.Experimental)]
- public async Task SendAsync(string prompt, string? displayPrompt = null, IList? attachments = null, SendMode? mode = null, bool? prepend = null, bool? billable = null, string? requiredTool = null, object? source = null, SendAgentMode? agentMode = null, IDictionary? requestHeaders = null, string? traceparent = null, string? tracestate = null, bool? wait = null, CancellationToken cancellationToken = default)
+ public async Task SendAsync(string prompt, string? displayPrompt = null, IList? attachments = null, SendMode? mode = null, bool? prepend = null, bool? billable = null, string? requiredTool = null, object? source = null, SendAgentMode? agentMode = null, IDictionary? requestHeaders = null, string? traceparent = null, string? tracestate = null, bool? wait = null, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(prompt);
_session.ThrowIfDisposed();
@@ -13760,7 +13841,7 @@ internal ModelApi(CopilotSession session)
/// Gets the currently selected model for the session.
/// The to monitor for cancellation requests. The default is .
- /// The currently selected model and reasoning effort for the session.
+ /// The currently selected model, reasoning effort, and context tier for the session. The context tier reflects `Session.getContextTier()`, restored from the session journal on resume.
public async Task GetCurrentAsync(CancellationToken cancellationToken = default)
{
_session.ThrowIfDisposed();
@@ -13774,10 +13855,10 @@ public async Task GetCurrentAsync(CancellationToken cancellationTo
/// Reasoning effort level to use for the model. "none" disables reasoning.
/// Reasoning summary mode to request for supported model clients.
/// Override individual model capabilities resolved by the runtime.
- /// Explicit context tier for the selected model. `"default"` / `"long_context"` pin the tier; `null` clears any previous explicit choice; `undefined` leaves the existing tier untouched.
+ /// Explicit context tier for the selected model. `"default"` / `"long_context"` apply the requested tier; omit this field to use normal model behavior with no explicit tier.
/// The to monitor for cancellation requests. The default is .
/// The model identifier active on the session after the switch.
- public async Task SwitchToAsync(string modelId, string? reasoningEffort = null, ReasoningSummary? reasoningSummary = null, ModelCapabilitiesOverride? modelCapabilities = null, ModelSwitchToRequestContextTier? contextTier = null, CancellationToken cancellationToken = default)
+ public async Task SwitchToAsync(string modelId, string? reasoningEffort = null, ReasoningSummary? reasoningSummary = null, ModelCapabilitiesOverride? modelCapabilities = null, ContextTier? contextTier = null, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(modelId);
_session.ThrowIfDisposed();
@@ -14702,6 +14783,7 @@ internal OptionsApi(CopilotSession session)
/// Whether to discover custom instructions on demand after successful file views (AGENTS.md / CLAUDE.md / .github/copilot-instructions.md surfacing). Combined with `skipCustomInstructions` and the runtime-side `ON_DEMAND_INSTRUCTIONS` feature flag.
/// Full set of installed plugins for the session. Replaces the existing list; the runtime invalidates the skills cache only when the list materially changes.
/// Whether to default custom agents to local-only execution.
+ /// When true, the selected custom agent's prompt is not injected into the user message (skill context is still injected). Used by automation triggers where the agent prompt is already in the problem statement.
/// Whether to skip loading custom instruction sources.
/// Instruction source IDs to exclude from the system prompt.
/// Whether to include the `Co-authored-by` trailer in commit messages.
@@ -14724,11 +14806,11 @@ internal OptionsApi(CopilotSession session)
/// Whether to enable skill directory scanning and loading. Falls back to enableConfigDiscovery when unset.
/// The to monitor for cancellation requests. The default is .
/// Indicates whether the session options patch was applied successfully.
- public async Task UpdateAsync(string? model = null, string? reasoningEffort = null, string? clientName = null, string? lspClientName = null, string? integrationId = null, IDictionary? featureFlags = null, bool? isExperimentalMode = null, object? provider = null, string? workingDirectory = null, IList? availableTools = null, IList? excludedTools = null, OptionsUpdateToolFilterPrecedence? toolFilterPrecedence = null, bool? enableScriptSafety = null, string? shellInitProfile = null, IList? shellProcessFlags = null, object? sandboxConfig = null, bool? logInteractiveShells = null, OptionsUpdateEnvValueMode? envValueMode = null, IList? skillDirectories = null, IList? disabledSkills = null, bool? enableOnDemandInstructionDiscovery = null, IList? installedPlugins = null, bool? customAgentsLocalOnly = null, bool? skipCustomInstructions = null, IList? disabledInstructionSources = null, bool? coauthorEnabled = null, string? trajectoryFile = null, bool? enableStreaming = null, string? copilotUrl = null, bool? askUserDisabled = null, bool? continueOnAutoMode = null, bool? runningInInteractiveMode = null, bool? enableReasoningSummaries = null, string? agentContext = null, string? eventsLogDirectory = null, IList
+/// Represents the session.extensions.attachments_pushed event.
+public sealed partial class SessionExtensionsAttachmentsPushedEvent : SessionEvent
+{
+ ///
+ [JsonIgnore]
+ public override string Type => "session.extensions.attachments_pushed";
+
+ /// The session.extensions.attachments_pushed event payload.
+ [JsonPropertyName("data")]
+ public required SessionExtensionsAttachmentsPushedData Data { get; set; }
+}
+
/// MCP App view called a tool on a connected MCP server (SEP-1865).
/// Represents the mcp_app.tool_call_complete event.
public sealed partial class McpAppToolCallCompleteEvent : SessionEvent
@@ -1300,7 +1314,7 @@ public sealed partial class SessionStartData
/// Context tier selected at session creation time for models with tiered context pricing; null when no tier is selected (e.g., non-tiered model).
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("contextTier")]
- public SessionStartDataContextTier? ContextTier { get; set; }
+ public ContextTier? ContextTier { get; set; }
/// Version string of the Copilot application.
[JsonPropertyName("copilotVersion")]
@@ -1364,7 +1378,7 @@ public sealed partial class SessionResumeData
/// Context tier currently selected at resume time; null when no tier is active.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("contextTier")]
- public SessionResumeDataContextTier? ContextTier { get; set; }
+ public ContextTier? ContextTier { get; set; }
/// When true, tool calls and permission requests left in flight by the previous session lifetime remain pending after resume and the agentic loop awaits their results. User sends are queued behind the pending work until all such requests reach a terminal state. When false (the default), any such tool calls and permission requests are immediately marked as interrupted on resume.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
@@ -1580,7 +1594,7 @@ public sealed partial class SessionModelChangeData
/// Context tier after the model change; null explicitly clears a previously selected tier.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("contextTier")]
- public SessionModelChangeDataContextTier? ContextTier { get; set; }
+ public ContextTier? ContextTier { get; set; }
/// Newly selected model identifier.
[JsonPropertyName("newModel")]
@@ -2024,7 +2038,7 @@ public sealed partial class UserMessageData
/// Files, selections, or GitHub references attached to the message.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("attachments")]
- public UserMessageAttachment[]? Attachments { get; set; }
+ public Attachment[]? Attachments { get; set; }
/// The user's message text as displayed in the timeline.
[JsonPropertyName("content")]
@@ -2453,6 +2467,11 @@ public sealed partial class ToolExecutionStartData
[JsonPropertyName("mcpToolName")]
public string? McpToolName { get; set; }
+ /// Model identifier that generated this tool call.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("model")]
+ public string? Model { get; set; }
+
/// Tool call ID of the parent tool invocation when this event originates from a sub-agent.
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("This member is deprecated and will be removed in a future version.")]
@@ -3353,6 +3372,14 @@ public sealed partial class SessionCanvasRegistryChangedData
public required CanvasRegistryChangedCanvas[] Canvases { get; set; }
}
+/// Schema for the `ExtensionsAttachmentsPushedData` type.
+public sealed partial class SessionExtensionsAttachmentsPushedData
+{
+ /// Attachments contributed by an extension; the host should surface these as composer pills and forward them via the next session.send call.
+ [JsonPropertyName("attachments")]
+ public required Attachment[] Attachments { get; set; }
+}
+
/// MCP App view called a tool on a connected MCP server (SEP-1865).
public sealed partial class McpAppToolCallCompleteData
{
@@ -3634,8 +3661,8 @@ public sealed partial class CompactionCompleteCompactionTokensUsed
}
/// Optional line range to scope the attachment to a specific section of the file.
-/// Nested data type for UserMessageAttachmentFileLineRange.
-public sealed partial class UserMessageAttachmentFileLineRange
+/// Nested data type for AttachmentFileLineRange.
+public sealed partial class AttachmentFileLineRange
{
/// End line number (1-based, inclusive).
[JsonPropertyName("end")]
@@ -3647,8 +3674,8 @@ public sealed partial class UserMessageAttachmentFileLineRange
}
/// File attachment.
-/// The file variant of .
-public sealed partial class UserMessageAttachmentFile : UserMessageAttachment
+/// The file variant of .
+public sealed partial class AttachmentFile : Attachment
{
///
[JsonIgnore]
@@ -3661,7 +3688,7 @@ public sealed partial class UserMessageAttachmentFile : UserMessageAttachment
/// Optional line range to scope the attachment to a specific section of the file.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("lineRange")]
- public UserMessageAttachmentFileLineRange? LineRange { get; set; }
+ public AttachmentFileLineRange? LineRange { get; set; }
/// Absolute file path.
[JsonPropertyName("path")]
@@ -3669,8 +3696,8 @@ public sealed partial class UserMessageAttachmentFile : UserMessageAttachment
}
/// Directory attachment.
-/// The directory variant of .
-public sealed partial class UserMessageAttachmentDirectory : UserMessageAttachment
+/// The directory variant of .
+public sealed partial class AttachmentDirectory : Attachment
{
///
[JsonIgnore]
@@ -3686,8 +3713,8 @@ public sealed partial class UserMessageAttachmentDirectory : UserMessageAttachme
}
/// End position of the selection.
-/// Nested data type for UserMessageAttachmentSelectionDetailsEnd.
-public sealed partial class UserMessageAttachmentSelectionDetailsEnd
+/// Nested data type for AttachmentSelectionDetailsEnd.
+public sealed partial class AttachmentSelectionDetailsEnd
{
/// End character offset within the line (0-based).
[JsonPropertyName("character")]
@@ -3699,8 +3726,8 @@ public sealed partial class UserMessageAttachmentSelectionDetailsEnd
}
/// Start position of the selection.
-/// Nested data type for UserMessageAttachmentSelectionDetailsStart.
-public sealed partial class UserMessageAttachmentSelectionDetailsStart
+/// Nested data type for AttachmentSelectionDetailsStart.
+public sealed partial class AttachmentSelectionDetailsStart
{
/// Start character offset within the line (0-based).
[JsonPropertyName("character")]
@@ -3712,21 +3739,21 @@ public sealed partial class UserMessageAttachmentSelectionDetailsStart
}
/// Position range of the selection within the file.
-/// Nested data type for UserMessageAttachmentSelectionDetails.
-public sealed partial class UserMessageAttachmentSelectionDetails
+/// Nested data type for AttachmentSelectionDetails.
+public sealed partial class AttachmentSelectionDetails
{
/// End position of the selection.
[JsonPropertyName("end")]
- public required UserMessageAttachmentSelectionDetailsEnd End { get; set; }
+ public required AttachmentSelectionDetailsEnd End { get; set; }
/// Start position of the selection.
[JsonPropertyName("start")]
- public required UserMessageAttachmentSelectionDetailsStart Start { get; set; }
+ public required AttachmentSelectionDetailsStart Start { get; set; }
}
/// Code selection attachment from an editor.
-/// The selection variant of .
-public sealed partial class UserMessageAttachmentSelection : UserMessageAttachment
+/// The selection variant of .
+public sealed partial class AttachmentSelection : Attachment
{
///
[JsonIgnore]
@@ -3742,7 +3769,7 @@ public sealed partial class UserMessageAttachmentSelection : UserMessageAttachme
/// Position range of the selection within the file.
[JsonPropertyName("selection")]
- public required UserMessageAttachmentSelectionDetails Selection { get; set; }
+ public required AttachmentSelectionDetails Selection { get; set; }
/// The selected text content.
[JsonPropertyName("text")]
@@ -3750,8 +3777,8 @@ public sealed partial class UserMessageAttachmentSelection : UserMessageAttachme
}
/// GitHub issue, pull request, or discussion reference.
-/// The github_reference variant of .
-public sealed partial class UserMessageAttachmentGithubReference : UserMessageAttachment
+/// The github_reference variant of .
+public sealed partial class AttachmentGitHubReference : Attachment
{
///
[JsonIgnore]
@@ -3763,7 +3790,7 @@ public sealed partial class UserMessageAttachmentGithubReference : UserMessageAt
/// Type of GitHub reference.
[JsonPropertyName("referenceType")]
- public required UserMessageAttachmentGithubReferenceType ReferenceType { get; set; }
+ public required AttachmentGitHubReferenceType ReferenceType { get; set; }
/// Current state of the referenced item (e.g., open, closed, merged).
[JsonPropertyName("state")]
@@ -3779,8 +3806,8 @@ public sealed partial class UserMessageAttachmentGithubReference : UserMessageAt
}
/// Blob attachment with inline base64-encoded data.
-/// The blob variant of .
-public sealed partial class UserMessageAttachmentBlob : UserMessageAttachment
+/// The blob variant of .
+public sealed partial class AttachmentBlob : Attachment
{
///
[JsonIgnore]
@@ -3801,17 +3828,56 @@ public sealed partial class UserMessageAttachmentBlob : UserMessageAttachment
public required string MimeType { get; set; }
}
-/// A user message attachment — a file, directory, code selection, blob, or GitHub reference.
+/// Structured context contributed by an extension. Composer pills displayed in the host are forwarded back through session.send.attachments, then rendered into the model prompt as an <extension_context> XML block.
+/// The extension_context variant of .
+public sealed partial class AttachmentExtensionContext : Attachment
+{
+ ///
+ [JsonIgnore]
+ public override string Type => "extension_context";
+
+ /// Provider-local canvas identifier when the push was bound to a canvas instance.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("canvasId")]
+ public string? CanvasId { get; set; }
+
+ /// ISO 8601 timestamp captured by the runtime when the push was accepted.
+ [JsonPropertyName("capturedAt")]
+ public required DateTimeOffset CapturedAt { get; set; }
+
+ /// Owning extension identifier. Runtime-derived from the caller's connection when produced via session.extensions.sendAttachmentsToMessage; preserved verbatim on subsequent transports.
+ [JsonPropertyName("extensionId")]
+ public required string ExtensionId { get; set; }
+
+ /// Open canvas instance identifier when the push was bound to a canvas instance.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("instanceId")]
+ public string? InstanceId { get; set; }
+
+ /// Caller-supplied JSON payload.
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [JsonPropertyName("payload")]
+ public JsonElement? Payload { get; set; }
+
+ /// Human-readable composer pill label.
+ [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Safe for generated string properties: JSON Schema minLength/maxLength map to string length validation, not reflection over trimmed Count members")]
+ [MinLength(1)]
+ [JsonPropertyName("title")]
+ public required string Title { get; set; }
+}
+
+/// A user message attachment — a file, directory, code selection, blob, GitHub reference, or extension-supplied context payload.
/// Polymorphic base type discriminated by type.
[JsonPolymorphic(
TypeDiscriminatorPropertyName = "type",
UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToBaseType)]
-[JsonDerivedType(typeof(UserMessageAttachmentFile), "file")]
-[JsonDerivedType(typeof(UserMessageAttachmentDirectory), "directory")]
-[JsonDerivedType(typeof(UserMessageAttachmentSelection), "selection")]
-[JsonDerivedType(typeof(UserMessageAttachmentGithubReference), "github_reference")]
-[JsonDerivedType(typeof(UserMessageAttachmentBlob), "blob")]
-public partial class UserMessageAttachment
+[JsonDerivedType(typeof(AttachmentFile), "file")]
+[JsonDerivedType(typeof(AttachmentDirectory), "directory")]
+[JsonDerivedType(typeof(AttachmentSelection), "selection")]
+[JsonDerivedType(typeof(AttachmentGitHubReference), "github_reference")]
+[JsonDerivedType(typeof(AttachmentBlob), "blob")]
+[JsonDerivedType(typeof(AttachmentExtensionContext), "extension_context")]
+public partial class Attachment
{
/// The type discriminator.
[JsonPropertyName("type")]
@@ -5914,7 +5980,7 @@ public WorkingDirectoryContextHostType(string value)
public string Value => _value ?? string.Empty;
/// Repository is hosted on GitHub.
- public static WorkingDirectoryContextHostType Github { get; } = new("github");
+ public static WorkingDirectoryContextHostType GitHub { get; } = new("github");
/// Repository is hosted on Azure DevOps.
public static WorkingDirectoryContextHostType Ado { get; } = new("ado");
@@ -5955,42 +6021,42 @@ public override void Write(Utf8JsonWriter writer, WorkingDirectoryContextHostTyp
}
}
-/// Defines the allowed values.
+/// Allowed values for the `ContextTier` enumeration.
[JsonConverter(typeof(Converter))]
[DebuggerDisplay("{Value,nq}")]
-public readonly struct SessionStartDataContextTier : IEquatable
+public readonly struct ContextTier : IEquatable
{
private readonly string? _value;
- /// Initializes a new instance of the struct.
- /// The value to associate with this .
+ /// Initializes a new instance of the struct.
+ /// The value to associate with this .
[JsonConstructor]
- public SessionStartDataContextTier(string value)
+ public ContextTier(string value)
{
ArgumentException.ThrowIfNullOrWhiteSpace(value);
_value = value;
}
- /// Gets the value associated with this .
+ /// Gets the value associated with this .
public string Value => _value ?? string.Empty;
/// Default context tier with standard context window size.
- public static SessionStartDataContextTier Default { get; } = new("default");
+ public static ContextTier Default { get; } = new("default");
/// Extended context tier with a larger context window.
- public static SessionStartDataContextTier LongContext { get; } = new("long_context");
+ public static ContextTier LongContext { get; } = new("long_context");
- /// Returns a value indicating whether two instances are equivalent.
- public static bool operator ==(SessionStartDataContextTier left, SessionStartDataContextTier right) => left.Equals(right);
+ /// Returns a value indicating whether two instances are equivalent.
+ public static bool operator ==(ContextTier left, ContextTier right) => left.Equals(right);
- /// Returns a value indicating whether two instances are not equivalent.
- public static bool operator !=(SessionStartDataContextTier left, SessionStartDataContextTier right) => !(left == right);
+ /// Returns a value indicating whether two instances are not equivalent.
+ public static bool operator !=(ContextTier left, ContextTier right) => !(left == right);
///
- public override bool Equals(object? obj) => obj is SessionStartDataContextTier other && Equals(other);
+ public override bool Equals(object? obj) => obj is ContextTier other && Equals(other);
///
- public bool Equals(SessionStartDataContextTier other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase);
+ public bool Equals(ContextTier other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase);
///
public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value);
@@ -5998,20 +6064,20 @@ public SessionStartDataContextTier(string value)
///
public override string ToString() => Value;
- /// Provides a for serializing instances.
+ /// Provides a for serializing instances.
[EditorBrowsable(EditorBrowsableState.Never)]
- public sealed class Converter : JsonConverter
+ public sealed class Converter : JsonConverter
{
///
- public override SessionStartDataContextTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ public override ContextTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
}
///
- public override void Write(Utf8JsonWriter writer, SessionStartDataContextTier value, JsonSerializerOptions options)
+ public override void Write(Utf8JsonWriter writer, ContextTier value, JsonSerializerOptions options)
{
- GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionStartDataContextTier));
+ GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(ContextTier));
}
}
}
@@ -6080,67 +6146,6 @@ public override void Write(Utf8JsonWriter writer, ReasoningSummary value, JsonSe
}
}
-/// Defines the allowed values.
-[JsonConverter(typeof(Converter))]
-[DebuggerDisplay("{Value,nq}")]
-public readonly struct SessionResumeDataContextTier : IEquatable
-{
- private readonly string? _value;
-
- /// Initializes a new instance of the struct.
- /// The value to associate with this .
- [JsonConstructor]
- public SessionResumeDataContextTier(string value)
- {
- ArgumentException.ThrowIfNullOrWhiteSpace(value);
- _value = value;
- }
-
- /// Gets the value associated with this .
- public string Value => _value ?? string.Empty;
-
- /// Default context tier with standard context window size.
- public static SessionResumeDataContextTier Default { get; } = new("default");
-
- /// Extended context tier with a larger context window.
- public static SessionResumeDataContextTier LongContext { get; } = new("long_context");
-
- /// Returns a value indicating whether two instances are equivalent.
- public static bool operator ==(SessionResumeDataContextTier left, SessionResumeDataContextTier right) => left.Equals(right);
-
- /// Returns a value indicating whether two instances are not equivalent.
- public static bool operator !=(SessionResumeDataContextTier left, SessionResumeDataContextTier right) => !(left == right);
-
- ///
- public override bool Equals(object? obj) => obj is SessionResumeDataContextTier other && Equals(other);
-
- ///
- public bool Equals(SessionResumeDataContextTier other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase);
-
- ///
- public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value);
-
- ///
- public override string ToString() => Value;
-
- /// Provides a for serializing instances.
- [EditorBrowsable(EditorBrowsableState.Never)]
- public sealed class Converter : JsonConverter
- {
- ///
- public override SessionResumeDataContextTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- {
- return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
- }
-
- ///
- public override void Write(Utf8JsonWriter writer, SessionResumeDataContextTier value, JsonSerializerOptions options)
- {
- GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionResumeDataContextTier));
- }
- }
-}
-
/// The type of operation performed on the autopilot objective state file.
[JsonConverter(typeof(Converter))]
[DebuggerDisplay("{Value,nq}")]
@@ -6272,67 +6277,6 @@ public override void Write(Utf8JsonWriter writer, AutopilotObjectiveChangedStatu
}
}
-/// Defines the allowed values.
-[JsonConverter(typeof(Converter))]
-[DebuggerDisplay("{Value,nq}")]
-public readonly struct SessionModelChangeDataContextTier : IEquatable
-{
- private readonly string? _value;
-
- /// Initializes a new instance of the struct.
- /// The value to associate with this .
- [JsonConstructor]
- public SessionModelChangeDataContextTier(string value)
- {
- ArgumentException.ThrowIfNullOrWhiteSpace(value);
- _value = value;
- }
-
- /// Gets the value associated with this .
- public string Value => _value ?? string.Empty;
-
- /// Default context tier with standard context window size.
- public static SessionModelChangeDataContextTier Default { get; } = new("default");
-
- /// Extended context tier with a larger context window.
- public static SessionModelChangeDataContextTier LongContext { get; } = new("long_context");
-
- /// Returns a value indicating whether two instances are equivalent.
- public static bool operator ==(SessionModelChangeDataContextTier left, SessionModelChangeDataContextTier right) => left.Equals(right);
-
- /// Returns a value indicating whether two instances are not equivalent.
- public static bool operator !=(SessionModelChangeDataContextTier left, SessionModelChangeDataContextTier right) => !(left == right);
-
- ///
- public override bool Equals(object? obj) => obj is SessionModelChangeDataContextTier other && Equals(other);
-
- ///
- public bool Equals(SessionModelChangeDataContextTier other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase);
-
- ///
- public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value);
-
- ///
- public override string ToString() => Value;
-
- /// Provides a for serializing instances.
- [EditorBrowsable(EditorBrowsableState.Never)]
- public sealed class Converter : JsonConverter
- {
- ///
- public override SessionModelChangeDataContextTier Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- {
- return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
- }
-
- ///
- public override void Write(Utf8JsonWriter writer, SessionModelChangeDataContextTier value, JsonSerializerOptions options)
- {
- GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(SessionModelChangeDataContextTier));
- }
- }
-}
-
/// The session mode the agent is operating in.
[JsonConverter(typeof(Converter))]
[DebuggerDisplay("{Value,nq}")]
@@ -6714,42 +6658,42 @@ public override void Write(Utf8JsonWriter writer, UserMessageAgentMode value, Js
/// Type of GitHub reference.
[JsonConverter(typeof(Converter))]
[DebuggerDisplay("{Value,nq}")]
-public readonly struct UserMessageAttachmentGithubReferenceType : IEquatable
+public readonly struct AttachmentGitHubReferenceType : IEquatable
{
private readonly string? _value;
- /// Initializes a new instance of the struct.
- /// The value to associate with this .
+ /// Initializes a new instance of the struct.
+ /// The value to associate with this .
[JsonConstructor]
- public UserMessageAttachmentGithubReferenceType(string value)
+ public AttachmentGitHubReferenceType(string value)
{
ArgumentException.ThrowIfNullOrWhiteSpace(value);
_value = value;
}
- /// Gets the value associated with this .
+ /// Gets the value associated with this .
public string Value => _value ?? string.Empty;
/// GitHub issue reference.
- public static UserMessageAttachmentGithubReferenceType Issue { get; } = new("issue");
+ public static AttachmentGitHubReferenceType Issue { get; } = new("issue");
/// GitHub pull request reference.
- public static UserMessageAttachmentGithubReferenceType Pr { get; } = new("pr");
+ public static AttachmentGitHubReferenceType Pr { get; } = new("pr");
/// GitHub discussion reference.
- public static UserMessageAttachmentGithubReferenceType Discussion { get; } = new("discussion");
+ public static AttachmentGitHubReferenceType Discussion { get; } = new("discussion");
- /// Returns a value indicating whether two instances are equivalent.
- public static bool operator ==(UserMessageAttachmentGithubReferenceType left, UserMessageAttachmentGithubReferenceType right) => left.Equals(right);
+ /// Returns a value indicating whether two instances are equivalent.
+ public static bool operator ==(AttachmentGitHubReferenceType left, AttachmentGitHubReferenceType right) => left.Equals(right);
- /// Returns a value indicating whether two instances are not equivalent.
- public static bool operator !=(UserMessageAttachmentGithubReferenceType left, UserMessageAttachmentGithubReferenceType right) => !(left == right);
+ /// Returns a value indicating whether two instances are not equivalent.
+ public static bool operator !=(AttachmentGitHubReferenceType left, AttachmentGitHubReferenceType right) => !(left == right);
///
- public override bool Equals(object? obj) => obj is UserMessageAttachmentGithubReferenceType other && Equals(other);
+ public override bool Equals(object? obj) => obj is AttachmentGitHubReferenceType other && Equals(other);
///
- public bool Equals(UserMessageAttachmentGithubReferenceType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase);
+ public bool Equals(AttachmentGitHubReferenceType other) => string.Equals(Value, other.Value, StringComparison.OrdinalIgnoreCase);
///
public override int GetHashCode() => StringComparer.OrdinalIgnoreCase.GetHashCode(Value);
@@ -6757,20 +6701,20 @@ public UserMessageAttachmentGithubReferenceType(string value)
///
public override string ToString() => Value;
- /// Provides a for serializing instances.
+ /// Provides a for serializing instances.
[EditorBrowsable(EditorBrowsableState.Never)]
- public sealed class Converter : JsonConverter
+ public sealed class Converter : JsonConverter
{
///
- public override UserMessageAttachmentGithubReferenceType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ public override AttachmentGitHubReferenceType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return new(GeneratedStringEnumJson.ReadValue(ref reader, typeToConvert));
}
///
- public override void Write(Utf8JsonWriter writer, UserMessageAttachmentGithubReferenceType value, JsonSerializerOptions options)
+ public override void Write(Utf8JsonWriter writer, AttachmentGitHubReferenceType value, JsonSerializerOptions options)
{
- GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(UserMessageAttachmentGithubReferenceType));
+ GeneratedStringEnumJson.WriteValue(writer, value.Value, typeof(AttachmentGitHubReferenceType));
}
}
}
@@ -8284,6 +8228,17 @@ public override void Write(Utf8JsonWriter writer, CanvasOpenedAvailability value
[JsonSerializable(typeof(AssistantUsageData))]
[JsonSerializable(typeof(AssistantUsageEvent))]
[JsonSerializable(typeof(AssistantUsageQuotaSnapshot))]
+[JsonSerializable(typeof(Attachment))]
+[JsonSerializable(typeof(AttachmentBlob))]
+[JsonSerializable(typeof(AttachmentDirectory))]
+[JsonSerializable(typeof(AttachmentExtensionContext))]
+[JsonSerializable(typeof(AttachmentFile))]
+[JsonSerializable(typeof(AttachmentFileLineRange))]
+[JsonSerializable(typeof(AttachmentGitHubReference))]
+[JsonSerializable(typeof(AttachmentSelection))]
+[JsonSerializable(typeof(AttachmentSelectionDetails))]
+[JsonSerializable(typeof(AttachmentSelectionDetailsEnd))]
+[JsonSerializable(typeof(AttachmentSelectionDetailsStart))]
[JsonSerializable(typeof(AutoModeSwitchCompletedData))]
[JsonSerializable(typeof(AutoModeSwitchCompletedEvent))]
[JsonSerializable(typeof(AutoModeSwitchRequestedData))]
@@ -8410,6 +8365,8 @@ public override void Write(Utf8JsonWriter writer, CanvasOpenedAvailability value
[JsonSerializable(typeof(SessionErrorData))]
[JsonSerializable(typeof(SessionErrorEvent))]
[JsonSerializable(typeof(SessionEvent))]
+[JsonSerializable(typeof(SessionExtensionsAttachmentsPushedData))]
+[JsonSerializable(typeof(SessionExtensionsAttachmentsPushedEvent))]
[JsonSerializable(typeof(SessionExtensionsLoadedData))]
[JsonSerializable(typeof(SessionExtensionsLoadedEvent))]
[JsonSerializable(typeof(SessionHandoffData))]
@@ -8528,16 +8485,6 @@ public override void Write(Utf8JsonWriter writer, CanvasOpenedAvailability value
[JsonSerializable(typeof(UserInputCompletedEvent))]
[JsonSerializable(typeof(UserInputRequestedData))]
[JsonSerializable(typeof(UserInputRequestedEvent))]
-[JsonSerializable(typeof(UserMessageAttachment))]
-[JsonSerializable(typeof(UserMessageAttachmentBlob))]
-[JsonSerializable(typeof(UserMessageAttachmentDirectory))]
-[JsonSerializable(typeof(UserMessageAttachmentFile))]
-[JsonSerializable(typeof(UserMessageAttachmentFileLineRange))]
-[JsonSerializable(typeof(UserMessageAttachmentGithubReference))]
-[JsonSerializable(typeof(UserMessageAttachmentSelection))]
-[JsonSerializable(typeof(UserMessageAttachmentSelectionDetails))]
-[JsonSerializable(typeof(UserMessageAttachmentSelectionDetailsEnd))]
-[JsonSerializable(typeof(UserMessageAttachmentSelectionDetailsStart))]
[JsonSerializable(typeof(UserMessageData))]
[JsonSerializable(typeof(UserMessageEvent))]
[JsonSerializable(typeof(UserToolSessionApproval))]
diff --git a/dotnet/src/Polyfills/DownlevelExtensions.cs b/dotnet/src/Polyfills/DownlevelExtensions.cs
index 0fdf70f3e..17c98643e 100644
--- a/dotnet/src/Polyfills/DownlevelExtensions.cs
+++ b/dotnet/src/Polyfills/DownlevelExtensions.cs
@@ -614,4 +614,35 @@ internal static class DownlevelValueTaskExtensions
public static ValueTask FromResult(T result) => new(result);
}
}
+
+ internal static class DownlevelTaskExtensions
+ {
+ extension(Task task)
+ {
+ public async Task WaitAsync(TimeSpan timeout, CancellationToken cancellationToken = default)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ using var delayCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
+ var completed = await Task.WhenAny(task, Task.Delay(timeout, delayCts.Token)).ConfigureAwait(false);
+ if (!ReferenceEquals(completed, task))
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ throw new TimeoutException();
+ }
+
+ delayCts.Cancel();
+ await task.ConfigureAwait(false);
+ }
+ }
+
+ extension(Task task)
+ {
+ public async Task WaitAsync(TimeSpan timeout, CancellationToken cancellationToken = default)
+ {
+ await ((Task)task).WaitAsync(timeout, cancellationToken).ConfigureAwait(false);
+ return await task.ConfigureAwait(false);
+ }
+ }
+ }
}
diff --git a/dotnet/src/Session.cs b/dotnet/src/Session.cs
index 6e7d5ea30..bd369867f 100644
--- a/dotnet/src/Session.cs
+++ b/dotnet/src/Session.cs
@@ -1576,14 +1576,40 @@ public async Task AbortAsync(CancellationToken cancellationToken = default)
///
/// await session.SetModelAsync("gpt-4.1");
/// await session.SetModelAsync("claude-sonnet-4.6", "high");
+ /// await session.SetModelAsync("gpt-4.1", new SetModelOptions { ContextTier = ContextTier.LongContext });
///
///
- public async Task SetModelAsync(string model, string? reasoningEffort, ModelCapabilitiesOverride? modelCapabilities = null, CancellationToken cancellationToken = default)
+ public Task SetModelAsync(string model, string? reasoningEffort, ModelCapabilitiesOverride? modelCapabilities = null, CancellationToken cancellationToken = default)
+ {
+ return SetModelAsync(
+ model,
+ new SetModelOptions
+ {
+ ReasoningEffort = reasoningEffort,
+ ModelCapabilities = modelCapabilities,
+ },
+ cancellationToken);
+ }
+
+ ///
+ /// Changes the model for this session.
+ /// The new model takes effect for the next message. Conversation history is preserved.
+ ///
+ /// Model ID to switch to (e.g., "gpt-4.1").
+ /// Settings for the new model.
+ /// Optional cancellation token.
+ public async Task SetModelAsync(string model, SetModelOptions options, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(model);
ThrowIfDisposed();
- await Rpc.Model.SwitchToAsync(model, reasoningEffort, reasoningSummary: null, modelCapabilities: modelCapabilities, cancellationToken: cancellationToken);
+ await Rpc.Model.SwitchToAsync(
+ model,
+ options.ReasoningEffort,
+ options.ReasoningSummary,
+ options.ModelCapabilities,
+ options.ContextTier,
+ cancellationToken);
}
///
@@ -1593,7 +1619,7 @@ public Task SetModelAsync(string model, CancellationToken cancellationToken = de
{
ThrowIfDisposed();
- return SetModelAsync(model, reasoningEffort: null, modelCapabilities: null, cancellationToken);
+ return SetModelAsync(model, new SetModelOptions(), cancellationToken);
}
///
@@ -1705,7 +1731,7 @@ internal record SendMessageRequest
public string SessionId { get; init; } = string.Empty;
public string Prompt { get; init; } = string.Empty;
public string? DisplayPrompt { get; init; }
- public IList? Attachments { get; init; }
+ public IList? Attachments { get; init; }
public string? Mode { get; init; }
[JsonPropertyName("agentMode")]
public AgentMode? AgentMode { get; init; }
@@ -1776,7 +1802,7 @@ internal void ThrowIfDisposed()
[JsonSerializable(typeof(SessionStartHookOutput))]
[JsonSerializable(typeof(SystemMessageTransformRpcResponse))]
[JsonSerializable(typeof(SystemMessageTransformSection))]
- [JsonSerializable(typeof(UserMessageAttachment))]
+ [JsonSerializable(typeof(Attachment))]
[JsonSerializable(typeof(UserPromptSubmittedHookInput))]
[JsonSerializable(typeof(UserPromptSubmittedHookOutput))]
internal partial class SessionJsonContext : JsonSerializerContext;
diff --git a/dotnet/src/Types.cs b/dotnet/src/Types.cs
index 2e1a217b3..7a2ad2951 100644
--- a/dotnet/src/Types.cs
+++ b/dotnet/src/Types.cs
@@ -2390,6 +2390,34 @@ public sealed class CloudSessionOptions
public CloudSessionRepository? Repository { get; set; }
}
+///
+/// Optional settings for .
+///
+public struct SetModelOptions
+{
+ ///
+ /// Reasoning effort level for the new model.
+ ///
+ public string? ReasoningEffort { get; set; }
+
+ ///
+ /// Reasoning summary mode for models that support configurable reasoning summaries.
+ ///
+ ///
+ /// Use to suppress summary output regardless of whether reasoning is enabled.
+ ///
+ public ReasoningSummary? ReasoningSummary { get; set; }
+
+ ///
+ /// Explicit context window tier for models that support it.
+ /// Leave unset to use normal model behavior with no explicit tier.
+ ///
+ public ContextTier? ContextTier { get; set; }
+
+ /// Per-property overrides for model capabilities, deep-merged over runtime defaults.
+ public ModelCapabilitiesOverride? ModelCapabilities { get; set; }
+}
+
///
/// Shared configuration properties for creating or resuming a Copilot session.
/// Use when creating a new session, or
@@ -2452,6 +2480,7 @@ protected SessionConfigBase(SessionConfigBase? other)
ManageScheduleEnabled = other.ManageScheduleEnabled;
ReasoningEffort = other.ReasoningEffort;
ReasoningSummary = other.ReasoningSummary;
+ ContextTier = other.ContextTier;
CreateSessionFsProvider = other.CreateSessionFsProvider;
GitHubToken = other.GitHubToken;
RemoteSession = other.RemoteSession;
@@ -2459,6 +2488,7 @@ protected SessionConfigBase(SessionConfigBase? other)
Canvases = other.Canvases is not null ? [.. other.Canvases] : null;
RequestCanvasRenderer = other.RequestCanvasRenderer;
RequestExtensions = other.RequestExtensions;
+ ExtensionSdkPath = other.ExtensionSdkPath;
ExtensionInfo = other.ExtensionInfo;
CanvasHandler = other.CanvasHandler;
#pragma warning restore GHCP001
@@ -2493,6 +2523,13 @@ protected SessionConfigBase(SessionConfigBase? other)
///
public ReasoningSummary? ReasoningSummary { get; set; }
+ ///
+ /// Context window tier for models that support it.
+ /// Use or
+ /// for the currently known tiers.
+ ///
+ public ContextTier? ContextTier { get; set; }
+
/// Per-property overrides for model capabilities, deep-merged over runtime defaults.
public ModelCapabilitiesOverride? ModelCapabilities { get; set; }
@@ -2820,6 +2857,16 @@ protected SessionConfigBase(SessionConfigBase? other)
[Experimental(Diagnostics.Experimental)]
public bool? RequestExtensions { get; set; }
+ ///
+ /// Optional override path to a copilot-sdk/ folder to inject into
+ /// extension subprocesses for this session in place of the bundled SDK.
+ /// When unset or invalid (missing folder, or missing index.js /
+ /// extension.js), the runtime falls back to the bundled SDK
+ /// without throwing. Takes precedence over any server-level default.
+ ///
+ [Experimental(Diagnostics.Experimental)]
+ public string? ExtensionSdkPath { get; set; }
+
///
/// Stable extension identity for canvas/tool providers on this connection.
/// Required when is set so the runtime can attribute
@@ -2980,7 +3027,7 @@ private MessageOptions(MessageOptions? other)
///
/// File or data attachments to include with the message.
///
- public IList? Attachments { get; set; }
+ public IList? Attachments { get; set; }
///
/// How to deliver the message. "enqueue" (default) appends to the message queue;
/// "immediate" interjects during an in-progress turn.
diff --git a/dotnet/test/E2E/BuiltinToolsE2ETests.cs b/dotnet/test/E2E/BuiltinToolsE2ETests.cs
index 863331e9d..467904577 100644
--- a/dotnet/test/E2E/BuiltinToolsE2ETests.cs
+++ b/dotnet/test/E2E/BuiltinToolsE2ETests.cs
@@ -16,6 +16,12 @@ namespace GitHub.Copilot.Test.E2E;
public class BuiltinToolsE2ETests(E2ETestFixture fixture, ITestOutputHelper output)
: E2ETestBase(fixture, "builtin_tools", output)
{
+ // Built-in tool tests spawn a real CLI subprocess and execute actual shell /
+ // file tools. Under slow/concurrent CI (notably Windows) this agent loop can
+ // briefly exceed the 60s SendAndWaitAsync default, so give it extra headroom
+ // while still failing fast on a genuine hang.
+ private static readonly TimeSpan SendTimeout = TimeSpan.FromSeconds(120);
+
[Fact]
public async Task Should_Capture_Exit_Code_In_Output()
{
@@ -23,7 +29,7 @@ public async Task Should_Capture_Exit_Code_In_Output()
var msg = await session.SendAndWaitAsync(new MessageOptions
{
Prompt = "Run 'echo hello && echo world'. Tell me the exact output.",
- });
+ }, SendTimeout);
var content = msg?.Data.Content ?? string.Empty;
Assert.Contains("hello", content);
Assert.Contains("world", content);
@@ -44,7 +50,7 @@ public async Task Should_Capture_Stderr_Output()
var msg = await session.SendAndWaitAsync(new MessageOptions
{
Prompt = "Run 'echo error_msg >&2; echo ok' and tell me what stderr said. Reply with just the stderr content.",
- });
+ }, SendTimeout);
Assert.Contains("error_msg", msg?.Data.Content ?? string.Empty);
}
@@ -56,7 +62,7 @@ public async Task Should_Read_File_With_Line_Range()
var msg = await session.SendAndWaitAsync(new MessageOptions
{
Prompt = "Read lines 2 through 4 of the file 'lines.txt' in this directory. Tell me what those lines contain.",
- });
+ }, SendTimeout);
var content = msg?.Data.Content ?? string.Empty;
Assert.Contains("line2", content);
Assert.Contains("line4", content);
@@ -69,7 +75,7 @@ public async Task Should_Handle_Nonexistent_File_Gracefully()
var msg = await session.SendAndWaitAsync(new MessageOptions
{
Prompt = "Try to read the file 'does_not_exist.txt'. If it doesn't exist, say 'FILE_NOT_FOUND'.",
- });
+ }, SendTimeout);
var content = (msg?.Data.Content ?? string.Empty).ToUpperInvariant();
// Match any of the common phrasings for a missing-file response.
Assert.True(
@@ -90,7 +96,7 @@ public async Task Should_Edit_A_File_Successfully()
var msg = await session.SendAndWaitAsync(new MessageOptions
{
Prompt = "Edit the file 'edit_me.txt': replace 'Hello World' with 'Hi Universe'. Then read it back and tell me its contents.",
- });
+ }, SendTimeout);
Assert.Contains("Hi Universe", msg?.Data.Content ?? string.Empty);
}
@@ -101,7 +107,7 @@ public async Task Should_Create_A_New_File()
var msg = await session.SendAndWaitAsync(new MessageOptions
{
Prompt = "Create a file called 'new_file.txt' with the content 'Created by test'. Then read it back to confirm.",
- });
+ }, SendTimeout);
Assert.Contains("Created by test", msg?.Data.Content ?? string.Empty);
}
@@ -113,7 +119,7 @@ public async Task Should_Search_For_Patterns_In_Files()
var msg = await session.SendAndWaitAsync(new MessageOptions
{
Prompt = "Search for lines starting with 'ap' in the file 'data.txt'. Tell me which lines matched.",
- });
+ }, SendTimeout);
var content = msg?.Data.Content ?? string.Empty;
Assert.Contains("apple", content);
Assert.Contains("apricot", content);
@@ -130,7 +136,7 @@ public async Task Should_Find_Files_By_Pattern()
var msg = await session.SendAndWaitAsync(new MessageOptions
{
Prompt = "Find all .ts files in this directory (recursively). List the filenames you found.",
- });
+ }, SendTimeout);
Assert.Contains("index.ts", msg?.Data.Content ?? string.Empty);
}
}
diff --git a/dotnet/test/E2E/PendingWorkResumeE2ETests.cs b/dotnet/test/E2E/PendingWorkResumeE2ETests.cs
index 9cc0785bf..b33079590 100644
--- a/dotnet/test/E2E/PendingWorkResumeE2ETests.cs
+++ b/dotnet/test/E2E/PendingWorkResumeE2ETests.cs
@@ -24,7 +24,6 @@ public async Task Should_Continue_Pending_Permission_Request_After_Resume()
{
var originalPermissionRequest = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
var releaseOriginalPermission = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
- var resumedToolInvoked = false;
await using var server = Ctx.CreateClient(options: new CopilotClientOptions { Connection = RuntimeConnection.ForTcp(connectionToken: SharedToken) });
await server.StartAsync();
@@ -66,10 +65,7 @@ await session1.SendAsync(new MessageOptions
[
AIFunctionFactory.Create(
([Description("Value to transform")] string value) =>
- {
- resumedToolInvoked = true;
- return $"PERMISSION_RESUMED_{value.ToUpperInvariant()}";
- },
+ $"PERMISSION_RESUMED_{value.ToUpperInvariant()}",
"resume_permission_tool")
],
});
@@ -79,11 +75,6 @@ await session1.SendAsync(new MessageOptions
new RpcPermissionDecisionApproveOnce());
Assert.True(permissionResult.Success);
- var answer = await TestHelper.GetFinalAssistantMessageAsync(session2, PendingWorkTimeout);
-
- Assert.True(resumedToolInvoked);
- Assert.Contains("PERMISSION_RESUMED_ALPHA", answer?.Data.Content ?? string.Empty);
-
await session2.DisposeAsync();
await resumedTcpClient.ForceStopAsync();
}
@@ -140,10 +131,6 @@ await session1.SendAsync(new MessageOptions
result: JsonDocument.Parse("\"EXTERNAL_RESUMED_BETA\"").RootElement.Clone());
Assert.True(toolResult.Success);
- var answer = await TestHelper.GetFinalAssistantMessageAsync(session2, PendingWorkTimeout);
-
- Assert.Contains("EXTERNAL_RESUMED_BETA", answer?.Data.Content ?? string.Empty);
-
await session2.DisposeAsync();
await resumedClient.ForceStopAsync();
}
@@ -161,7 +148,23 @@ async Task BlockingExternalTool([Description("Value to look up")] string
}
[Fact]
- public async Task Should_Keep_Pending_External_Tool_Handleable_On_Warm_Resume_When_ContinuePendingWork_Is_False()
+ public Task Should_Keep_Pending_External_Tool_Handleable_On_Warm_Resume_When_ContinuePendingWork_Is_False() =>
+ AssertPendingExternalToolHandleableOnResumeAsync(
+ disconnectOriginalClient: false,
+ expectedSessionWasActive: true,
+ expectedHandleResult: true);
+
+ [Fact]
+ public Task Should_Keep_Pending_External_Tool_Handleable_On_Cold_Resume_When_ContinuePendingWork_Is_False() =>
+ AssertPendingExternalToolHandleableOnResumeAsync(
+ disconnectOriginalClient: true,
+ expectedSessionWasActive: false,
+ expectedHandleResult: false);
+
+ private async Task AssertPendingExternalToolHandleableOnResumeAsync(
+ bool disconnectOriginalClient,
+ bool expectedSessionWasActive,
+ bool expectedHandleResult)
{
var originalToolStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
var releaseOriginalTool = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
@@ -191,28 +194,54 @@ await session1.SendAsync(new MessageOptions
var toolEvent = await toolRequested;
Assert.Equal("beta", await originalToolStarted.Task.WaitAsync(PendingWorkTimeout));
- await suspendedClient.ForceStopAsync();
+ if (disconnectOriginalClient)
+ {
+ await suspendedClient.ForceStopAsync();
+ }
await using var resumedClient = Ctx.CreateClient(options: new CopilotClientOptions { Connection = RuntimeConnection.ForUri(cliUrl, connectionToken: SharedToken) });
- var session2 = await resumedClient.ResumeSessionAsync(sessionId, new ResumeSessionConfig
+
+ // In warm mode the original client still owns the tool registration;
+ // re-registering it from the resumed client would cause a name-clash. In
+ // cold mode the original is gone, so we register a fresh throwing handler
+ // to assert the runtime doesn't re-invoke the tool on resume (orphan
+ // auto-completion happens internally).
+ var resumeConfig = new ResumeSessionConfig
{
ContinuePendingWork = false,
OnPermissionRequest = PermissionHandler.ApproveAll,
- });
+ };
+ if (disconnectOriginalClient)
+ {
+ resumeConfig.Tools = [AIFunctionFactory.Create(ResumedExternalTool, "resume_external_tool")];
+ }
+
+ var session2 = await resumedClient.ResumeSessionAsync(sessionId, resumeConfig);
var resumeEvent = await GetSingleResumeEventAsync(session2);
Assert.Equal(false, resumeEvent.Data.ContinuePendingWork);
- Assert.Equal(true, resumeEvent.Data.SessionWasActive);
+ Assert.Equal(expectedSessionWasActive, resumeEvent.Data.SessionWasActive);
+ // Warm: the runtime still has the pending request and HandlePendingToolCall
+ // will succeed.
+ // Cold: the runtime auto-completed the orphaned tool call with a synthetic
+ // interrupt result during resume, so HandlePendingToolCall correctly reports
+ // success=false. The session should still be healthy for new turns.
var resumedResult = await session2.Rpc.Tools.HandlePendingToolCallAsync(
toolEvent.Data.RequestId,
result: JsonDocument.Parse("\"EXTERNAL_RESUMED_BETA\"").RootElement.Clone());
- Assert.True(resumedResult.Success);
-
- // continuePendingWork=false may interrupt agent continuation before this response,
- // but the pending call should still accept an explicit completion.
+ Assert.Equal(expectedHandleResult, resumedResult.Success);
Assert.Equal(1, invocationCount);
+ if (!expectedHandleResult)
+ {
+ var followUp = await session2.SendAndWaitAsync(new MessageOptions
+ {
+ Prompt = "Reply with exactly: COLD_RESUMED_FOLLOWUP",
+ });
+ Assert.Contains("COLD_RESUMED_FOLLOWUP", followUp?.Data.Content ?? string.Empty);
+ }
+
await session2.DisposeAsync();
await resumedClient.ForceStopAsync();
}
@@ -228,6 +257,10 @@ async Task BlockingExternalTool([Description("Value to look up")] string
originalToolStarted.TrySetResult(value);
return await releaseOriginalTool.Task;
}
+
+ [Description("Looks up a value after resumption")]
+ string ResumedExternalTool([Description("Value to look up")] string value) =>
+ throw new InvalidOperationException("Resumed-session handler should not be invoked");
}
[Fact]
diff --git a/dotnet/test/E2E/RpcSessionStateE2ETests.cs b/dotnet/test/E2E/RpcSessionStateE2ETests.cs
index 1f35a9173..41c08cbd1 100644
--- a/dotnet/test/E2E/RpcSessionStateE2ETests.cs
+++ b/dotnet/test/E2E/RpcSessionStateE2ETests.cs
@@ -314,7 +314,7 @@ await TestHelper.WaitForConditionAsync(
Branch = branch,
Repository = "github/copilot-sdk-e2e",
RepositoryHost = "github.com",
- HostType = SessionWorkingDirectoryContextHostType.Github,
+ HostType = SessionWorkingDirectoryContextHostType.GitHub,
BaseCommit = "0000000000000000000000000000000000000000",
HeadCommit = "1111111111111111111111111111111111111111",
};
diff --git a/dotnet/test/E2E/SessionConfigE2ETests.cs b/dotnet/test/E2E/SessionConfigE2ETests.cs
index a763b6b72..30c7ce500 100644
--- a/dotnet/test/E2E/SessionConfigE2ETests.cs
+++ b/dotnet/test/E2E/SessionConfigE2ETests.cs
@@ -492,7 +492,7 @@ await session.SendAndWaitAsync(new MessageOptions
Prompt = "What color is this pixel? Reply in one word.",
Attachments =
[
- new UserMessageAttachmentBlob
+ new AttachmentBlob
{
Data = pngBase64,
MimeType = "image/png",
@@ -517,7 +517,7 @@ await session.SendAndWaitAsync(new MessageOptions
Prompt = "Summarize the attached file",
Attachments =
[
- new UserMessageAttachmentFile
+ new AttachmentFile
{
Path = attachedPath,
DisplayName = "attached.txt",
diff --git a/dotnet/test/E2E/SessionE2ETests.cs b/dotnet/test/E2E/SessionE2ETests.cs
index 7825f479c..979144b6e 100644
--- a/dotnet/test/E2E/SessionE2ETests.cs
+++ b/dotnet/test/E2E/SessionE2ETests.cs
@@ -715,7 +715,7 @@ await session.SendAndWaitAsync(new MessageOptions
Prompt = "Describe this image",
Attachments =
[
- new UserMessageAttachmentBlob
+ new AttachmentBlob
{
Data = pngBase64,
MimeType = "image/png",
@@ -740,17 +740,17 @@ await session.SendAndWaitAsync(new MessageOptions
Prompt = "Read the attached file and reply with its contents.",
Attachments =
[
- new UserMessageAttachmentFile
+ new AttachmentFile
{
DisplayName = "attached-file.txt",
Path = filePath,
- LineRange = new UserMessageAttachmentFileLineRange { Start = 1, End = 1 },
+ LineRange = new AttachmentFileLineRange { Start = 1, End = 1 },
},
],
});
var userMessage = (await session.GetEventsAsync()).OfType().Last();
- var attachment = Assert.IsType(Assert.Single(userMessage.Data.Attachments!));
+ var attachment = Assert.IsType(Assert.Single(userMessage.Data.Attachments!));
Assert.Equal("attached-file.txt", attachment.DisplayName);
Assert.Equal(filePath, attachment.Path);
Assert.Equal(1, attachment.LineRange!.Start);
@@ -771,7 +771,7 @@ await session.SendAndWaitAsync(new MessageOptions
Prompt = "List the attached directory.",
Attachments =
[
- new UserMessageAttachmentDirectory
+ new AttachmentDirectory
{
DisplayName = "attached-directory",
Path = directoryPath,
@@ -780,7 +780,7 @@ await session.SendAndWaitAsync(new MessageOptions
});
var userMessage = (await session.GetEventsAsync()).OfType().Last();
- var attachment = Assert.IsType(Assert.Single(userMessage.Data.Attachments!));
+ var attachment = Assert.IsType(Assert.Single(userMessage.Data.Attachments!));
Assert.Equal("attached-directory", attachment.DisplayName);
Assert.Equal(directoryPath, attachment.Path);
}
@@ -798,22 +798,22 @@ await session.SendAndWaitAsync(new MessageOptions
Prompt = "Summarize the selected code.",
Attachments =
[
- new UserMessageAttachmentSelection
+ new AttachmentSelection
{
DisplayName = "selected-file.cs",
FilePath = filePath,
Text = "string Value = \"SELECTION_SENTINEL\";",
- Selection = new UserMessageAttachmentSelectionDetails
+ Selection = new AttachmentSelectionDetails
{
- Start = new UserMessageAttachmentSelectionDetailsStart { Line = 1, Character = 10 },
- End = new UserMessageAttachmentSelectionDetailsEnd { Line = 1, Character = 45 },
+ Start = new AttachmentSelectionDetailsStart { Line = 1, Character = 10 },
+ End = new AttachmentSelectionDetailsEnd { Line = 1, Character = 45 },
},
},
],
});
var userMessage = (await session.GetEventsAsync()).OfType().Last();
- var attachment = Assert.IsType(Assert.Single(userMessage.Data.Attachments!));
+ var attachment = Assert.IsType(Assert.Single(userMessage.Data.Attachments!));
Assert.Equal("selected-file.cs", attachment.DisplayName);
Assert.Equal(filePath, attachment.FilePath);
Assert.Equal("string Value = \"SELECTION_SENTINEL\";", attachment.Text);
@@ -824,7 +824,7 @@ await session.SendAndWaitAsync(new MessageOptions
}
[Fact]
- public async Task Should_Send_With_Github_Reference_Attachment()
+ public async Task Should_Send_With_GitHub_Reference_Attachment()
{
var session = await CreateSessionAsync();
@@ -833,10 +833,10 @@ await session.SendAndWaitAsync(new MessageOptions
Prompt = "Using only the GitHub reference metadata in this message, summarize the reference. Do not call any tools.",
Attachments =
[
- new UserMessageAttachmentGithubReference
+ new AttachmentGitHubReference
{
Number = 1234,
- ReferenceType = UserMessageAttachmentGithubReferenceType.Issue,
+ ReferenceType = AttachmentGitHubReferenceType.Issue,
State = "open",
Title = "Add E2E attachment coverage",
Url = "https://github.com/github/copilot-sdk/issues/1234",
@@ -845,9 +845,9 @@ await session.SendAndWaitAsync(new MessageOptions
});
var userMessage = (await session.GetEventsAsync()).OfType().Last();
- var attachment = Assert.IsType(Assert.Single(userMessage.Data.Attachments!));
+ var attachment = Assert.IsType(Assert.Single(userMessage.Data.Attachments!));
Assert.Equal(1234, attachment.Number);
- Assert.Equal(UserMessageAttachmentGithubReferenceType.Issue, attachment.ReferenceType);
+ Assert.Equal(AttachmentGitHubReferenceType.Issue, attachment.ReferenceType);
Assert.Equal("open", attachment.State);
Assert.Equal("Add E2E attachment coverage", attachment.Title);
Assert.Equal("https://github.com/github/copilot-sdk/issues/1234", attachment.Url);
diff --git a/dotnet/test/E2E/SessionMcpAndAgentConfigE2ETests.cs b/dotnet/test/E2E/SessionMcpAndAgentConfigE2ETests.cs
index 18a8835a6..796c02121 100644
--- a/dotnet/test/E2E/SessionMcpAndAgentConfigE2ETests.cs
+++ b/dotnet/test/E2E/SessionMcpAndAgentConfigE2ETests.cs
@@ -23,9 +23,7 @@ public async Task Should_Accept_MCP_Server_Configuration_On_Session_Create()
await WaitForMcpServerStatusAsync(session, "test-server", McpServerStatus.Connected);
// Simple interaction to verify session works
- await session.SendAsync(new MessageOptions { Prompt = "What is 2+2?" });
-
- var message = await TestHelper.GetFinalAssistantMessageAsync(session);
+ var message = await session.SendAndWaitAsync(new MessageOptions { Prompt = "What is 2+2?" });
Assert.NotNull(message);
Assert.Contains("4", message!.Data.Content);
@@ -112,9 +110,7 @@ public async Task Should_Accept_Custom_Agent_Configuration_On_Session_Create()
Assert.Matches(@"^[a-f0-9-]+$", session.SessionId);
// Simple interaction to verify session works
- await session.SendAsync(new MessageOptions { Prompt = "What is 5+5?" });
-
- var message = await TestHelper.GetFinalAssistantMessageAsync(session);
+ var message = await session.SendAndWaitAsync(new MessageOptions { Prompt = "What is 5+5?" });
Assert.NotNull(message);
Assert.Contains("10", message!.Data.Content);
diff --git a/dotnet/test/Polyfills/TaskExtensions.cs b/dotnet/test/Polyfills/TaskExtensions.cs
deleted file mode 100644
index 04096e81d..000000000
--- a/dotnet/test/Polyfills/TaskExtensions.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- *--------------------------------------------------------------------------------------------*/
-
-// Polyfills for Task APIs not available on .NET Framework.
-// These are test-only and not optimized for production use.
-
-#if !NET8_0_OR_GREATER
-
-using System.Threading;
-
-namespace System.Threading.Tasks;
-
-internal static class TestDownlevelTaskExtensions
-{
- extension(Task task)
- {
- public Task WaitAsync(TimeSpan timeout)
- {
- if (task.IsCompleted)
- {
- return task;
- }
-
- return WaitAsyncCore(task, timeout);
- }
- }
-
- extension(Task task)
- {
- public Task WaitAsync(TimeSpan timeout)
- {
- if (task.IsCompleted)
- {
- return task;
- }
-
- return WaitAsyncCoreGeneric(task, timeout);
- }
- }
-
- private static async Task WaitAsyncCore(Task task, TimeSpan timeout)
- {
- using var cts = new CancellationTokenSource();
- var delayTask = Task.Delay(timeout, cts.Token);
- var completedTask = await Task.WhenAny(task, delayTask).ConfigureAwait(false);
- if (completedTask == task)
- {
- cts.Cancel();
- await task.ConfigureAwait(false);
- }
- else
- {
- throw new TimeoutException();
- }
- }
-
- private static async Task WaitAsyncCoreGeneric(Task task, TimeSpan timeout)
- {
- using var cts = new CancellationTokenSource();
- var delayTask = Task.Delay(timeout, cts.Token);
- var completedTask = await Task.WhenAny(task, delayTask).ConfigureAwait(false);
- if (completedTask == task)
- {
- cts.Cancel();
- return await task.ConfigureAwait(false);
- }
-
- throw new TimeoutException();
- }
-}
-
-#endif
diff --git a/dotnet/test/Unit/CloneTests.cs b/dotnet/test/Unit/CloneTests.cs
index 926a39b75..f64057824 100644
--- a/dotnet/test/Unit/CloneTests.cs
+++ b/dotnet/test/Unit/CloneTests.cs
@@ -69,12 +69,14 @@ public void SessionConfig_Clone_CopiesAllProperties()
Model = "gpt-4",
ReasoningEffort = "high",
ReasoningSummary = ReasoningSummary.Detailed,
+ ContextTier = ContextTier.LongContext,
ConfigDirectory = "/config",
AvailableTools = ["tool1", "tool2"],
ExcludedTools = ["tool3"],
WorkingDirectory = "/workspace",
Streaming = true,
EnableSessionTelemetry = false,
+ EnableOnDemandInstructionDiscovery = true,
IncludeSubAgentStreamingEvents = false,
McpServers = new Dictionary { ["server1"] = new McpStdioServerConfig { Command = "echo" } },
McpOAuthTokenStorage = McpOAuthTokenStorageMode.Persistent,
@@ -106,12 +108,14 @@ public void SessionConfig_Clone_CopiesAllProperties()
Assert.Equal(original.Model, clone.Model);
Assert.Equal(original.ReasoningEffort, clone.ReasoningEffort);
Assert.Equal(original.ReasoningSummary, clone.ReasoningSummary);
+ Assert.Equal(original.ContextTier, clone.ContextTier);
Assert.Equal(original.ConfigDirectory, clone.ConfigDirectory);
Assert.Equal(original.AvailableTools, clone.AvailableTools);
Assert.Equal(original.ExcludedTools, clone.ExcludedTools);
Assert.Equal(original.WorkingDirectory, clone.WorkingDirectory);
Assert.Equal(original.Streaming, clone.Streaming);
Assert.Equal(original.EnableSessionTelemetry, clone.EnableSessionTelemetry);
+ Assert.Equal(original.EnableOnDemandInstructionDiscovery, clone.EnableOnDemandInstructionDiscovery);
Assert.Equal(original.IncludeSubAgentStreamingEvents, clone.IncludeSubAgentStreamingEvents);
Assert.Equal(original.McpServers.Count, clone.McpServers!.Count);
Assert.Equal(original.McpOAuthTokenStorage, clone.McpOAuthTokenStorage);
@@ -227,7 +231,7 @@ public void MessageOptions_Clone_CopiesAllProperties()
var original = new MessageOptions
{
Prompt = "Hello",
- Attachments = [new UserMessageAttachmentFile { Path = "/test.txt", DisplayName = "test.txt" }],
+ Attachments = [new AttachmentFile { Path = "/test.txt", DisplayName = "test.txt" }],
Mode = "chat",
};
@@ -243,12 +247,12 @@ public void MessageOptions_Clone_AttachmentsAreIndependent()
{
var original = new MessageOptions
{
- Attachments = [new UserMessageAttachmentFile { Path = "/test.txt", DisplayName = "test.txt" }],
+ Attachments = [new AttachmentFile { Path = "/test.txt", DisplayName = "test.txt" }],
};
var clone = original.Clone();
- clone.Attachments!.Add(new UserMessageAttachmentFile { Path = "/other.txt", DisplayName = "other.txt" });
+ clone.Attachments!.Add(new AttachmentFile { Path = "/other.txt", DisplayName = "other.txt" });
Assert.Single(original.Attachments!);
}
@@ -377,6 +381,19 @@ public void ResumeSessionConfig_Clone_CopiesReasoningSummary()
Assert.Equal(original.ReasoningSummary, clone.ReasoningSummary);
}
+ [Fact]
+ public void ResumeSessionConfig_Clone_CopiesContextTier()
+ {
+ var original = new ResumeSessionConfig
+ {
+ ContextTier = ContextTier.LongContext,
+ };
+
+ var clone = original.Clone();
+
+ Assert.Equal(original.ContextTier, clone.ContextTier);
+ }
+
[Fact]
public void ResumeSessionConfig_Clone_CopiesPluginDirectoriesAndLargeOutput()
{
@@ -423,6 +440,52 @@ public void ResumeSessionConfig_Clone_PreservesEnableSessionTelemetryDefault()
Assert.Null(clone.EnableSessionTelemetry);
}
+ [Fact]
+ public void SessionConfig_Clone_CopiesEnableOnDemandInstructionDiscovery()
+ {
+ var original = new SessionConfig
+ {
+ EnableOnDemandInstructionDiscovery = false,
+ };
+
+ var clone = original.Clone();
+
+ Assert.False(clone.EnableOnDemandInstructionDiscovery);
+ }
+
+ [Fact]
+ public void ResumeSessionConfig_Clone_CopiesEnableOnDemandInstructionDiscovery()
+ {
+ var original = new ResumeSessionConfig
+ {
+ EnableOnDemandInstructionDiscovery = true,
+ };
+
+ var clone = original.Clone();
+
+ Assert.True(clone.EnableOnDemandInstructionDiscovery);
+ }
+
+ [Fact]
+ public void SessionConfig_Clone_PreservesEnableOnDemandInstructionDiscoveryDefault()
+ {
+ var original = new SessionConfig();
+
+ var clone = original.Clone();
+
+ Assert.Null(clone.EnableOnDemandInstructionDiscovery);
+ }
+
+ [Fact]
+ public void ResumeSessionConfig_Clone_PreservesEnableOnDemandInstructionDiscoveryDefault()
+ {
+ var original = new ResumeSessionConfig();
+
+ var clone = original.Clone();
+
+ Assert.Null(clone.EnableOnDemandInstructionDiscovery);
+ }
+
[Fact]
public void SessionConfig_Clone_CopiesMcpOAuthTokenStorage()
{
diff --git a/dotnet/test/Unit/SerializationTests.cs b/dotnet/test/Unit/SerializationTests.cs
index 321ff61fe..b0797d34b 100644
--- a/dotnet/test/Unit/SerializationTests.cs
+++ b/dotnet/test/Unit/SerializationTests.cs
@@ -196,6 +196,31 @@ public void SessionRequests_CanSerializeReasoningSummary_WithSdkOptions()
Assert.Equal("none", resumeDocument.RootElement.GetProperty("reasoningSummary").GetString());
}
+ [Fact]
+ public void SessionRequests_CanSerializeContextTier_WithSdkOptions()
+ {
+ var options = GetSerializerOptions();
+ var createRequestType = GetNestedType(typeof(CopilotClient), "CreateSessionRequest");
+ var createRequest = CreateInternalRequest(
+ createRequestType,
+ ("SessionId", "session-id"),
+ ("ContextTier", ContextTier.LongContext));
+
+ var createJson = JsonSerializer.Serialize(createRequest, createRequestType, options);
+ using var createDocument = JsonDocument.Parse(createJson);
+ Assert.Equal("long_context", createDocument.RootElement.GetProperty("contextTier").GetString());
+
+ var resumeRequestType = GetNestedType(typeof(CopilotClient), "ResumeSessionRequest");
+ var resumeRequest = CreateInternalRequest(
+ resumeRequestType,
+ ("SessionId", "session-id"),
+ ("ContextTier", ContextTier.Default));
+
+ var resumeJson = JsonSerializer.Serialize(resumeRequest, resumeRequestType, options);
+ using var resumeDocument = JsonDocument.Parse(resumeJson);
+ Assert.Equal("default", resumeDocument.RootElement.GetProperty("contextTier").GetString());
+ }
+
[Fact]
public void SessionRequests_CanSerializePluginDirectoriesAndLargeOutput_WithSdkOptions()
{
@@ -274,6 +299,60 @@ public void ResumeSessionRequest_CanSerializeEnableSessionTelemetry_WithSdkOptio
Assert.False(root.GetProperty("enableSessionTelemetry").GetBoolean());
}
+ [Fact]
+ public void CreateSessionRequest_CanSerializeEnableOnDemandInstructionDiscovery_WithSdkOptions()
+ {
+ var options = GetSerializerOptions();
+ var requestType = GetNestedType(typeof(CopilotClient), "CreateSessionRequest");
+
+ var requestTrue = CreateInternalRequest(
+ requestType,
+ ("SessionId", "session-id"),
+ ("EnableOnDemandInstructionDiscovery", true));
+ var rootTrue = JsonDocument.Parse(JsonSerializer.Serialize(requestTrue, requestType, options)).RootElement;
+ Assert.True(rootTrue.GetProperty("enableOnDemandInstructionDiscovery").GetBoolean());
+
+ var requestFalse = CreateInternalRequest(
+ requestType,
+ ("SessionId", "session-id"),
+ ("EnableOnDemandInstructionDiscovery", false));
+ var rootFalse = JsonDocument.Parse(JsonSerializer.Serialize(requestFalse, requestType, options)).RootElement;
+ Assert.False(rootFalse.GetProperty("enableOnDemandInstructionDiscovery").GetBoolean());
+
+ var requestOmitted = CreateInternalRequest(
+ requestType,
+ ("SessionId", "session-id"));
+ var rootOmitted = JsonDocument.Parse(JsonSerializer.Serialize(requestOmitted, requestType, options)).RootElement;
+ Assert.False(rootOmitted.TryGetProperty("enableOnDemandInstructionDiscovery", out _));
+ }
+
+ [Fact]
+ public void ResumeSessionRequest_CanSerializeEnableOnDemandInstructionDiscovery_WithSdkOptions()
+ {
+ var options = GetSerializerOptions();
+ var requestType = GetNestedType(typeof(CopilotClient), "ResumeSessionRequest");
+
+ var requestTrue = CreateInternalRequest(
+ requestType,
+ ("SessionId", "session-id"),
+ ("EnableOnDemandInstructionDiscovery", true));
+ var rootTrue = JsonDocument.Parse(JsonSerializer.Serialize(requestTrue, requestType, options)).RootElement;
+ Assert.True(rootTrue.GetProperty("enableOnDemandInstructionDiscovery").GetBoolean());
+
+ var requestFalse = CreateInternalRequest(
+ requestType,
+ ("SessionId", "session-id"),
+ ("EnableOnDemandInstructionDiscovery", false));
+ var rootFalse = JsonDocument.Parse(JsonSerializer.Serialize(requestFalse, requestType, options)).RootElement;
+ Assert.False(rootFalse.GetProperty("enableOnDemandInstructionDiscovery").GetBoolean());
+
+ var requestOmitted = CreateInternalRequest(
+ requestType,
+ ("SessionId", "session-id"));
+ var rootOmitted = JsonDocument.Parse(JsonSerializer.Serialize(requestOmitted, requestType, options)).RootElement;
+ Assert.False(rootOmitted.TryGetProperty("enableOnDemandInstructionDiscovery", out _));
+ }
+
[Fact]
public void ResumeSessionRequest_CanSerializeOpenCanvases_WithSdkOptions()
{
diff --git a/go/README.md b/go/README.md
index 568d75f9d..0ceaabb73 100644
--- a/go/README.md
+++ b/go/README.md
@@ -2,8 +2,6 @@
A Go SDK for programmatic access to the GitHub Copilot CLI.
-> **Note:** This SDK is in public preview and may change in breaking ways.
-
## Installation
```bash
@@ -104,13 +102,13 @@ That's it! When your application calls `copilot.NewClient` without a `Connection
- `Start(ctx context.Context) error` - Start the CLI server
- `Stop() error` - Stop the CLI server
- `ForceStop()` - Forcefully stop without graceful cleanup
-- `CreateSession(config *SessionConfig) (*Session, error)` - Create a new session
-- `ResumeSession(sessionID string, config *ResumeSessionConfig) (*Session, error)` - Resume an existing session
-- `ResumeSessionWithOptions(sessionID string, config *ResumeSessionConfig) (*Session, error)` - Resume with additional configuration
-- `ListSessions(filter *SessionListFilter) ([]SessionMetadata, error)` - List sessions (with optional filter)
-- `DeleteSession(sessionID string) error` - Delete a session permanently
+- `CreateSession(ctx context.Context, config *SessionConfig) (*Session, error)` - Create a new session
+- `ResumeSession(ctx context.Context, sessionID string, config *ResumeSessionConfig) (*Session, error)` - Resume an existing session
+- `ResumeSessionWithOptions(ctx context.Context, sessionID string, config *ResumeSessionConfig) (*Session, error)` - Resume with additional configuration
+- `ListSessions(ctx context.Context, filter *SessionListFilter) ([]SessionMetadata, error)` - List sessions (with optional filter)
+- `DeleteSession(ctx context.Context, sessionID string) error` - Delete a session permanently
- `GetLastSessionID(ctx context.Context) (*string, error)` - Get the ID of the most recently updated session
-- `Ping(message string) (*PingResponse, error)` - Ping the server
+- `Ping(ctx context.Context, message string) (*PingResponse, error)` - Ping the server
- `RuntimePort() int` - TCP port the runtime is listening on (0 if stdio)
- `GetForegroundSessionID(ctx context.Context) (*string, error)` - Get the session ID currently displayed in TUI (TUI+server mode only)
- `SetForegroundSessionID(ctx context.Context, sessionID string) error` - Request TUI to display a specific session (TUI+server mode only)
@@ -138,17 +136,17 @@ Event types: `SessionLifecycleCreated`, `SessionLifecycleDeleted`, `SessionLifec
- `Connection` (RuntimeConnection): How the SDK connects to the runtime. Construct via one of:
- `StdioConnection{Path, Args}` — spawn a runtime over stdio (the default if `Connection` is nil)
- - `TcpConnection{Port, ConnectionToken, Path, Args}` — spawn a runtime that listens on TCP
- - `UriConnection{URL, ConnectionToken}` — connect to an already-running runtime (no process spawned)
+ - `TCPConnection{Port, ConnectionToken, Path, Args}` — spawn a runtime that listens on TCP
+ - `URIConnection{URL, ConnectionToken}` — connect to an already-running runtime (no process spawned)
When `Path` is empty for stdio/tcp, the SDK uses the bundled CLI (or `COPILOT_CLI_PATH` env var).
- `WorkingDirectory` (string): Working directory for the runtime process
-- `BaseDirectory` (string): Base directory for Copilot data (session state, config, etc.). Sets `COPILOT_HOME` on the spawned runtime. When empty, the runtime defaults to `~/.copilot`. Ignored with `UriConnection`. This does **not** affect where the Go SDK extracts the embedded CLI binary; use `embeddedcli.Config.Dir` for the extraction/cache location.
+- `BaseDirectory` (string): Base directory for Copilot data (session state, config, etc.). Sets `COPILOT_HOME` on the spawned runtime. When empty, the runtime defaults to `~/.copilot`. Ignored with `URIConnection`. This does **not** affect where the Go SDK extracts the embedded CLI binary; use `embeddedcli.Config.Dir` for the extraction/cache location.
- `LogLevel` (string): Log level. When empty (default), the runtime uses its own default level (the SDK does not pass `--log-level`).
- `Env` ([]string): Environment variables for the runtime process (default: inherits from current process)
- `GitHubToken` (string): GitHub token for authentication. When provided, takes priority over other auth methods.
-- `UseLoggedInUser` (\*bool): Whether to use logged-in user for authentication (default: true, but false when `GitHubToken` is provided). Cannot be used with `UriConnection`.
-- `EnableRemoteSessions` (bool): Enable remote session support (Mission Control integration). Ignored with `UriConnection`.
+- `UseLoggedInUser` (\*bool): Whether to use logged-in user for authentication (default: true, but false when `GitHubToken` is provided). Cannot be used with `URIConnection`.
+- `EnableRemoteSessions` (bool): Enable remote session support (Mission Control integration). Ignored with `URIConnection`.
- `Telemetry` (\*TelemetryConfig): OpenTelemetry configuration for the runtime. Providing this enables telemetry — no separate flag needed. See [Telemetry](#telemetry) below.
**SessionConfig:**
@@ -253,7 +251,7 @@ The SDK supports image attachments via the `Attachments` field in `MessageOption
_, err = session.Send(context.Background(), copilot.MessageOptions{
Prompt: "What's in this image?",
Attachments: []copilot.Attachment{
- &copilot.UserMessageAttachmentFile{
+ &copilot.AttachmentFile{
DisplayName: "image.jpg",
Path: "/path/to/image.jpg",
},
@@ -265,7 +263,7 @@ mimeType := "image/png"
_, err = session.Send(context.Background(), copilot.MessageOptions{
Prompt: "What's in this image?",
Attachments: []copilot.Attachment{
- &copilot.UserMessageAttachmentBlob{
+ &copilot.AttachmentBlob{
Data: base64ImageData,
MIMEType: mimeType,
},
@@ -497,7 +495,7 @@ The SDK supports custom OpenAI-compatible API providers (BYOK - Bring Your Own K
- `BaseURL` (string): API endpoint URL (required)
- `APIKey` (string): API key (optional for local providers like Ollama)
- `BearerToken` (string): Bearer token for authentication (takes precedence over APIKey)
-- `WireApi` (string): API format for OpenAI/Azure - "completions" or "responses" (default: "completions")
+- `WireAPI` (string): API format for OpenAI/Azure - "completions" or "responses" (default: "completions")
- `Azure.APIVersion` (string): Azure API version (default: "2024-10-21")
**Example with Ollama:**
@@ -804,7 +802,7 @@ confirmed, err := ui.Confirm(ctx, "Deploy to production?")
choice, ok, err := ui.Select(ctx, "Pick an environment", []string{"staging", "production"})
// Text input — returns (text, ok bool, error)
-name, ok, err := ui.Input(ctx, "Enter the release name", &copilot.UiInputOptions{
+name, ok, err := ui.Input(ctx, "Enter the release name", &copilot.UIInputOptions{
Title: "Release Name",
Description: "A short name for the release",
MinLength: copilot.Int(1),
@@ -812,11 +810,10 @@ name, ok, err := ui.Input(ctx, "Enter the release name", &copilot.UiInputOptions
})
// Full custom elicitation with a schema
-result, err := ui.Elicitation(ctx, "Configure deployment", rpc.RequestedSchema{
- Type: rpc.RequestedSchemaTypeObject,
- Properties: map[string]rpc.Property{
- "target": {Type: rpc.PropertyTypeString, Enum: []string{"staging", "production"}},
- "force": {Type: rpc.PropertyTypeBoolean},
+result, err := ui.Elicitation(ctx, "Configure deployment", copilot.ElicitationSchema{
+ Properties: map[string]any{
+ "target": map[string]any{"type": "string", "enum": []string{"staging", "production"}},
+ "force": map[string]any{"type": "boolean"},
},
Required: []string{"target"},
})
@@ -841,7 +838,7 @@ session, err := client.CreateSession(ctx, &copilot.SessionConfig{
// Return the user's response
return copilot.ElicitationResult{
- Action: "accept",
+ Action: copilot.ElicitationActionAccept,
Content: map[string]any{"confirmed": true},
}, nil
},
diff --git a/go/canvas.go b/go/canvas.go
index 43263a813..375f7c6ee 100644
--- a/go/canvas.go
+++ b/go/canvas.go
@@ -25,7 +25,7 @@ type CanvasDeclaration struct {
// Description is a short, single-sentence description shown to the agent in canvas catalogs.
Description string `json:"description"`
// InputSchema is the JSON Schema for the `input` payload accepted by `canvas.open`.
- InputSchema map[string]any `json:"inputSchema,omitempty"`
+ InputSchema map[string]any `json:"inputSchema,omitzero"`
// Actions are the agent-callable actions this canvas exposes.
Actions []rpc.CanvasAction `json:"actions,omitempty"`
}
diff --git a/go/canvas_test.go b/go/canvas_test.go
index c6f74772a..b7ced02bf 100644
--- a/go/canvas_test.go
+++ b/go/canvas_test.go
@@ -136,7 +136,7 @@ func TestCanvasAdapter_DispatchesToHandler(t *testing.T) {
session := newTestCanvasSession("s1")
session.registerCanvasHandler(handler)
- openResp, err := session.clientSessionApis.Canvas.Open(&rpc.CanvasProviderOpenRequest{
+ openResp, err := session.clientSessionAPIs.Canvas.Open(&rpc.CanvasProviderOpenRequest{
SessionID: "s1",
ExtensionID: "project:echo",
CanvasID: "echo",
@@ -156,7 +156,7 @@ func TestCanvasAdapter_DispatchesToHandler(t *testing.T) {
t.Fatalf("response URL not propagated: %+v", openResp)
}
- actionResp, err := session.clientSessionApis.Canvas.Invoke(&rpc.CanvasProviderInvokeActionRequest{
+ actionResp, err := session.clientSessionAPIs.Canvas.Invoke(&rpc.CanvasProviderInvokeActionRequest{
SessionID: "s1",
ExtensionID: "project:echo",
CanvasID: "echo",
@@ -178,7 +178,7 @@ func TestCanvasAdapter_DispatchesToHandler(t *testing.T) {
t.Fatalf("unexpected action result: %#v", actionResp)
}
- closeResp, err := session.clientSessionApis.Canvas.Close(&rpc.CanvasProviderCloseRequest{
+ closeResp, err := session.clientSessionAPIs.Canvas.Close(&rpc.CanvasProviderCloseRequest{
SessionID: "s1",
ExtensionID: "project:echo",
CanvasID: "echo",
@@ -198,7 +198,7 @@ func TestCanvasAdapter_DispatchesToHandler(t *testing.T) {
func TestCanvasAdapter_NoHandler_ReturnsUnsetError(t *testing.T) {
session := newTestCanvasSession("s1")
- _, err := session.clientSessionApis.Canvas.Open(&rpc.CanvasProviderOpenRequest{SessionID: "s1"})
+ _, err := session.clientSessionAPIs.Canvas.Open(&rpc.CanvasProviderOpenRequest{SessionID: "s1"})
assertCanvasJSONRPCError(t, err, "canvas_handler_unset", "")
}
@@ -208,7 +208,7 @@ func TestCanvasAdapter_HandlerCanvasError_Wired(t *testing.T) {
openErr: NewCanvasError("permission_denied", "nope"),
})
- _, err := session.clientSessionApis.Canvas.Open(&rpc.CanvasProviderOpenRequest{SessionID: "s1"})
+ _, err := session.clientSessionAPIs.Canvas.Open(&rpc.CanvasProviderOpenRequest{SessionID: "s1"})
assertCanvasJSONRPCError(t, err, "permission_denied", "nope")
}
@@ -218,11 +218,11 @@ func TestCanvasAdapter_HandlerGenericError_WrappedAsCanvasHandlerError(t *testin
openErr: errors.New("boom"),
})
- _, err := session.clientSessionApis.Canvas.Open(&rpc.CanvasProviderOpenRequest{SessionID: "s1"})
+ _, err := session.clientSessionAPIs.Canvas.Open(&rpc.CanvasProviderOpenRequest{SessionID: "s1"})
assertCanvasJSONRPCError(t, err, "canvas_handler_error", "boom")
}
-func TestCanvasRegisterClientSessionApiHandlers_RawJSONRoundTrip(t *testing.T) {
+func TestCanvasRegisterClientSessionAPIHandlers_RawJSONRoundTrip(t *testing.T) {
clientToServerReader, clientToServerWriter := io.Pipe()
serverToClientReader, serverToClientWriter := io.Pipe()
@@ -233,9 +233,9 @@ func TestCanvasRegisterClientSessionApiHandlers_RawJSONRoundTrip(t *testing.T) {
openResult: rpc.CanvasProviderOpenResult{Status: strPtr("ready")},
actionResult: map[string]any{"count": float64(2)},
})
- rpc.RegisterClientSessionApiHandlers(server, func(sessionID string) *rpc.ClientSessionApiHandlers {
+ rpc.RegisterClientSessionAPIHandlers(server, func(sessionID string) *rpc.ClientSessionAPIHandlers {
if sessionID == "s1" {
- return session.clientSessionApis
+ return session.clientSessionAPIs
}
return nil
})
@@ -417,9 +417,9 @@ func assertCanvasJSONRPCError(t *testing.T, err error, wantCode, wantMessage str
func newTestCanvasSession(sessionID string) *Session {
session := &Session{
SessionID: sessionID,
- clientSessionApis: &rpc.ClientSessionApiHandlers{},
+ clientSessionAPIs: &rpc.ClientSessionAPIHandlers{},
}
- session.clientSessionApis.Canvas = newCanvasClientSessionAdapter(session)
+ session.clientSessionAPIs.Canvas = newCanvasClientSessionAdapter(session)
return session
}
diff --git a/go/client.go b/go/client.go
index 11c7e6234..cad460557 100644
--- a/go/client.go
+++ b/go/client.go
@@ -52,18 +52,18 @@ import (
"github.com/github/copilot-sdk/go/rpc"
)
-func validateSessionFsConfig(config *SessionFsConfig) error {
+func validateSessionFSConfig(config *SessionFSConfig) error {
if config == nil {
return nil
}
if config.InitialWorkingDirectory == "" {
- return errors.New("SessionFs.InitialWorkingDirectory is required")
+ return errors.New("SessionFS.InitialWorkingDirectory is required")
}
if config.SessionStatePath == "" {
- return errors.New("SessionFs.SessionStatePath is required")
+ return errors.New("SessionFS.SessionStatePath is required")
}
- if config.Conventions != rpc.SessionFsSetProviderConventionsPosix && config.Conventions != rpc.SessionFsSetProviderConventionsWindows {
- return errors.New("SessionFs.Conventions must be either 'posix' or 'windows'")
+ if config.Conventions != rpc.SessionFSSetProviderConventionsPosix && config.Conventions != rpc.SessionFSSetProviderConventionsWindows {
+ return errors.New("SessionFS.Conventions must be either 'posix' or 'windows'")
}
return nil
}
@@ -80,7 +80,7 @@ func validateSessionFsConfig(config *SessionFsConfig) error {
//
// // Or connect to an existing server
// client := copilot.NewClient(&copilot.ClientOptions{
-// CLIUrl: "localhost:3000",
+// Connection: copilot.URIConnection{URL: "localhost:3000"},
// })
//
// if err := client.Start(); err != nil {
@@ -99,7 +99,7 @@ type Client struct {
isExternalServer bool
conn net.Conn // stores net.Conn for external TCP connections
useStdio bool // resolved value from options
- // resolved process options for the spawned runtime (zero values for UriConnection)
+ // resolved process options for the spawned runtime (zero values for URIConnection)
cliPath string
cliArgs []string
port int
@@ -123,11 +123,11 @@ type Client struct {
// RPC provides typed server-scoped RPC methods.
// This field is nil until the client is connected via Start().
- RPC *rpc.ServerRpc
+ RPC *rpc.ServerRPC
// internalRPC provides SDK-internal RPC methods (handshake helpers etc.).
// Lowercase = not exported; external callers cannot reach it.
- internalRPC *rpc.InternalServerRpc
+ internalRPC *rpc.InternalServerRPC
}
// NewClient creates a new Copilot runtime client with the given options.
@@ -150,7 +150,7 @@ type Client struct {
//
// // Connect to an already-running runtime
// client := copilot.NewClient(&copilot.ClientOptions{
-// Connection: copilot.UriConnection{URL: "localhost:8080"},
+// Connection: copilot.URIConnection{URL: "localhost:8080"},
// })
func NewClient(options *ClientOptions) *Client {
opts := ClientOptions{}
@@ -180,7 +180,7 @@ func NewClient(options *ClientOptions) *Client {
if len(conn.Args) > 0 {
client.cliArgs = append([]string{}, conn.Args...)
}
- case TcpConnection:
+ case TCPConnection:
client.useStdio = false
client.cliPath = conn.Path
if len(conn.Args) > 0 {
@@ -188,11 +188,11 @@ func NewClient(options *ClientOptions) *Client {
}
client.port = conn.Port
client.tcpConnectionToken = conn.ConnectionToken
- case UriConnection:
+ case URIConnection:
if conn.URL == "" {
- panic("UriConnection requires a non-empty URL")
+ panic("URIConnection requires a non-empty URL")
}
- host, port := parseCliUrl(conn.URL)
+ host, port := parseCLIURL(conn.URL)
client.actualHost = host
client.actualPort = port
client.isExternalServer = true
@@ -204,7 +204,7 @@ func NewClient(options *ClientOptions) *Client {
// Validate auth options when connecting to an external runtime.
if client.isExternalServer && (opts.GitHubToken != "" || opts.UseLoggedInUser != nil) {
- panic("GitHubToken and UseLoggedInUser cannot be used with UriConnection (external runtime manages its own auth)")
+ panic("GitHubToken and UseLoggedInUser cannot be used with URIConnection (external runtime manages its own auth)")
}
// Default Env to current environment if not set
@@ -230,8 +230,8 @@ func NewClient(options *ClientOptions) *Client {
if opts.OnListModels != nil {
client.onListModels = opts.OnListModels
}
- if opts.SessionFs != nil {
- if err := validateSessionFsConfig(opts.SessionFs); err != nil {
+ if opts.SessionFS != nil {
+ if err := validateSessionFSConfig(opts.SessionFS); err != nil {
panic(err.Error())
}
}
@@ -266,19 +266,19 @@ func setEnvValue(env []string, key string, value string) []string {
return append(filtered, key+"="+value)
}
-// parseCliUrl parses a CLI URL into host and port components.
+// parseCLIURL parses a CLI URL into host and port components.
//
// Supports formats: "host:port", "http://host:port", "https://host:port", or just "port".
// Panics if the URL format is invalid or the port is out of range.
-func parseCliUrl(url string) (string, int) {
+func parseCLIURL(url string) (string, int) {
// Remove protocol if present
- cleanUrl, _ := strings.CutPrefix(url, "https://")
- cleanUrl, _ = strings.CutPrefix(cleanUrl, "http://")
+ cleanURL, _ := strings.CutPrefix(url, "https://")
+ cleanURL, _ = strings.CutPrefix(cleanURL, "http://")
// Parse host:port or port format
var host string
var portStr string
- if before, after, found := strings.Cut(cleanUrl, ":"); found {
+ if before, after, found := strings.Cut(cleanURL, ":"); found {
host = before
portStr = after
} else {
@@ -293,7 +293,7 @@ func parseCliUrl(url string) (string, int) {
// Validate port
port, err := strconv.Atoi(portStr)
if err != nil || port <= 0 || port > 65535 {
- panic(fmt.Sprintf("Invalid port in CLIUrl: %s", url))
+ panic(fmt.Sprintf("Invalid port in URIConnection: %s", url))
}
return host, port
@@ -302,7 +302,7 @@ func parseCliUrl(url string) (string, int) {
// Start starts the CLI server (if not using an external server) and establishes
// a connection.
//
-// If connecting to an external server (via CLIUrl), only establishes the connection.
+// If connecting to an external server (via URIConnection), only establishes the connection.
// Otherwise, spawns the CLI server process and then connects.
//
// This method is called automatically when creating a session if AutoStart is true (default).
@@ -350,19 +350,19 @@ func (c *Client) Start(ctx context.Context) error {
}
// If a session filesystem provider was configured, register it.
- if c.options.SessionFs != nil {
- req := &rpc.SessionFsSetProviderRequest{
- InitialCwd: c.options.SessionFs.InitialWorkingDirectory,
- SessionStatePath: c.options.SessionFs.SessionStatePath,
- Conventions: c.options.SessionFs.Conventions,
+ if c.options.SessionFS != nil {
+ req := &rpc.SessionFSSetProviderRequest{
+ InitialCwd: c.options.SessionFS.InitialWorkingDirectory,
+ SessionStatePath: c.options.SessionFS.SessionStatePath,
+ Conventions: c.options.SessionFS.Conventions,
}
- if c.options.SessionFs.Capabilities != nil {
- sqlite := c.options.SessionFs.Capabilities.Sqlite
- req.Capabilities = &rpc.SessionFsSetProviderCapabilities{
+ if c.options.SessionFS.Capabilities != nil {
+ sqlite := c.options.SessionFS.Capabilities.Sqlite
+ req.Capabilities = &rpc.SessionFSSetProviderCapabilities{
Sqlite: &sqlite,
}
}
- _, err := c.RPC.SessionFs.SetProvider(ctx, req)
+ _, err := c.RPC.SessionFS.SetProvider(ctx, req)
if err != nil {
killErr := c.killProcess()
c.state = stateError
@@ -605,10 +605,9 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses
req.ClientName = config.ClientName
req.ReasoningEffort = config.ReasoningEffort
req.ReasoningSummary = config.ReasoningSummary
+ req.ContextTier = config.ContextTier
req.ConfigDir = config.ConfigDirectory
- if config.EnableConfigDiscovery {
- req.EnableConfigDiscovery = Bool(true)
- }
+ req.EnableConfigDiscovery = config.EnableConfigDiscovery
req.SkipEmbeddingRetrieval = config.SkipEmbeddingRetrieval
req.EmbeddingCacheStorage = config.EmbeddingCacheStorage
req.OrganizationCustomInstructions = config.OrganizationCustomInstructions
@@ -654,6 +653,7 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses
req.Canvases = config.Canvases
req.RequestCanvasRenderer = config.RequestCanvasRenderer
req.RequestExtensions = config.RequestExtensions
+ req.ExtensionSDKPath = config.ExtensionSDKPath
if len(config.Commands) > 0 {
cmds := make([]wireCommand, 0, len(config.Commands))
@@ -671,8 +671,8 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses
if config.OnAutoModeSwitchRequest != nil {
req.RequestAutoModeSwitch = Bool(true)
}
- if config.EnableMcpApps {
- req.RequestMcpApps = Bool(true)
+ if config.EnableMCPApps {
+ req.RequestMCPApps = Bool(true)
}
if config.Streaming != nil {
@@ -687,7 +687,7 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses
req.RequestUserInput = Bool(true)
}
if config.Hooks != nil && (config.Hooks.OnPreToolUse != nil ||
- config.Hooks.OnPreMcpToolCall != nil ||
+ config.Hooks.OnPreMCPToolCall != nil ||
config.Hooks.OnPostToolUse != nil ||
config.Hooks.OnPostToolUseFailure != nil ||
config.Hooks.OnUserPromptSubmitted != nil ||
@@ -764,23 +764,23 @@ func (c *Client) CreateSession(ctx context.Context, config *SessionConfig) (*Ses
c.sessions[sessionID] = s
c.sessionsMux.Unlock()
- if c.options.SessionFs != nil {
- if config.CreateSessionFsProvider == nil {
+ if c.options.SessionFS != nil {
+ if config.CreateSessionFSProvider == nil {
c.sessionsMux.Lock()
delete(c.sessions, sessionID)
c.sessionsMux.Unlock()
- return nil, fmt.Errorf("CreateSessionFsProvider is required in session config when SessionFs is enabled in client options")
+ return nil, fmt.Errorf("CreateSessionFSProvider is required in session config when SessionFS is enabled in client options")
}
- provider := config.CreateSessionFsProvider(s)
- if c.options.SessionFs.Capabilities != nil && c.options.SessionFs.Capabilities.Sqlite {
- if _, ok := provider.(SessionFsSqliteProvider); !ok {
+ provider := config.CreateSessionFSProvider(s)
+ if c.options.SessionFS.Capabilities != nil && c.options.SessionFS.Capabilities.Sqlite {
+ if _, ok := provider.(SessionFSSqliteProvider); !ok {
c.sessionsMux.Lock()
delete(c.sessions, sessionID)
c.sessionsMux.Unlock()
- return nil, fmt.Errorf("SessionFs capabilities declare SQLite support but the provider does not implement SessionFsSqliteProvider")
+ return nil, fmt.Errorf("SessionFS capabilities declare SQLite support but the provider does not implement SessionFSSqliteProvider")
}
}
- s.clientSessionApis.SessionFs = newSessionFsAdapter(provider)
+ s.clientSessionAPIs.SessionFS = newSessionFSAdapter(provider)
}
return s, nil
}
@@ -916,6 +916,7 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string,
req.Model = config.Model
req.ReasoningEffort = config.ReasoningEffort
req.ReasoningSummary = config.ReasoningSummary
+ req.ContextTier = config.ContextTier
systemMessage := c.systemMessageForMode(config.SystemMessage)
wireSystemMessage, transformCallbacks := extractTransformCallbacks(systemMessage)
req.SystemMessage = wireSystemMessage
@@ -946,7 +947,7 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string,
req.RequestUserInput = Bool(true)
}
if config.Hooks != nil && (config.Hooks.OnPreToolUse != nil ||
- config.Hooks.OnPreMcpToolCall != nil ||
+ config.Hooks.OnPreMCPToolCall != nil ||
config.Hooks.OnPostToolUse != nil ||
config.Hooks.OnPostToolUseFailure != nil ||
config.Hooks.OnUserPromptSubmitted != nil ||
@@ -957,9 +958,7 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string,
}
req.WorkingDirectory = config.WorkingDirectory
req.ConfigDir = config.ConfigDirectory
- if config.EnableConfigDiscovery {
- req.EnableConfigDiscovery = Bool(true)
- }
+ req.EnableConfigDiscovery = config.EnableConfigDiscovery
req.SkipEmbeddingRetrieval = config.SkipEmbeddingRetrieval
req.EmbeddingCacheStorage = config.EmbeddingCacheStorage
req.OrganizationCustomInstructions = config.OrganizationCustomInstructions
@@ -971,9 +970,7 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string,
if config.SuppressResumeEvent {
req.DisableResume = Bool(true)
}
- if config.ContinuePendingWork {
- req.ContinuePendingWork = Bool(true)
- }
+ req.ContinuePendingWork = config.ContinuePendingWork
req.MCPServers = config.MCPServers
req.MCPOAuthTokenStorage = config.MCPOAuthTokenStorage
req.EnvValueMode = "direct"
@@ -992,6 +989,7 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string,
req.OpenCanvases = config.OpenCanvases
req.RequestCanvasRenderer = config.RequestCanvasRenderer
req.RequestExtensions = config.RequestExtensions
+ req.ExtensionSDKPath = config.ExtensionSDKPath
if config.OnPermissionRequest != nil {
req.RequestPermission = Bool(true)
}
@@ -1012,8 +1010,8 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string,
if config.OnAutoModeSwitchRequest != nil {
req.RequestAutoModeSwitch = Bool(true)
}
- if config.EnableMcpApps {
- req.RequestMcpApps = Bool(true)
+ if config.EnableMCPApps {
+ req.RequestMCPApps = Bool(true)
}
traceparent, tracestate := getTraceContext(ctx)
@@ -1058,23 +1056,23 @@ func (c *Client) ResumeSessionWithOptions(ctx context.Context, sessionID string,
c.sessions[sessionID] = session
c.sessionsMux.Unlock()
- if c.options.SessionFs != nil {
- if config.CreateSessionFsProvider == nil {
+ if c.options.SessionFS != nil {
+ if config.CreateSessionFSProvider == nil {
c.sessionsMux.Lock()
delete(c.sessions, sessionID)
c.sessionsMux.Unlock()
- return nil, fmt.Errorf("CreateSessionFsProvider is required in session config when SessionFs is enabled in client options")
+ return nil, fmt.Errorf("CreateSessionFSProvider is required in session config when SessionFS is enabled in client options")
}
- provider := config.CreateSessionFsProvider(session)
- if c.options.SessionFs.Capabilities != nil && c.options.SessionFs.Capabilities.Sqlite {
- if _, ok := provider.(SessionFsSqliteProvider); !ok {
+ provider := config.CreateSessionFSProvider(session)
+ if c.options.SessionFS.Capabilities != nil && c.options.SessionFS.Capabilities.Sqlite {
+ if _, ok := provider.(SessionFSSqliteProvider); !ok {
c.sessionsMux.Lock()
delete(c.sessions, sessionID)
c.sessionsMux.Unlock()
- return nil, fmt.Errorf("SessionFs capabilities declare SQLite support but the provider does not implement SessionFsSqliteProvider")
+ return nil, fmt.Errorf("SessionFS capabilities declare SQLite support but the provider does not implement SessionFSSqliteProvider")
}
}
- session.clientSessionApis.SessionFs = newSessionFsAdapter(provider)
+ session.clientSessionAPIs.SessionFS = newSessionFSAdapter(provider)
}
result, err := c.client.Request("session.resume", req)
@@ -1558,7 +1556,7 @@ func (c *Client) verifyProtocolVersion(ctx context.Context) error {
if c.client == nil {
return fmt.Errorf("client not connected")
}
- maxVersion := GetSdkProtocolVersion()
+ maxVersion := GetSDKProtocolVersion()
var serverVersion *int
tokenPtr := (*string)(nil)
@@ -1747,8 +1745,8 @@ func (c *Client) startCLIServer(ctx context.Context) error {
c.state = stateDisconnected
}()
})
- c.RPC = rpc.NewServerRpc(c.client)
- c.internalRPC = rpc.NewInternalServerRpc(c.client)
+ c.RPC = rpc.NewServerRPC(c.client)
+ c.internalRPC = rpc.NewInternalServerRPC(c.client)
c.setupNotificationHandler()
c.client.Start()
@@ -1866,11 +1864,11 @@ func (c *Client) connectToServer(ctx context.Context) error {
}
// Connect via TCP
- return c.connectViaTcp(ctx)
+ return c.connectViaTCP(ctx)
}
-// connectViaTcp connects to the CLI server via TCP socket.
-func (c *Client) connectViaTcp(ctx context.Context) error {
+// connectViaTCP connects to the CLI server via TCP socket.
+func (c *Client) connectViaTCP(ctx context.Context) error {
if c.actualPort == 0 {
return fmt.Errorf("server port not available")
}
@@ -1900,8 +1898,8 @@ func (c *Client) connectViaTcp(ctx context.Context) error {
c.state = stateDisconnected
}()
})
- c.RPC = rpc.NewServerRpc(c.client)
- c.internalRPC = rpc.NewInternalServerRpc(c.client)
+ c.RPC = rpc.NewServerRPC(c.client)
+ c.internalRPC = rpc.NewInternalServerRPC(c.client)
c.setupNotificationHandler()
c.client.Start()
@@ -1917,14 +1915,14 @@ func (c *Client) setupNotificationHandler() {
c.client.SetRequestHandler("autoModeSwitch.request", jsonrpc2.RequestHandlerFor(c.handleAutoModeSwitchRequest))
c.client.SetRequestHandler("hooks.invoke", jsonrpc2.RequestHandlerFor(c.handleHooksInvoke))
c.client.SetRequestHandler("systemMessage.transform", jsonrpc2.RequestHandlerFor(c.handleSystemMessageTransform))
- rpc.RegisterClientSessionApiHandlers(c.client, func(sessionID string) *rpc.ClientSessionApiHandlers {
+ rpc.RegisterClientSessionAPIHandlers(c.client, func(sessionID string) *rpc.ClientSessionAPIHandlers {
c.sessionsMux.Lock()
defer c.sessionsMux.Unlock()
session := c.sessions[sessionID]
if session == nil {
return nil
}
- return session.clientSessionApis
+ return session.clientSessionAPIs
})
}
diff --git a/go/client_test.go b/go/client_test.go
index 155f81368..d5ba47da8 100644
--- a/go/client_test.go
+++ b/go/client_test.go
@@ -22,7 +22,7 @@ import (
func TestClient_URLParsing(t *testing.T) {
t.Run("should parse port-only URL format", func(t *testing.T) {
client := NewClient(&ClientOptions{
- Connection: UriConnection{URL: "8080"},
+ Connection: URIConnection{URL: "8080"},
})
if client.actualPort != 8080 {
t.Errorf("Expected port 8080, got %d", client.actualPort)
@@ -37,7 +37,7 @@ func TestClient_URLParsing(t *testing.T) {
t.Run("should parse host:port URL format", func(t *testing.T) {
client := NewClient(&ClientOptions{
- Connection: UriConnection{URL: "127.0.0.1:9000"},
+ Connection: URIConnection{URL: "127.0.0.1:9000"},
})
if client.actualPort != 9000 || client.actualHost != "127.0.0.1" {
t.Errorf("Expected 127.0.0.1:9000, got %s:%d", client.actualHost, client.actualPort)
@@ -46,7 +46,7 @@ func TestClient_URLParsing(t *testing.T) {
t.Run("should parse http://host:port URL format", func(t *testing.T) {
client := NewClient(&ClientOptions{
- Connection: UriConnection{URL: "http://localhost:7000"},
+ Connection: URIConnection{URL: "http://localhost:7000"},
})
if client.actualPort != 7000 || client.actualHost != "localhost" {
t.Errorf("Expected localhost:7000, got %s:%d", client.actualHost, client.actualPort)
@@ -55,7 +55,7 @@ func TestClient_URLParsing(t *testing.T) {
t.Run("should parse https://host:port URL format", func(t *testing.T) {
client := NewClient(&ClientOptions{
- Connection: UriConnection{URL: "https://example.com:443"},
+ Connection: URIConnection{URL: "https://example.com:443"},
})
if client.actualPort != 443 || client.actualHost != "example.com" {
t.Errorf("Expected example.com:443, got %s:%d", client.actualHost, client.actualPort)
@@ -68,7 +68,7 @@ func TestClient_URLParsing(t *testing.T) {
t.Error("Expected panic for invalid URL format")
}
}()
- NewClient(&ClientOptions{Connection: UriConnection{URL: "invalid-url"}})
+ NewClient(&ClientOptions{Connection: URIConnection{URL: "invalid-url"}})
})
t.Run("should panic for invalid port - too high", func(t *testing.T) {
@@ -77,7 +77,7 @@ func TestClient_URLParsing(t *testing.T) {
t.Error("Expected panic")
}
}()
- NewClient(&ClientOptions{Connection: UriConnection{URL: "localhost:99999"}})
+ NewClient(&ClientOptions{Connection: URIConnection{URL: "localhost:99999"}})
})
t.Run("should panic for invalid port - zero", func(t *testing.T) {
@@ -86,7 +86,7 @@ func TestClient_URLParsing(t *testing.T) {
t.Error("Expected panic")
}
}()
- NewClient(&ClientOptions{Connection: UriConnection{URL: "localhost:0"}})
+ NewClient(&ClientOptions{Connection: URIConnection{URL: "localhost:0"}})
})
t.Run("should panic for invalid port - negative", func(t *testing.T) {
@@ -95,16 +95,16 @@ func TestClient_URLParsing(t *testing.T) {
t.Error("Expected panic")
}
}()
- NewClient(&ClientOptions{Connection: UriConnection{URL: "localhost:-1"}})
+ NewClient(&ClientOptions{Connection: URIConnection{URL: "localhost:-1"}})
})
- t.Run("should panic when UriConnection has empty URL", func(t *testing.T) {
+ t.Run("should panic when URIConnection has empty URL", func(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Error("Expected panic for empty URL")
}
}()
- NewClient(&ClientOptions{Connection: UriConnection{}})
+ NewClient(&ClientOptions{Connection: URIConnection{}})
})
t.Run("stdio connection uses stdio transport", func(t *testing.T) {
@@ -115,9 +115,9 @@ func TestClient_URLParsing(t *testing.T) {
})
t.Run("tcp connection uses tcp transport", func(t *testing.T) {
- client := NewClient(&ClientOptions{Connection: TcpConnection{Port: 8080}})
+ client := NewClient(&ClientOptions{Connection: TCPConnection{Port: 8080}})
if client.useStdio {
- t.Error("Expected useStdio=false for TcpConnection")
+ t.Error("Expected useStdio=false for TCPConnection")
}
if client.port != 8080 {
t.Errorf("Expected port=8080, got %d", client.port)
@@ -126,31 +126,31 @@ func TestClient_URLParsing(t *testing.T) {
t.Run("uri connection is treated as external server", func(t *testing.T) {
client := NewClient(&ClientOptions{
- Connection: UriConnection{URL: "localhost:8080"},
+ Connection: URIConnection{URL: "localhost:8080"},
})
if !client.isExternalServer {
- t.Error("Expected isExternalServer=true for UriConnection")
+ t.Error("Expected isExternalServer=true for URIConnection")
}
})
}
-func TestClient_SessionFsConfig(t *testing.T) {
+func TestClient_SessionFSConfig(t *testing.T) {
t.Run("should throw error when InitialWorkingDirectory is missing", func(t *testing.T) {
defer func() {
if r := recover(); r == nil {
- t.Error("Expected panic for missing SessionFs.InitialWorkingDirectory")
+ t.Error("Expected panic for missing SessionFS.InitialWorkingDirectory")
} else {
- matched, _ := regexp.MatchString("SessionFs.InitialWorkingDirectory is required", r.(string))
+ matched, _ := regexp.MatchString("SessionFS.InitialWorkingDirectory is required", r.(string))
if !matched {
- t.Errorf("Expected panic message to contain 'SessionFs.InitialWorkingDirectory is required', got: %v", r)
+ t.Errorf("Expected panic message to contain 'SessionFS.InitialWorkingDirectory is required', got: %v", r)
}
}
}()
NewClient(&ClientOptions{
- SessionFs: &SessionFsConfig{
+ SessionFS: &SessionFSConfig{
SessionStatePath: "/session-state",
- Conventions: rpc.SessionFsSetProviderConventionsPosix,
+ Conventions: rpc.SessionFSSetProviderConventionsPosix,
},
})
})
@@ -158,19 +158,19 @@ func TestClient_SessionFsConfig(t *testing.T) {
t.Run("should throw error when SessionStatePath is missing", func(t *testing.T) {
defer func() {
if r := recover(); r == nil {
- t.Error("Expected panic for missing SessionFs.SessionStatePath")
+ t.Error("Expected panic for missing SessionFS.SessionStatePath")
} else {
- matched, _ := regexp.MatchString("SessionFs.SessionStatePath is required", r.(string))
+ matched, _ := regexp.MatchString("SessionFS.SessionStatePath is required", r.(string))
if !matched {
- t.Errorf("Expected panic message to contain 'SessionFs.SessionStatePath is required', got: %v", r)
+ t.Errorf("Expected panic message to contain 'SessionFS.SessionStatePath is required', got: %v", r)
}
}
}()
NewClient(&ClientOptions{
- SessionFs: &SessionFsConfig{
+ SessionFS: &SessionFSConfig{
InitialWorkingDirectory: "/",
- Conventions: rpc.SessionFsSetProviderConventionsPosix,
+ Conventions: rpc.SessionFSSetProviderConventionsPosix,
},
})
})
@@ -216,12 +216,12 @@ func TestClient_AuthOptions(t *testing.T) {
}
})
- t.Run("should panic when GitHubToken is used with UriConnection", func(t *testing.T) {
+ t.Run("should panic when GitHubToken is used with URIConnection", func(t *testing.T) {
defer func() {
if r := recover(); r == nil {
- t.Error("Expected panic for auth options with UriConnection")
+ t.Error("Expected panic for auth options with URIConnection")
} else {
- matched, _ := regexp.MatchString("GitHubToken and UseLoggedInUser cannot be used with UriConnection", r.(string))
+ matched, _ := regexp.MatchString("GitHubToken and UseLoggedInUser cannot be used with URIConnection", r.(string))
if !matched {
t.Errorf("Expected panic message about auth options, got: %v", r)
}
@@ -229,20 +229,20 @@ func TestClient_AuthOptions(t *testing.T) {
}()
NewClient(&ClientOptions{
- Connection: UriConnection{URL: "localhost:8080"},
+ Connection: URIConnection{URL: "localhost:8080"},
GitHubToken: "gho_test_token",
})
})
- t.Run("should panic when UseLoggedInUser is used with UriConnection", func(t *testing.T) {
+ t.Run("should panic when UseLoggedInUser is used with URIConnection", func(t *testing.T) {
defer func() {
if r := recover(); r == nil {
- t.Error("Expected panic for auth options with UriConnection")
+ t.Error("Expected panic for auth options with URIConnection")
}
}()
NewClient(&ClientOptions{
- Connection: UriConnection{URL: "localhost:8080"},
+ Connection: URIConnection{URL: "localhost:8080"},
UseLoggedInUser: Bool(false),
})
})
@@ -434,6 +434,105 @@ func TestSessionRequests_ReasoningSummary(t *testing.T) {
})
}
+func TestSessionRequests_ContextTier(t *testing.T) {
+ t.Run("create includes contextTier in JSON when set", func(t *testing.T) {
+ req := createSessionRequest{ContextTier: ContextTierLongContext}
+ data, err := json.Marshal(req)
+ if err != nil {
+ t.Fatalf("Failed to marshal: %v", err)
+ }
+ var m map[string]any
+ if err := json.Unmarshal(data, &m); err != nil {
+ t.Fatalf("Failed to unmarshal: %v", err)
+ }
+ if m["contextTier"] != "long_context" {
+ t.Errorf("Expected contextTier to be 'long_context', got %v", m["contextTier"])
+ }
+ })
+
+ t.Run("resume includes contextTier in JSON when set", func(t *testing.T) {
+ req := resumeSessionRequest{SessionID: "s1", ContextTier: ContextTierDefault}
+ data, err := json.Marshal(req)
+ if err != nil {
+ t.Fatalf("Failed to marshal: %v", err)
+ }
+ var m map[string]any
+ if err := json.Unmarshal(data, &m); err != nil {
+ t.Fatalf("Failed to unmarshal: %v", err)
+ }
+ if m["contextTier"] != "default" {
+ t.Errorf("Expected contextTier to be 'default', got %v", m["contextTier"])
+ }
+ })
+}
+
+func TestSessionRequests_EnableConfigDiscovery(t *testing.T) {
+ t.Run("create includes enableConfigDiscovery when true", func(t *testing.T) {
+ req := createSessionRequest{EnableConfigDiscovery: Bool(true)}
+ data, err := json.Marshal(req)
+ if err != nil {
+ t.Fatalf("Failed to marshal: %v", err)
+ }
+ var m map[string]any
+ if err := json.Unmarshal(data, &m); err != nil {
+ t.Fatalf("Failed to unmarshal: %v", err)
+ }
+ if m["enableConfigDiscovery"] != true {
+ t.Errorf("Expected enableConfigDiscovery to be true, got %v", m["enableConfigDiscovery"])
+ }
+ })
+
+ t.Run("create includes enableConfigDiscovery when false", func(t *testing.T) {
+ req := createSessionRequest{EnableConfigDiscovery: Bool(false)}
+ data, err := json.Marshal(req)
+ if err != nil {
+ t.Fatalf("Failed to marshal: %v", err)
+ }
+ var m map[string]any
+ if err := json.Unmarshal(data, &m); err != nil {
+ t.Fatalf("Failed to unmarshal: %v", err)
+ }
+ if m["enableConfigDiscovery"] != false {
+ t.Errorf("Expected enableConfigDiscovery to be false, got %v", m["enableConfigDiscovery"])
+ }
+ })
+
+ t.Run("create omits enableConfigDiscovery when unset", func(t *testing.T) {
+ req := createSessionRequest{}
+ data, _ := json.Marshal(req)
+ var m map[string]any
+ json.Unmarshal(data, &m)
+ if _, ok := m["enableConfigDiscovery"]; ok {
+ t.Error("Expected enableConfigDiscovery to be omitted when unset")
+ }
+ })
+
+ t.Run("resume includes enableConfigDiscovery when false", func(t *testing.T) {
+ req := resumeSessionRequest{SessionID: "s1", EnableConfigDiscovery: Bool(false)}
+ data, err := json.Marshal(req)
+ if err != nil {
+ t.Fatalf("Failed to marshal: %v", err)
+ }
+ var m map[string]any
+ if err := json.Unmarshal(data, &m); err != nil {
+ t.Fatalf("Failed to unmarshal: %v", err)
+ }
+ if m["enableConfigDiscovery"] != false {
+ t.Errorf("Expected enableConfigDiscovery to be false, got %v", m["enableConfigDiscovery"])
+ }
+ })
+
+ t.Run("resume omits enableConfigDiscovery when unset", func(t *testing.T) {
+ req := resumeSessionRequest{SessionID: "s1"}
+ data, _ := json.Marshal(req)
+ var m map[string]any
+ json.Unmarshal(data, &m)
+ if _, ok := m["enableConfigDiscovery"]; ok {
+ t.Error("Expected enableConfigDiscovery to be omitted when unset")
+ }
+ })
+}
+
func TestSessionRequests_PluginDirectoriesAndLargeOutput(t *testing.T) {
pluginDirs := []string{"/tmp/plugins/a", "/tmp/plugins/b"}
enabled := true
@@ -768,7 +867,7 @@ func TestListModelsWithCustomHandler(t *testing.T) {
Name: "My Custom Model",
Capabilities: ModelCapabilities{
Supports: ModelSupports{Vision: false, ReasoningEffort: false},
- Limits: ModelLimits{MaxContextWindowTokens: 128000},
+ Limits: ModelLimits{MaxContextWindowTokens: Int(128000)},
},
},
}
@@ -800,7 +899,7 @@ func TestListModelsHandlerCachesResults(t *testing.T) {
Name: "Cached Model",
Capabilities: ModelCapabilities{
Supports: ModelSupports{Vision: false, ReasoningEffort: false},
- Limits: ModelLimits{MaxContextWindowTokens: 128000},
+ Limits: ModelLimits{MaxContextWindowTokens: Int(128000)},
},
},
}
@@ -1114,10 +1213,10 @@ func TestResumeSessionRequest_RequestElicitation(t *testing.T) {
})
}
-func TestCreateSessionRequest_RequestMcpApps(t *testing.T) {
- t.Run("sends requestMcpApps flag when EnableMcpApps is set", func(t *testing.T) {
+func TestCreateSessionRequest_RequestMCPApps(t *testing.T) {
+ t.Run("sends requestMCPApps flag when EnableMCPApps is set", func(t *testing.T) {
req := createSessionRequest{
- RequestMcpApps: Bool(true),
+ RequestMCPApps: Bool(true),
}
data, err := json.Marshal(req)
if err != nil {
@@ -1132,7 +1231,7 @@ func TestCreateSessionRequest_RequestMcpApps(t *testing.T) {
}
})
- t.Run("does not send requestMcpApps when EnableMcpApps is unset", func(t *testing.T) {
+ t.Run("does not send requestMcpApps when EnableMCPApps is unset", func(t *testing.T) {
req := createSessionRequest{}
data, _ := json.Marshal(req)
var m map[string]any
@@ -1143,11 +1242,11 @@ func TestCreateSessionRequest_RequestMcpApps(t *testing.T) {
})
}
-func TestResumeSessionRequest_RequestMcpApps(t *testing.T) {
- t.Run("sends requestMcpApps flag when EnableMcpApps is set", func(t *testing.T) {
+func TestResumeSessionRequest_RequestMCPApps(t *testing.T) {
+ t.Run("sends requestMcpApps flag when EnableMCPApps is set", func(t *testing.T) {
req := resumeSessionRequest{
SessionID: "s1",
- RequestMcpApps: Bool(true),
+ RequestMCPApps: Bool(true),
}
data, err := json.Marshal(req)
if err != nil {
@@ -1162,7 +1261,7 @@ func TestResumeSessionRequest_RequestMcpApps(t *testing.T) {
}
})
- t.Run("does not send requestMcpApps when EnableMcpApps is unset", func(t *testing.T) {
+ t.Run("does not send requestMcpApps when RequestMCPApps is unset", func(t *testing.T) {
req := resumeSessionRequest{SessionID: "s1"}
data, _ := json.Marshal(req)
var m map[string]any
@@ -1301,6 +1400,24 @@ func TestResumeSessionRequest_ContinuePendingWork(t *testing.T) {
}
})
+ t.Run("forwards continuePendingWork when false", func(t *testing.T) {
+ req := resumeSessionRequest{
+ SessionID: "s1",
+ ContinuePendingWork: Bool(false),
+ }
+ data, err := json.Marshal(req)
+ if err != nil {
+ t.Fatalf("Failed to marshal: %v", err)
+ }
+ var m map[string]any
+ if err := json.Unmarshal(data, &m); err != nil {
+ t.Fatalf("Failed to unmarshal: %v", err)
+ }
+ if m["continuePendingWork"] != false {
+ t.Errorf("Expected continuePendingWork to be false, got %v", m["continuePendingWork"])
+ }
+ })
+
t.Run("omits continuePendingWork when not set", func(t *testing.T) {
req := resumeSessionRequest{SessionID: "s1"}
data, _ := json.Marshal(req)
@@ -1445,6 +1562,100 @@ func TestResumeSessionRequest_IncludeSubAgentStreamingEvents(t *testing.T) {
})
}
+func TestCreateSessionRequest_EnableOnDemandInstructionDiscovery(t *testing.T) {
+ t.Run("forwards explicit true", func(t *testing.T) {
+ req := createSessionRequest{
+ EnableOnDemandInstructionDiscovery: Bool(true),
+ }
+ data, err := json.Marshal(req)
+ if err != nil {
+ t.Fatalf("Failed to marshal: %v", err)
+ }
+ var m map[string]any
+ if err := json.Unmarshal(data, &m); err != nil {
+ t.Fatalf("Failed to unmarshal: %v", err)
+ }
+ if m["enableOnDemandInstructionDiscovery"] != true {
+ t.Errorf("Expected enableOnDemandInstructionDiscovery to be true, got %v", m["enableOnDemandInstructionDiscovery"])
+ }
+ })
+
+ t.Run("preserves explicit false", func(t *testing.T) {
+ req := createSessionRequest{
+ EnableOnDemandInstructionDiscovery: Bool(false),
+ }
+ data, err := json.Marshal(req)
+ if err != nil {
+ t.Fatalf("Failed to marshal: %v", err)
+ }
+ var m map[string]any
+ if err := json.Unmarshal(data, &m); err != nil {
+ t.Fatalf("Failed to unmarshal: %v", err)
+ }
+ if m["enableOnDemandInstructionDiscovery"] != false {
+ t.Errorf("Expected enableOnDemandInstructionDiscovery to be false, got %v", m["enableOnDemandInstructionDiscovery"])
+ }
+ })
+
+ t.Run("omits enableOnDemandInstructionDiscovery when not set", func(t *testing.T) {
+ req := createSessionRequest{}
+ data, _ := json.Marshal(req)
+ var m map[string]any
+ json.Unmarshal(data, &m)
+ if _, ok := m["enableOnDemandInstructionDiscovery"]; ok {
+ t.Error("Expected enableOnDemandInstructionDiscovery to be omitted when not set")
+ }
+ })
+}
+
+func TestResumeSessionRequest_EnableOnDemandInstructionDiscovery(t *testing.T) {
+ t.Run("forwards explicit true", func(t *testing.T) {
+ req := resumeSessionRequest{
+ SessionID: "s1",
+ EnableOnDemandInstructionDiscovery: Bool(true),
+ }
+ data, err := json.Marshal(req)
+ if err != nil {
+ t.Fatalf("Failed to marshal: %v", err)
+ }
+ var m map[string]any
+ if err := json.Unmarshal(data, &m); err != nil {
+ t.Fatalf("Failed to unmarshal: %v", err)
+ }
+ if m["enableOnDemandInstructionDiscovery"] != true {
+ t.Errorf("Expected enableOnDemandInstructionDiscovery to be true, got %v", m["enableOnDemandInstructionDiscovery"])
+ }
+ })
+
+ t.Run("preserves explicit false", func(t *testing.T) {
+ req := resumeSessionRequest{
+ SessionID: "s1",
+ EnableOnDemandInstructionDiscovery: Bool(false),
+ }
+ data, err := json.Marshal(req)
+ if err != nil {
+ t.Fatalf("Failed to marshal: %v", err)
+ }
+ var m map[string]any
+ if err := json.Unmarshal(data, &m); err != nil {
+ t.Fatalf("Failed to unmarshal: %v", err)
+ }
+ if m["enableOnDemandInstructionDiscovery"] != false {
+ t.Errorf("Expected enableOnDemandInstructionDiscovery to be false, got %v", m["enableOnDemandInstructionDiscovery"])
+ }
+ })
+
+ t.Run("omits enableOnDemandInstructionDiscovery when not set", func(t *testing.T) {
+ req := resumeSessionRequest{SessionID: "s1"}
+ data, _ := json.Marshal(req)
+ var m map[string]any
+ json.Unmarshal(data, &m)
+ if _, ok := m["enableOnDemandInstructionDiscovery"]; ok {
+ t.Error("Expected enableOnDemandInstructionDiscovery to be omitted when not set")
+ }
+ })
+}
+
func TestCreateSessionResponse_Capabilities(t *testing.T) {
t.Run("reads capabilities from session.create response", func(t *testing.T) {
responseJSON := `{"sessionId":"s1","workspacePath":"/tmp","capabilities":{"ui":{"elicitation":true}}}`
diff --git a/go/definetool.go b/go/definetool.go
index ccaa69a58..bc223dc10 100644
--- a/go/definetool.go
+++ b/go/definetool.go
@@ -159,7 +159,7 @@ func ConvertMCPCallToolResult(value any) (ToolResult, bool) {
}
binaryResults = append(binaryResults, ToolBinaryResult{
Data: data,
- MimeType: mimeType,
+ MIMEType: mimeType,
Type: "image",
})
case "resource":
@@ -175,7 +175,7 @@ func ConvertMCPCallToolResult(value any) (ToolResult, bool) {
uri, _ := resRaw["uri"].(string)
binaryResults = append(binaryResults, ToolBinaryResult{
Data: blob,
- MimeType: mimeType,
+ MIMEType: mimeType,
Type: "resource",
Description: uri,
})
diff --git a/go/definetool_test.go b/go/definetool_test.go
index cc9fecb2c..f7161fb94 100644
--- a/go/definetool_test.go
+++ b/go/definetool_test.go
@@ -358,8 +358,8 @@ func TestConvertMCPCallToolResult(t *testing.T) {
if result.BinaryResultsForLLM[0].Data != "base64data" {
t.Errorf("Expected data 'base64data', got %q", result.BinaryResultsForLLM[0].Data)
}
- if result.BinaryResultsForLLM[0].MimeType != "image/png" {
- t.Errorf("Expected mimeType 'image/png', got %q", result.BinaryResultsForLLM[0].MimeType)
+ if result.BinaryResultsForLLM[0].MIMEType != "image/png" {
+ t.Errorf("Expected mimeType 'image/png', got %q", result.BinaryResultsForLLM[0].MIMEType)
}
})
diff --git a/go/internal/e2e/agent_and_compact_rpc_e2e_test.go b/go/internal/e2e/agent_and_compact_rpc_e2e_test.go
index cfb879917..c02a8571d 100644
--- a/go/internal/e2e/agent_and_compact_rpc_e2e_test.go
+++ b/go/internal/e2e/agent_and_compact_rpc_e2e_test.go
@@ -11,7 +11,7 @@ import (
"github.com/github/copilot-sdk/go/rpc"
)
-func TestAgentSelectionRpcE2E(t *testing.T) {
+func TestAgentSelectionRPCE2E(t *testing.T) {
cliPath := testharness.CLIPath()
if cliPath == "" {
t.Fatal("CLI not found. Run 'npm install' in the nodejs directory first.")
@@ -333,7 +333,7 @@ func agentSummaries(agents []rpc.AgentInfo) []string {
return summaries
}
-func TestSessionCompactionRpcE2E(t *testing.T) {
+func TestSessionCompactionRPCE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient()
t.Cleanup(func() { client.ForceStop() })
diff --git a/go/internal/e2e/builtin_tools_e2e_test.go b/go/internal/e2e/builtin_tools_e2e_test.go
index a25108fed..7b48018e0 100644
--- a/go/internal/e2e/builtin_tools_e2e_test.go
+++ b/go/internal/e2e/builtin_tools_e2e_test.go
@@ -1,16 +1,24 @@
package e2e
import (
+ "context"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
+ "time"
copilot "github.com/github/copilot-sdk/go"
"github.com/github/copilot-sdk/go/internal/e2e/testharness"
)
+// Built-in tool tests spawn a real CLI subprocess and execute actual shell /
+// file tools. Under slow/concurrent CI (notably Windows) this agent loop can
+// briefly exceed the 60s SendAndWait default, so give it extra headroom while
+// still failing fast on a genuine hang.
+const sendTimeout = 120 * time.Second
+
func TestBuiltinToolsE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient()
@@ -27,7 +35,9 @@ func TestBuiltinToolsE2E(t *testing.T) {
}
t.Cleanup(func() { _ = session.Disconnect() })
- msg, err := session.SendAndWait(t.Context(), copilot.MessageOptions{
+ sendCtx, cancel := context.WithTimeout(t.Context(), sendTimeout)
+ defer cancel()
+ msg, err := session.SendAndWait(sendCtx, copilot.MessageOptions{
Prompt: "Run 'echo hello && echo world'. Tell me the exact output.",
})
if err != nil {
@@ -55,7 +65,9 @@ func TestBuiltinToolsE2E(t *testing.T) {
}
t.Cleanup(func() { _ = session.Disconnect() })
- msg, err := session.SendAndWait(t.Context(), copilot.MessageOptions{
+ sendCtx, cancel := context.WithTimeout(t.Context(), sendTimeout)
+ defer cancel()
+ msg, err := session.SendAndWait(sendCtx, copilot.MessageOptions{
Prompt: "Run 'echo error_msg >&2; echo ok' and tell me what stderr said. Reply with just the stderr content.",
})
if err != nil {
@@ -82,7 +94,9 @@ func TestBuiltinToolsE2E(t *testing.T) {
}
t.Cleanup(func() { _ = session.Disconnect() })
- msg, err := session.SendAndWait(t.Context(), copilot.MessageOptions{
+ sendCtx, cancel := context.WithTimeout(t.Context(), sendTimeout)
+ defer cancel()
+ msg, err := session.SendAndWait(sendCtx, copilot.MessageOptions{
Prompt: "Read lines 2 through 4 of the file 'lines.txt' in this directory. Tell me what those lines contain.",
})
if err != nil {
@@ -106,7 +120,9 @@ func TestBuiltinToolsE2E(t *testing.T) {
}
t.Cleanup(func() { _ = session.Disconnect() })
- msg, err := session.SendAndWait(t.Context(), copilot.MessageOptions{
+ sendCtx, cancel := context.WithTimeout(t.Context(), sendTimeout)
+ defer cancel()
+ msg, err := session.SendAndWait(sendCtx, copilot.MessageOptions{
Prompt: "Try to read the file 'does_not_exist.txt'. If it doesn't exist, say 'FILE_NOT_FOUND'.",
})
if err != nil {
@@ -139,7 +155,9 @@ func TestBuiltinToolsE2E(t *testing.T) {
}
t.Cleanup(func() { _ = session.Disconnect() })
- msg, err := session.SendAndWait(t.Context(), copilot.MessageOptions{
+ sendCtx, cancel := context.WithTimeout(t.Context(), sendTimeout)
+ defer cancel()
+ msg, err := session.SendAndWait(sendCtx, copilot.MessageOptions{
Prompt: "Edit the file 'edit_me.txt': replace 'Hello World' with 'Hi Universe'. Then read it back and tell me its contents.",
})
if err != nil {
@@ -162,7 +180,9 @@ func TestBuiltinToolsE2E(t *testing.T) {
}
t.Cleanup(func() { _ = session.Disconnect() })
- msg, err := session.SendAndWait(t.Context(), copilot.MessageOptions{
+ sendCtx, cancel := context.WithTimeout(t.Context(), sendTimeout)
+ defer cancel()
+ msg, err := session.SendAndWait(sendCtx, copilot.MessageOptions{
Prompt: "Create a file called 'new_file.txt' with the content 'Created by test'. Then read it back to confirm.",
})
if err != nil {
@@ -189,7 +209,9 @@ func TestBuiltinToolsE2E(t *testing.T) {
}
t.Cleanup(func() { _ = session.Disconnect() })
- msg, err := session.SendAndWait(t.Context(), copilot.MessageOptions{
+ sendCtx, cancel := context.WithTimeout(t.Context(), sendTimeout)
+ defer cancel()
+ msg, err := session.SendAndWait(sendCtx, copilot.MessageOptions{
Prompt: "Search for lines starting with 'ap' in the file 'data.txt'. Tell me which lines matched.",
})
if err != nil {
@@ -223,7 +245,9 @@ func TestBuiltinToolsE2E(t *testing.T) {
}
t.Cleanup(func() { _ = session.Disconnect() })
- msg, err := session.SendAndWait(t.Context(), copilot.MessageOptions{
+ sendCtx, cancel := context.WithTimeout(t.Context(), sendTimeout)
+ defer cancel()
+ msg, err := session.SendAndWait(sendCtx, copilot.MessageOptions{
Prompt: "Find all .ts files in this directory (recursively). List the filenames you found.",
})
if err != nil {
diff --git a/go/internal/e2e/client_api_e2e_test.go b/go/internal/e2e/client_api_e2e_test.go
index 15e97b5a7..3b0c88845 100644
--- a/go/internal/e2e/client_api_e2e_test.go
+++ b/go/internal/e2e/client_api_e2e_test.go
@@ -9,7 +9,7 @@ import (
)
// Mirrors dotnet/test/ClientSessionManagementTests.cs (snapshot category "client_api").
-func TestClientApiE2E(t *testing.T) {
+func TestClientAPIE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient()
t.Cleanup(func() { client.ForceStop() })
diff --git a/go/internal/e2e/client_e2e_test.go b/go/internal/e2e/client_e2e_test.go
index e4dfed2d4..d7fc3f06a 100644
--- a/go/internal/e2e/client_e2e_test.go
+++ b/go/internal/e2e/client_e2e_test.go
@@ -44,7 +44,7 @@ func TestClientE2E(t *testing.T) {
t.Run("should start and connect to server using tcp", func(t *testing.T) {
client := copilot.NewClient(&copilot.ClientOptions{
- Connection: copilot.TcpConnection{Path: cliPath},
+ Connection: copilot.TCPConnection{Path: cliPath},
})
t.Cleanup(func() { client.ForceStop() })
diff --git a/go/internal/e2e/client_options_e2e_test.go b/go/internal/e2e/client_options_e2e_test.go
index 7f4121af2..4f8b74f2b 100644
--- a/go/internal/e2e/client_options_e2e_test.go
+++ b/go/internal/e2e/client_options_e2e_test.go
@@ -17,12 +17,12 @@ import (
// Go's ClientOptions is a plain struct with no setter validation; equivalent behavior is covered
// in package-level unit tests.
func TestClientOptionsE2E(t *testing.T) {
- t.Run("should listen on configured tcp port", func(t *testing.T) {
+ t.Run("should listen on configured TCP port", func(t *testing.T) {
ctx := testharness.NewTestContext(t)
- port := getAvailableTcpPort(t)
+ port := getAvailableTCPPort(t)
client := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.TcpConnection{Path: ctx.CLIPath, Port: port}
+ opts.Connection = copilot.TCPConnection{Path: ctx.CLIPath, Port: port}
})
t.Cleanup(func() { client.ForceStop() })
@@ -159,9 +159,10 @@ func TestClientOptionsE2E(t *testing.T) {
}
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
- EnableConfigDiscovery: true,
- IncludeSubAgentStreamingEvents: copilot.Bool(false),
- OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
+ EnableConfigDiscovery: copilot.Bool(true),
+ EnableOnDemandInstructionDiscovery: copilot.Bool(true),
+ IncludeSubAgentStreamingEvents: copilot.Bool(false),
+ OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
if err != nil {
t.Fatalf("CreateSession failed: %v", err)
@@ -187,6 +188,9 @@ func TestClientOptionsE2E(t *testing.T) {
if v, ok := params["enableConfigDiscovery"].(bool); !ok || v != true {
t.Errorf("Expected session.create.params.enableConfigDiscovery=true, got %v", params["enableConfigDiscovery"])
}
+ if v, ok := params["enableOnDemandInstructionDiscovery"].(bool); !ok || v != true {
+ t.Errorf("Expected session.create.params.enableOnDemandInstructionDiscovery=true, got %v", params["enableOnDemandInstructionDiscovery"])
+ }
if v, ok := params["includeSubAgentStreamingEvents"].(bool); !ok || v != false {
t.Errorf("Expected session.create.params.includeSubAgentStreamingEvents=false, got %v", params["includeSubAgentStreamingEvents"])
}
@@ -237,19 +241,19 @@ func TestClientOptionsUnit(t *testing.T) {
}
})
- t.Run("should panic when GitHubToken used with UriConnection", func(t *testing.T) {
+ t.Run("should panic when GitHubToken used with URIConnection", func(t *testing.T) {
assertPanics(t, func() {
_ = copilot.NewClient(&copilot.ClientOptions{
- Connection: copilot.UriConnection{URL: "localhost:8080"},
+ Connection: copilot.URIConnection{URL: "localhost:8080"},
GitHubToken: "gho_test_token",
})
})
})
- t.Run("should panic when UseLoggedInUser used with UriConnection", func(t *testing.T) {
+ t.Run("should panic when UseLoggedInUser used with URIConnection", func(t *testing.T) {
assertPanics(t, func() {
_ = copilot.NewClient(&copilot.ClientOptions{
- Connection: copilot.UriConnection{URL: "localhost:8080"},
+ Connection: copilot.URIConnection{URL: "localhost:8080"},
UseLoggedInUser: copilot.Bool(false),
})
})
@@ -274,7 +278,7 @@ func TestClientOptionsUnit(t *testing.T) {
})
}
-func getAvailableTcpPort(t *testing.T) int {
+func getAvailableTCPPort(t *testing.T) int {
t.Helper()
listener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
diff --git a/go/internal/e2e/commands_and_elicitation_e2e_test.go b/go/internal/e2e/commands_and_elicitation_e2e_test.go
index 68b9badd1..8d2d40f2f 100644
--- a/go/internal/e2e/commands_and_elicitation_e2e_test.go
+++ b/go/internal/e2e/commands_and_elicitation_e2e_test.go
@@ -14,7 +14,7 @@ import (
func TestCommandsE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
client1 := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.TcpConnection{Path: opts.Connection.(copilot.StdioConnection).Path, ConnectionToken: sharedTcpToken}
+ opts.Connection = copilot.TCPConnection{Path: opts.Connection.(copilot.StdioConnection).Path, ConnectionToken: sharedTCPToken}
})
t.Cleanup(func() { client1.ForceStop() })
@@ -33,7 +33,7 @@ func TestCommandsE2E(t *testing.T) {
}
client2 := copilot.NewClient(&copilot.ClientOptions{
- Connection: copilot.UriConnection{URL: fmt.Sprintf("localhost:%d", runtimePort), ConnectionToken: sharedTcpToken},
+ Connection: copilot.URIConnection{URL: fmt.Sprintf("localhost:%d", runtimePort), ConnectionToken: sharedTCPToken},
})
t.Cleanup(func() { client2.ForceStop() })
@@ -437,7 +437,7 @@ func TestUIElicitationCallbackE2E(t *testing.T) {
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
OnElicitationRequest: func(ctx copilot.ElicitationContext) (copilot.ElicitationResult, error) {
- return copilot.ElicitationResult{Action: "accept", Content: map[string]any{}}, nil
+ return copilot.ElicitationResult{Action: copilot.ElicitationActionAccept, Content: map[string]any{}}, nil
},
})
if err != nil {
@@ -481,7 +481,7 @@ func TestUIElicitationCallbackE2E(t *testing.T) {
t.Errorf("Expected RequestedSchema to contain 'confirmed' property")
}
return copilot.ElicitationResult{
- Action: "accept",
+ Action: copilot.ElicitationActionAccept,
Content: map[string]any{"confirmed": true},
}, nil
},
@@ -505,7 +505,7 @@ func TestUIElicitationCallbackE2E(t *testing.T) {
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
OnElicitationRequest: func(ec copilot.ElicitationContext) (copilot.ElicitationResult, error) {
- return copilot.ElicitationResult{Action: "decline"}, nil
+ return copilot.ElicitationResult{Action: copilot.ElicitationActionDecline}, nil
},
})
if err != nil {
@@ -534,7 +534,7 @@ func TestUIElicitationCallbackE2E(t *testing.T) {
t.Errorf("Expected RequestedSchema to contain 'selection' property")
}
return copilot.ElicitationResult{
- Action: "accept",
+ Action: copilot.ElicitationActionAccept,
Content: map[string]any{"selection": "beta"},
}, nil
},
@@ -568,7 +568,7 @@ func TestUIElicitationCallbackE2E(t *testing.T) {
t.Errorf("Expected RequestedSchema to contain 'value' property")
}
return copilot.ElicitationResult{
- Action: "accept",
+ Action: copilot.ElicitationActionAccept,
Content: map[string]any{"value": "typed value"},
}, nil
},
@@ -579,7 +579,7 @@ func TestUIElicitationCallbackE2E(t *testing.T) {
minLen := 1
maxLen := 20
- value, ok, err := session.UI().Input(t.Context(), "Enter value", &copilot.UiInputOptions{
+ value, ok, err := session.UI().Input(t.Context(), "Enter value", &copilot.UIInputOptions{
Title: "Value",
Description: "A value to test",
MinLength: &minLen,
@@ -601,9 +601,9 @@ func TestUIElicitationCallbackE2E(t *testing.T) {
ctx.ConfigureForTest(t)
responses := []copilot.ElicitationResult{
- {Action: "accept", Content: map[string]any{"name": "Mona"}},
- {Action: "decline"},
- {Action: "cancel"},
+ {Action: copilot.ElicitationActionAccept, Content: map[string]any{"name": "Mona"}},
+ {Action: copilot.ElicitationActionDecline},
+ {Action: copilot.ElicitationActionCancel},
}
var idx int
@@ -625,9 +625,8 @@ func TestUIElicitationCallbackE2E(t *testing.T) {
t.Fatalf("CreateSession failed: %v", err)
}
- schema := rpc.UIElicitationSchema{
- Type: rpc.UIElicitationSchemaTypeObject,
- Properties: map[string]rpc.UIElicitationSchemaProperty{
+ schema := copilot.ElicitationSchema{
+ Properties: map[string]any{
"name": &rpc.UIElicitationSchemaPropertyString{},
},
Required: []string{"name"},
@@ -637,10 +636,10 @@ func TestUIElicitationCallbackE2E(t *testing.T) {
if err != nil {
t.Fatalf("Elicitation accept call failed: %v", err)
}
- if accept.Action != "accept" {
+ if accept.Action != copilot.ElicitationActionAccept {
t.Errorf("Expected accept.Action='accept', got %q", accept.Action)
}
- if accept.Content == nil || fmt.Sprintf("%v", accept.Content["name"]) != "Mona" {
+ if accept.Content == nil || accept.Content["name"] != "Mona" {
t.Errorf("Expected accept.Content[name]='Mona', got %v", accept.Content)
}
@@ -648,7 +647,7 @@ func TestUIElicitationCallbackE2E(t *testing.T) {
if err != nil {
t.Fatalf("Elicitation decline call failed: %v", err)
}
- if decline.Action != "decline" {
+ if decline.Action != copilot.ElicitationActionDecline {
t.Errorf("Expected decline.Action='decline', got %q", decline.Action)
}
@@ -656,7 +655,7 @@ func TestUIElicitationCallbackE2E(t *testing.T) {
if err != nil {
t.Fatalf("Elicitation cancel call failed: %v", err)
}
- if cancel.Action != "cancel" {
+ if cancel.Action != copilot.ElicitationActionCancel {
t.Errorf("Expected cancel.Action='cancel', got %q", cancel.Action)
}
})
@@ -681,7 +680,7 @@ func TestUIElicitationCallbackE2E(t *testing.T) {
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
OnElicitationRequest: func(ec copilot.ElicitationContext) (copilot.ElicitationResult, error) {
- return copilot.ElicitationResult{Action: "accept", Content: map[string]any{}}, nil
+ return copilot.ElicitationResult{Action: copilot.ElicitationActionAccept, Content: map[string]any{}}, nil
},
})
if err != nil {
@@ -694,35 +693,20 @@ func TestUIElicitationCallbackE2E(t *testing.T) {
})
}
-// schemaHasProperty reports whether the elicitation schema map has a top-level
-// property with the given name. RequestedSchema["properties"] is typically a
-// map[string]rpc.UIElicitationSchemaProperty, but we accept any map[string]X.
-func schemaHasProperty(schema map[string]any, name string) bool {
+// schemaHasProperty reports whether the elicitation schema has a top-level
+// property with the given name.
+func schemaHasProperty(schema *copilot.ElicitationSchema, name string) bool {
if schema == nil {
return false
}
- props, ok := schema["properties"]
- if !ok || props == nil {
- return false
- }
- switch p := props.(type) {
- case map[string]any:
- _, found := p[name]
- return found
- case map[string]rpc.UIElicitationSchemaProperty:
- _, found := p[name]
- return found
- default:
- // Fallback: marshal/unmarshal via reflection-friendly route.
- // For test diagnostic purposes we treat unknown shapes as not found.
- return false
- }
+ _, found := schema.Properties[name]
+ return found
}
func TestUIElicitationMultiClientE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
client1 := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.TcpConnection{Path: opts.Connection.(copilot.StdioConnection).Path, ConnectionToken: sharedTcpToken}
+ opts.Connection = copilot.TCPConnection{Path: opts.Connection.(copilot.StdioConnection).Path, ConnectionToken: sharedTCPToken}
})
t.Cleanup(func() { client1.ForceStop() })
@@ -770,13 +754,13 @@ func TestUIElicitationMultiClientE2E(t *testing.T) {
// Client2 joins with elicitation handler — should trigger capabilities.changed
client2 := copilot.NewClient(&copilot.ClientOptions{
- Connection: copilot.UriConnection{URL: fmt.Sprintf("localhost:%d", runtimePort), ConnectionToken: sharedTcpToken},
+ Connection: copilot.URIConnection{URL: fmt.Sprintf("localhost:%d", runtimePort), ConnectionToken: sharedTCPToken},
})
session2, err := client2.ResumeSession(t.Context(), session1.SessionID, &copilot.ResumeSessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
SuppressResumeEvent: true,
OnElicitationRequest: func(ctx copilot.ElicitationContext) (copilot.ElicitationResult, error) {
- return copilot.ElicitationResult{Action: "accept", Content: map[string]any{}}, nil
+ return copilot.ElicitationResult{Action: copilot.ElicitationActionAccept, Content: map[string]any{}}, nil
},
})
if err != nil {
@@ -830,13 +814,13 @@ func TestUIElicitationMultiClientE2E(t *testing.T) {
// Client3 (dedicated for this test) joins with elicitation handler
client3 := copilot.NewClient(&copilot.ClientOptions{
- Connection: copilot.UriConnection{URL: fmt.Sprintf("localhost:%d", runtimePort), ConnectionToken: sharedTcpToken},
+ Connection: copilot.URIConnection{URL: fmt.Sprintf("localhost:%d", runtimePort), ConnectionToken: sharedTCPToken},
})
_, err = client3.ResumeSession(t.Context(), session1.SessionID, &copilot.ResumeSessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
SuppressResumeEvent: true,
OnElicitationRequest: func(ctx copilot.ElicitationContext) (copilot.ElicitationResult, error) {
- return copilot.ElicitationResult{Action: "accept", Content: map[string]any{}}, nil
+ return copilot.ElicitationResult{Action: copilot.ElicitationActionAccept, Content: map[string]any{}}, nil
},
})
if err != nil {
diff --git a/go/internal/e2e/connection_token_test.go b/go/internal/e2e/connection_token_test.go
index f68bb0bf8..6d36000b3 100644
--- a/go/internal/e2e/connection_token_test.go
+++ b/go/internal/e2e/connection_token_test.go
@@ -13,7 +13,7 @@ func TestConnectionToken(t *testing.T) {
t.Run("explicit token round-trips successfully", func(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.TcpConnection{
+ opts.Connection = copilot.TCPConnection{
Path: ctx.CLIPath,
ConnectionToken: "right-token",
}
@@ -36,7 +36,7 @@ func TestConnectionToken(t *testing.T) {
t.Run("auto-generated token round-trips successfully", func(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.TcpConnection{Path: ctx.CLIPath}
+ opts.Connection = copilot.TCPConnection{Path: ctx.CLIPath}
})
t.Cleanup(func() { client.ForceStop() })
@@ -56,7 +56,7 @@ func TestConnectionToken(t *testing.T) {
t.Run("sibling client with wrong token is rejected", func(t *testing.T) {
ctx := testharness.NewTestContext(t)
good := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.TcpConnection{
+ opts.Connection = copilot.TCPConnection{
Path: ctx.CLIPath,
ConnectionToken: "right-token",
}
@@ -72,7 +72,7 @@ func TestConnectionToken(t *testing.T) {
}
bad := copilot.NewClient(&copilot.ClientOptions{
- Connection: copilot.UriConnection{
+ Connection: copilot.URIConnection{
URL: fmt.Sprintf("localhost:%d", port),
ConnectionToken: "wrong",
},
@@ -91,7 +91,7 @@ func TestConnectionToken(t *testing.T) {
t.Run("sibling client with no token is rejected", func(t *testing.T) {
ctx := testharness.NewTestContext(t)
good := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.TcpConnection{
+ opts.Connection = copilot.TCPConnection{
Path: ctx.CLIPath,
ConnectionToken: "right-token",
}
@@ -107,7 +107,7 @@ func TestConnectionToken(t *testing.T) {
}
none := copilot.NewClient(&copilot.ClientOptions{
- Connection: copilot.UriConnection{URL: fmt.Sprintf("localhost:%d", port)},
+ Connection: copilot.URIConnection{URL: fmt.Sprintf("localhost:%d", port)},
})
t.Cleanup(func() { none.ForceStop() })
diff --git a/go/internal/e2e/mcp_and_agents_e2e_test.go b/go/internal/e2e/mcp_and_agents_e2e_test.go
index 4c7f29bc8..e4bd34e26 100644
--- a/go/internal/e2e/mcp_and_agents_e2e_test.go
+++ b/go/internal/e2e/mcp_and_agents_e2e_test.go
@@ -31,7 +31,7 @@ func TestMCPServersE2E(t *testing.T) {
if session.SessionID == "" {
t.Error("Expected non-empty session ID")
}
- waitForMCPServerStatus(t, session, "test-server", rpc.McpServerStatusConnected)
+ waitForMCPServerStatus(t, session, "test-server", rpc.MCPServerStatusConnected)
// Simple interaction to verify session works
_, err = session.Send(t.Context(), copilot.MessageOptions{
@@ -59,7 +59,7 @@ func TestMCPServersE2E(t *testing.T) {
mcpServers := map[string]copilot.MCPServerConfig{
"test-server": copilot.MCPStdioServerConfig{
Command: "git",
- Tools: &[]string{"*"},
+ Tools: []string{"*"},
},
}
@@ -107,7 +107,7 @@ func TestMCPServersE2E(t *testing.T) {
if session2.SessionID != sessionID {
t.Errorf("Expected session ID %s, got %s", sessionID, session2.SessionID)
}
- waitForMCPServerStatus(t, session2, "test-server", rpc.McpServerStatusConnected)
+ waitForMCPServerStatus(t, session2, "test-server", rpc.MCPServerStatusConnected)
session2.Disconnect()
})
@@ -125,7 +125,7 @@ func TestMCPServersE2E(t *testing.T) {
"env-echo": copilot.MCPStdioServerConfig{
Command: "node",
Args: []string{mcpServerPath},
- Tools: &[]string{"*"},
+ Tools: []string{"*"},
Env: map[string]string{"TEST_SECRET": "hunter2"},
WorkingDirectory: mcpServerDir,
},
@@ -142,7 +142,7 @@ func TestMCPServersE2E(t *testing.T) {
if session.SessionID == "" {
t.Error("Expected non-empty session ID")
}
- waitForMCPServerStatus(t, session, "env-echo", rpc.McpServerStatusConnected)
+ waitForMCPServerStatus(t, session, "env-echo", rpc.MCPServerStatusConnected)
message, err := session.SendAndWait(t.Context(), copilot.MessageOptions{
Prompt: "Use the env-echo/get_env tool to read the TEST_SECRET environment variable. Reply with just the value, nothing else.",
@@ -174,8 +174,8 @@ func TestMCPServersE2E(t *testing.T) {
if session.SessionID == "" {
t.Error("Expected non-empty session ID")
}
- waitForMCPServerStatus(t, session, "server1", rpc.McpServerStatusConnected)
- waitForMCPServerStatus(t, session, "server2", rpc.McpServerStatusConnected)
+ waitForMCPServerStatus(t, session, "server1", rpc.MCPServerStatusConnected)
+ waitForMCPServerStatus(t, session, "server2", rpc.MCPServerStatusConnected)
session.Disconnect()
})
@@ -408,7 +408,7 @@ func TestCombinedConfigurationE2E(t *testing.T) {
if session.SessionID == "" {
t.Error("Expected non-empty session ID")
}
- waitForMCPServerStatus(t, session, "shared-server", rpc.McpServerStatusConnected)
+ waitForMCPServerStatus(t, session, "shared-server", rpc.MCPServerStatusConnected)
session.Disconnect()
})
diff --git a/go/internal/e2e/mcp_server_helpers_test.go b/go/internal/e2e/mcp_server_helpers_test.go
index f6cf2ad6b..1860067ed 100644
--- a/go/internal/e2e/mcp_server_helpers_test.go
+++ b/go/internal/e2e/mcp_server_helpers_test.go
@@ -23,20 +23,20 @@ func testMCPServers(t *testing.T, serverNames ...string) map[string]copilot.MCPS
mcpServers[serverName] = copilot.MCPStdioServerConfig{
Command: "node",
Args: []string{mcpServerPath},
- Tools: &[]string{"*"},
+ Tools: []string{"*"},
WorkingDirectory: mcpServerDir,
}
}
return mcpServers
}
-func waitForMCPServerStatus(t *testing.T, session *copilot.Session, serverName string, expectedStatus rpc.McpServerStatus) {
+func waitForMCPServerStatus(t *testing.T, session *copilot.Session, serverName string, expectedStatus rpc.MCPServerStatus) {
t.Helper()
var lastStatus string
deadline := time.Now().Add(60 * time.Second)
for time.Now().Before(deadline) {
- result, err := session.RPC.Mcp.List(t.Context())
+ result, err := session.RPC.MCP.List(t.Context())
if err != nil {
lastStatus = err.Error()
} else {
diff --git a/go/internal/e2e/multi_client_e2e_test.go b/go/internal/e2e/multi_client_e2e_test.go
index a5c852bc8..742145536 100644
--- a/go/internal/e2e/multi_client_e2e_test.go
+++ b/go/internal/e2e/multi_client_e2e_test.go
@@ -18,7 +18,7 @@ func TestMultiClientE2E(t *testing.T) {
// Use TCP mode so a second client can connect to the same CLI process
ctx := testharness.NewTestContext(t)
client1 := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.TcpConnection{Path: opts.Connection.(copilot.StdioConnection).Path, ConnectionToken: sharedTcpToken}
+ opts.Connection = copilot.TCPConnection{Path: opts.Connection.(copilot.StdioConnection).Path, ConnectionToken: sharedTCPToken}
})
t.Cleanup(func() { client1.ForceStop() })
@@ -37,7 +37,7 @@ func TestMultiClientE2E(t *testing.T) {
}
client2 := copilot.NewClient(&copilot.ClientOptions{
- Connection: copilot.UriConnection{URL: fmt.Sprintf("localhost:%d", runtimePort), ConnectionToken: sharedTcpToken},
+ Connection: copilot.URIConnection{URL: fmt.Sprintf("localhost:%d", runtimePort), ConnectionToken: sharedTCPToken},
})
t.Cleanup(func() { client2.ForceStop() })
@@ -487,7 +487,7 @@ func TestMultiClientE2E(t *testing.T) {
// Recreate client2 for cleanup (but don't rejoin the session)
client2 = copilot.NewClient(&copilot.ClientOptions{
- Connection: copilot.UriConnection{URL: fmt.Sprintf("localhost:%d", runtimePort), ConnectionToken: sharedTcpToken},
+ Connection: copilot.URIConnection{URL: fmt.Sprintf("localhost:%d", runtimePort), ConnectionToken: sharedTCPToken},
})
// Now only stable_tool should be available
diff --git a/go/internal/e2e/pending_work_resume_e2e_test.go b/go/internal/e2e/pending_work_resume_e2e_test.go
index 552886413..00419aec5 100644
--- a/go/internal/e2e/pending_work_resume_e2e_test.go
+++ b/go/internal/e2e/pending_work_resume_e2e_test.go
@@ -1,7 +1,6 @@
package e2e
import (
- "context"
"errors"
"fmt"
"strings"
@@ -18,17 +17,17 @@ const pendingWorkTimeout = 60 * time.Second
// Mirrors dotnet/test/PendingWorkResumeTests.cs (snapshot category "pending_work_resume").
//
-// Each subtest spawns a TCP server client, connects a "suspended" client through CLIUrl,
-// triggers some pending work (permission request or external tool call), then ForceStops
-// the suspended client (preserving session state) and resumes from a fresh client with
-// ContinuePendingWork=true.
+// Most subtests spawn a TCP server client, connect a "suspended" client through URIConnection
+// trigger pending work, then ForceStop the suspended client (preserving session state)
+// and resume from a fresh client with ContinuePendingWork=true. Warm-join coverage keeps
+// the original client connected while a second client resumes the same session.
func TestPendingWorkResumeE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
t.Run("should continue pending permission request after resume", func(t *testing.T) {
ctx.ConfigureForTest(t)
- _, cliURL := startTcpServer(t, ctx)
+ _, cliURL := startTCPServer(t, ctx)
type ValueParams struct {
Value string `json:"value" jsonschema:"Value to transform"`
@@ -43,7 +42,7 @@ func TestPendingWorkResumeE2E(t *testing.T) {
releasePermission := make(chan rpc.PermissionDecision, 1)
suspendedClient := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.UriConnection{URL: cliURL, ConnectionToken: sharedTcpToken}
+ opts.Connection = copilot.URIConnection{URL: cliURL, ConnectionToken: sharedTCPToken}
})
session1, err := suspendedClient.CreateSession(t.Context(), &copilot.SessionConfig{
Tools: []copilot.Tool{originalTool},
@@ -97,23 +96,18 @@ func TestPendingWorkResumeE2E(t *testing.T) {
// Snap the suspended client offline before the original handler resolves.
suspendedClient.ForceStop()
- var resumedToolInvoked bool
- var mu sync.Mutex
resumedTool := copilot.DefineTool("resume_permission_tool", "Transforms a value after permission is granted",
func(params ValueParams, inv copilot.ToolInvocation) (string, error) {
- mu.Lock()
- resumedToolInvoked = true
- mu.Unlock()
return "PERMISSION_RESUMED_" + strings.ToUpper(params.Value), nil
})
resumedClient := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.UriConnection{URL: cliURL, ConnectionToken: sharedTcpToken}
+ opts.Connection = copilot.URIConnection{URL: cliURL, ConnectionToken: sharedTCPToken}
})
t.Cleanup(func() { resumedClient.ForceStop() })
session2, err := resumedClient.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{
- ContinuePendingWork: true,
+ ContinuePendingWork: copilot.Bool(true),
OnPermissionRequest: func(_ copilot.PermissionRequest, _ copilot.PermissionInvocation) (rpc.PermissionDecision, error) {
return &rpc.PermissionDecisionNoResult{}, nil
},
@@ -134,24 +128,6 @@ func TestPendingWorkResumeE2E(t *testing.T) {
t.Fatalf("Expected HandlePendingPermissionRequest to succeed, got %+v", permResult)
}
- ctxFinal, cancel := context.WithTimeout(t.Context(), pendingWorkTimeout)
- defer cancel()
- answer, err := testharness.GetFinalAssistantMessage(ctxFinal, session2)
- if err != nil {
- t.Fatalf("Failed to wait for final assistant message: %v", err)
- }
-
- mu.Lock()
- invoked := resumedToolInvoked
- mu.Unlock()
- if !invoked {
- t.Error("Expected resumed tool implementation to be invoked")
- }
-
- if assistant, ok := answer.Data.(*copilot.AssistantMessageData); !ok || !strings.Contains(assistant.Content, "PERMISSION_RESUMED_ALPHA") {
- t.Errorf("Expected response to contain 'PERMISSION_RESUMED_ALPHA', got %v", answer.Data)
- }
-
// Allow original handler to unblock so cleanup proceeds.
select {
case releasePermission <- &rpc.PermissionDecisionUserNotAvailable{}:
@@ -164,7 +140,7 @@ func TestPendingWorkResumeE2E(t *testing.T) {
t.Run("should continue pending external tool request after resume", func(t *testing.T) {
ctx.ConfigureForTest(t)
- _, cliURL := startTcpServer(t, ctx)
+ _, cliURL := startTCPServer(t, ctx)
type ValueParams struct {
Value string `json:"value" jsonschema:"Value to look up"`
@@ -183,7 +159,7 @@ func TestPendingWorkResumeE2E(t *testing.T) {
})
suspendedClient := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.UriConnection{URL: cliURL, ConnectionToken: sharedTcpToken}
+ opts.Connection = copilot.URIConnection{URL: cliURL, ConnectionToken: sharedTCPToken}
})
session1, err := suspendedClient.CreateSession(t.Context(), &copilot.SessionConfig{
Tools: []copilot.Tool{originalTool},
@@ -219,12 +195,12 @@ func TestPendingWorkResumeE2E(t *testing.T) {
suspendedClient.ForceStop()
resumedClient := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.UriConnection{URL: cliURL, ConnectionToken: sharedTcpToken}
+ opts.Connection = copilot.URIConnection{URL: cliURL, ConnectionToken: sharedTCPToken}
})
t.Cleanup(func() { resumedClient.ForceStop() })
session2, err := resumedClient.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{
- ContinuePendingWork: true,
+ ContinuePendingWork: copilot.Bool(true),
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
if err != nil {
@@ -242,16 +218,6 @@ func TestPendingWorkResumeE2E(t *testing.T) {
t.Errorf("Expected HandlePendingToolCall to succeed, got %+v", toolResult)
}
- ctxFinal, cancel := context.WithTimeout(t.Context(), pendingWorkTimeout)
- defer cancel()
- answer, err := testharness.GetFinalAssistantMessage(ctxFinal, session2)
- if err != nil {
- t.Fatalf("Failed to wait for final assistant message: %v", err)
- }
- if assistant, ok := answer.Data.(*copilot.AssistantMessageData); !ok || !strings.Contains(assistant.Content, "EXTERNAL_RESUMED_BETA") {
- t.Errorf("Expected response to contain 'EXTERNAL_RESUMED_BETA', got %v", answer.Data)
- }
-
select {
case releaseTool <- "ORIGINAL_SHOULD_NOT_WIN":
default:
@@ -263,7 +229,7 @@ func TestPendingWorkResumeE2E(t *testing.T) {
t.Run("should continue parallel pending external tool requests after resume", func(t *testing.T) {
ctx.ConfigureForTest(t)
- _, cliURL := startTcpServer(t, ctx)
+ _, cliURL := startTCPServer(t, ctx)
type ValueParams struct {
Value string `json:"value" jsonschema:"Value to look up"`
@@ -291,7 +257,7 @@ func TestPendingWorkResumeE2E(t *testing.T) {
})
suspendedClient := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.UriConnection{URL: cliURL, ConnectionToken: sharedTcpToken}
+ opts.Connection = copilot.URIConnection{URL: cliURL, ConnectionToken: sharedTCPToken}
})
session1, err := suspendedClient.CreateSession(t.Context(), &copilot.SessionConfig{
Tools: []copilot.Tool{originalA, originalB},
@@ -334,12 +300,12 @@ func TestPendingWorkResumeE2E(t *testing.T) {
suspendedClient.ForceStop()
resumedClient := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.UriConnection{URL: cliURL, ConnectionToken: sharedTcpToken}
+ opts.Connection = copilot.URIConnection{URL: cliURL, ConnectionToken: sharedTCPToken}
})
t.Cleanup(func() { resumedClient.ForceStop() })
session2, err := resumedClient.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{
- ContinuePendingWork: true,
+ ContinuePendingWork: copilot.Bool(true),
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
if err != nil {
@@ -377,12 +343,12 @@ func TestPendingWorkResumeE2E(t *testing.T) {
t.Run("should resume successfully when no pending work exists", func(t *testing.T) {
ctx.ConfigureForTest(t)
- _, cliURL := startTcpServer(t, ctx)
+ _, cliURL := startTCPServer(t, ctx)
var sessionID string
func() {
firstClient := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.UriConnection{URL: cliURL, ConnectionToken: sharedTcpToken}
+ opts.Connection = copilot.URIConnection{URL: cliURL, ConnectionToken: sharedTCPToken}
})
defer firstClient.ForceStop()
@@ -408,12 +374,12 @@ func TestPendingWorkResumeE2E(t *testing.T) {
}()
resumedClient := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.UriConnection{URL: cliURL, ConnectionToken: sharedTcpToken}
+ opts.Connection = copilot.URIConnection{URL: cliURL, ConnectionToken: sharedTCPToken}
})
t.Cleanup(func() { resumedClient.ForceStop() })
resumedSession, err := resumedClient.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{
- ContinuePendingWork: true,
+ ContinuePendingWork: copilot.Bool(true),
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
if err != nil {
@@ -433,131 +399,177 @@ func TestPendingWorkResumeE2E(t *testing.T) {
resumedSession.Disconnect()
})
- t.Run("should keep pending external tool handleable on warm resume when continuependingwork is false", func(t *testing.T) {
- ctx.ConfigureForTest(t)
-
- _, cliURL := startTcpServer(t, ctx)
-
- type ValueParams struct {
- Value string `json:"value" jsonschema:"Value to look up"`
- }
- toolStarted := make(chan string, 1)
- releaseTool := make(chan string, 1)
-
- originalTool := copilot.DefineTool("resume_external_tool", "Looks up a value after resumption",
- func(params ValueParams, inv copilot.ToolInvocation) (string, error) {
- select {
- case toolStarted <- params.Value:
- default:
- }
- return <-releaseTool, nil
+ for _, scenario := range []struct {
+ name string
+ disconnectOriginalClient bool
+ expectedSessionWasActive bool
+ expectedHandleResult bool
+ }{
+ {name: "warm", disconnectOriginalClient: false, expectedSessionWasActive: true, expectedHandleResult: true},
+ {name: "cold", disconnectOriginalClient: true, expectedSessionWasActive: false, expectedHandleResult: false},
+ } {
+ scenario := scenario
+ t.Run(fmt.Sprintf("should keep pending external tool handleable on %s resume when continuependingwork is false", scenario.name), func(t *testing.T) {
+ ctx.ConfigureForTest(t)
+
+ _, cliURL := startTCPServer(t, ctx)
+
+ type ValueParams struct {
+ Value string `json:"value" jsonschema:"Value to look up"`
+ }
+ toolStarted := make(chan string, 1)
+ releaseTool := make(chan string, 1)
+
+ originalTool := copilot.DefineTool("resume_external_tool", "Looks up a value after resumption",
+ func(params ValueParams, inv copilot.ToolInvocation) (string, error) {
+ select {
+ case toolStarted <- params.Value:
+ default:
+ }
+ return <-releaseTool, nil
+ })
+
+ suspendedClient := ctx.NewClient(func(opts *copilot.ClientOptions) {
+ opts.Connection = copilot.URIConnection{URL: cliURL, ConnectionToken: sharedTCPToken}
})
+ if !scenario.disconnectOriginalClient {
+ defer suspendedClient.ForceStop()
+ }
+ session1, err := suspendedClient.CreateSession(t.Context(), &copilot.SessionConfig{
+ Tools: []copilot.Tool{originalTool},
+ OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
+ })
+ if err != nil {
+ t.Fatalf("Failed to create session: %v", err)
+ }
+ sessionID := session1.SessionID
- suspendedClient := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.UriConnection{URL: cliURL, ConnectionToken: sharedTcpToken}
- })
- session1, err := suspendedClient.CreateSession(t.Context(), &copilot.SessionConfig{
- Tools: []copilot.Tool{originalTool},
- OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
- })
- if err != nil {
- t.Fatalf("Failed to create session: %v", err)
- }
- sessionID := session1.SessionID
-
- toolEventCh := waitForExternalToolRequests(session1, []string{"resume_external_tool"})
+ toolEventCh := waitForExternalToolRequests(session1, []string{"resume_external_tool"})
- if _, err := session1.Send(t.Context(), copilot.MessageOptions{
- Prompt: "Use resume_external_tool with value 'beta', then reply with the result.",
- }); err != nil {
- t.Fatalf("Failed to send message: %v", err)
- }
+ if _, err := session1.Send(t.Context(), copilot.MessageOptions{
+ Prompt: "Use resume_external_tool with value 'beta', then reply with the result.",
+ }); err != nil {
+ t.Fatalf("Failed to send message: %v", err)
+ }
- toolEvents, err := waitForExternalToolResults(toolEventCh, pendingWorkTimeout)
- if err != nil {
- t.Fatalf("waiting for external tool requests: %v", err)
- }
- toolEvent := toolEvents["resume_external_tool"]
+ toolEvents, err := waitForExternalToolResults(toolEventCh, pendingWorkTimeout)
+ if err != nil {
+ t.Fatalf("waiting for external tool requests: %v", err)
+ }
+ toolEvent := toolEvents["resume_external_tool"]
- select {
- case v := <-toolStarted:
- if v != "beta" {
- t.Errorf("Expected original tool started with 'beta', got %q", v)
+ select {
+ case v := <-toolStarted:
+ if v != "beta" {
+ t.Errorf("Expected original tool started with 'beta', got %q", v)
+ }
+ case <-time.After(pendingWorkTimeout):
+ t.Fatal("Timed out waiting for original tool to start")
}
- case <-time.After(pendingWorkTimeout):
- t.Fatal("Timed out waiting for original tool to start")
- }
- suspendedClient.ForceStop()
+ if scenario.disconnectOriginalClient {
+ suspendedClient.ForceStop()
+ }
- resumedClient := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.UriConnection{URL: cliURL, ConnectionToken: sharedTcpToken}
- })
- t.Cleanup(func() { resumedClient.ForceStop() })
+ resumedClient := ctx.NewClient(func(opts *copilot.ClientOptions) {
+ opts.Connection = copilot.URIConnection{URL: cliURL, ConnectionToken: sharedTCPToken}
+ })
+ t.Cleanup(func() { resumedClient.ForceStop() })
+
+ // In warm mode the original client still owns the tool registration;
+ // re-registering it from the resumed client would cause a name-clash. In
+ // cold mode the original is gone, so we register a fresh throwing handler
+ // to assert the runtime doesn't re-invoke the tool on resume (orphan
+ // auto-completion happens internally).
+ resumeConfig := &copilot.ResumeSessionConfig{
+ ContinuePendingWork: copilot.Bool(false),
+ OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
+ }
+ if scenario.disconnectOriginalClient {
+ resumeConfig.Tools = []copilot.Tool{
+ copilot.DefineTool("resume_external_tool", "Looks up a value after resumption",
+ func(_ ValueParams, _ copilot.ToolInvocation) (string, error) {
+ t.Errorf("Resumed-session handler should not be invoked")
+ return "", fmt.Errorf("resumed-session handler should not be invoked")
+ }),
+ }
+ }
- session2, err := resumedClient.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{
- ContinuePendingWork: false,
- OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
- })
- if err != nil {
- t.Fatalf("Failed to resume session: %v", err)
- }
+ session2, err := resumedClient.ResumeSession(t.Context(), sessionID, resumeConfig)
+ if err != nil {
+ t.Fatalf("Failed to resume session: %v", err)
+ }
- // Verify resume event reflects ContinuePendingWork=false and SessionWasActive=true
- messages, err := session2.GetEvents(t.Context())
- if err != nil {
- t.Fatalf("GetEvents failed: %v", err)
- }
- var resumeEvent *copilot.SessionResumeData
- for _, msg := range messages {
- if msg.Type() == copilot.SessionEventTypeSessionResume {
- if d, ok := msg.Data.(*copilot.SessionResumeData); ok {
- resumeEvent = d
- break
+ messages, err := session2.GetEvents(t.Context())
+ if err != nil {
+ t.Fatalf("GetEvents failed: %v", err)
+ }
+ var resumeEvent *copilot.SessionResumeData
+ for _, msg := range messages {
+ if msg.Type() == copilot.SessionEventTypeSessionResume {
+ if d, ok := msg.Data.(*copilot.SessionResumeData); ok {
+ resumeEvent = d
+ break
+ }
}
}
- }
- if resumeEvent == nil {
- t.Fatal("Expected a session.resume event")
- return
- }
- if resumeEvent.ContinuePendingWork == nil || *resumeEvent.ContinuePendingWork != false {
- t.Errorf("Expected ContinuePendingWork=false in resume event, got %v", resumeEvent.ContinuePendingWork)
- }
- if resumeEvent.SessionWasActive == nil || *resumeEvent.SessionWasActive != true {
- t.Errorf("Expected SessionWasActive=true in resume event, got %v", resumeEvent.SessionWasActive)
- }
+ if resumeEvent == nil {
+ t.Fatal("Expected a session.resume event")
+ return
+ }
+ if resumeEvent.ContinuePendingWork != nil && *resumeEvent.ContinuePendingWork {
+ t.Errorf("Expected ContinuePendingWork=false in resume event, got %v", resumeEvent.ContinuePendingWork)
+ }
+ if resumeEvent.SessionWasActive == nil || *resumeEvent.SessionWasActive != scenario.expectedSessionWasActive {
+ t.Errorf("Expected SessionWasActive=%t in resume event, got %v", scenario.expectedSessionWasActive, resumeEvent.SessionWasActive)
+ }
- // Even with ContinuePendingWork=false, the pending tool call should still be
- // handleable via HandlePendingToolCall.
- toolResult, err := session2.RPC.Tools.HandlePendingToolCall(t.Context(), &rpc.HandlePendingToolCallRequest{
- RequestID: toolEvent.RequestID,
- Result: rpc.ExternalToolStringResult("EXTERNAL_RESUMED_BETA"),
- })
- if err != nil {
- t.Fatalf("Failed to handle pending tool call: %v", err)
- }
- if !toolResult.Success {
- t.Errorf("Expected HandlePendingToolCall to succeed, got %+v", toolResult)
- }
+ // In warm mode the runtime still has the pending request; in cold mode the
+ // runtime auto-completed the orphan with a synthetic interrupt result during
+ // resume, so HandlePendingToolCall is expected to report Success=false.
+ toolResult, err := session2.RPC.Tools.HandlePendingToolCall(t.Context(), &rpc.HandlePendingToolCallRequest{
+ RequestID: toolEvent.RequestID,
+ Result: rpc.ExternalToolStringResult("EXTERNAL_RESUMED_BETA"),
+ })
+ if err != nil {
+ t.Fatalf("Failed to handle pending tool call: %v", err)
+ }
+ if toolResult.Success != scenario.expectedHandleResult {
+ t.Errorf("Expected HandlePendingToolCall Success=%t, got %+v", scenario.expectedHandleResult, toolResult)
+ }
- select {
- case releaseTool <- "ORIGINAL_SHOULD_NOT_WIN":
- default:
- }
+ if !scenario.expectedHandleResult {
+ // Cold path: orphan auto-completion does not trigger an LLM turn on its
+ // own, but the session should remain healthy for new work.
+ followUp, err := session2.SendAndWait(t.Context(), copilot.MessageOptions{
+ Prompt: "Reply with exactly: COLD_RESUMED_FOLLOWUP",
+ })
+ if err != nil {
+ t.Fatalf("Failed to send follow-up turn: %v", err)
+ }
+ if assistant, ok := followUp.Data.(*copilot.AssistantMessageData); !ok || !strings.Contains(assistant.Content, "COLD_RESUMED_FOLLOWUP") {
+ t.Errorf("Expected follow-up answer to contain 'COLD_RESUMED_FOLLOWUP', got %v", followUp.Data)
+ }
+ }
- session2.Disconnect()
- })
+ select {
+ case releaseTool <- "ORIGINAL_SHOULD_NOT_WIN":
+ default:
+ }
+
+ session2.Disconnect()
+ })
+ }
t.Run("should report continuependingwork true in resume event", func(t *testing.T) {
ctx.ConfigureForTest(t)
- _, cliURL := startTcpServer(t, ctx)
+ _, cliURL := startTCPServer(t, ctx)
var sessionID string
func() {
firstClient := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.UriConnection{URL: cliURL, ConnectionToken: sharedTcpToken}
+ opts.Connection = copilot.URIConnection{URL: cliURL, ConnectionToken: sharedTCPToken}
})
defer firstClient.ForceStop()
@@ -583,12 +595,12 @@ func TestPendingWorkResumeE2E(t *testing.T) {
}()
resumedClient := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.UriConnection{URL: cliURL, ConnectionToken: sharedTcpToken}
+ opts.Connection = copilot.URIConnection{URL: cliURL, ConnectionToken: sharedTCPToken}
})
t.Cleanup(func() { resumedClient.ForceStop() })
resumedSession, err := resumedClient.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{
- ContinuePendingWork: true,
+ ContinuePendingWork: copilot.Bool(true),
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
if err != nil {
@@ -646,18 +658,18 @@ func serverCliURL(t *testing.T, server *copilot.Client) string {
return fmt.Sprintf("localhost:%d", port)
}
-// sharedTcpToken is the connection token used by startTcpServer and any sibling
+// sharedTCPToken is the connection token used by startTCPServer and any sibling
// client that connects via the resulting CLI URL. Tests use a fixed token rather
// than the auto-generated one because the second client is constructed without
// access to the first client's internal state.
-const sharedTcpToken = "tcp-shared-test-token"
+const sharedTCPToken = "tcp-shared-test-token"
-// startTcpServer starts a TCP-mode server client and returns its CLI URL.
+// startTCPServer starts a TCP-mode server client and returns its CLI URL.
// It triggers an initial connection so RuntimePort is populated.
-func startTcpServer(t *testing.T, ctx *testharness.TestContext) (*copilot.Client, string) {
+func startTCPServer(t *testing.T, ctx *testharness.TestContext) (*copilot.Client, string) {
t.Helper()
server := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.TcpConnection{Path: opts.Connection.(copilot.StdioConnection).Path, ConnectionToken: sharedTcpToken}
+ opts.Connection = copilot.TCPConnection{Path: opts.Connection.(copilot.StdioConnection).Path, ConnectionToken: sharedTCPToken}
})
t.Cleanup(func() { server.ForceStop() })
// Trigger connection so we can read the port. CreateSession+Disconnect is the
diff --git a/go/internal/e2e/permissions_e2e_test.go b/go/internal/e2e/permissions_e2e_test.go
index 9d3b11da8..60a0e65f3 100644
--- a/go/internal/e2e/permissions_e2e_test.go
+++ b/go/internal/e2e/permissions_e2e_test.go
@@ -843,7 +843,7 @@ func TestPermissionsE2E(t *testing.T) {
IncludeTempDirectory: &includeTemp,
Unrestricted: &unrestricted,
},
- Urls: &rpc.PermissionUrlsConfig{
+ URLs: &rpc.PermissionURLsConfig{
InitialAllowed: []string{"https://example.invalid/permissions-configure"},
Unrestricted: &unrestricted,
},
@@ -971,18 +971,18 @@ func TestPermissionsE2E(t *testing.T) {
t.Fatalf("Expected ModifyRules(remove) Success=true")
}
- enableUrls, err := session.RPC.Permissions.Urls().SetUnrestrictedMode(t.Context(), &rpc.PermissionUrlsSetUnrestrictedModeParams{Enabled: true})
+ enableURLs, err := session.RPC.Permissions.URLs().SetUnrestrictedMode(t.Context(), &rpc.PermissionURLsSetUnrestrictedModeParams{Enabled: true})
if err != nil {
- t.Fatalf("Permissions.Urls.SetUnrestrictedMode(true) failed: %v", err)
+ t.Fatalf("Permissions.URLs.SetUnrestrictedMode(true) failed: %v", err)
}
- if !enableUrls.Success {
+ if !enableURLs.Success {
t.Fatalf("Expected SetUnrestrictedMode(true) Success=true")
}
- disableUrls, err := session.RPC.Permissions.Urls().SetUnrestrictedMode(t.Context(), &rpc.PermissionUrlsSetUnrestrictedModeParams{Enabled: false})
+ disableURLs, err := session.RPC.Permissions.URLs().SetUnrestrictedMode(t.Context(), &rpc.PermissionURLsSetUnrestrictedModeParams{Enabled: false})
if err != nil {
- t.Fatalf("Permissions.Urls.SetUnrestrictedMode(false) failed: %v", err)
+ t.Fatalf("Permissions.URLs.SetUnrestrictedMode(false) failed: %v", err)
}
- if !disableUrls.Success {
+ if !disableURLs.Success {
t.Fatalf("Expected SetUnrestrictedMode(false) Success=true")
}
})
diff --git a/go/internal/e2e/pre_mcp_tool_call_hook_e2e_test.go b/go/internal/e2e/pre_mcp_tool_call_hook_e2e_test.go
index 2253f3825..184727092 100644
--- a/go/internal/e2e/pre_mcp_tool_call_hook_e2e_test.go
+++ b/go/internal/e2e/pre_mcp_tool_call_hook_e2e_test.go
@@ -10,7 +10,7 @@ import (
"github.com/github/copilot-sdk/go/internal/e2e/testharness"
)
-func TestPreMcpToolCallHookE2E(t *testing.T) {
+func TestPreMCPToolCallHookE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient()
t.Cleanup(func() { client.ForceStop() })
@@ -19,13 +19,12 @@ func TestPreMcpToolCallHookE2E(t *testing.T) {
metaEchoServer := filepath.Join(testHarnessDir, "test-mcp-meta-echo-server.mjs")
metaEchoConfig := func() map[string]copilot.MCPServerConfig {
- tools := []string{"*"}
return map[string]copilot.MCPServerConfig{
"meta-echo": copilot.MCPStdioServerConfig{
Command: "node",
Args: []string{metaEchoServer},
WorkingDirectory: testHarnessDir,
- Tools: &tools,
+ Tools: []string{"*"},
},
}
}
@@ -35,18 +34,18 @@ func TestPreMcpToolCallHookE2E(t *testing.T) {
var (
mu sync.Mutex
- inputs []copilot.PreMcpToolCallHookInput
+ inputs []copilot.PreMCPToolCallHookInput
)
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
MCPServers: metaEchoConfig(),
Hooks: &copilot.SessionHooks{
- OnPreMcpToolCall: func(input copilot.PreMcpToolCallHookInput, invocation copilot.HookInvocation) (*copilot.PreMcpToolCallHookOutput, error) {
+ OnPreMCPToolCall: func(input copilot.PreMCPToolCallHookInput, invocation copilot.HookInvocation) (*copilot.PreMCPToolCallHookOutput, error) {
mu.Lock()
inputs = append(inputs, input)
mu.Unlock()
- return &copilot.PreMcpToolCallHookOutput{
+ return &copilot.PreMCPToolCallHookOutput{
MetaToUse: map[string]any{
"injected": "by-hook",
"source": "test",
@@ -98,18 +97,18 @@ func TestPreMcpToolCallHookE2E(t *testing.T) {
var (
mu sync.Mutex
- inputs []copilot.PreMcpToolCallHookInput
+ inputs []copilot.PreMCPToolCallHookInput
)
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
MCPServers: metaEchoConfig(),
Hooks: &copilot.SessionHooks{
- OnPreMcpToolCall: func(input copilot.PreMcpToolCallHookInput, invocation copilot.HookInvocation) (*copilot.PreMcpToolCallHookOutput, error) {
+ OnPreMCPToolCall: func(input copilot.PreMCPToolCallHookInput, invocation copilot.HookInvocation) (*copilot.PreMCPToolCallHookOutput, error) {
mu.Lock()
inputs = append(inputs, input)
mu.Unlock()
- return &copilot.PreMcpToolCallHookOutput{
+ return &copilot.PreMCPToolCallHookOutput{
MetaToUse: map[string]any{
"completely": "replaced",
},
@@ -154,18 +153,18 @@ func TestPreMcpToolCallHookE2E(t *testing.T) {
var (
mu sync.Mutex
- inputs []copilot.PreMcpToolCallHookInput
+ inputs []copilot.PreMCPToolCallHookInput
)
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
MCPServers: metaEchoConfig(),
Hooks: &copilot.SessionHooks{
- OnPreMcpToolCall: func(input copilot.PreMcpToolCallHookInput, invocation copilot.HookInvocation) (*copilot.PreMcpToolCallHookOutput, error) {
+ OnPreMCPToolCall: func(input copilot.PreMCPToolCallHookInput, invocation copilot.HookInvocation) (*copilot.PreMCPToolCallHookOutput, error) {
mu.Lock()
inputs = append(inputs, input)
mu.Unlock()
- return &copilot.PreMcpToolCallHookOutput{
+ return &copilot.PreMCPToolCallHookOutput{
MetaToUse: nil,
}, nil
},
diff --git a/go/internal/e2e/rpc_e2e_test.go b/go/internal/e2e/rpc_e2e_test.go
index ccbf26d1d..fcf843814 100644
--- a/go/internal/e2e/rpc_e2e_test.go
+++ b/go/internal/e2e/rpc_e2e_test.go
@@ -9,7 +9,7 @@ import (
"github.com/github/copilot-sdk/go/rpc"
)
-func TestRpcE2E(t *testing.T) {
+func TestRPCE2E(t *testing.T) {
cliPath := testharness.CLIPath()
if cliPath == "" {
t.Fatal("CLI not found. Run 'npm install' in the nodejs directory first.")
@@ -113,7 +113,7 @@ func TestRpcE2E(t *testing.T) {
})
}
-func TestSessionRpcE2E(t *testing.T) {
+func TestSessionRPCE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient()
t.Cleanup(func() { client.ForceStop() })
diff --git a/go/internal/e2e/rpc_event_log_e2e_test.go b/go/internal/e2e/rpc_event_log_e2e_test.go
index 63614b4e2..4e491026c 100644
--- a/go/internal/e2e/rpc_event_log_e2e_test.go
+++ b/go/internal/e2e/rpc_event_log_e2e_test.go
@@ -12,7 +12,7 @@ import (
const rpcEventLogTimeout = 30 * time.Second
// Mirrors dotnet/test/E2E/RpcEventLogE2ETests.cs (snapshot category "rpc_event_log").
-func TestRpcEventLogE2E(t *testing.T) {
+func TestRPCEventLogE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient()
t.Cleanup(func() { client.ForceStop() })
@@ -29,7 +29,7 @@ func TestRpcEventLogE2E(t *testing.T) {
waitForRPCCondition(t, rpcEventLogTimeout, "persisted session.plan_changed event", func() (bool, error) {
var err error
read, err = session.RPC.EventLog.Read(t.Context(), &rpc.EventLogReadRequest{
- Max: rpcPtr(int32(100)),
+ Max: rpcPtr(int64(100)),
WaitMs: rpcPtr(int32(0)),
})
if err != nil {
@@ -67,7 +67,7 @@ func TestRpcEventLogE2E(t *testing.T) {
}
read, err = session.RPC.EventLog.Read(t.Context(), &rpc.EventLogReadRequest{
Cursor: &tail.Cursor,
- Max: rpcPtr(int32(10)),
+ Max: rpcPtr(int64(10)),
WaitMs: rpcPtr(int32(0)),
})
return err == nil && read.CursorStatus == rpc.EventsCursorStatusOk && len(read.Events) == 0, err
@@ -131,7 +131,7 @@ func TestRpcEventLogE2E(t *testing.T) {
go func() {
result, err := session.RPC.EventLog.Read(t.Context(), &rpc.EventLogReadRequest{
Cursor: &tail.Cursor,
- Max: rpcPtr(int32(10)),
+ Max: rpcPtr(int64(10)),
WaitMs: rpcPtr(int32(5000)),
Types: &rpc.EventLogTypes{StringArray: []string{string(copilot.SessionEventTypeSessionTitleChanged)}},
})
diff --git a/go/internal/e2e/rpc_event_side_effects_e2e_test.go b/go/internal/e2e/rpc_event_side_effects_e2e_test.go
index 765a570a2..ef66ec83e 100644
--- a/go/internal/e2e/rpc_event_side_effects_e2e_test.go
+++ b/go/internal/e2e/rpc_event_side_effects_e2e_test.go
@@ -14,7 +14,7 @@ import (
const rpcEventSideEffectsTimeout = 30 * time.Second
// Mirrors dotnet/test/RpcEventSideEffectsE2ETests.cs (snapshot category "rpc_event_side_effects").
-func TestRpcEventSideEffectsE2E(t *testing.T) {
+func TestRPCEventSideEffectsE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient()
t.Cleanup(func() { client.ForceStop() })
diff --git a/go/internal/e2e/rpc_mcp_and_skills_e2e_test.go b/go/internal/e2e/rpc_mcp_and_skills_e2e_test.go
index 9f358644b..22f53c48a 100644
--- a/go/internal/e2e/rpc_mcp_and_skills_e2e_test.go
+++ b/go/internal/e2e/rpc_mcp_and_skills_e2e_test.go
@@ -14,7 +14,7 @@ import (
// Mirrors dotnet/test/RpcMcpAndSkillsTests.cs (snapshot category "rpc_mcp_and_skills").
// Tests session-scoped MCP, skills, plugins, and extensions RPCs.
-func TestRpcMcpAndSkillsE2E(t *testing.T) {
+func TestRPCMCPAndSkillsE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
// --yolo auto-approves extension permission gates at the CLI level,
// preventing breakage from new gates (e.g., extension-permission-access).
@@ -27,7 +27,7 @@ func TestRpcMcpAndSkillsE2E(t *testing.T) {
t.Run("should list and toggle session skills", func(t *testing.T) {
skillName := fmt.Sprintf("session-rpc-skill-%s", randomHex(t))
- skillsDir := createMcpSkillsRpcDirectory(t, ctx.WorkDir, "session-rpc-skills", skillName, "Session skill controlled by RPC.")
+ skillsDir := createMCPSkillsRPCDirectory(t, ctx.WorkDir, "session-rpc-skills", skillName, "Session skill controlled by RPC.")
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
@@ -65,7 +65,7 @@ func TestRpcMcpAndSkillsE2E(t *testing.T) {
t.Run("should ensure skills are loaded and list invoked skills", func(t *testing.T) {
skillName := fmt.Sprintf("ensure-rpc-skill-%s", randomHex(t))
- skillsDir := createMcpSkillsRpcDirectory(t, ctx.WorkDir, "session-rpc-skills", skillName, "Skill loaded explicitly by RPC.")
+ skillsDir := createMCPSkillsRPCDirectory(t, ctx.WorkDir, "session-rpc-skills", skillName, "Skill loaded explicitly by RPC.")
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
@@ -150,10 +150,10 @@ func TestRpcMcpAndSkillsE2E(t *testing.T) {
t.Fatalf("CreateSession failed: %v", err)
}
- waitForMCPServerStatus(t, session, serverName, rpc.McpServerStatusConnected)
- result, err := session.RPC.Mcp.List(t.Context())
+ waitForMCPServerStatus(t, session, serverName, rpc.MCPServerStatusConnected)
+ result, err := session.RPC.MCP.List(t.Context())
if err != nil {
- t.Fatalf("Mcp.List failed: %v", err)
+ t.Fatalf("MCP.List failed: %v", err)
}
var found bool
for _, server := range result.Servers {
@@ -180,36 +180,36 @@ func TestRpcMcpAndSkillsE2E(t *testing.T) {
t.Fatalf("CreateSession failed: %v", err)
}
- waitForMCPServerStatus(t, session, serverName, rpc.McpServerStatusConnected)
- direct, err := session.RPC.Mcp.SetEnvValueMode(t.Context(), &rpc.McpSetEnvValueModeParams{Mode: rpc.McpSetEnvValueModeDetailsDirect})
+ waitForMCPServerStatus(t, session, serverName, rpc.MCPServerStatusConnected)
+ direct, err := session.RPC.MCP.SetEnvValueMode(t.Context(), &rpc.MCPSetEnvValueModeParams{Mode: rpc.MCPSetEnvValueModeDetailsDirect})
if err != nil {
- t.Fatalf("Mcp.SetEnvValueMode(direct) failed: %v", err)
+ t.Fatalf("MCP.SetEnvValueMode(direct) failed: %v", err)
}
- if direct.Mode != rpc.McpSetEnvValueModeDetailsDirect {
+ if direct.Mode != rpc.MCPSetEnvValueModeDetailsDirect {
t.Fatalf("Expected direct env value mode, got %+v", direct)
}
- indirect, err := session.RPC.Mcp.SetEnvValueMode(t.Context(), &rpc.McpSetEnvValueModeParams{Mode: rpc.McpSetEnvValueModeDetailsIndirect})
+ indirect, err := session.RPC.MCP.SetEnvValueMode(t.Context(), &rpc.MCPSetEnvValueModeParams{Mode: rpc.MCPSetEnvValueModeDetailsIndirect})
if err != nil {
- t.Fatalf("Mcp.SetEnvValueMode(indirect) failed: %v", err)
+ t.Fatalf("MCP.SetEnvValueMode(indirect) failed: %v", err)
}
- if indirect.Mode != rpc.McpSetEnvValueModeDetailsIndirect {
+ if indirect.Mode != rpc.MCPSetEnvValueModeDetailsIndirect {
t.Fatalf("Expected indirect env value mode, got %+v", indirect)
}
- removeGitHub, err := session.RPC.Mcp.RemoveGitHub(t.Context())
+ removeGitHub, err := session.RPC.MCP.RemoveGitHub(t.Context())
if err != nil {
- t.Fatalf("Mcp.RemoveGitHub failed: %v", err)
+ t.Fatalf("MCP.RemoveGitHub failed: %v", err)
}
if removeGitHub.Removed {
t.Fatalf("Expected RemoveGitHub=false for explicitly configured server, got %+v", removeGitHub)
}
- servers, err := session.RPC.Mcp.List(t.Context())
+ servers, err := session.RPC.MCP.List(t.Context())
if err != nil {
- t.Fatalf("Mcp.List failed: %v", err)
+ t.Fatalf("MCP.List failed: %v", err)
}
var stillConnected bool
for _, server := range servers.Servers {
- if server.Name == serverName && server.Status == rpc.McpServerStatusConnected {
+ if server.Name == serverName && server.Status == rpc.MCPServerStatusConnected {
stillConnected = true
break
}
@@ -228,27 +228,27 @@ func TestRpcMcpAndSkillsE2E(t *testing.T) {
if err != nil {
t.Fatalf("CreateSession failed: %v", err)
}
- waitForMCPServerStatus(t, session, serverName, rpc.McpServerStatusConnected)
+ waitForMCPServerStatus(t, session, serverName, rpc.MCPServerStatusConnected)
- cancelMissing, err := session.RPC.Mcp.CancelSamplingExecution(t.Context(), &rpc.McpCancelSamplingExecutionParams{RequestID: "missing-" + randomHex(t)})
+ cancelMissing, err := session.RPC.MCP.CancelSamplingExecution(t.Context(), &rpc.MCPCancelSamplingExecutionParams{RequestID: "missing-" + randomHex(t)})
if err != nil {
- t.Fatalf("Mcp.CancelSamplingExecution failed: %v", err)
+ t.Fatalf("MCP.CancelSamplingExecution failed: %v", err)
}
if cancelMissing.Cancelled {
t.Fatal("Expected cancelling missing sampling execution to report Cancelled=false")
}
- result, err := session.RPC.Mcp.ExecuteSampling(t.Context(), &rpc.McpExecuteSamplingParams{
+ result, err := session.RPC.MCP.ExecuteSampling(t.Context(), &rpc.MCPExecuteSamplingParams{
RequestID: "sampling-" + randomHex(t),
ServerName: "missing-sampling-server",
- McpRequestID: "mcp-request-" + randomHex(t),
- Request: rpc.McpExecuteSamplingRequest{},
+ MCPRequestID: "mcp-request-" + randomHex(t),
+ Request: rpc.MCPExecuteSamplingRequest{},
})
if err != nil {
- assertRpcError(t, "Mcp.ExecuteSampling", func() error { return err }, "sampling")
+ assertRPCError(t, "MCP.ExecuteSampling", func() error { return err }, "sampling")
return
}
- if result.Action != rpc.McpSamplingExecutionActionFailure {
+ if result.Action != rpc.MCPSamplingExecutionActionFailure {
t.Fatalf("Expected sampling failure action, got %+v", result)
}
if result.Result != nil || result.Error == nil || strings.TrimSpace(*result.Error) == "" {
@@ -306,8 +306,8 @@ func TestRpcMcpAndSkillsE2E(t *testing.T) {
}
})
- t.Run("should round trip mcp app host context", func(t *testing.T) {
- mcpAppsClient := createMcpAppsClient(ctx)
+ t.Run("should round trip MCP app host context", func(t *testing.T) {
+ mcpAppsClient := createMCPAppsClient(ctx)
t.Cleanup(func() { mcpAppsClient.ForceStop() })
session, err := mcpAppsClient.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
@@ -316,14 +316,14 @@ func TestRpcMcpAndSkillsE2E(t *testing.T) {
t.Fatalf("CreateSession failed: %v", err)
}
- displayMode := rpc.McpAppsSetHostContextDetailsDisplayModeInline
- platform := rpc.McpAppsSetHostContextDetailsPlatformDesktop
- theme := rpc.McpAppsSetHostContextDetailsThemeDark
- if _, err := session.RPC.Mcp.Apps().SetHostContext(t.Context(), &rpc.McpAppsSetHostContextRequest{
- Context: rpc.McpAppsSetHostContextDetails{
- AvailableDisplayModes: []rpc.McpAppsSetHostContextDetailsAvailableDisplayMode{
- rpc.McpAppsSetHostContextDetailsAvailableDisplayModeInline,
- rpc.McpAppsSetHostContextDetailsAvailableDisplayModeFullscreen,
+ displayMode := rpc.MCPAppsSetHostContextDetailsDisplayModeInline
+ platform := rpc.MCPAppsSetHostContextDetailsPlatformDesktop
+ theme := rpc.MCPAppsSetHostContextDetailsThemeDark
+ if _, err := session.RPC.MCP.Apps().SetHostContext(t.Context(), &rpc.MCPAppsSetHostContextRequest{
+ Context: rpc.MCPAppsSetHostContextDetails{
+ AvailableDisplayModes: []rpc.MCPAppsSetHostContextDetailsAvailableDisplayMode{
+ rpc.MCPAppsSetHostContextDetailsAvailableDisplayModeInline,
+ rpc.MCPAppsSetHostContextDetailsAvailableDisplayModeFullscreen,
},
DisplayMode: &displayMode,
Locale: rpcPtr("en-GB"),
@@ -333,12 +333,12 @@ func TestRpcMcpAndSkillsE2E(t *testing.T) {
UserAgent: rpcPtr("go-sdk-e2e"),
},
}); err != nil {
- t.Fatalf("Mcp.Apps.SetHostContext failed: %v", err)
+ t.Fatalf("MCP.Apps.SetHostContext failed: %v", err)
}
- result, err := session.RPC.Mcp.Apps().GetHostContext(t.Context())
+ result, err := session.RPC.MCP.Apps().GetHostContext(t.Context())
if err != nil {
- t.Fatalf("Mcp.Apps.GetHostContext failed: %v", err)
+ t.Fatalf("MCP.Apps.GetHostContext failed: %v", err)
}
if result.Context.DisplayMode == nil || string(*result.Context.DisplayMode) != "inline" ||
result.Context.Locale == nil || *result.Context.Locale != "en-GB" ||
@@ -362,7 +362,7 @@ func TestRpcMcpAndSkillsE2E(t *testing.T) {
servers[serverName] = stdio
}
- mcpAppsClient := createMcpAppsClient(ctx)
+ mcpAppsClient := createMCPAppsClient(ctx)
t.Cleanup(func() { mcpAppsClient.ForceStop() })
session, err := mcpAppsClient.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
@@ -371,31 +371,31 @@ func TestRpcMcpAndSkillsE2E(t *testing.T) {
if err != nil {
t.Fatalf("CreateSession failed: %v", err)
}
- waitForMCPServerStatus(t, session, serverName, rpc.McpServerStatusConnected)
- waitForMCPServerStatus(t, session, otherServerName, rpc.McpServerStatusConnected)
+ waitForMCPServerStatus(t, session, serverName, rpc.MCPServerStatusConnected)
+ waitForMCPServerStatus(t, session, otherServerName, rpc.MCPServerStatusConnected)
- diagnose, err := session.RPC.Mcp.Apps().Diagnose(t.Context(), &rpc.McpAppsDiagnoseRequest{ServerName: serverName})
+ diagnose, err := session.RPC.MCP.Apps().Diagnose(t.Context(), &rpc.MCPAppsDiagnoseRequest{ServerName: serverName})
if err != nil {
- t.Fatalf("Mcp.Apps.Diagnose failed: %v", err)
+ t.Fatalf("MCP.Apps.Diagnose failed: %v", err)
}
if !diagnose.Server.Connected || diagnose.Server.ToolCount < 1 {
t.Fatalf("Expected connected MCP app diagnose result with tools, got %+v", diagnose)
}
- assertMcpAppsResultOrImplementedError(t, "Mcp.Apps.ListTools(self)", func() (any, error) {
- return session.RPC.Mcp.Apps().ListTools(t.Context(), &rpc.McpAppsListToolsRequest{
+ assertMCPAppsResultOrImplementedError(t, "MCP.Apps.ListTools(self)", func() (any, error) {
+ return session.RPC.MCP.Apps().ListTools(t.Context(), &rpc.MCPAppsListToolsRequest{
ServerName: serverName,
OriginServerName: serverName,
})
})
- assertMcpAppsResultOrImplementedError(t, "Mcp.Apps.ListTools(other)", func() (any, error) {
- return session.RPC.Mcp.Apps().ListTools(t.Context(), &rpc.McpAppsListToolsRequest{
+ assertMCPAppsResultOrImplementedError(t, "MCP.Apps.ListTools(other)", func() (any, error) {
+ return session.RPC.MCP.Apps().ListTools(t.Context(), &rpc.MCPAppsListToolsRequest{
ServerName: serverName,
OriginServerName: otherServerName,
})
})
- assertMcpAppsResultOrImplementedError(t, "Mcp.Apps.CallTool", func() (any, error) {
- return session.RPC.Mcp.Apps().CallTool(t.Context(), &rpc.McpAppsCallToolRequest{
+ assertMCPAppsResultOrImplementedError(t, "MCP.Apps.CallTool", func() (any, error) {
+ return session.RPC.MCP.Apps().CallTool(t.Context(), &rpc.MCPAppsCallToolRequest{
ServerName: serverName,
OriginServerName: serverName,
ToolName: "get_env",
@@ -406,7 +406,7 @@ func TestRpcMcpAndSkillsE2E(t *testing.T) {
t.Run("should report error when mcp app resource is not available", func(t *testing.T) {
const serverName = "rpc-apps-resource-server"
- mcpAppsClient := createMcpAppsClient(ctx)
+ mcpAppsClient := createMCPAppsClient(ctx)
t.Cleanup(func() { mcpAppsClient.ForceStop() })
session, err := mcpAppsClient.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
@@ -415,9 +415,9 @@ func TestRpcMcpAndSkillsE2E(t *testing.T) {
if err != nil {
t.Fatalf("CreateSession failed: %v", err)
}
- waitForMCPServerStatus(t, session, serverName, rpc.McpServerStatusConnected)
+ waitForMCPServerStatus(t, session, serverName, rpc.MCPServerStatusConnected)
- _, err = session.RPC.Mcp.Apps().ReadResource(t.Context(), &rpc.McpAppsReadResourceRequest{
+ _, err = session.RPC.MCP.Apps().ReadResource(t.Context(), &rpc.MCPAppsReadResourceRequest{
ServerName: serverName,
URI: "ui://missing-resource",
})
@@ -439,20 +439,20 @@ func TestRpcMcpAndSkillsE2E(t *testing.T) {
t.Fatalf("CreateSession failed: %v", err)
}
- assertRpcError(t, "Mcp.Enable", func() error {
- _, e := session.RPC.Mcp.Enable(t.Context(), &rpc.McpEnableRequest{ServerName: "missing-server"})
+ assertRPCError(t, "MCP.Enable", func() error {
+ _, e := session.RPC.MCP.Enable(t.Context(), &rpc.MCPEnableRequest{ServerName: "missing-server"})
return e
}, "no mcp host initialized")
- assertRpcError(t, "Mcp.Disable", func() error {
- _, e := session.RPC.Mcp.Disable(t.Context(), &rpc.McpDisableRequest{ServerName: "missing-server"})
+ assertRPCError(t, "MCP.Disable", func() error {
+ _, e := session.RPC.MCP.Disable(t.Context(), &rpc.MCPDisableRequest{ServerName: "missing-server"})
return e
}, "no mcp host initialized")
- assertRpcError(t, "Mcp.Reload", func() error {
- _, e := session.RPC.Mcp.Reload(t.Context())
+ assertRPCError(t, "MCP.Reload", func() error {
+ _, e := session.RPC.MCP.Reload(t.Context())
return e
}, "mcp config reload not available")
- assertRpcError(t, "Mcp.Oauth.Login", func() error {
- _, e := session.RPC.Mcp.Oauth().Login(t.Context(), &rpc.McpOauthLoginRequest{ServerName: "missing-server"})
+ assertRPCError(t, "MCP.Oauth.Login", func() error {
+ _, e := session.RPC.MCP.Oauth().Login(t.Context(), &rpc.MCPOauthLoginRequest{ServerName: "missing-server"})
return e
}, "mcp host is not available")
})
@@ -466,10 +466,10 @@ func TestRpcMcpAndSkillsE2E(t *testing.T) {
if err != nil {
t.Fatalf("CreateSession failed: %v", err)
}
- waitForMCPServerStatus(t, session, serverName, rpc.McpServerStatusConnected)
+ waitForMCPServerStatus(t, session, serverName, rpc.MCPServerStatusConnected)
- assertRpcError(t, "Mcp.Oauth.Login", func() error {
- _, e := session.RPC.Mcp.Oauth().Login(t.Context(), &rpc.McpOauthLoginRequest{ServerName: "missing-server"})
+ assertRPCError(t, "MCP.Oauth.Login", func() error {
+ _, e := session.RPC.MCP.Oauth().Login(t.Context(), &rpc.MCPOauthLoginRequest{ServerName: "missing-server"})
return e
}, "is not configured")
})
@@ -483,13 +483,13 @@ func TestRpcMcpAndSkillsE2E(t *testing.T) {
if err != nil {
t.Fatalf("CreateSession failed: %v", err)
}
- waitForMCPServerStatus(t, session, serverName, rpc.McpServerStatusConnected)
+ waitForMCPServerStatus(t, session, serverName, rpc.MCPServerStatusConnected)
force := true
clientName := "SDK E2E"
callback := "Done"
- assertRpcError(t, "Mcp.Oauth.Login", func() error {
- _, e := session.RPC.Mcp.Oauth().Login(t.Context(), &rpc.McpOauthLoginRequest{
+ assertRPCError(t, "MCP.Oauth.Login", func() error {
+ _, e := session.RPC.MCP.Oauth().Login(t.Context(), &rpc.MCPOauthLoginRequest{
ServerName: serverName,
ForceReauth: &force,
ClientName: &clientName,
@@ -507,24 +507,24 @@ func TestRpcMcpAndSkillsE2E(t *testing.T) {
t.Fatalf("CreateSession failed: %v", err)
}
- assertRpcError(t, "Extensions.Enable", func() error {
+ assertRPCError(t, "Extensions.Enable", func() error {
_, e := session.RPC.Extensions.Enable(t.Context(), &rpc.ExtensionsEnableRequest{ID: "missing-extension"})
return e
}, "extensions not available")
- assertRpcError(t, "Extensions.Disable", func() error {
+ assertRPCError(t, "Extensions.Disable", func() error {
_, e := session.RPC.Extensions.Disable(t.Context(), &rpc.ExtensionsDisableRequest{ID: "missing-extension"})
return e
}, "extensions not available")
- assertRpcError(t, "Extensions.Reload", func() error {
+ assertRPCError(t, "Extensions.Reload", func() error {
_, e := session.RPC.Extensions.Reload(t.Context())
return e
}, "extensions not available")
})
}
-// createMcpSkillsRpcDirectory creates a unique skills directory containing a single
+// createMCPSkillsRPCDirectory creates a unique skills directory containing a single
// SKILL.md and returns the parent directory suitable for SkillDirectories.
-func createMcpSkillsRpcDirectory(t *testing.T, workDir, baseName, skillName, description string) string {
+func createMCPSkillsRPCDirectory(t *testing.T, workDir, baseName, skillName, description string) string {
t.Helper()
skillsDir := filepath.Join(workDir, baseName, randomHex(t))
if err := os.MkdirAll(skillsDir, 0755); err != nil {
@@ -570,13 +570,13 @@ func assertSkillState(t *testing.T, list *rpc.SkillList, name string, enabled bo
return matched
}
-func createMcpAppsClient(ctx *testharness.TestContext) *copilot.Client {
+func createMCPAppsClient(ctx *testharness.TestContext) *copilot.Client {
return ctx.NewClient(func(opts *copilot.ClientOptions) {
opts.Env = append(opts.Env, "COPILOT_MCP_APPS=true", "MCP_APPS=true")
})
}
-func assertMcpAppsResultOrImplementedError(t *testing.T, name string, action func() (any, error)) {
+func assertMCPAppsResultOrImplementedError(t *testing.T, name string, action func() (any, error)) {
t.Helper()
result, err := action()
if err == nil {
@@ -584,11 +584,11 @@ func assertMcpAppsResultOrImplementedError(t *testing.T, name string, action fun
t.Fatalf("%s returned nil result", name)
}
switch value := result.(type) {
- case *rpc.McpAppsListToolsResult:
+ case *rpc.MCPAppsListToolsResult:
if value.Tools == nil {
t.Fatalf("%s returned nil Tools", name)
}
- case *rpc.SessionMcpAppsCallToolResult:
+ case *rpc.SessionMCPAppsCallToolResult:
if value == nil {
t.Fatalf("%s returned nil CallTool result", name)
}
@@ -603,7 +603,7 @@ func assertMcpAppsResultOrImplementedError(t *testing.T, name string, action fun
}
}
-func assertRpcError(t *testing.T, name string, action func() error, expectedSubstring string) {
+func assertRPCError(t *testing.T, name string, action func() error, expectedSubstring string) {
t.Helper()
err := action()
if err == nil {
diff --git a/go/internal/e2e/rpc_mcp_config_e2e_test.go b/go/internal/e2e/rpc_mcp_config_e2e_test.go
index 528c92080..4e950fa3c 100644
--- a/go/internal/e2e/rpc_mcp_config_e2e_test.go
+++ b/go/internal/e2e/rpc_mcp_config_e2e_test.go
@@ -9,9 +9,9 @@ import (
)
// Mirrors dotnet/test/RpcMcpConfigTests.cs (snapshot category "rpc_mcp_config").
-// Tests server-scoped MCP configuration management via mcp.config.* RPCs.
-func TestRpcMcpConfigE2E(t *testing.T) {
- t.Run("should call server mcp config rpcs", func(t *testing.T) {
+// Tests server-scoped MCP configuration management via MCP.Config.* RPCs.
+func TestRPCMCPConfigE2E(t *testing.T) {
+ t.Run("should call server MCP config rpcs", func(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient()
t.Cleanup(func() { client.ForceStop() })
@@ -21,18 +21,18 @@ func TestRpcMcpConfigE2E(t *testing.T) {
serverName := fmt.Sprintf("sdk-test-%s", randomHex(t))
- baseConfig := &rpc.McpServerConfigStdio{
+ baseConfig := &rpc.MCPServerConfigStdio{
Command: "node",
Args: []string{"-v"},
}
- updatedConfig := &rpc.McpServerConfigStdio{
+ updatedConfig := &rpc.MCPServerConfigStdio{
Command: "node",
Args: []string{"--version"},
}
- initial, err := client.RPC.Mcp.Config().List(t.Context())
+ initial, err := client.RPC.MCP.Config().List(t.Context())
if err != nil {
- t.Fatalf("Mcp.Config.List (initial) failed: %v", err)
+ t.Fatalf("MCP.Config.List (initial) failed: %v", err)
}
if _, present := initial.Servers[serverName]; present {
t.Fatalf("Did not expect %q to be present initially", serverName)
@@ -40,40 +40,40 @@ func TestRpcMcpConfigE2E(t *testing.T) {
// Best-effort cleanup if a subtest assertion fails mid-flight.
t.Cleanup(func() {
- _, _ = client.RPC.Mcp.Config().Remove(t.Context(), &rpc.McpConfigRemoveRequest{Name: serverName})
+ _, _ = client.RPC.MCP.Config().Remove(t.Context(), &rpc.MCPConfigRemoveRequest{Name: serverName})
})
- if _, err := client.RPC.Mcp.Config().Add(t.Context(), &rpc.McpConfigAddRequest{
+ if _, err := client.RPC.MCP.Config().Add(t.Context(), &rpc.MCPConfigAddRequest{
Name: serverName,
Config: baseConfig,
}); err != nil {
- t.Fatalf("Mcp.Config.Add failed: %v", err)
+ t.Fatalf("MCP.Config.Add failed: %v", err)
}
- afterAdd, err := client.RPC.Mcp.Config().List(t.Context())
+ afterAdd, err := client.RPC.MCP.Config().List(t.Context())
if err != nil {
- t.Fatalf("Mcp.Config.List (after add) failed: %v", err)
+ t.Fatalf("MCP.Config.List (after add) failed: %v", err)
}
if _, present := afterAdd.Servers[serverName]; !present {
t.Fatalf("Expected %q to be present after Add", serverName)
}
- if _, err := client.RPC.Mcp.Config().Update(t.Context(), &rpc.McpConfigUpdateRequest{
+ if _, err := client.RPC.MCP.Config().Update(t.Context(), &rpc.MCPConfigUpdateRequest{
Name: serverName,
Config: updatedConfig,
}); err != nil {
- t.Fatalf("Mcp.Config.Update failed: %v", err)
+ t.Fatalf("MCP.Config.Update failed: %v", err)
}
- afterUpdate, err := client.RPC.Mcp.Config().List(t.Context())
+ afterUpdate, err := client.RPC.MCP.Config().List(t.Context())
if err != nil {
- t.Fatalf("Mcp.Config.List (after update) failed: %v", err)
+ t.Fatalf("MCP.Config.List (after update) failed: %v", err)
}
updated, present := afterUpdate.Servers[serverName]
if !present {
t.Fatalf("Expected %q to still be present after Update", serverName)
}
- updatedLocal, ok := updated.(*rpc.McpServerConfigStdio)
+ updatedLocal, ok := updated.(*rpc.MCPServerConfigStdio)
if !ok {
t.Fatalf("Expected local MCP config, got %T", updated)
}
@@ -84,27 +84,27 @@ func TestRpcMcpConfigE2E(t *testing.T) {
t.Errorf("Expected args[0]='--version', got %v", updatedLocal.Args)
}
- if _, err := client.RPC.Mcp.Config().Disable(t.Context(), &rpc.McpConfigDisableRequest{Names: []string{serverName}}); err != nil {
- t.Fatalf("Mcp.Config.Disable failed: %v", err)
+ if _, err := client.RPC.MCP.Config().Disable(t.Context(), &rpc.MCPConfigDisableRequest{Names: []string{serverName}}); err != nil {
+ t.Fatalf("MCP.Config.Disable failed: %v", err)
}
- if _, err := client.RPC.Mcp.Config().Enable(t.Context(), &rpc.McpConfigEnableRequest{Names: []string{serverName}}); err != nil {
- t.Fatalf("Mcp.Config.Enable failed: %v", err)
+ if _, err := client.RPC.MCP.Config().Enable(t.Context(), &rpc.MCPConfigEnableRequest{Names: []string{serverName}}); err != nil {
+ t.Fatalf("MCP.Config.Enable failed: %v", err)
}
- if _, err := client.RPC.Mcp.Config().Remove(t.Context(), &rpc.McpConfigRemoveRequest{Name: serverName}); err != nil {
- t.Fatalf("Mcp.Config.Remove failed: %v", err)
+ if _, err := client.RPC.MCP.Config().Remove(t.Context(), &rpc.MCPConfigRemoveRequest{Name: serverName}); err != nil {
+ t.Fatalf("MCP.Config.Remove failed: %v", err)
}
- afterRemove, err := client.RPC.Mcp.Config().List(t.Context())
+ afterRemove, err := client.RPC.MCP.Config().List(t.Context())
if err != nil {
- t.Fatalf("Mcp.Config.List (after remove) failed: %v", err)
+ t.Fatalf("MCP.Config.List (after remove) failed: %v", err)
}
if _, present := afterRemove.Servers[serverName]; present {
t.Errorf("Expected %q to be removed", serverName)
}
})
- t.Run("should round trip http mcp oauth config rpc", func(t *testing.T) {
+ t.Run("should round trip http MCP oauth config rpc", func(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient()
t.Cleanup(func() { client.ForceStop() })
@@ -114,19 +114,19 @@ func TestRpcMcpConfigE2E(t *testing.T) {
serverName := fmt.Sprintf("sdk-http-oauth-%s", randomHex(t))
- httpType := rpc.McpServerConfigHTTPTypeHTTP
+ httpType := rpc.MCPServerConfigHTTPTypeHTTP
urlBase := "https://example.com/mcp"
urlUpdated := "https://example.com/updated-mcp"
clientID := "client-id"
clientIDUpdated := "updated-client-id"
- grantClientCreds := rpc.McpServerConfigHTTPOauthGrantTypeClientCredentials
- grantAuthCode := rpc.McpServerConfigHTTPOauthGrantTypeAuthorizationCode
+ grantClientCreds := rpc.MCPServerConfigHTTPOauthGrantTypeClientCredentials
+ grantAuthCode := rpc.MCPServerConfigHTTPOauthGrantTypeAuthorizationCode
var publicFalse = false
var publicTrue = true
var timeoutBase int64 = 3000
var timeoutUpdated int64 = 4000
- baseConfig := &rpc.McpServerConfigHTTP{
+ baseConfig := &rpc.MCPServerConfigHTTP{
Type: &httpType,
URL: urlBase,
Headers: map[string]string{"Authorization": "Bearer token"},
@@ -136,7 +136,7 @@ func TestRpcMcpConfigE2E(t *testing.T) {
Tools: []string{"*"},
Timeout: &timeoutBase,
}
- updatedConfig := &rpc.McpServerConfigHTTP{
+ updatedConfig := &rpc.MCPServerConfigHTTP{
Type: &httpType,
URL: urlUpdated,
OauthClientID: &clientIDUpdated,
@@ -147,25 +147,25 @@ func TestRpcMcpConfigE2E(t *testing.T) {
}
t.Cleanup(func() {
- _, _ = client.RPC.Mcp.Config().Remove(t.Context(), &rpc.McpConfigRemoveRequest{Name: serverName})
+ _, _ = client.RPC.MCP.Config().Remove(t.Context(), &rpc.MCPConfigRemoveRequest{Name: serverName})
})
- if _, err := client.RPC.Mcp.Config().Add(t.Context(), &rpc.McpConfigAddRequest{
+ if _, err := client.RPC.MCP.Config().Add(t.Context(), &rpc.MCPConfigAddRequest{
Name: serverName,
Config: baseConfig,
}); err != nil {
- t.Fatalf("Mcp.Config.Add failed: %v", err)
+ t.Fatalf("MCP.Config.Add failed: %v", err)
}
- afterAdd, err := client.RPC.Mcp.Config().List(t.Context())
+ afterAdd, err := client.RPC.MCP.Config().List(t.Context())
if err != nil {
- t.Fatalf("Mcp.Config.List (after add) failed: %v", err)
+ t.Fatalf("MCP.Config.List (after add) failed: %v", err)
}
added, present := afterAdd.Servers[serverName]
if !present {
t.Fatalf("Expected %q to be present after Add", serverName)
}
- addedHTTP, ok := added.(*rpc.McpServerConfigHTTP)
+ addedHTTP, ok := added.(*rpc.MCPServerConfigHTTP)
if !ok {
t.Fatalf("Expected HTTP MCP config, got %T", added)
}
@@ -188,21 +188,21 @@ func TestRpcMcpConfigE2E(t *testing.T) {
t.Errorf("Expected oauthGrantType='client_credentials', got %v", addedHTTP.OauthGrantType)
}
- if _, err := client.RPC.Mcp.Config().Update(t.Context(), &rpc.McpConfigUpdateRequest{
+ if _, err := client.RPC.MCP.Config().Update(t.Context(), &rpc.MCPConfigUpdateRequest{
Name: serverName,
Config: updatedConfig,
}); err != nil {
- t.Fatalf("Mcp.Config.Update failed: %v", err)
+ t.Fatalf("MCP.Config.Update failed: %v", err)
}
- afterUpdate, err := client.RPC.Mcp.Config().List(t.Context())
+ afterUpdate, err := client.RPC.MCP.Config().List(t.Context())
if err != nil {
- t.Fatalf("Mcp.Config.List (after update) failed: %v", err)
+ t.Fatalf("MCP.Config.List (after update) failed: %v", err)
}
updated, present := afterUpdate.Servers[serverName]
if !present {
t.Fatalf("Expected %q to still be present after Update", serverName)
}
- updatedHTTP, ok := updated.(*rpc.McpServerConfigHTTP)
+ updatedHTTP, ok := updated.(*rpc.MCPServerConfigHTTP)
if !ok {
t.Fatalf("Expected HTTP MCP config, got %T", updated)
}
@@ -225,13 +225,13 @@ func TestRpcMcpConfigE2E(t *testing.T) {
t.Errorf("Expected timeout=4000, got %v", updatedHTTP.Timeout)
}
- if _, err := client.RPC.Mcp.Config().Remove(t.Context(), &rpc.McpConfigRemoveRequest{Name: serverName}); err != nil {
- t.Fatalf("Mcp.Config.Remove failed: %v", err)
+ if _, err := client.RPC.MCP.Config().Remove(t.Context(), &rpc.MCPConfigRemoveRequest{Name: serverName}); err != nil {
+ t.Fatalf("MCP.Config.Remove failed: %v", err)
}
- afterRemove, err := client.RPC.Mcp.Config().List(t.Context())
+ afterRemove, err := client.RPC.MCP.Config().List(t.Context())
if err != nil {
- t.Fatalf("Mcp.Config.List (after remove) failed: %v", err)
+ t.Fatalf("MCP.Config.List (after remove) failed: %v", err)
}
if _, present := afterRemove.Servers[serverName]; present {
t.Errorf("Expected %q to be removed", serverName)
diff --git a/go/internal/e2e/rpc_queue_e2e_test.go b/go/internal/e2e/rpc_queue_e2e_test.go
index ff567fab1..7ab0b1793 100644
--- a/go/internal/e2e/rpc_queue_e2e_test.go
+++ b/go/internal/e2e/rpc_queue_e2e_test.go
@@ -11,7 +11,7 @@ import (
)
// Mirrors dotnet/test/E2E/RpcQueueE2ETests.cs (snapshot category "rpc_queue").
-func TestRpcQueueE2E(t *testing.T) {
+func TestRPCQueueE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient()
t.Cleanup(func() { client.ForceStop() })
diff --git a/go/internal/e2e/rpc_remote_e2e_test.go b/go/internal/e2e/rpc_remote_e2e_test.go
index b1243526b..52b8beeda 100644
--- a/go/internal/e2e/rpc_remote_e2e_test.go
+++ b/go/internal/e2e/rpc_remote_e2e_test.go
@@ -11,7 +11,7 @@ import (
)
// Mirrors dotnet/test/E2E/RpcRemoteE2ETests.cs (snapshot category "rpc_remote").
-func TestRpcRemoteE2E(t *testing.T) {
+func TestRPCRemoteE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient()
t.Cleanup(func() { client.ForceStop() })
diff --git a/go/internal/e2e/rpc_schedule_e2e_test.go b/go/internal/e2e/rpc_schedule_e2e_test.go
index 359cd20e1..a20d48174 100644
--- a/go/internal/e2e/rpc_schedule_e2e_test.go
+++ b/go/internal/e2e/rpc_schedule_e2e_test.go
@@ -10,7 +10,7 @@ import (
)
// Mirrors dotnet/test/E2E/RpcScheduleE2ETests.cs (snapshot category "rpc_schedule").
-func TestRpcScheduleE2E(t *testing.T) {
+func TestRPCScheduleE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient()
t.Cleanup(func() { client.ForceStop() })
diff --git a/go/internal/e2e/rpc_server_e2e_test.go b/go/internal/e2e/rpc_server_e2e_test.go
index 66288aa0e..6f6c77e7d 100644
--- a/go/internal/e2e/rpc_server_e2e_test.go
+++ b/go/internal/e2e/rpc_server_e2e_test.go
@@ -15,7 +15,7 @@ import (
// Mirrors dotnet/test/RpcServerTests.cs (snapshot category "rpc_server").
// Tests server-scoped (non-session) RPCs.
-func TestRpcServerE2E(t *testing.T) {
+func TestRPCServerE2E(t *testing.T) {
t.Run("should call rpc ping with typed params and result", func(t *testing.T) {
ctx := testharness.NewTestContext(t)
ctx.ConfigureForTest(t)
@@ -161,17 +161,17 @@ func TestRpcServerE2E(t *testing.T) {
t.Fatalf("Start failed: %v", err)
}
- result, err := client.RPC.SessionFs.SetProvider(t.Context(), &rpc.SessionFsSetProviderRequest{
+ result, err := client.RPC.SessionFS.SetProvider(t.Context(), &rpc.SessionFSSetProviderRequest{
InitialCwd: "/",
SessionStatePath: "/session-state",
- Conventions: rpc.SessionFsSetProviderConventionsPosix,
- Capabilities: &rpc.SessionFsSetProviderCapabilities{Sqlite: rpcPtr(true)},
+ Conventions: rpc.SessionFSSetProviderConventionsPosix,
+ Capabilities: &rpc.SessionFSSetProviderCapabilities{Sqlite: rpcPtr(true)},
})
if err != nil {
- t.Fatalf("SessionFs.SetProvider failed: %v", err)
+ t.Fatalf("SessionFS.SetProvider failed: %v", err)
}
if !result.Success {
- t.Fatalf("Expected SessionFs.SetProvider Success=true, got %+v", result)
+ t.Fatalf("Expected SessionFS.SetProvider Success=true, got %+v", result)
}
})
@@ -281,7 +281,7 @@ func TestRpcServerE2E(t *testing.T) {
t.Fatalf("Expected non-negative size for %q, got %d", sessionID, size)
}
- inUse, err := client.RPC.Sessions.CheckInUse(t.Context(), &rpc.SessionsCheckInUseRequest{SessionIds: []string{sessionID, missingSessionID}})
+ inUse, err := client.RPC.Sessions.CheckInUse(t.Context(), &rpc.SessionsCheckInUseRequest{SessionIDs: []string{sessionID, missingSessionID}})
if err != nil {
t.Fatalf("Sessions.CheckInUse failed: %v", err)
}
@@ -379,7 +379,7 @@ func TestRpcServerE2E(t *testing.T) {
if _, err := client.RPC.Sessions.ReleaseLock(t.Context(), &rpc.SessionsReleaseLockRequest{SessionID: sessionID}); err != nil {
t.Fatalf("Sessions.ReleaseLock failed: %v", err)
}
- inUse, err := client.RPC.Sessions.CheckInUse(t.Context(), &rpc.SessionsCheckInUseRequest{SessionIds: []string{sessionID}})
+ inUse, err := client.RPC.Sessions.CheckInUse(t.Context(), &rpc.SessionsCheckInUseRequest{SessionIDs: []string{sessionID}})
if err != nil {
t.Fatalf("Sessions.CheckInUse failed: %v", err)
}
@@ -419,7 +419,7 @@ func TestRpcServerE2E(t *testing.T) {
OlderThanDays: 0,
DryRun: rpcPtr(true),
IncludeNamed: rpcPtr(true),
- ExcludeSessionIds: []string{},
+ ExcludeSessionIDs: []string{},
})
if err != nil {
t.Fatalf("Sessions.PruneOld failed: %v", err)
@@ -435,7 +435,7 @@ func TestRpcServerE2E(t *testing.T) {
}
deleted, err := client.RPC.Sessions.BulkDelete(t.Context(), &rpc.SessionsBulkDeleteRequest{
- SessionIds: []string{sessionID, missingSessionID},
+ SessionIDs: []string{sessionID, missingSessionID},
})
if err != nil {
t.Fatalf("Sessions.BulkDelete failed: %v", err)
@@ -474,7 +474,7 @@ func TestRpcServerE2E(t *testing.T) {
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
SessionID: sessionID,
WorkingDirectory: workingDirectory,
- EnableConfigDiscovery: false,
+ EnableConfigDiscovery: copilot.Bool(false),
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
})
if err != nil {
@@ -532,12 +532,12 @@ func TestRpcServerE2E(t *testing.T) {
}
skillName := fmt.Sprintf("server-rpc-skill-%s", randomHex(t))
- skillsDir := createMcpSkillsRpcDirectory(t, ctx.WorkDir, "server-rpc-skills", skillName, "Skill discovered by server-scoped RPC tests.")
+ skillsDir := createMCPSkillsRPCDirectory(t, ctx.WorkDir, "server-rpc-skills", skillName, "Skill discovered by server-scoped RPC tests.")
workingDir := ctx.WorkDir
- mcp, err := client.RPC.Mcp.Discover(t.Context(), &rpc.McpDiscoverRequest{WorkingDirectory: &workingDir})
+ mcp, err := client.RPC.MCP.Discover(t.Context(), &rpc.MCPDiscoverRequest{WorkingDirectory: &workingDir})
if err != nil {
- t.Fatalf("Mcp.Discover failed: %v", err)
+ t.Fatalf("MCP.Discover failed: %v", err)
}
if mcp.Servers == nil {
t.Errorf("Expected non-nil Servers")
diff --git a/go/internal/e2e/rpc_session_state_e2e_test.go b/go/internal/e2e/rpc_session_state_e2e_test.go
index 1744cb10f..f6698f082 100644
--- a/go/internal/e2e/rpc_session_state_e2e_test.go
+++ b/go/internal/e2e/rpc_session_state_e2e_test.go
@@ -15,7 +15,7 @@ import (
//
// Reuses snapshot files in test/snapshots/rpc_session_state/. Tests that don't issue
// LLM calls don't need snapshots.
-func TestRpcSessionStateE2E(t *testing.T) {
+func TestRPCSessionStateE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient()
t.Cleanup(func() { client.ForceStop() })
@@ -515,7 +515,7 @@ func TestRpcSessionStateE2E(t *testing.T) {
repo := "github/copilot-sdk-e2e"
repoHost := "github.com"
- hostType := rpc.SessionWorkingDirectoryContextHostTypeGithub
+ hostType := rpc.SessionWorkingDirectoryContextHostTypeGitHub
baseCommit := "0000000000000000000000000000000000000000"
headCommit := "1111111111111111111111111111111111111111"
if _, err := session.RPC.Metadata.RecordContextChange(t.Context(), &rpc.MetadataRecordContextChangeRequest{
@@ -1097,9 +1097,9 @@ func TestRpcSessionStateE2E(t *testing.T) {
t.Errorf("session.history.truncate should be implemented; error suggests it isn't: %v", err)
}
- _, err = session.RPC.Mcp.Oauth().Login(t.Context(), &rpc.McpOauthLoginRequest{ServerName: "missing-server"})
+ _, err = session.RPC.MCP.Oauth().Login(t.Context(), &rpc.MCPOauthLoginRequest{ServerName: "missing-server"})
if err == nil {
- t.Fatal("Expected Mcp.Oauth.Login with unknown server to fail")
+ t.Fatal("Expected MCP.Oauth.Login with unknown server to fail")
}
if strings.Contains(strings.ToLower(err.Error()), "unhandled method session.mcp.oauth.login") {
t.Errorf("session.mcp.oauth.login should be implemented; error suggests it isn't: %v", err)
diff --git a/go/internal/e2e/rpc_shell_and_fleet_e2e_test.go b/go/internal/e2e/rpc_shell_and_fleet_e2e_test.go
index 7655d179e..d7ffd725d 100644
--- a/go/internal/e2e/rpc_shell_and_fleet_e2e_test.go
+++ b/go/internal/e2e/rpc_shell_and_fleet_e2e_test.go
@@ -17,7 +17,7 @@ import (
)
// Mirrors dotnet/test/RpcShellAndFleetTests.cs (snapshot category "rpc_shell_and_fleet").
-func TestRpcShellAndFleetE2E(t *testing.T) {
+func TestRPCShellAndFleetE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient()
t.Cleanup(func() { client.ForceStop() })
diff --git a/go/internal/e2e/rpc_tasks_and_handlers_e2e_test.go b/go/internal/e2e/rpc_tasks_and_handlers_e2e_test.go
index bda0f2ad3..60ae3f1fd 100644
--- a/go/internal/e2e/rpc_tasks_and_handlers_e2e_test.go
+++ b/go/internal/e2e/rpc_tasks_and_handlers_e2e_test.go
@@ -11,7 +11,7 @@ import (
)
// Mirrors dotnet/test/RpcTasksAndHandlersTests.cs (snapshot category "rpc_tasks_and_handlers").
-func TestRpcTasksAndHandlersE2E(t *testing.T) {
+func TestRPCTasksAndHandlersE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient()
t.Cleanup(func() { client.ForceStop() })
@@ -311,7 +311,7 @@ func TestRpcTasksAndHandlersE2E(t *testing.T) {
OnElicitationRequest: func(ctx copilot.ElicitationContext) (copilot.ElicitationResult, error) {
handlerContext <- ctx
return copilot.ElicitationResult{
- Action: "accept",
+ Action: copilot.ElicitationActionAccept,
Content: map[string]any{
"answer": "from handler",
"confirmed": true,
@@ -347,7 +347,7 @@ func TestRpcTasksAndHandlersE2E(t *testing.T) {
if ctx.SessionID != session.SessionID || ctx.Message != "Need details" {
t.Fatalf("Unexpected elicitation context: %+v", ctx)
}
- if _, ok := ctx.RequestedSchema["properties"]; !ok {
+ if ctx.RequestedSchema == nil || ctx.RequestedSchema.Properties == nil {
t.Fatalf("Expected requested schema to include properties, got %+v", ctx.RequestedSchema)
}
if response.Action != rpc.UIElicitationResponseActionAccept {
diff --git a/go/internal/e2e/rpc_workspace_checkpoints_e2e_test.go b/go/internal/e2e/rpc_workspace_checkpoints_e2e_test.go
index a11a2fef2..87c3c8da8 100644
--- a/go/internal/e2e/rpc_workspace_checkpoints_e2e_test.go
+++ b/go/internal/e2e/rpc_workspace_checkpoints_e2e_test.go
@@ -11,7 +11,7 @@ import (
)
// Mirrors dotnet/test/E2E/RpcWorkspaceCheckpointsE2ETests.cs (snapshot category "rpc_workspace_checkpoints").
-func TestRpcWorkspaceCheckpointsE2E(t *testing.T) {
+func TestRPCWorkspaceCheckpointsE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
client := ctx.NewClient()
t.Cleanup(func() { client.ForceStop() })
diff --git a/go/internal/e2e/session_e2e_test.go b/go/internal/e2e/session_e2e_test.go
index f73bef7ea..dc2d54ca8 100644
--- a/go/internal/e2e/session_e2e_test.go
+++ b/go/internal/e2e/session_e2e_test.go
@@ -1103,7 +1103,7 @@ func TestSessionBlobAttachmentE2E(t *testing.T) {
_, err = session.SendAndWait(t.Context(), copilot.MessageOptions{
Prompt: "Describe this image",
Attachments: []copilot.Attachment{
- &copilot.UserMessageAttachmentBlob{
+ &copilot.AttachmentBlob{
Data: data,
MIMEType: mimeType,
DisplayName: &displayName,
@@ -1256,7 +1256,7 @@ func getEventMessage(evt copilot.SessionEvent) string {
}
// TestSessionAttachments mirrors the C# Should_Send_With_*_Attachment tests in SessionTests.cs.
-// Each subtest exercises a different UserMessageAttachment shape end-to-end through SendAndWait
+// Each subtest exercises a different Attachment shape end-to-end through SendAndWait
// and verifies the resulting user.message event captured by GetEvents.
func TestSessionAttachmentsE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
@@ -1286,17 +1286,17 @@ func TestSessionAttachmentsE2E(t *testing.T) {
path := filePath
_, err = session.SendAndWait(t.Context(), copilot.MessageOptions{
Prompt: "Read the attached file and reply with its contents.",
- Attachments: []copilot.Attachment{&copilot.UserMessageAttachmentFile{
+ Attachments: []copilot.Attachment{&copilot.AttachmentFile{
DisplayName: displayName,
Path: path,
- LineRange: &copilot.UserMessageAttachmentFileLineRange{Start: 1, End: 1},
+ LineRange: &copilot.AttachmentFileLineRange{Start: 1, End: 1},
}},
})
if err != nil {
t.Fatalf("SendAndWait failed: %v", err)
}
- attachment, ok := lastUserAttachment(t, session).(*copilot.UserMessageAttachmentFile)
+ attachment, ok := lastUserAttachment(t, session).(*copilot.AttachmentFile)
if !ok {
t.Fatalf("Expected file attachment, got %T", lastUserAttachment(t, session))
}
@@ -1333,7 +1333,7 @@ func TestSessionAttachmentsE2E(t *testing.T) {
path := directoryPath
_, err = session.SendAndWait(t.Context(), copilot.MessageOptions{
Prompt: "List the attached directory.",
- Attachments: []copilot.Attachment{&copilot.UserMessageAttachmentDirectory{
+ Attachments: []copilot.Attachment{&copilot.AttachmentDirectory{
DisplayName: displayName,
Path: path,
}},
@@ -1342,7 +1342,7 @@ func TestSessionAttachmentsE2E(t *testing.T) {
t.Fatalf("SendAndWait failed: %v", err)
}
- attachment, ok := lastUserAttachment(t, session).(*copilot.UserMessageAttachmentDirectory)
+ attachment, ok := lastUserAttachment(t, session).(*copilot.AttachmentDirectory)
if !ok {
t.Fatalf("Expected directory attachment, got %T", lastUserAttachment(t, session))
}
@@ -1374,13 +1374,13 @@ func TestSessionAttachmentsE2E(t *testing.T) {
text := `string Value = "SELECTION_SENTINEL";`
_, err = session.SendAndWait(t.Context(), copilot.MessageOptions{
Prompt: "Summarize the selected code.",
- Attachments: []copilot.Attachment{&copilot.UserMessageAttachmentSelection{
+ Attachments: []copilot.Attachment{&copilot.AttachmentSelection{
DisplayName: displayName,
FilePath: filePathCopy,
Text: text,
- Selection: copilot.UserMessageAttachmentSelectionDetails{
- Start: copilot.UserMessageAttachmentSelectionDetailsStart{Line: 1, Character: 10},
- End: copilot.UserMessageAttachmentSelectionDetailsEnd{Line: 1, Character: 45},
+ Selection: copilot.AttachmentSelectionDetails{
+ Start: copilot.AttachmentSelectionDetailsStart{Line: 1, Character: 10},
+ End: copilot.AttachmentSelectionDetailsEnd{Line: 1, Character: 45},
},
}},
})
@@ -1388,7 +1388,7 @@ func TestSessionAttachmentsE2E(t *testing.T) {
t.Fatalf("SendAndWait failed: %v", err)
}
- attachment, ok := lastUserAttachment(t, session).(*copilot.UserMessageAttachmentSelection)
+ attachment, ok := lastUserAttachment(t, session).(*copilot.AttachmentSelection)
if !ok {
t.Fatalf("Expected selection attachment, got %T", lastUserAttachment(t, session))
}
@@ -1420,13 +1420,13 @@ func TestSessionAttachmentsE2E(t *testing.T) {
}
number := int64(1234)
- referenceType := copilot.UserMessageAttachmentGithubReferenceTypeIssue
+ referenceType := copilot.AttachmentGitHubReferenceTypeIssue
state := "open"
title := "Add E2E attachment coverage"
url := "https://github.com/github/copilot-sdk/issues/1234"
_, err = session.SendAndWait(t.Context(), copilot.MessageOptions{
Prompt: "Using only the GitHub reference metadata in this message, summarize the reference. Do not call any tools.",
- Attachments: []copilot.Attachment{&copilot.UserMessageAttachmentGithubReference{
+ Attachments: []copilot.Attachment{&copilot.AttachmentGitHubReference{
Number: number,
ReferenceType: referenceType,
State: state,
@@ -1438,14 +1438,14 @@ func TestSessionAttachmentsE2E(t *testing.T) {
t.Fatalf("SendAndWait failed: %v", err)
}
- attachment, ok := lastUserAttachment(t, session).(*copilot.UserMessageAttachmentGithubReference)
+ attachment, ok := lastUserAttachment(t, session).(*copilot.AttachmentGitHubReference)
if !ok {
t.Fatalf("Expected GitHub reference attachment, got %T", lastUserAttachment(t, session))
}
if attachment.Number != 1234 {
t.Errorf("Expected Number=1234, got %v", attachment.Number)
}
- if attachment.ReferenceType != copilot.UserMessageAttachmentGithubReferenceTypeIssue {
+ if attachment.ReferenceType != copilot.AttachmentGitHubReferenceTypeIssue {
t.Errorf("Expected ReferenceType=Issue, got %v", attachment.ReferenceType)
}
if attachment.State != "open" {
diff --git a/go/internal/e2e/session_fs_e2e_test.go b/go/internal/e2e/session_fs_e2e_test.go
index ef392ebbc..3ba91c799 100644
--- a/go/internal/e2e/session_fs_e2e_test.go
+++ b/go/internal/e2e/session_fs_e2e_test.go
@@ -15,17 +15,17 @@ import (
"github.com/github/copilot-sdk/go/rpc"
)
-func TestSessionFsE2E(t *testing.T) {
+func TestSessionFSE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
providerRoot := t.TempDir()
sessionStatePath := createSessionStatePath(t)
- sessionFsConfig := &copilot.SessionFsConfig{
+ sessionFSConfig := &copilot.SessionFSConfig{
InitialWorkingDirectory: "/",
SessionStatePath: sessionStatePath,
- Conventions: rpc.SessionFsSetProviderConventionsPosix,
+ Conventions: rpc.SessionFSSetProviderConventionsPosix,
}
- createSessionFsHandler := func(session *copilot.Session) copilot.SessionFsProvider {
- return &testSessionFsHandler{
+ createSessionFSHandler := func(session *copilot.Session) copilot.SessionFSProvider {
+ return &testSessionFSHandler{
root: providerRoot,
sessionID: session.SessionID,
}
@@ -35,7 +35,7 @@ func TestSessionFsE2E(t *testing.T) {
}
client := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.SessionFs = sessionFsConfig
+ opts.SessionFS = sessionFSConfig
})
t.Cleanup(func() { client.ForceStop() })
@@ -44,7 +44,7 @@ func TestSessionFsE2E(t *testing.T) {
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
- CreateSessionFsProvider: createSessionFsHandler,
+ CreateSessionFSProvider: createSessionFSHandler,
})
if err != nil {
t.Fatalf("Failed to create session: %v", err)
@@ -81,7 +81,7 @@ func TestSessionFsE2E(t *testing.T) {
session1, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
- CreateSessionFsProvider: createSessionFsHandler,
+ CreateSessionFSProvider: createSessionFSHandler,
})
if err != nil {
t.Fatalf("Failed to create session: %v", err)
@@ -111,7 +111,7 @@ func TestSessionFsE2E(t *testing.T) {
session2, err := client.ResumeSession(t.Context(), sessionID, &copilot.ResumeSessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
- CreateSessionFsProvider: createSessionFsHandler,
+ CreateSessionFSProvider: createSessionFSHandler,
})
if err != nil {
t.Fatalf("Failed to resume session: %v", err)
@@ -139,7 +139,7 @@ func TestSessionFsE2E(t *testing.T) {
ctx.ConfigureForTest(t)
client1 := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.TcpConnection{Path: ctx.CLIPath}
+ opts.Connection = copilot.TCPConnection{Path: ctx.CLIPath}
})
t.Cleanup(func() { client1.ForceStop() })
@@ -155,25 +155,25 @@ func TestSessionFsE2E(t *testing.T) {
}
client2 := copilot.NewClient(&copilot.ClientOptions{
- Connection: copilot.UriConnection{URL: fmt.Sprintf("localhost:%d", runtimePort)},
+ Connection: copilot.URIConnection{URL: fmt.Sprintf("localhost:%d", runtimePort)},
LogLevel: "error",
Env: ctx.Env(),
- SessionFs: sessionFsConfig,
+ SessionFS: sessionFSConfig,
})
t.Cleanup(func() { client2.ForceStop() })
if err := client2.Start(t.Context()); err == nil {
- t.Fatal("Expected Start to fail when SessionFs provider is set after sessions already exist")
+ t.Fatal("Expected Start to fail when SessionFS provider is set after sessions already exist")
}
})
- t.Run("should map large output handling into SessionFs", func(t *testing.T) {
+ t.Run("should map large output handling into SessionFS", func(t *testing.T) {
ctx.ConfigureForTest(t)
suppliedFileContent := strings.Repeat("x", 100_000)
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
- CreateSessionFsProvider: createSessionFsHandler,
+ CreateSessionFSProvider: createSessionFSHandler,
Tools: []copilot.Tool{
copilot.DefineTool("get_big_string", "Returns a large string",
func(_ struct{}, inv copilot.ToolInvocation) (string, error) {
@@ -213,12 +213,12 @@ func TestSessionFsE2E(t *testing.T) {
}
})
- t.Run("should succeed with compaction while using SessionFs", func(t *testing.T) {
+ t.Run("should succeed with compaction while using SessionFS", func(t *testing.T) {
ctx.ConfigureForTest(t)
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
- CreateSessionFsProvider: createSessionFsHandler,
+ CreateSessionFSProvider: createSessionFSHandler,
})
if err != nil {
t.Fatalf("Failed to create session: %v", err)
@@ -252,12 +252,12 @@ func TestSessionFsE2E(t *testing.T) {
t.Fatalf("Timed out waiting for checkpoint rewrite: %v", err)
}
})
- t.Run("should write workspace metadata via SessionFs", func(t *testing.T) {
+ t.Run("should write workspace metadata via SessionFS", func(t *testing.T) {
ctx.ConfigureForTest(t)
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
- CreateSessionFsProvider: createSessionFsHandler,
+ CreateSessionFSProvider: createSessionFSHandler,
})
if err != nil {
t.Fatalf("Failed to create session: %v", err)
@@ -277,7 +277,7 @@ func TestSessionFsE2E(t *testing.T) {
t.Fatalf("Expected response to contain 56, got %q", content)
}
- // WorkspaceManager should have created workspace.yaml via SessionFs
+ // WorkspaceManager should have created workspace.yaml via SessionFS
workspaceYamlPath := p(session.SessionID, sessionStatePath+"/workspace.yaml")
if err := waitForFileContent(workspaceYamlPath, "id:", 5*time.Second); err != nil {
t.Fatalf("Timed out waiting for workspace.yaml content: %v", err)
@@ -294,12 +294,12 @@ func TestSessionFsE2E(t *testing.T) {
}
})
- t.Run("should persist plan.md via SessionFs", func(t *testing.T) {
+ t.Run("should persist plan.md via SessionFS", func(t *testing.T) {
ctx.ConfigureForTest(t)
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
- CreateSessionFsProvider: createSessionFsHandler,
+ CreateSessionFSProvider: createSessionFSHandler,
})
if err != nil {
t.Fatalf("Failed to create session: %v", err)
@@ -339,12 +339,12 @@ func createSessionStatePath(t *testing.T) string {
return filepath.ToSlash(filepath.Join(t.TempDir(), "session-state"))
}
-type testSessionFsHandler struct {
+type testSessionFSHandler struct {
root string
sessionID string
}
-func (h *testSessionFsHandler) ReadFile(path string) (string, error) {
+func (h *testSessionFSHandler) ReadFile(path string) (string, error) {
content, err := os.ReadFile(providerPath(h.root, h.sessionID, path))
if err != nil {
return "", err
@@ -352,7 +352,7 @@ func (h *testSessionFsHandler) ReadFile(path string) (string, error) {
return string(content), nil
}
-func (h *testSessionFsHandler) WriteFile(path string, content string, mode *int) error {
+func (h *testSessionFSHandler) WriteFile(path string, content string, mode *int) error {
fullPath := providerPath(h.root, h.sessionID, path)
if err := os.MkdirAll(filepath.Dir(fullPath), 0o755); err != nil {
return err
@@ -364,7 +364,7 @@ func (h *testSessionFsHandler) WriteFile(path string, content string, mode *int)
return os.WriteFile(fullPath, []byte(content), perm)
}
-func (h *testSessionFsHandler) AppendFile(path string, content string, mode *int) error {
+func (h *testSessionFSHandler) AppendFile(path string, content string, mode *int) error {
fullPath := providerPath(h.root, h.sessionID, path)
if err := os.MkdirAll(filepath.Dir(fullPath), 0o755); err != nil {
return err
@@ -382,7 +382,7 @@ func (h *testSessionFsHandler) AppendFile(path string, content string, mode *int
return err
}
-func (h *testSessionFsHandler) Exists(path string) (bool, error) {
+func (h *testSessionFSHandler) Exists(path string) (bool, error) {
_, err := os.Stat(providerPath(h.root, h.sessionID, path))
if err == nil {
return true, nil
@@ -393,13 +393,13 @@ func (h *testSessionFsHandler) Exists(path string) (bool, error) {
return false, err
}
-func (h *testSessionFsHandler) Stat(path string) (*copilot.SessionFsFileInfo, error) {
+func (h *testSessionFSHandler) Stat(path string) (*copilot.SessionFSFileInfo, error) {
info, err := os.Stat(providerPath(h.root, h.sessionID, path))
if err != nil {
return nil, err
}
ts := info.ModTime().UTC()
- return &copilot.SessionFsFileInfo{
+ return &copilot.SessionFSFileInfo{
IsFile: !info.IsDir(),
IsDirectory: info.IsDir(),
Size: info.Size(),
@@ -408,7 +408,7 @@ func (h *testSessionFsHandler) Stat(path string) (*copilot.SessionFsFileInfo, er
}, nil
}
-func (h *testSessionFsHandler) MakeDirectory(path string, recursive bool, mode *int) error {
+func (h *testSessionFSHandler) MakeDirectory(path string, recursive bool, mode *int) error {
fullPath := providerPath(h.root, h.sessionID, path)
perm := os.FileMode(0o777)
if mode != nil {
@@ -420,7 +420,7 @@ func (h *testSessionFsHandler) MakeDirectory(path string, recursive bool, mode *
return os.Mkdir(fullPath, perm)
}
-func (h *testSessionFsHandler) ReadDirectory(path string) ([]string, error) {
+func (h *testSessionFSHandler) ReadDirectory(path string) ([]string, error) {
entries, err := os.ReadDir(providerPath(h.root, h.sessionID, path))
if err != nil {
return nil, err
@@ -432,18 +432,18 @@ func (h *testSessionFsHandler) ReadDirectory(path string) ([]string, error) {
return names, nil
}
-func (h *testSessionFsHandler) ReadDirectoryWithTypes(path string) ([]rpc.SessionFsReaddirWithTypesEntry, error) {
+func (h *testSessionFSHandler) ReadDirectoryWithTypes(path string) ([]rpc.SessionFSReaddirWithTypesEntry, error) {
entries, err := os.ReadDir(providerPath(h.root, h.sessionID, path))
if err != nil {
return nil, err
}
- result := make([]rpc.SessionFsReaddirWithTypesEntry, 0, len(entries))
+ result := make([]rpc.SessionFSReaddirWithTypesEntry, 0, len(entries))
for _, entry := range entries {
- entryType := rpc.SessionFsReaddirWithTypesEntryTypeFile
+ entryType := rpc.SessionFSReaddirWithTypesEntryTypeFile
if entry.IsDir() {
- entryType = rpc.SessionFsReaddirWithTypesEntryTypeDirectory
+ entryType = rpc.SessionFSReaddirWithTypesEntryTypeDirectory
}
- result = append(result, rpc.SessionFsReaddirWithTypesEntry{
+ result = append(result, rpc.SessionFSReaddirWithTypesEntry{
Name: entry.Name(),
Type: entryType,
})
@@ -451,7 +451,7 @@ func (h *testSessionFsHandler) ReadDirectoryWithTypes(path string) ([]rpc.Sessio
return result, nil
}
-func (h *testSessionFsHandler) Remove(path string, recursive bool, force bool) error {
+func (h *testSessionFSHandler) Remove(path string, recursive bool, force bool) error {
fullPath := providerPath(h.root, h.sessionID, path)
var err error
if recursive {
@@ -465,7 +465,7 @@ func (h *testSessionFsHandler) Remove(path string, recursive bool, force bool) e
return err
}
-func (h *testSessionFsHandler) Rename(src string, dest string) error {
+func (h *testSessionFSHandler) Rename(src string, dest string) error {
destPath := providerPath(h.root, h.sessionID, dest)
if err := os.MkdirAll(filepath.Dir(destPath), 0o755); err != nil {
return err
@@ -525,13 +525,13 @@ func waitForFileContent(path string, needle string, timeout time.Duration) error
return fmt.Errorf("file %s did not contain %q", path, needle)
}
-// TestSessionFsHandlerOperations mirrors the C# Should_Map_All_SessionFs_Handler_Operations test.
-// It exercises every operation on testSessionFsHandler directly to ensure the test helper
+// TestSessionFSHandlerOperations mirrors the C# Should_Map_All_SessionFS_Handler_Operations test.
+// It exercises every operation on testSessionFSHandler directly to ensure the test helper
// implementation routes file operations correctly to the per-session provider root.
-func TestSessionFsHandlerOperationsE2E(t *testing.T) {
+func TestSessionFSHandlerOperationsE2E(t *testing.T) {
providerRoot := t.TempDir()
sessionID := "handler-session"
- handler := &testSessionFsHandler{root: providerRoot, sessionID: sessionID}
+ handler := &testSessionFSHandler{root: providerRoot, sessionID: sessionID}
if err := handler.MakeDirectory("/workspace/nested", true, nil); err != nil {
t.Fatalf("Mkdir failed: %v", err)
@@ -589,7 +589,7 @@ func TestSessionFsHandlerOperationsE2E(t *testing.T) {
}
var found bool
for _, entry := range typedEntries {
- if entry.Name == "file.txt" && entry.Type == rpc.SessionFsReaddirWithTypesEntryTypeFile {
+ if entry.Name == "file.txt" && entry.Type == rpc.SessionFSReaddirWithTypesEntryTypeFile {
found = true
break
}
diff --git a/go/internal/e2e/session_fs_sqlite_e2e_test.go b/go/internal/e2e/session_fs_sqlite_e2e_test.go
index f7e849f56..fa3b49e48 100644
--- a/go/internal/e2e/session_fs_sqlite_e2e_test.go
+++ b/go/internal/e2e/session_fs_sqlite_e2e_test.go
@@ -20,7 +20,7 @@ type sqliteCall struct {
Query string
}
-// inMemorySqliteProvider is a SessionFsProvider backed by in-memory maps with a stub SQLite handler.
+// inMemorySqliteProvider is a SessionFSProvider backed by in-memory maps with a stub SQLite handler.
// The stub returns plausible canned responses based on query type rather than executing real SQL.
// This avoids pulling in a real SQLite dependency (which would force a go directive bump across
// all scenario go.mod files).
@@ -83,17 +83,17 @@ func (p *inMemorySqliteProvider) Exists(path string) (bool, error) {
return isFile || isDir, nil
}
-func (p *inMemorySqliteProvider) Stat(path string) (*copilot.SessionFsFileInfo, error) {
+func (p *inMemorySqliteProvider) Stat(path string) (*copilot.SessionFSFileInfo, error) {
p.mu.Lock()
defer p.mu.Unlock()
now := time.Now().UTC()
if p.dirs[path] {
- return &copilot.SessionFsFileInfo{
+ return &copilot.SessionFSFileInfo{
IsFile: false, IsDirectory: true, Size: 0, Mtime: now, Birthtime: now,
}, nil
}
if content, ok := p.files[path]; ok {
- return &copilot.SessionFsFileInfo{
+ return &copilot.SessionFSFileInfo{
IsFile: true, IsDirectory: false, Size: int64(len(content)), Mtime: now, Birthtime: now,
}, nil
}
@@ -143,17 +143,17 @@ func (p *inMemorySqliteProvider) ReadDirectory(path string) ([]string, error) {
return result, nil
}
-func (p *inMemorySqliteProvider) ReadDirectoryWithTypes(path string) ([]rpc.SessionFsReaddirWithTypesEntry, error) {
+func (p *inMemorySqliteProvider) ReadDirectoryWithTypes(path string) ([]rpc.SessionFSReaddirWithTypesEntry, error) {
p.mu.Lock()
defer p.mu.Unlock()
prefix := strings.TrimRight(path, "/") + "/"
- entries := map[string]rpc.SessionFsReaddirWithTypesEntryType{}
+ entries := map[string]rpc.SessionFSReaddirWithTypesEntryType{}
for d := range p.dirs {
if strings.HasPrefix(d, prefix) {
rest := d[len(prefix):]
if rest != "" {
name := strings.SplitN(rest, "/", 2)[0]
- entries[name] = rpc.SessionFsReaddirWithTypesEntryTypeDirectory
+ entries[name] = rpc.SessionFSReaddirWithTypesEntryTypeDirectory
}
}
}
@@ -163,14 +163,14 @@ func (p *inMemorySqliteProvider) ReadDirectoryWithTypes(path string) ([]rpc.Sess
if rest != "" {
name := strings.SplitN(rest, "/", 2)[0]
if _, exists := entries[name]; !exists {
- entries[name] = rpc.SessionFsReaddirWithTypesEntryTypeFile
+ entries[name] = rpc.SessionFSReaddirWithTypesEntryTypeFile
}
}
}
}
- result := make([]rpc.SessionFsReaddirWithTypesEntry, 0, len(entries))
+ result := make([]rpc.SessionFSReaddirWithTypesEntry, 0, len(entries))
for name, typ := range entries {
- result = append(result, rpc.SessionFsReaddirWithTypesEntry{Name: name, Type: typ})
+ result = append(result, rpc.SessionFSReaddirWithTypesEntry{Name: name, Type: typ})
}
sort.Slice(result, func(i, j int) bool { return result[i].Name < result[j].Name })
return result, nil
@@ -195,7 +195,7 @@ func (p *inMemorySqliteProvider) Rename(src string, dest string) error {
return nil
}
-func (p *inMemorySqliteProvider) SqliteQuery(queryType rpc.SessionFsSqliteQueryType, query string, params map[string]any) (*copilot.SessionFsSqliteQueryResult, error) {
+func (p *inMemorySqliteProvider) SqliteQuery(queryType rpc.SessionFSSqliteQueryType, query string, params map[string]any) (*copilot.SessionFSSqliteQueryResult, error) {
p.mu.Lock()
defer p.mu.Unlock()
p.hadQuery = true
@@ -211,26 +211,26 @@ func (p *inMemorySqliteProvider) SqliteQuery(queryType rpc.SessionFsSqliteQueryT
// normally without pulling in a real SQLite dependency.
upper := strings.ToUpper(strings.TrimSpace(query))
switch queryType {
- case rpc.SessionFsSqliteQueryTypeExec:
- return &copilot.SessionFsSqliteQueryResult{Columns: []string{}, Rows: []map[string]any{}}, nil
- case rpc.SessionFsSqliteQueryTypeRun:
+ case rpc.SessionFSSqliteQueryTypeExec:
+ return &copilot.SessionFSSqliteQueryResult{Columns: []string{}, Rows: []map[string]any{}}, nil
+ case rpc.SessionFSSqliteQueryTypeRun:
lastID := int64(1)
- return &copilot.SessionFsSqliteQueryResult{
+ return &copilot.SessionFSSqliteQueryResult{
Columns: []string{},
Rows: []map[string]any{},
RowsAffected: 1,
LastInsertRowid: &lastID,
}, nil
- case rpc.SessionFsSqliteQueryTypeQuery:
+ case rpc.SessionFSSqliteQueryTypeQuery:
if strings.Contains(upper, "SELECT") {
- return &copilot.SessionFsSqliteQueryResult{
+ return &copilot.SessionFSSqliteQueryResult{
Columns: []string{"id", "name"},
Rows: []map[string]any{{"id": "a1", "name": "Widget"}},
}, nil
}
- return &copilot.SessionFsSqliteQueryResult{Columns: []string{}, Rows: []map[string]any{}}, nil
+ return &copilot.SessionFSSqliteQueryResult{Columns: []string{}, Rows: []map[string]any{}}, nil
}
- return &copilot.SessionFsSqliteQueryResult{Columns: []string{}, Rows: []map[string]any{}}, nil
+ return &copilot.SessionFSSqliteQueryResult{Columns: []string{}, Rows: []map[string]any{}}, nil
}
func (p *inMemorySqliteProvider) SqliteExists() (bool, error) {
@@ -239,27 +239,27 @@ func (p *inMemorySqliteProvider) SqliteExists() (bool, error) {
return p.hadQuery, nil
}
-func TestSessionFsSqliteE2E(t *testing.T) {
+func TestSessionFSSqliteE2E(t *testing.T) {
ctx := testharness.NewTestContext(t)
sessionStatePath := createSessionStatePath(t)
- sessionFsConfig := &copilot.SessionFsConfig{
+ sessionFSConfig := &copilot.SessionFSConfig{
InitialWorkingDirectory: "/",
SessionStatePath: sessionStatePath,
- Conventions: rpc.SessionFsSetProviderConventionsPosix,
- Capabilities: &copilot.SessionFsCapabilities{Sqlite: true},
+ Conventions: rpc.SessionFSSetProviderConventionsPosix,
+ Capabilities: &copilot.SessionFSCapabilities{Sqlite: true},
}
var sqliteCalls []sqliteCall
var providers sync.Map
- createSessionFsHandler := func(session *copilot.Session) copilot.SessionFsProvider {
+ createSessionFSHandler := func(session *copilot.Session) copilot.SessionFSProvider {
p := newInMemorySqliteProvider(session.SessionID, &sqliteCalls)
providers.Store(session.SessionID, p)
return p
}
client := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.SessionFs = sessionFsConfig
+ opts.SessionFS = sessionFSConfig
})
t.Cleanup(func() { client.ForceStop() })
@@ -269,7 +269,7 @@ func TestSessionFsSqliteE2E(t *testing.T) {
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
- CreateSessionFsProvider: createSessionFsHandler,
+ CreateSessionFSProvider: createSessionFSHandler,
})
if err != nil {
t.Fatalf("Failed to create session: %v", err)
@@ -307,7 +307,7 @@ func TestSessionFsSqliteE2E(t *testing.T) {
session, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
- CreateSessionFsProvider: createSessionFsHandler,
+ CreateSessionFSProvider: createSessionFSHandler,
})
if err != nil {
t.Fatalf("Failed to create session: %v", err)
diff --git a/go/internal/e2e/skills_e2e_test.go b/go/internal/e2e/skills_e2e_test.go
index 80cb4f686..06a96cf95 100644
--- a/go/internal/e2e/skills_e2e_test.go
+++ b/go/internal/e2e/skills_e2e_test.go
@@ -258,7 +258,7 @@ func TestSkillsE2E(t *testing.T) {
disabledSession, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
WorkingDirectory: projectDir,
- EnableConfigDiscovery: false,
+ EnableConfigDiscovery: copilot.Bool(false),
})
if err != nil {
t.Fatalf("CreateSession (disabled) failed: %v", err)
@@ -278,7 +278,7 @@ func TestSkillsE2E(t *testing.T) {
enabledSession, err := client.CreateSession(t.Context(), &copilot.SessionConfig{
OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
WorkingDirectory: projectDir,
- EnableConfigDiscovery: true,
+ EnableConfigDiscovery: copilot.Bool(true),
})
if err != nil {
t.Fatalf("CreateSession (enabled) failed: %v", err)
diff --git a/go/internal/e2e/suspend_e2e_test.go b/go/internal/e2e/suspend_e2e_test.go
index 672481a4f..8909193e2 100644
--- a/go/internal/e2e/suspend_e2e_test.go
+++ b/go/internal/e2e/suspend_e2e_test.go
@@ -48,10 +48,10 @@ func TestSuspendE2E(t *testing.T) {
t.Run("should allow resume and continue conversation after suspend", func(t *testing.T) {
ctx.ConfigureForTest(t)
- _, cliURL := startTcpServer(t, ctx)
+ _, cliURL := startTCPServer(t, ctx)
client1 := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.UriConnection{URL: cliURL, ConnectionToken: sharedTcpToken}
+ opts.Connection = copilot.URIConnection{URL: cliURL, ConnectionToken: sharedTCPToken}
})
t.Cleanup(func() { client1.ForceStop() })
@@ -75,7 +75,7 @@ func TestSuspendE2E(t *testing.T) {
client1.ForceStop()
client2 := ctx.NewClient(func(opts *copilot.ClientOptions) {
- opts.Connection = copilot.UriConnection{URL: cliURL, ConnectionToken: sharedTcpToken}
+ opts.Connection = copilot.URIConnection{URL: cliURL, ConnectionToken: sharedTCPToken}
})
t.Cleanup(func() { client2.ForceStop() })
diff --git a/go/internal/e2e/testharness/context.go b/go/internal/e2e/testharness/context.go
index cae966667..fae5623aa 100644
--- a/go/internal/e2e/testharness/context.go
+++ b/go/internal/e2e/testharness/context.go
@@ -231,7 +231,7 @@ func (c *TestContext) NewClient(opts ...func(*copilot.ClientOptions)) *copilot.C
opt(options)
}
- _, externalRuntime := options.Connection.(copilot.UriConnection)
+ _, externalRuntime := options.Connection.(copilot.URIConnection)
if options.GitHubToken == "" && !externalRuntime {
options.GitHubToken = defaultGitHubToken
}
diff --git a/go/mode_empty.go b/go/mode_empty.go
index a3e58ad9c..05b7e28bb 100644
--- a/go/mode_empty.go
+++ b/go/mode_empty.go
@@ -20,21 +20,21 @@ func validateNewClientForMode(opts *ClientOptions) {
}
// Empty mode requires durable, app-owned storage. Either:
// - the app supplied a BaseDirectory the runtime can write to,
- // - the app supplied a SessionFs implementation,
+ // - the app supplied a SessionFS implementation,
// - or the app is connecting to an externally-managed runtime via
- // UriConnection (in which case the host owns storage).
+ // URIConnection (in which case the host owns storage).
if opts.BaseDirectory != "" {
return
}
- if opts.SessionFs != nil {
+ if opts.SessionFS != nil {
return
}
- if _, ok := opts.Connection.(UriConnection); ok {
+ if _, ok := opts.Connection.(URIConnection); ok {
return
}
- panic("Client is in Mode=ModeEmpty but neither BaseDirectory, SessionFs, nor a UriConnection was supplied. " +
- "Empty mode requires explicit, per-tenant storage; set ClientOptions.BaseDirectory or .SessionFs, " +
- "or connect to an externally-managed runtime via UriConnection.")
+ panic("Client is in Mode=ModeEmpty but neither BaseDirectory, SessionFS, nor a URIConnection was supplied. " +
+ "Empty mode requires explicit, per-tenant storage; set ClientOptions.BaseDirectory or .SessionFS, " +
+ "or connect to an externally-managed runtime via URIConnection.")
}
// validateToolFilterList rejects bare "*" entries with an actionable error
@@ -45,7 +45,7 @@ func validateToolFilterList(field string, list []string) error {
if entry == "*" {
return fmt.Errorf(
"invalid %s entry %q: there is no bare wildcard. "+
- "Use one or more of NewToolSet().AddBuiltIn(\"*\"), .AddMcp(\"*\"), or .AddCustom(\"*\") "+
+ "Use one or more of NewToolSet().AddBuiltIn(\"*\"), .AddMCP(\"*\"), or .AddCustom(\"*\") "+
"to target a specific source",
field, entry)
}
diff --git a/go/rpc/generated_rpc_api_shape_test.go b/go/rpc/generated_rpc_api_shape_test.go
index bddbb263d..a6b357d54 100644
--- a/go/rpc/generated_rpc_api_shape_test.go
+++ b/go/rpc/generated_rpc_api_shape_test.go
@@ -16,8 +16,8 @@ var (
_ ExternalToolResult = (*ExternalToolTextResultForLlm)(nil)
_ FilterMapping = FilterMappingEnumMap{}
_ FilterMapping = ContentFilterModeMarkdown
- _ McpServerConfig = (*McpServerConfigHTTP)(nil)
- _ McpServerConfig = (*McpServerConfigStdio)(nil)
+ _ MCPServerConfig = (*MCPServerConfigHTTP)(nil)
+ _ MCPServerConfig = (*MCPServerConfigStdio)(nil)
_ UIElicitationFieldValue = UIElicitationStringValue("")
_ UIElicitationFieldValue = UIElicitationStringArrayValue(nil)
_ UIElicitationFieldValue = UIElicitationBooleanValue(false)
@@ -34,12 +34,12 @@ func TestGeneratedRPCAPIShape(t *testing.T) {
assertInterfaceType(t, file, "FilterMapping")
assertTypeExpr(t, fileSet, findTypeSpec(t, file, "FilterMappingEnumMap").Type, "map[string]ContentFilterMode")
- assertInterfaceType(t, file, "McpServerConfig")
- assertStructFieldType(t, file, fileSet, "McpConfigAddRequest", "Config", "McpServerConfig")
- assertStructFieldType(t, file, fileSet, "McpConfigList", "Servers", "map[string]McpServerConfig")
- assertStructFieldType(t, file, fileSet, "McpConfigUpdateRequest", "Config", "McpServerConfig")
- assertStructFieldType(t, file, fileSet, "McpServerConfigHTTP", "FilterMapping", "FilterMapping")
- assertStructFieldType(t, file, fileSet, "McpServerConfigStdio", "FilterMapping", "FilterMapping")
+ assertInterfaceType(t, file, "MCPServerConfig")
+ assertStructFieldType(t, file, fileSet, "MCPConfigAddRequest", "Config", "MCPServerConfig")
+ assertStructFieldType(t, file, fileSet, "MCPConfigList", "Servers", "map[string]MCPServerConfig")
+ assertStructFieldType(t, file, fileSet, "MCPConfigUpdateRequest", "Config", "MCPServerConfig")
+ assertStructFieldType(t, file, fileSet, "MCPServerConfigHTTP", "FilterMapping", "FilterMapping")
+ assertStructFieldType(t, file, fileSet, "MCPServerConfigStdio", "FilterMapping", "FilterMapping")
assertInterfaceType(t, file, "UIElicitationFieldValue")
assertTypeExpr(t, fileSet, findTypeSpec(t, file, "UIElicitationStringArrayValue").Type, "[]string")
diff --git a/go/rpc/generated_rpc_union_test.go b/go/rpc/generated_rpc_union_test.go
index c6f4c3b79..131409f04 100644
--- a/go/rpc/generated_rpc_union_test.go
+++ b/go/rpc/generated_rpc_union_test.go
@@ -84,8 +84,8 @@ func TestFilterMappingJSONUnion(t *testing.T) {
}
}
-func TestMcpServerConfigJSONUnion(t *testing.T) {
- var localConfig McpServerConfig = &McpServerConfigStdio{
+func TestMCPServerConfigJSONUnion(t *testing.T) {
+ var localConfig MCPServerConfig = &MCPServerConfigStdio{
Args: []string{"-v"},
Command: "node",
}
@@ -97,16 +97,16 @@ func TestMcpServerConfigJSONUnion(t *testing.T) {
t.Fatalf("marshal local config = %s", raw)
}
- decodedLocal, err := unmarshalMcpServerConfig([]byte(`{"args":["-v"],"command":"node"}`))
+ decodedLocal, err := unmarshalMCPServerConfig([]byte(`{"args":["-v"],"command":"node"}`))
if err != nil {
t.Fatalf("unmarshal local config: %v", err)
}
- decodedLocalValue, ok := decodedLocal.(*McpServerConfigStdio)
+ decodedLocalValue, ok := decodedLocal.(*MCPServerConfigStdio)
if !ok || decodedLocalValue.Command != "node" || len(decodedLocalValue.Args) != 1 || decodedLocalValue.Args[0] != "-v" {
t.Fatalf("unmarshal local config = %#v", decodedLocal)
}
- var httpConfig McpServerConfig = &McpServerConfigHTTP{URL: "https://example.com/mcp"}
+ var httpConfig MCPServerConfig = &MCPServerConfigHTTP{URL: "https://example.com/mcp"}
raw, err = json.Marshal(httpConfig)
if err != nil {
t.Fatalf("marshal HTTP config: %v", err)
@@ -115,21 +115,21 @@ func TestMcpServerConfigJSONUnion(t *testing.T) {
t.Fatalf("marshal HTTP config = %s", raw)
}
- decodedHTTP, err := unmarshalMcpServerConfig([]byte(`{"url":"https://example.com/mcp"}`))
+ decodedHTTP, err := unmarshalMCPServerConfig([]byte(`{"url":"https://example.com/mcp"}`))
if err != nil {
t.Fatalf("unmarshal HTTP config: %v", err)
}
- decodedHTTPValue, ok := decodedHTTP.(*McpServerConfigHTTP)
+ decodedHTTPValue, ok := decodedHTTP.(*MCPServerConfigHTTP)
if !ok || decodedHTTPValue.URL != "https://example.com/mcp" {
t.Fatalf("unmarshal HTTP config = %#v", decodedHTTP)
}
- decodedRaw, err := unmarshalMcpServerConfig([]byte(`{"name":"future"}`))
+ decodedRaw, err := unmarshalMCPServerConfig([]byte(`{"name":"future"}`))
if err != nil {
t.Fatalf("unmarshal raw config: %v", err)
}
- if _, ok := decodedRaw.(*RawMcpServerConfigData); !ok {
- t.Fatalf("unmarshal raw config = %T, want *RawMcpServerConfigData", decodedRaw)
+ if _, ok := decodedRaw.(*RawMCPServerConfigData); !ok {
+ t.Fatalf("unmarshal raw config = %T, want *RawMCPServerConfigData", decodedRaw)
}
}
@@ -195,7 +195,7 @@ func TestCommandsInvokeUnmarshalsSlashCommandInvocationResult(t *testing.T) {
})
input := "details"
- result, err := NewSessionRpc(client, "session-1").Commands.Invoke(t.Context(), &CommandsInvokeRequest{
+ result, err := NewSessionRPC(client, "session-1").Commands.Invoke(t.Context(), &CommandsInvokeRequest{
Input: &input,
Name: "help",
})
diff --git a/go/rpc/zrpc.go b/go/rpc/zrpc.go
index 3f6e7577b..d6ae99b6c 100644
--- a/go/rpc/zrpc.go
+++ b/go/rpc/zrpc.go
@@ -81,8 +81,8 @@ type AgentInfo struct {
ID string `json:"id"`
// MCP server configurations attached to this agent, keyed by server name. Server config
// shape mirrors the MCP `mcpServers` schema.
- // Experimental: McpServers is part of an experimental API and may change or be removed.
- McpServers map[string]any `json:"mcpServers,omitempty"`
+ // Experimental: MCPServers is part of an experimental API and may change or be removed.
+ MCPServers map[string]any `json:"mcpServers,omitzero"`
// Preferred model id for this agent. When omitted, inherits the outer agent's model.
Model *string `json:"model,omitempty"`
// Unique identifier of the custom agent
@@ -91,11 +91,11 @@ type AgentInfo struct {
// from disk; remote agents do not have a path.
Path *string `json:"path,omitempty"`
// Skill names preloaded into this agent's context. Omitted means none.
- Skills []string `json:"skills,omitempty"`
+ Skills []string `json:"skills,omitzero"`
// Where the agent definition was loaded from
Source *AgentInfoSource `json:"source,omitempty"`
// Allowed tool names for this agent. Empty array means none; omitted means inherit defaults.
- Tools []string `json:"tools,omitempty"`
+ Tools []string `json:"tools,omitzero"`
// Whether the agent can be selected directly by the user. Agents marked `false` are
// subagent-only.
UserInvocable *bool `json:"userInvocable,omitempty"`
@@ -328,6 +328,178 @@ type AllowAllPermissionState struct {
Enabled bool `json:"enabled"`
}
+// A user message attachment — a file, directory, code selection, blob, GitHub reference, or
+// extension-supplied context payload
+// Experimental: Attachment is part of an experimental API and may change or be removed.
+type Attachment interface {
+ attachment()
+ Type() AttachmentType
+}
+
+type RawAttachmentData struct {
+ Discriminator AttachmentType
+ Raw json.RawMessage
+}
+
+func (RawAttachmentData) attachment() {}
+func (r RawAttachmentData) Type() AttachmentType {
+ return r.Discriminator
+}
+
+// Blob attachment with inline base64-encoded data
+// Experimental: AttachmentBlob is part of an experimental API and may change or be removed.
+type AttachmentBlob struct {
+ // Base64-encoded content
+ Data string `json:"data"`
+ // User-facing display name for the attachment
+ DisplayName *string `json:"displayName,omitempty"`
+ // MIME type of the inline data
+ MIMEType string `json:"mimeType"`
+}
+
+func (AttachmentBlob) attachment() {}
+func (AttachmentBlob) Type() AttachmentType {
+ return AttachmentTypeBlob
+}
+
+// Directory attachment
+// Experimental: AttachmentDirectory is part of an experimental API and may change or be
+// removed.
+type AttachmentDirectory struct {
+ // User-facing display name for the attachment
+ DisplayName string `json:"displayName"`
+ // Absolute directory path
+ Path string `json:"path"`
+}
+
+func (AttachmentDirectory) attachment() {}
+func (AttachmentDirectory) Type() AttachmentType {
+ return AttachmentTypeDirectory
+}
+
+// Structured context contributed by an extension. Composer pills displayed in the host are
+// forwarded back through session.send.attachments, then rendered into the model prompt as
+// an XML block.
+// Experimental: AttachmentExtensionContext is part of an experimental API and may change or
+// be removed.
+type AttachmentExtensionContext struct {
+ // Provider-local canvas identifier when the push was bound to a canvas instance
+ CanvasID *string `json:"canvasId,omitempty"`
+ // ISO 8601 timestamp captured by the runtime when the push was accepted
+ CapturedAt time.Time `json:"capturedAt"`
+ // Owning extension identifier. Runtime-derived from the caller's connection when produced
+ // via session.extensions.sendAttachmentsToMessage; preserved verbatim on subsequent
+ // transports.
+ ExtensionID string `json:"extensionId"`
+ // Open canvas instance identifier when the push was bound to a canvas instance
+ InstanceID *string `json:"instanceId,omitempty"`
+ // Caller-supplied JSON payload
+ Payload any `json:"payload,omitempty"`
+ // Human-readable composer pill label
+ Title string `json:"title"`
+}
+
+func (AttachmentExtensionContext) attachment() {}
+func (AttachmentExtensionContext) Type() AttachmentType {
+ return AttachmentTypeExtensionContext
+}
+
+// File attachment
+// Experimental: AttachmentFile is part of an experimental API and may change or be removed.
+type AttachmentFile struct {
+ // User-facing display name for the attachment
+ DisplayName string `json:"displayName"`
+ // Optional line range to scope the attachment to a specific section of the file
+ LineRange *AttachmentFileLineRange `json:"lineRange,omitempty"`
+ // Absolute file path
+ Path string `json:"path"`
+}
+
+func (AttachmentFile) attachment() {}
+func (AttachmentFile) Type() AttachmentType {
+ return AttachmentTypeFile
+}
+
+// GitHub issue, pull request, or discussion reference
+// Experimental: AttachmentGitHubReference is part of an experimental API and may change or
+// be removed.
+type AttachmentGitHubReference struct {
+ // Issue, pull request, or discussion number
+ Number int64 `json:"number"`
+ // Type of GitHub reference
+ ReferenceType AttachmentGitHubReferenceType `json:"referenceType"`
+ // Current state of the referenced item (e.g., open, closed, merged)
+ State string `json:"state"`
+ // Title of the referenced item
+ Title string `json:"title"`
+ // URL to the referenced item on GitHub
+ URL string `json:"url"`
+}
+
+func (AttachmentGitHubReference) attachment() {}
+func (AttachmentGitHubReference) Type() AttachmentType {
+ return AttachmentTypeGitHubReference
+}
+
+// Code selection attachment from an editor
+// Experimental: AttachmentSelection is part of an experimental API and may change or be
+// removed.
+type AttachmentSelection struct {
+ // User-facing display name for the selection
+ DisplayName string `json:"displayName"`
+ // Absolute path to the file containing the selection
+ FilePath string `json:"filePath"`
+ // Position range of the selection within the file
+ Selection AttachmentSelectionDetails `json:"selection"`
+ // The selected text content
+ Text string `json:"text"`
+}
+
+func (AttachmentSelection) attachment() {}
+func (AttachmentSelection) Type() AttachmentType {
+ return AttachmentTypeSelection
+}
+
+// Optional line range to scope the attachment to a specific section of the file
+// Experimental: AttachmentFileLineRange is part of an experimental API and may change or be
+// removed.
+type AttachmentFileLineRange struct {
+ // End line number (1-based, inclusive)
+ End int64 `json:"end"`
+ // Start line number (1-based)
+ Start int64 `json:"start"`
+}
+
+// Position range of the selection within the file
+// Experimental: AttachmentSelectionDetails is part of an experimental API and may change or
+// be removed.
+type AttachmentSelectionDetails struct {
+ // End position of the selection
+ End AttachmentSelectionDetailsEnd `json:"end"`
+ // Start position of the selection
+ Start AttachmentSelectionDetailsStart `json:"start"`
+}
+
+// End position of the selection
+// Experimental: AttachmentSelectionDetailsEnd is part of an experimental API and may change
+// or be removed.
+type AttachmentSelectionDetailsEnd struct {
+ // End character offset within the line (0-based)
+ Character int64 `json:"character"`
+ // End line number (0-based)
+ Line int64 `json:"line"`
+}
+
+// Start position of the selection
+// Experimental: AttachmentSelectionDetailsStart is part of an experimental API and may
+// change or be removed.
+type AttachmentSelectionDetailsStart struct {
+ // Start character offset within the line (0-based)
+ Character int64 `json:"character"`
+ // Start line number (0-based)
+ Line int64 `json:"line"`
+}
+
// The new auth credentials to install on the session. When omitted or `undefined`, the call
// is a no-op and the session's existing credentials are preserved. The runtime stores the
// value verbatim and uses it for outbound model/API requests; it does NOT re-validate or
@@ -408,8 +580,8 @@ func (EnvAuthInfo) Type() AuthInfoType {
}
// Schema for the `GhCliAuthInfo` type.
-// Experimental: GhCliAuthInfo is part of an experimental API and may change or be removed.
-type GhCliAuthInfo struct {
+// Experimental: GhCLIAuthInfo is part of an experimental API and may change or be removed.
+type GhCLIAuthInfo struct {
// Snapshot of the authenticated user's Copilot subscription info, if known. Mirrors the
// GitHub API `/copilot_internal/v2/token` user response shape — the runtime trusts this
// verbatim and does not re-fetch when set.
@@ -422,9 +594,9 @@ type GhCliAuthInfo struct {
Token string `json:"token"`
}
-func (GhCliAuthInfo) authInfo() {}
-func (GhCliAuthInfo) Type() AuthInfoType {
- return AuthInfoTypeGhCli
+func (GhCLIAuthInfo) authInfo() {}
+func (GhCLIAuthInfo) Type() AuthInfoType {
+ return AuthInfoTypeGhCLI
}
// Schema for the `HMACAuthInfo` type.
@@ -435,14 +607,14 @@ type HMACAuthInfo struct {
// verbatim and does not re-fetch when set.
CopilotUser *CopilotUserResponse `json:"copilotUser,omitempty"`
// HMAC secret used to sign requests.
- Hmac string `json:"hmac"`
+ HMAC string `json:"hmac"`
// Authentication host. HMAC auth always targets the public GitHub host.
Host HMACAuthInfoHost `json:"host"`
}
func (HMACAuthInfo) authInfo() {}
func (HMACAuthInfo) Type() AuthInfoType {
- return AuthInfoTypeHmac
+ return AuthInfoTypeHMAC
}
// Schema for the `TokenAuthInfo` type.
@@ -801,22 +973,22 @@ type CopilotUserResponse struct {
AssignedDate *string `json:"assigned_date,omitempty"`
CanSignupForLimited *bool `json:"can_signup_for_limited,omitempty"`
ChatEnabled *bool `json:"chat_enabled,omitempty"`
- CliRemoteControlEnabled *bool `json:"cli_remote_control_enabled,omitempty"`
+ CLIRemoteControlEnabled *bool `json:"cli_remote_control_enabled,omitempty"`
CloudSessionStorageEnabled *bool `json:"cloud_session_storage_enabled,omitempty"`
CodexAgentEnabled *bool `json:"codex_agent_enabled,omitempty"`
CopilotignoreEnabled *bool `json:"copilotignore_enabled,omitempty"`
CopilotPlan *string `json:"copilot_plan,omitempty"`
// Schema for the `CopilotUserResponseEndpoints` type.
Endpoints *CopilotUserResponseEndpoints `json:"endpoints,omitempty"`
- IsMcpEnabled *bool `json:"is_mcp_enabled,omitempty"`
- LimitedUserQuotas map[string]float64 `json:"limited_user_quotas,omitempty"`
+ IsMCPEnabled *bool `json:"is_mcp_enabled,omitempty"`
+ LimitedUserQuotas map[string]float64 `json:"limited_user_quotas,omitzero"`
LimitedUserResetDate *string `json:"limited_user_reset_date,omitempty"`
Login *string `json:"login,omitempty"`
- MonthlyQuotas map[string]float64 `json:"monthly_quotas,omitempty"`
- OrganizationList []CopilotUserResponseOrganizationListItem `json:"organization_list,omitempty"`
- OrganizationLoginList []string `json:"organization_login_list,omitempty"`
+ MonthlyQuotas map[string]float64 `json:"monthly_quotas,omitzero"`
+ OrganizationList []CopilotUserResponseOrganizationListItem `json:"organization_list,omitzero"`
+ OrganizationLoginList []string `json:"organization_login_list,omitzero"`
QuotaResetDate *string `json:"quota_reset_date,omitempty"`
- QuotaResetDateUtc *string `json:"quota_reset_date_utc,omitempty"`
+ QuotaResetDateUTC *string `json:"quota_reset_date_utc,omitempty"`
// Schema for the `CopilotUserResponseQuotaSnapshots` type.
QuotaSnapshots *CopilotUserResponseQuotaSnapshots `json:"quota_snapshots,omitempty"`
RestrictedTelemetry *bool `json:"restricted_telemetry,omitempty"`
@@ -863,7 +1035,7 @@ type CopilotUserResponseQuotaSnapshotsChat struct {
QuotaRemaining *float64 `json:"quota_remaining,omitempty"`
QuotaResetAt *float64 `json:"quota_reset_at,omitempty"`
Remaining *float64 `json:"remaining,omitempty"`
- TimestampUtc *string `json:"timestamp_utc,omitempty"`
+ TimestampUTC *string `json:"timestamp_utc,omitempty"`
TokenBasedBilling *bool `json:"token_based_billing,omitempty"`
Unlimited *bool `json:"unlimited,omitempty"`
}
@@ -881,7 +1053,7 @@ type CopilotUserResponseQuotaSnapshotsCompletions struct {
QuotaRemaining *float64 `json:"quota_remaining,omitempty"`
QuotaResetAt *float64 `json:"quota_reset_at,omitempty"`
Remaining *float64 `json:"remaining,omitempty"`
- TimestampUtc *string `json:"timestamp_utc,omitempty"`
+ TimestampUTC *string `json:"timestamp_utc,omitempty"`
TokenBasedBilling *bool `json:"token_based_billing,omitempty"`
Unlimited *bool `json:"unlimited,omitempty"`
}
@@ -899,14 +1071,18 @@ type CopilotUserResponseQuotaSnapshotsPremiumInteractions struct {
QuotaRemaining *float64 `json:"quota_remaining,omitempty"`
QuotaResetAt *float64 `json:"quota_reset_at,omitempty"`
Remaining *float64 `json:"remaining,omitempty"`
- TimestampUtc *string `json:"timestamp_utc,omitempty"`
+ TimestampUTC *string `json:"timestamp_utc,omitempty"`
TokenBasedBilling *bool `json:"token_based_billing,omitempty"`
Unlimited *bool `json:"unlimited,omitempty"`
}
-// The currently selected model and reasoning effort for the session.
+// The currently selected model, reasoning effort, and context tier for the session. The
+// context tier reflects `Session.getContextTier()`, restored from the session journal on
+// resume.
// Experimental: CurrentModel is part of an experimental API and may change or be removed.
type CurrentModel struct {
+ // Context tier for models that support multiple context-window sizes.
+ ContextTier *ContextTier `json:"contextTier,omitempty"`
// Currently active model identifier
ModelID *string `json:"modelId,omitempty"`
// Reasoning effort level currently applied to the active model, when one is set. Reads
@@ -924,11 +1100,11 @@ type CurrentToolMetadata struct {
// Tool description
Description string `json:"description"`
// JSON Schema for tool input
- InputSchema map[string]any `json:"input_schema,omitempty"`
+ InputSchema map[string]any `json:"input_schema,omitzero"`
// MCP server name for MCP-backed tools
- McpServerName *string `json:"mcpServerName,omitempty"`
+ MCPServerName *string `json:"mcpServerName,omitempty"`
// Raw MCP tool name for MCP-backed tools
- McpToolName *string `json:"mcpToolName,omitempty"`
+ MCPToolName *string `json:"mcpToolName,omitempty"`
// Model-facing tool name
Name string `json:"name"`
// Optional MCP/config namespaced tool name
@@ -940,7 +1116,7 @@ type CurrentToolMetadata struct {
// removed.
type DiscoveredCanvas struct {
// Actions the agent or host may invoke on an open instance
- Actions []CanvasAction `json:"actions,omitempty"`
+ Actions []CanvasAction `json:"actions,omitzero"`
// Provider-local canvas identifier
CanvasID string `json:"canvasId"`
// Short, single-sentence description shown to the agent in canvas catalogs.
@@ -956,15 +1132,15 @@ type DiscoveredCanvas struct {
}
// Schema for the `DiscoveredMcpServer` type.
-type DiscoveredMcpServer struct {
+type DiscoveredMCPServer struct {
// Whether the server is enabled (not in the disabled list)
Enabled bool `json:"enabled"`
// Server name (config key)
Name string `json:"name"`
// Configuration source: user, workspace, plugin, or builtin
- Source McpServerSource `json:"source"`
+ Source MCPServerSource `json:"source"`
// Server transport type: stdio, http, sse (deprecated), or memory
- Type *DiscoveredMcpServerType `json:"type,omitempty"`
+ Type *DiscoveredMCPServerType `json:"type,omitempty"`
}
// Slash-prefixed command string to enqueue for FIFO processing.
@@ -998,7 +1174,7 @@ type EventLogReadRequest struct {
// beginning of the session's persisted history.
Cursor *string `json:"cursor,omitempty"`
// Maximum number of events to return in this batch (1–1000, default 200).
- Max *int32 `json:"max,omitempty"`
+ Max *int64 `json:"max,omitempty"`
// Either '*' to receive all event types, or a non-empty list of event types to receive
Types *EventLogTypes `json:"types,omitempty"`
// Milliseconds to wait for new events when the cursor is at the tail of history. 0
@@ -1135,9 +1311,9 @@ func (ExternalToolTextResultForLlm) externalToolResult() {}
// or be removed.
type ExternalToolTextResultForLlm struct {
// Base64-encoded binary results returned to the model
- BinaryResultsForLlm []ExternalToolTextResultForLlmBinaryResultsForLlm `json:"binaryResultsForLlm,omitempty"`
+ BinaryResultsForLlm []ExternalToolTextResultForLlmBinaryResultsForLlm `json:"binaryResultsForLlm,omitzero"`
// Structured content blocks from the tool
- Contents []ExternalToolTextResultForLlmContent `json:"contents,omitempty"`
+ Contents []ExternalToolTextResultForLlmContent `json:"contents,omitzero"`
// Optional error message for failed executions
Error *string `json:"error,omitempty"`
// Execution outcome classification. Optional for back-compat; normalized to 'success' (or
@@ -1148,7 +1324,7 @@ type ExternalToolTextResultForLlm struct {
// Text result returned to the model
TextResultForLlm string `json:"textResultForLlm"`
// Optional tool-specific telemetry
- ToolTelemetry map[string]any `json:"toolTelemetry,omitempty"`
+ ToolTelemetry map[string]any `json:"toolTelemetry,omitzero"`
}
// Binary result returned by a tool for the model
@@ -1160,7 +1336,7 @@ type ExternalToolTextResultForLlmBinaryResultsForLlm struct {
// Human-readable description of the binary data
Description *string `json:"description,omitempty"`
// Optional metadata from the producing tool.
- Metadata map[string]any `json:"metadata,omitempty"`
+ Metadata map[string]any `json:"metadata,omitzero"`
// MIME type of the binary data
MIMEType string `json:"mimeType"`
// Binary result type discriminator. Use "image" for images and "resource" for other binary
@@ -1237,7 +1413,7 @@ type ExternalToolTextResultForLlmContentResourceLink struct {
// Human-readable description of the resource
Description *string `json:"description,omitempty"`
// Icons associated with this resource
- Icons []ExternalToolTextResultForLlmContentResourceLinkIcon `json:"icons,omitempty"`
+ Icons []ExternalToolTextResultForLlmContentResourceLinkIcon `json:"icons,omitzero"`
// MIME type of the resource content
MIMEType *string `json:"mimeType,omitempty"`
// Resource name identifier
@@ -1334,7 +1510,7 @@ type ExternalToolTextResultForLlmContentResourceLinkIcon struct {
// MIME type of the icon image
MIMEType *string `json:"mimeType,omitempty"`
// Available icon sizes (e.g., ['16x16', '32x32'])
- Sizes []string `json:"sizes,omitempty"`
+ Sizes []string `json:"sizes,omitzero"`
// URL or path to the icon image
Src string `json:"src"`
// Theme variant this icon is intended for
@@ -1524,21 +1700,21 @@ type InstalledPlugin struct {
// Experimental: InstalledPluginSource is part of an experimental API and may change or be
// removed.
type InstalledPluginSource struct {
- InstalledPluginSourceGithub *InstalledPluginSourceGithub
+ InstalledPluginSourceGitHub *InstalledPluginSourceGitHub
InstalledPluginSourceLocal *InstalledPluginSourceLocal
InstalledPluginSourceURL *InstalledPluginSourceURL
String *string
}
-// Schema for the `InstalledPluginSourceGithub` type.
-// Experimental: InstalledPluginSourceGithub is part of an experimental API and may change
+// Schema for the `InstalledPluginSourceGitHub` type.
+// Experimental: InstalledPluginSourceGitHub is part of an experimental API and may change
// or be removed.
-type InstalledPluginSourceGithub struct {
+type InstalledPluginSourceGitHub struct {
Path *string `json:"path,omitempty"`
Ref *string `json:"ref,omitempty"`
Repo string `json:"repo"`
// Constant value. Always "github".
- Source InstalledPluginSourceGithubSource `json:"source"`
+ Source InstalledPluginSourceGitHubSource `json:"source"`
}
// Schema for the `InstalledPluginSourceLocal` type.
@@ -1575,7 +1751,7 @@ type InstructionsGetSourcesResult struct {
type InstructionsSources struct {
// Glob pattern(s) from frontmatter — when set, this instruction applies only to matching
// files
- ApplyTo []string `json:"applyTo,omitempty"`
+ ApplyTo []string `json:"applyTo,omitzero"`
// Raw content of the instruction file
Content string `json:"content"`
// When true, this source starts disabled and must be toggled on by the user
@@ -1637,11 +1813,11 @@ type LspInitializeRequest struct {
}
// MCP server, tool name, and arguments to invoke from an MCP App view.
-// Experimental: McpAppsCallToolRequest is part of an experimental API and may change or be
+// Experimental: MCPAppsCallToolRequest is part of an experimental API and may change or be
// removed.
-type McpAppsCallToolRequest struct {
+type MCPAppsCallToolRequest struct {
// Tool arguments
- Arguments map[string]any `json:"arguments,omitempty"`
+ Arguments map[string]any `json:"arguments,omitzero"`
// **Required.** Server whose ui:// view issued the request. Per SEP-1865 ('callable by the
// app from this server only'), the call is rejected when this differs from `serverName`,
// and rejected outright when missing.
@@ -1653,39 +1829,39 @@ type McpAppsCallToolRequest struct {
}
// Capability negotiation snapshot
-// Experimental: McpAppsDiagnoseCapability is part of an experimental API and may change or
+// Experimental: MCPAppsDiagnoseCapability is part of an experimental API and may change or
// be removed.
-type McpAppsDiagnoseCapability struct {
+type MCPAppsDiagnoseCapability struct {
// Whether the runtime advertises `extensions.io.modelcontextprotocol/ui` to MCP servers
Advertised bool `json:"advertised"`
// Whether the MCP_APPS feature flag (or COPILOT_MCP_APPS env override) is on
FeatureFlagEnabled bool `json:"featureFlagEnabled"`
// Whether the session has the `mcp-apps` capability
- SessionHasMcpApps bool `json:"sessionHasMcpApps"`
+ SessionHasMCPApps bool `json:"sessionHasMcpApps"`
}
// MCP server to diagnose MCP Apps wiring for.
-// Experimental: McpAppsDiagnoseRequest is part of an experimental API and may change or be
+// Experimental: MCPAppsDiagnoseRequest is part of an experimental API and may change or be
// removed.
-type McpAppsDiagnoseRequest struct {
+type MCPAppsDiagnoseRequest struct {
// MCP server to probe
ServerName string `json:"serverName"`
}
// Diagnostic snapshot of MCP Apps wiring for the named server.
-// Experimental: McpAppsDiagnoseResult is part of an experimental API and may change or be
+// Experimental: MCPAppsDiagnoseResult is part of an experimental API and may change or be
// removed.
-type McpAppsDiagnoseResult struct {
+type MCPAppsDiagnoseResult struct {
// Capability negotiation snapshot
- Capability McpAppsDiagnoseCapability `json:"capability"`
+ Capability MCPAppsDiagnoseCapability `json:"capability"`
// What the server returned for this session
- Server McpAppsDiagnoseServer `json:"server"`
+ Server MCPAppsDiagnoseServer `json:"server"`
}
// What the server returned for this session
-// Experimental: McpAppsDiagnoseServer is part of an experimental API and may change or be
+// Experimental: MCPAppsDiagnoseServer is part of an experimental API and may change or be
// removed.
-type McpAppsDiagnoseServer struct {
+type MCPAppsDiagnoseServer struct {
// Whether the named server is currently connected
Connected bool `json:"connected"`
// Up to 5 tool names with `_meta.ui` for quick inspection
@@ -1697,27 +1873,27 @@ type McpAppsDiagnoseServer struct {
}
// Current host context advertised to MCP App guests.
-// Experimental: McpAppsHostContext is part of an experimental API and may change or be
+// Experimental: MCPAppsHostContext is part of an experimental API and may change or be
// removed.
-type McpAppsHostContext struct {
+type MCPAppsHostContext struct {
// Current host context
- Context McpAppsHostContextDetails `json:"context"`
+ Context MCPAppsHostContextDetails `json:"context"`
}
// Current host context
-// Experimental: McpAppsHostContextDetails is part of an experimental API and may change or
+// Experimental: MCPAppsHostContextDetails is part of an experimental API and may change or
// be removed.
-type McpAppsHostContextDetails struct {
+type MCPAppsHostContextDetails struct {
// Display modes the host supports
- AvailableDisplayModes []McpAppsHostContextDetailsAvailableDisplayMode `json:"availableDisplayModes,omitempty"`
+ AvailableDisplayModes []MCPAppsHostContextDetailsAvailableDisplayMode `json:"availableDisplayModes,omitzero"`
// Current display mode (SEP-1865)
- DisplayMode *McpAppsHostContextDetailsDisplayMode `json:"displayMode,omitempty"`
+ DisplayMode *MCPAppsHostContextDetailsDisplayMode `json:"displayMode,omitempty"`
// BCP-47 locale, e.g. 'en-US'
Locale *string `json:"locale,omitempty"`
// Platform type for responsive design
- Platform *McpAppsHostContextDetailsPlatform `json:"platform,omitempty"`
+ Platform *MCPAppsHostContextDetailsPlatform `json:"platform,omitempty"`
// UI theme preference per SEP-1865
- Theme *McpAppsHostContextDetailsTheme `json:"theme,omitempty"`
+ Theme *MCPAppsHostContextDetailsTheme `json:"theme,omitempty"`
// IANA timezone, e.g. 'America/New_York'
TimeZone *string `json:"timeZone,omitempty"`
// Host application identifier
@@ -1725,9 +1901,9 @@ type McpAppsHostContextDetails struct {
}
// MCP server to list app-callable tools for.
-// Experimental: McpAppsListToolsRequest is part of an experimental API and may change or be
+// Experimental: MCPAppsListToolsRequest is part of an experimental API and may change or be
// removed.
-type McpAppsListToolsRequest struct {
+type MCPAppsListToolsRequest struct {
// **Required.** Server whose ui:// view issued the request. Per SEP-1865 ('callable by the
// app from this server only'), the call is rejected when this differs from `serverName`,
// and rejected outright when missing.
@@ -1737,17 +1913,17 @@ type McpAppsListToolsRequest struct {
}
// App-callable tools from the named MCP server.
-// Experimental: McpAppsListToolsResult is part of an experimental API and may change or be
+// Experimental: MCPAppsListToolsResult is part of an experimental API and may change or be
// removed.
-type McpAppsListToolsResult struct {
+type MCPAppsListToolsResult struct {
// App-callable tools from the server
Tools []map[string]any `json:"tools"`
}
// MCP server and resource URI to fetch.
-// Experimental: McpAppsReadResourceRequest is part of an experimental API and may change or
+// Experimental: MCPAppsReadResourceRequest is part of an experimental API and may change or
// be removed.
-type McpAppsReadResourceRequest struct {
+type MCPAppsReadResourceRequest struct {
// Name of the MCP server hosting the resource
ServerName string `json:"serverName"`
// Resource URI (typically ui://...)
@@ -1755,21 +1931,21 @@ type McpAppsReadResourceRequest struct {
}
// Resource contents returned by the MCP server.
-// Experimental: McpAppsReadResourceResult is part of an experimental API and may change or
+// Experimental: MCPAppsReadResourceResult is part of an experimental API and may change or
// be removed.
-type McpAppsReadResourceResult struct {
+type MCPAppsReadResourceResult struct {
// Resource contents returned by the server
- Contents []McpAppsResourceContent `json:"contents"`
+ Contents []MCPAppsResourceContent `json:"contents"`
}
// Schema for the `McpAppsResourceContent` type.
-// Experimental: McpAppsResourceContent is part of an experimental API and may change or be
+// Experimental: MCPAppsResourceContent is part of an experimental API and may change or be
// removed.
-type McpAppsResourceContent struct {
+type MCPAppsResourceContent struct {
// Base64-encoded binary content
Blob *string `json:"blob,omitempty"`
// Resource-level metadata (CSP, permissions, etc.)
- Meta map[string]any `json:"_meta,omitempty"`
+ Meta map[string]any `json:"_meta,omitzero"`
// MIME type of the content
MIMEType *string `json:"mimeType,omitempty"`
// Text content (e.g. HTML)
@@ -1779,19 +1955,19 @@ type McpAppsResourceContent struct {
}
// Host context advertised to MCP App guests
-// Experimental: McpAppsSetHostContextDetails is part of an experimental API and may change
+// Experimental: MCPAppsSetHostContextDetails is part of an experimental API and may change
// or be removed.
-type McpAppsSetHostContextDetails struct {
+type MCPAppsSetHostContextDetails struct {
// Display modes the host supports
- AvailableDisplayModes []McpAppsSetHostContextDetailsAvailableDisplayMode `json:"availableDisplayModes,omitempty"`
+ AvailableDisplayModes []MCPAppsSetHostContextDetailsAvailableDisplayMode `json:"availableDisplayModes,omitzero"`
// Current display mode (SEP-1865)
- DisplayMode *McpAppsSetHostContextDetailsDisplayMode `json:"displayMode,omitempty"`
+ DisplayMode *MCPAppsSetHostContextDetailsDisplayMode `json:"displayMode,omitempty"`
// BCP-47 locale, e.g. 'en-US'
Locale *string `json:"locale,omitempty"`
// Platform type for responsive design
- Platform *McpAppsSetHostContextDetailsPlatform `json:"platform,omitempty"`
+ Platform *MCPAppsSetHostContextDetailsPlatform `json:"platform,omitempty"`
// UI theme preference per SEP-1865
- Theme *McpAppsSetHostContextDetailsTheme `json:"theme,omitempty"`
+ Theme *MCPAppsSetHostContextDetailsTheme `json:"theme,omitempty"`
// IANA timezone, e.g. 'America/New_York'
TimeZone *string `json:"timeZone,omitempty"`
// Host application identifier
@@ -1799,26 +1975,26 @@ type McpAppsSetHostContextDetails struct {
}
// Host context to advertise to MCP App guests.
-// Experimental: McpAppsSetHostContextRequest is part of an experimental API and may change
+// Experimental: MCPAppsSetHostContextRequest is part of an experimental API and may change
// or be removed.
-type McpAppsSetHostContextRequest struct {
+type MCPAppsSetHostContextRequest struct {
// Host context advertised to MCP App guests
- Context McpAppsSetHostContextDetails `json:"context"`
+ Context MCPAppsSetHostContextDetails `json:"context"`
}
// The requestId previously passed to executeSampling that should be cancelled.
-// Experimental: McpCancelSamplingExecutionParams is part of an experimental API and may
+// Experimental: MCPCancelSamplingExecutionParams is part of an experimental API and may
// change or be removed.
-type McpCancelSamplingExecutionParams struct {
+type MCPCancelSamplingExecutionParams struct {
// The requestId previously passed to executeSampling that should be cancelled
RequestID string `json:"requestId"`
}
// Indicates whether an in-flight sampling execution with the given requestId was found and
// cancelled.
-// Experimental: McpCancelSamplingExecutionResult is part of an experimental API and may
+// Experimental: MCPCancelSamplingExecutionResult is part of an experimental API and may
// change or be removed.
-type McpCancelSamplingExecutionResult struct {
+type MCPCancelSamplingExecutionResult struct {
// True if an in-flight execution with the given requestId was found and signalled to
// cancel. False when no such execution is in flight (already completed, never started, or
// cancelled by another caller).
@@ -1826,106 +2002,106 @@ type McpCancelSamplingExecutionResult struct {
}
// MCP server name and configuration to add to user configuration.
-type McpConfigAddRequest struct {
+type MCPConfigAddRequest struct {
// MCP server configuration (stdio process or remote HTTP/SSE)
- Config McpServerConfig `json:"config"`
+ Config MCPServerConfig `json:"config"`
// Unique name for the MCP server
Name string `json:"name"`
}
-type McpConfigAddResult struct {
+type MCPConfigAddResult struct {
}
// MCP server names to disable for new sessions.
-type McpConfigDisableRequest struct {
+type MCPConfigDisableRequest struct {
// Names of MCP servers to disable. Each server is added to the persisted disabled list so
// new sessions skip it. Already-disabled names are ignored. Active sessions keep their
// current connections until they end.
Names []string `json:"names"`
}
-type McpConfigDisableResult struct {
+type MCPConfigDisableResult struct {
}
// MCP server names to enable for new sessions.
-type McpConfigEnableRequest struct {
+type MCPConfigEnableRequest struct {
// Names of MCP servers to enable. Each server is removed from the persisted disabled list
// so new sessions spawn it. Unknown or already-enabled names are ignored.
Names []string `json:"names"`
}
-type McpConfigEnableResult struct {
+type MCPConfigEnableResult struct {
}
// User-configured MCP servers, keyed by server name.
-type McpConfigList struct {
+type MCPConfigList struct {
// All MCP servers from user config, keyed by name
- Servers map[string]McpServerConfig `json:"servers"`
+ Servers map[string]MCPServerConfig `json:"servers"`
}
-type McpConfigReloadResult struct {
+type MCPConfigReloadResult struct {
}
// MCP server name to remove from user configuration.
-type McpConfigRemoveRequest struct {
+type MCPConfigRemoveRequest struct {
// Name of the MCP server to remove
Name string `json:"name"`
}
-type McpConfigRemoveResult struct {
+type MCPConfigRemoveResult struct {
}
// MCP server name and replacement configuration to write to user configuration.
-type McpConfigUpdateRequest struct {
+type MCPConfigUpdateRequest struct {
// MCP server configuration (stdio process or remote HTTP/SSE)
- Config McpServerConfig `json:"config"`
+ Config MCPServerConfig `json:"config"`
// Name of the MCP server to update
Name string `json:"name"`
}
-type McpConfigUpdateResult struct {
+type MCPConfigUpdateResult struct {
}
// Name of the MCP server to disable for the session.
-// Experimental: McpDisableRequest is part of an experimental API and may change or be
+// Experimental: MCPDisableRequest is part of an experimental API and may change or be
// removed.
-type McpDisableRequest struct {
+type MCPDisableRequest struct {
// Name of the MCP server to disable
ServerName string `json:"serverName"`
}
// Optional working directory used as context for MCP server discovery.
-type McpDiscoverRequest struct {
+type MCPDiscoverRequest struct {
// Working directory used as context for discovery (e.g., plugin resolution)
WorkingDirectory *string `json:"workingDirectory,omitempty"`
}
// MCP servers discovered from user, workspace, plugin, and built-in sources.
-type McpDiscoverResult struct {
+type MCPDiscoverResult struct {
// MCP servers discovered from all sources
- Servers []DiscoveredMcpServer `json:"servers"`
+ Servers []DiscoveredMCPServer `json:"servers"`
}
// Name of the MCP server to enable for the session.
-// Experimental: McpEnableRequest is part of an experimental API and may change or be
+// Experimental: MCPEnableRequest is part of an experimental API and may change or be
// removed.
-type McpEnableRequest struct {
+type MCPEnableRequest struct {
// Name of the MCP server to enable
ServerName string `json:"serverName"`
}
// Identifiers and raw MCP CreateMessageRequest params used to run a sampling inference.
-// Experimental: McpExecuteSamplingParams is part of an experimental API and may change or
+// Experimental: MCPExecuteSamplingParams is part of an experimental API and may change or
// be removed.
-type McpExecuteSamplingParams struct {
+type MCPExecuteSamplingParams struct {
// The original MCP JSON-RPC request ID (string or number). Used by the runtime to correlate
// the inference with the originating MCP request for telemetry; this is distinct from
// `requestId` (which is the schema-level cancellation handle).
- McpRequestID any `json:"mcpRequestId"`
+ MCPRequestID any `json:"mcpRequestId"`
// Raw MCP CreateMessageRequest params, as received in the `sampling.requested` event.
// Treated as opaque at the schema layer; the runtime converts the embedded MCP messages
// into the OpenAI chat-completion shape internally.
- Request McpExecuteSamplingRequest `json:"request"`
+ Request MCPExecuteSamplingRequest `json:"request"`
// Caller-provided unique identifier for this sampling execution. Use this same ID with
// cancelSamplingExecution to cancel the in-flight call. Must be unique within the session
// for the lifetime of the call.
@@ -1937,24 +2113,24 @@ type McpExecuteSamplingParams struct {
// Raw MCP CreateMessageRequest params, as received in the `sampling.requested` event.
// Treated as opaque at the schema layer; the runtime converts the embedded MCP messages
// into the OpenAI chat-completion shape internally.
-// Experimental: McpExecuteSamplingRequest is part of an experimental API and may change or
+// Experimental: MCPExecuteSamplingRequest is part of an experimental API and may change or
// be removed.
-type McpExecuteSamplingRequest struct {
+type MCPExecuteSamplingRequest struct {
}
// MCP CreateMessageResult payload (with optional 'tools' extension), present when
// action='success'. Treated as opaque at the schema layer; consumers should
// construct/consume it per the MCP CreateMessageResult shape.
-// Experimental: McpExecuteSamplingResult is part of an experimental API and may change or
+// Experimental: MCPExecuteSamplingResult is part of an experimental API and may change or
// be removed.
-type McpExecuteSamplingResult struct {
+type MCPExecuteSamplingResult struct {
}
// Remote MCP server name and optional overrides controlling reauthentication, OAuth client
// display name, and the callback success-page copy.
-// Experimental: McpOauthLoginRequest is part of an experimental API and may change or be
+// Experimental: MCPOauthLoginRequest is part of an experimental API and may change or be
// removed.
-type McpOauthLoginRequest struct {
+type MCPOauthLoginRequest struct {
// Optional override for the body text shown on the OAuth loopback callback success page.
// When omitted, the runtime applies a neutral fallback; callers driving interactive auth
// should pass surface-specific copy telling the user where to return.
@@ -1975,9 +2151,9 @@ type McpOauthLoginRequest struct {
// OAuth authorization URL the caller should open, or empty when cached tokens already
// authenticated the server.
-// Experimental: McpOauthLoginResult is part of an experimental API and may change or be
+// Experimental: MCPOauthLoginResult is part of an experimental API and may change or be
// removed.
-type McpOauthLoginResult struct {
+type MCPOauthLoginResult struct {
// URL the caller should open in a browser to complete OAuth. Omitted when cached tokens
// were still valid and no browser interaction was needed — the server is already
// reconnected in that case. When present, the runtime starts the callback listener before
@@ -1988,9 +2164,9 @@ type McpOauthLoginResult struct {
// Indicates whether the auto-managed `github` MCP server was removed (false when nothing to
// remove).
-// Experimental: McpRemoveGitHubResult is part of an experimental API and may change or be
+// Experimental: MCPRemoveGitHubResult is part of an experimental API and may change or be
// removed.
-type McpRemoveGitHubResult struct {
+type MCPRemoveGitHubResult struct {
// True when the auto-managed `github` MCP server was removed; false when no removal
// happened (e.g. user has explicitly configured a `github` server, or the server was not
// registered).
@@ -1998,106 +2174,106 @@ type McpRemoveGitHubResult struct {
}
// Outcome of an MCP sampling execution: success result, failure error, or cancellation.
-// Experimental: McpSamplingExecutionResult is part of an experimental API and may change or
+// Experimental: MCPSamplingExecutionResult is part of an experimental API and may change or
// be removed.
-type McpSamplingExecutionResult struct {
+type MCPSamplingExecutionResult struct {
// Outcome of the sampling inference. 'success' produced a response; 'failure' encountered
// an error (including agent-side rejection by content filter or criteria); 'cancelled' the
// caller cancelled this execution via cancelSamplingExecution.
- Action McpSamplingExecutionAction `json:"action"`
+ Action MCPSamplingExecutionAction `json:"action"`
// Error description, present when action='failure'.
Error *string `json:"error,omitempty"`
// MCP CreateMessageResult payload (with optional 'tools' extension), present when
// action='success'. Treated as opaque at the schema layer; consumers should
// construct/consume it per the MCP CreateMessageResult shape.
- Result *McpExecuteSamplingResult `json:"result,omitempty"`
+ Result *MCPExecuteSamplingResult `json:"result,omitempty"`
}
// Schema for the `McpServer` type.
-// Experimental: McpServer is part of an experimental API and may change or be removed.
-type McpServer struct {
+// Experimental: MCPServer is part of an experimental API and may change or be removed.
+type MCPServer struct {
// Error message if the server failed to connect
Error *string `json:"error,omitempty"`
// Server name (config key)
Name string `json:"name"`
// Configuration source: user, workspace, plugin, or builtin
- Source *McpServerSource `json:"source,omitempty"`
+ Source *MCPServerSource `json:"source,omitempty"`
// Connection status: connected, failed, needs-auth, pending, disabled, or not_configured
- Status McpServerStatus `json:"status"`
+ Status MCPServerStatus `json:"status"`
}
// Set to `true` to use defaults, or provide an object with additional auth or OIDC settings.
-type McpServerAuthConfig interface {
+type MCPServerAuthConfig interface {
mcpServerAuthConfig()
}
-type McpServerAuthConfigBoolean bool
+type MCPServerAuthConfigBoolean bool
-func (McpServerAuthConfigBoolean) mcpServerAuthConfig() {}
+func (MCPServerAuthConfigBoolean) mcpServerAuthConfig() {}
-func (McpServerAuthConfigRedirectPort) mcpServerAuthConfig() {}
+func (MCPServerAuthConfigRedirectPort) mcpServerAuthConfig() {}
// Authentication settings with optional redirect port configuration.
-type McpServerAuthConfigRedirectPort struct {
+type MCPServerAuthConfigRedirectPort struct {
// Fixed port for the OAuth redirect callback server.
RedirectPort *int32 `json:"redirectPort,omitempty"`
}
// MCP server configuration (stdio process or remote HTTP/SSE)
-type McpServerConfig interface {
+type MCPServerConfig interface {
mcpServerConfig()
}
-type RawMcpServerConfigData struct {
+type RawMCPServerConfigData struct {
Raw json.RawMessage
}
-func (RawMcpServerConfigData) mcpServerConfig() {}
+func (RawMCPServerConfigData) mcpServerConfig() {}
// Remote MCP server configuration accessed over HTTP or SSE.
-type McpServerConfigHTTP struct {
+type MCPServerConfigHTTP struct {
// Set to `true` to use defaults, or provide an object with additional auth or OIDC settings.
- Auth McpServerAuthConfig `json:"auth,omitempty"`
+ Auth MCPServerAuthConfig `json:"auth,omitempty"`
// Content filtering mode to apply to all tools, or a map of tool name to content filtering
// mode.
FilterMapping FilterMapping `json:"filterMapping,omitempty"`
// HTTP headers to include in requests to the remote MCP server.
- Headers map[string]string `json:"headers,omitempty"`
+ Headers map[string]string `json:"headers,omitzero"`
// Whether this server is a built-in fallback used when the user has not configured their
// own server.
IsDefaultServer *bool `json:"isDefaultServer,omitempty"`
// OAuth client ID for a pre-registered remote MCP OAuth client.
OauthClientID *string `json:"oauthClientId,omitempty"`
// OAuth grant type to use when authenticating to the remote MCP server.
- OauthGrantType *McpServerConfigHTTPOauthGrantType `json:"oauthGrantType,omitempty"`
+ OauthGrantType *MCPServerConfigHTTPOauthGrantType `json:"oauthGrantType,omitempty"`
// Whether the configured OAuth client is public and does not require a client secret.
OauthPublicClient *bool `json:"oauthPublicClient,omitempty"`
// Set to `true` to use defaults, or provide an object with additional auth or OIDC settings.
- Oidc McpServerAuthConfig `json:"oidc,omitempty"`
+ Oidc MCPServerAuthConfig `json:"oidc,omitempty"`
// Timeout in milliseconds for tool calls to this server.
Timeout *int64 `json:"timeout,omitempty"`
// Tools to include. Defaults to all tools if not specified.
- Tools []string `json:"tools,omitempty"`
+ Tools []string `json:"tools,omitzero"`
// Remote transport type. Defaults to "http" when omitted.
- Type *McpServerConfigHTTPType `json:"type,omitempty"`
+ Type *MCPServerConfigHTTPType `json:"type,omitempty"`
// URL of the remote MCP server endpoint.
URL string `json:"url"`
}
-func (McpServerConfigHTTP) mcpServerConfig() {}
+func (MCPServerConfigHTTP) mcpServerConfig() {}
// Stdio MCP server configuration launched as a child process.
-type McpServerConfigStdio struct {
+type MCPServerConfigStdio struct {
// Command-line arguments passed to the Stdio MCP server process.
- Args []string `json:"args,omitempty"`
+ Args []string `json:"args,omitzero"`
// Set to `true` to use defaults, or provide an object with additional auth or OIDC settings.
- Auth McpServerAuthConfig `json:"auth,omitempty"`
+ Auth MCPServerAuthConfig `json:"auth,omitempty"`
// Executable command used to start the Stdio MCP server process.
Command string `json:"command"`
// Working directory for the Stdio MCP server process.
Cwd *string `json:"cwd,omitempty"`
// Environment variables to pass to the Stdio MCP server process.
- Env map[string]string `json:"env,omitempty"`
+ Env map[string]string `json:"env,omitzero"`
// Content filtering mode to apply to all tools, or a map of tool name to content filtering
// mode.
FilterMapping FilterMapping `json:"filterMapping,omitempty"`
@@ -2105,40 +2281,40 @@ type McpServerConfigStdio struct {
// own server.
IsDefaultServer *bool `json:"isDefaultServer,omitempty"`
// Set to `true` to use defaults, or provide an object with additional auth or OIDC settings.
- Oidc McpServerAuthConfig `json:"oidc,omitempty"`
+ Oidc MCPServerAuthConfig `json:"oidc,omitempty"`
// Timeout in milliseconds for tool calls to this server.
Timeout *int64 `json:"timeout,omitempty"`
// Tools to include. Defaults to all tools if not specified.
- Tools []string `json:"tools,omitempty"`
+ Tools []string `json:"tools,omitzero"`
}
-func (McpServerConfigStdio) mcpServerConfig() {}
+func (MCPServerConfigStdio) mcpServerConfig() {}
// MCP servers configured for the session, with their connection status.
-// Experimental: McpServerList is part of an experimental API and may change or be removed.
-type McpServerList struct {
+// Experimental: MCPServerList is part of an experimental API and may change or be removed.
+type MCPServerList struct {
// Configured MCP servers
- Servers []McpServer `json:"servers"`
+ Servers []MCPServer `json:"servers"`
}
// Mode controlling how MCP server env values are resolved (`direct` or `indirect`).
-// Experimental: McpSetEnvValueModeParams is part of an experimental API and may change or
+// Experimental: MCPSetEnvValueModeParams is part of an experimental API and may change or
// be removed.
-type McpSetEnvValueModeParams struct {
+type MCPSetEnvValueModeParams struct {
// How environment-variable values supplied to MCP servers are resolved. "direct" passes
// literal string values; "indirect" treats values as references (e.g. names of environment
// variables on the host) that the runtime resolves before launch. Defaults to the runtime's
// startup mode; clients that intentionally launch MCP servers with literal values (e.g. CLI
// prompt mode and ACP) set this to "direct".
- Mode McpSetEnvValueModeDetails `json:"mode"`
+ Mode MCPSetEnvValueModeDetails `json:"mode"`
}
// Env-value mode recorded on the session after the update.
-// Experimental: McpSetEnvValueModeResult is part of an experimental API and may change or
+// Experimental: MCPSetEnvValueModeResult is part of an experimental API and may change or
// be removed.
-type McpSetEnvValueModeResult struct {
+type MCPSetEnvValueModeResult struct {
// Mode recorded on the session after the update
- Mode McpSetEnvValueModeDetails `json:"mode"`
+ Mode MCPSetEnvValueModeDetails `json:"mode"`
}
// Model identifier and token limits used to compute the context-info breakdown.
@@ -2286,7 +2462,7 @@ type Model struct {
// Policy state (if applicable)
Policy *ModelPolicy `json:"policy,omitempty"`
// Supported reasoning effort levels (only present if model supports reasoning effort)
- SupportedReasoningEfforts []string `json:"supportedReasoningEfforts,omitempty"`
+ SupportedReasoningEfforts []string `json:"supportedReasoningEfforts,omitzero"`
}
// Billing information
@@ -2303,7 +2479,8 @@ type ModelBillingTokenPrices struct {
BatchSize *int64 `json:"batchSize,omitempty"`
// AI Credits cost per billing batch of cached tokens
CachePrice *float64 `json:"cachePrice,omitempty"`
- // Maximum context window tokens for the default tier
+ // Prompt token budget (max_prompt_tokens) for the default tier. The total context window is
+ // this value plus the model's max_output_tokens.
ContextMax *int64 `json:"contextMax,omitempty"`
// AI Credits cost per billing batch of input tokens
InputPrice *float64 `json:"inputPrice,omitempty"`
@@ -2317,7 +2494,8 @@ type ModelBillingTokenPrices struct {
type ModelBillingTokenPricesLongContext struct {
// AI Credits cost per billing batch of cached tokens
CachePrice *float64 `json:"cachePrice,omitempty"`
- // Maximum context window tokens for the long context tier
+ // Prompt token budget (max_prompt_tokens) for the long context tier. The total context
+ // window is this value plus the model's max_output_tokens.
ContextMax *int64 `json:"contextMax,omitempty"`
// AI Credits cost per billing batch of input tokens
InputPrice *float64 `json:"inputPrice,omitempty"`
@@ -2388,7 +2566,7 @@ type ModelCapabilitiesOverrideLimitsVision struct {
// Maximum image size in bytes
MaxPromptImageSize *int64 `json:"max_prompt_image_size,omitempty"`
// MIME types the model accepts
- SupportedMediaTypes []string `json:"supported_media_types,omitempty"`
+ SupportedMediaTypes []string `json:"supported_media_types,omitzero"`
}
// Feature flags indicating what the model supports
@@ -2462,10 +2640,9 @@ type ModelsListRequest struct {
// Experimental: ModelSwitchToRequest is part of an experimental API and may change or be
// removed.
type ModelSwitchToRequest struct {
- // Explicit context tier for the selected model. `"default"` / `"long_context"` pin the
- // tier; `null` clears any previous explicit choice; `undefined` leaves the existing tier
- // untouched.
- ContextTier *ModelSwitchToRequestContextTier `json:"contextTier,omitempty"`
+ // Explicit context tier for the selected model. `"default"` / `"long_context"` apply the
+ // requested tier; omit this field to use normal model behavior with no explicit tier.
+ ContextTier *ContextTier `json:"contextTier,omitempty"`
// Override individual model capabilities resolved by the runtime
ModelCapabilities *ModelCapabilitiesOverride `json:"modelCapabilities,omitempty"`
// Model identifier to switch to
@@ -2867,33 +3044,33 @@ func (PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess) Kin
}
// Schema for the `PermissionDecisionApproveForLocationApprovalMcp` type.
-// Experimental: PermissionDecisionApproveForLocationApprovalMcp is part of an experimental
+// Experimental: PermissionDecisionApproveForLocationApprovalMCP is part of an experimental
// API and may change or be removed.
-type PermissionDecisionApproveForLocationApprovalMcp struct {
+type PermissionDecisionApproveForLocationApprovalMCP struct {
// MCP server name.
ServerName string `json:"serverName"`
// MCP tool name, or null to cover every tool on the server.
ToolName *string `json:"toolName"`
}
-func (PermissionDecisionApproveForLocationApprovalMcp) permissionDecisionApproveForLocationApproval() {
+func (PermissionDecisionApproveForLocationApprovalMCP) permissionDecisionApproveForLocationApproval() {
}
-func (PermissionDecisionApproveForLocationApprovalMcp) Kind() PermissionDecisionApproveForLocationApprovalKind {
- return PermissionDecisionApproveForLocationApprovalKindMcp
+func (PermissionDecisionApproveForLocationApprovalMCP) Kind() PermissionDecisionApproveForLocationApprovalKind {
+ return PermissionDecisionApproveForLocationApprovalKindMCP
}
// Schema for the `PermissionDecisionApproveForLocationApprovalMcpSampling` type.
-// Experimental: PermissionDecisionApproveForLocationApprovalMcpSampling is part of an
+// Experimental: PermissionDecisionApproveForLocationApprovalMCPSampling is part of an
// experimental API and may change or be removed.
-type PermissionDecisionApproveForLocationApprovalMcpSampling struct {
+type PermissionDecisionApproveForLocationApprovalMCPSampling struct {
// MCP server name.
ServerName string `json:"serverName"`
}
-func (PermissionDecisionApproveForLocationApprovalMcpSampling) permissionDecisionApproveForLocationApproval() {
+func (PermissionDecisionApproveForLocationApprovalMCPSampling) permissionDecisionApproveForLocationApproval() {
}
-func (PermissionDecisionApproveForLocationApprovalMcpSampling) Kind() PermissionDecisionApproveForLocationApprovalKind {
- return PermissionDecisionApproveForLocationApprovalKindMcpSampling
+func (PermissionDecisionApproveForLocationApprovalMCPSampling) Kind() PermissionDecisionApproveForLocationApprovalKind {
+ return PermissionDecisionApproveForLocationApprovalKindMCPSampling
}
// Schema for the `PermissionDecisionApproveForLocationApprovalMemory` type.
@@ -3010,32 +3187,32 @@ func (PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess) Kind
}
// Schema for the `PermissionDecisionApproveForSessionApprovalMcp` type.
-// Experimental: PermissionDecisionApproveForSessionApprovalMcp is part of an experimental
+// Experimental: PermissionDecisionApproveForSessionApprovalMCP is part of an experimental
// API and may change or be removed.
-type PermissionDecisionApproveForSessionApprovalMcp struct {
+type PermissionDecisionApproveForSessionApprovalMCP struct {
// MCP server name.
ServerName string `json:"serverName"`
// MCP tool name, or null to cover every tool on the server.
ToolName *string `json:"toolName"`
}
-func (PermissionDecisionApproveForSessionApprovalMcp) permissionDecisionApproveForSessionApproval() {}
-func (PermissionDecisionApproveForSessionApprovalMcp) Kind() PermissionDecisionApproveForSessionApprovalKind {
- return PermissionDecisionApproveForSessionApprovalKindMcp
+func (PermissionDecisionApproveForSessionApprovalMCP) permissionDecisionApproveForSessionApproval() {}
+func (PermissionDecisionApproveForSessionApprovalMCP) Kind() PermissionDecisionApproveForSessionApprovalKind {
+ return PermissionDecisionApproveForSessionApprovalKindMCP
}
// Schema for the `PermissionDecisionApproveForSessionApprovalMcpSampling` type.
-// Experimental: PermissionDecisionApproveForSessionApprovalMcpSampling is part of an
+// Experimental: PermissionDecisionApproveForSessionApprovalMCPSampling is part of an
// experimental API and may change or be removed.
-type PermissionDecisionApproveForSessionApprovalMcpSampling struct {
+type PermissionDecisionApproveForSessionApprovalMCPSampling struct {
// MCP server name.
ServerName string `json:"serverName"`
}
-func (PermissionDecisionApproveForSessionApprovalMcpSampling) permissionDecisionApproveForSessionApproval() {
+func (PermissionDecisionApproveForSessionApprovalMCPSampling) permissionDecisionApproveForSessionApproval() {
}
-func (PermissionDecisionApproveForSessionApprovalMcpSampling) Kind() PermissionDecisionApproveForSessionApprovalKind {
- return PermissionDecisionApproveForSessionApprovalKindMcpSampling
+func (PermissionDecisionApproveForSessionApprovalMCPSampling) Kind() PermissionDecisionApproveForSessionApprovalKind {
+ return PermissionDecisionApproveForSessionApprovalKindMCPSampling
}
// Schema for the `PermissionDecisionApproveForSessionApprovalMemory` type.
@@ -3173,7 +3350,7 @@ type PermissionPathsConfig struct {
// directory). When `unrestricted` is true, these are still pre-populated on the
// UnrestrictedPathManager so they remain visible via getDirectories() (e.g. for @-mention
// completion).
- AdditionalDirectories []string `json:"additionalDirectories,omitempty"`
+ AdditionalDirectories []string `json:"additionalDirectories,omitzero"`
// Whether to include the system temp directory in the allowed list (defaults to true).
// Ignored when `unrestricted` is true.
IncludeTempDirectory *bool `json:"includeTempDirectory,omitempty"`
@@ -3274,8 +3451,8 @@ type PermissionsConfigureAdditionalContentExclusionPolicy struct {
// Experimental: PermissionsConfigureAdditionalContentExclusionPolicyRule is part of an
// experimental API and may change or be removed.
type PermissionsConfigureAdditionalContentExclusionPolicyRule struct {
- IfAnyMatch []string `json:"ifAnyMatch,omitempty"`
- IfNoneMatch []string `json:"ifNoneMatch,omitempty"`
+ IfAnyMatch []string `json:"ifAnyMatch,omitzero"`
+ IfNoneMatch []string `json:"ifNoneMatch,omitzero"`
Paths []string `json:"paths"`
// Schema for the `PermissionsConfigureAdditionalContentExclusionPolicyRuleSource` type.
Source PermissionsConfigureAdditionalContentExclusionPolicyRuleSource `json:"source"`
@@ -3296,7 +3473,7 @@ type PermissionsConfigureParams struct {
// If specified, replaces the host-supplied GitHub Content Exclusion policies on the session
// (combined with natively-discovered policies when evaluating tool/file access). Omit to
// leave the current policies unchanged.
- AdditionalContentExclusionPolicies []PermissionsConfigureAdditionalContentExclusionPolicy `json:"additionalContentExclusionPolicies,omitempty"`
+ AdditionalContentExclusionPolicies []PermissionsConfigureAdditionalContentExclusionPolicy `json:"additionalContentExclusionPolicies,omitzero"`
// If specified, sets whether path/URL read permission requests are auto-approved. Omit to
// leave the current value unchanged.
ApproveAllReadPermissionRequests *bool `json:"approveAllReadPermissionRequests,omitempty"`
@@ -3313,7 +3490,7 @@ type PermissionsConfigureParams struct {
// If specified, replaces the session's URL-permission policy. The runtime constructs a
// fresh DefaultUrlManager based on these inputs. Omit to leave the current URL policy
// unchanged.
- Urls *PermissionUrlsConfig `json:"urls,omitempty"`
+ URLs *PermissionURLsConfig `json:"urls,omitempty"`
}
// Indicates whether the operation succeeded.
@@ -3415,32 +3592,32 @@ func (PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess) Kind(
}
// Schema for the `PermissionsLocationsAddToolApprovalDetailsMcp` type.
-// Experimental: PermissionsLocationsAddToolApprovalDetailsMcp is part of an experimental
+// Experimental: PermissionsLocationsAddToolApprovalDetailsMCP is part of an experimental
// API and may change or be removed.
-type PermissionsLocationsAddToolApprovalDetailsMcp struct {
+type PermissionsLocationsAddToolApprovalDetailsMCP struct {
// MCP server name.
ServerName string `json:"serverName"`
// MCP tool name, or null to cover every tool on the server.
ToolName *string `json:"toolName"`
}
-func (PermissionsLocationsAddToolApprovalDetailsMcp) permissionsLocationsAddToolApprovalDetails() {}
-func (PermissionsLocationsAddToolApprovalDetailsMcp) Kind() PermissionsLocationsAddToolApprovalDetailsKind {
- return PermissionsLocationsAddToolApprovalDetailsKindMcp
+func (PermissionsLocationsAddToolApprovalDetailsMCP) permissionsLocationsAddToolApprovalDetails() {}
+func (PermissionsLocationsAddToolApprovalDetailsMCP) Kind() PermissionsLocationsAddToolApprovalDetailsKind {
+ return PermissionsLocationsAddToolApprovalDetailsKindMCP
}
// Schema for the `PermissionsLocationsAddToolApprovalDetailsMcpSampling` type.
-// Experimental: PermissionsLocationsAddToolApprovalDetailsMcpSampling is part of an
+// Experimental: PermissionsLocationsAddToolApprovalDetailsMCPSampling is part of an
// experimental API and may change or be removed.
-type PermissionsLocationsAddToolApprovalDetailsMcpSampling struct {
+type PermissionsLocationsAddToolApprovalDetailsMCPSampling struct {
// MCP server name.
ServerName string `json:"serverName"`
}
-func (PermissionsLocationsAddToolApprovalDetailsMcpSampling) permissionsLocationsAddToolApprovalDetails() {
+func (PermissionsLocationsAddToolApprovalDetailsMCPSampling) permissionsLocationsAddToolApprovalDetails() {
}
-func (PermissionsLocationsAddToolApprovalDetailsMcpSampling) Kind() PermissionsLocationsAddToolApprovalDetailsKind {
- return PermissionsLocationsAddToolApprovalDetailsKindMcpSampling
+func (PermissionsLocationsAddToolApprovalDetailsMCPSampling) Kind() PermissionsLocationsAddToolApprovalDetailsKind {
+ return PermissionsLocationsAddToolApprovalDetailsKindMCPSampling
}
// Schema for the `PermissionsLocationsAddToolApprovalDetailsMemory` type.
@@ -3491,9 +3668,9 @@ type PermissionsLocationsAddToolApprovalResult struct {
// or be removed.
type PermissionsModifyRulesParams struct {
// Rules to add to the scope. Applied before `remove`/`removeAll`.
- Add []PermissionRule `json:"add,omitempty"`
+ Add []PermissionRule `json:"add,omitzero"`
// Specific rules to remove from the scope. Ignored when `removeAll` is true.
- Remove []PermissionRule `json:"remove,omitempty"`
+ Remove []PermissionRule `json:"remove,omitzero"`
// When true, removes every rule currently in the scope (after any `add` is applied). Useful
// for clearing the location scope wholesale.
RemoveAll *bool `json:"removeAll,omitempty"`
@@ -3566,6 +3743,8 @@ type PermissionsResetSessionApprovalsResult struct {
type PermissionsSetAllowAllRequest struct {
// Whether to enable full allow-all permissions
Enabled bool `json:"enabled"`
+ // Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers.
+ Source *PermissionsSetAllowAllSource `json:"source,omitempty"`
}
// Allow-all toggle for tool permission requests, with an optional telemetry source.
@@ -3605,9 +3784,9 @@ type PermissionsSetRequiredResult struct {
}
// Indicates whether the operation succeeded.
-// Experimental: PermissionsUrlsSetUnrestrictedModeResult is part of an experimental API and
+// Experimental: PermissionsURLsSetUnrestrictedModeResult is part of an experimental API and
// may change or be removed.
-type PermissionsUrlsSetUnrestrictedModeResult struct {
+type PermissionsURLsSetUnrestrictedModeResult struct {
// Whether the operation succeeded
Success bool `json:"success"`
}
@@ -3615,21 +3794,21 @@ type PermissionsUrlsSetUnrestrictedModeResult struct {
// If specified, replaces the session's URL-permission policy. The runtime constructs a
// fresh DefaultUrlManager based on these inputs. Omit to leave the current URL policy
// unchanged.
-// Experimental: PermissionUrlsConfig is part of an experimental API and may change or be
+// Experimental: PermissionURLsConfig is part of an experimental API and may change or be
// removed.
-type PermissionUrlsConfig struct {
+type PermissionURLsConfig struct {
// Initial list of allowed URL/domain patterns. Patterns may include path components.
// Ignored when `unrestricted` is true.
- InitialAllowed []string `json:"initialAllowed,omitempty"`
+ InitialAllowed []string `json:"initialAllowed,omitzero"`
// If true, the runtime allows access to all URLs without prompting. Initial allow-list is
// ignored when this is true.
Unrestricted *bool `json:"unrestricted,omitempty"`
}
// Whether the URL-permission policy should run in unrestricted mode.
-// Experimental: PermissionUrlsSetUnrestrictedModeParams is part of an experimental API and
+// Experimental: PermissionURLsSetUnrestrictedModeParams is part of an experimental API and
// may change or be removed.
-type PermissionUrlsSetUnrestrictedModeParams struct {
+type PermissionURLsSetUnrestrictedModeParams struct {
// Whether to allow access to all URLs without prompting. Toggles the runtime's
// URL-permission policy in place.
Enabled bool `json:"enabled"`
@@ -3691,6 +3870,167 @@ type PluginList struct {
Plugins []Plugin `json:"plugins"`
}
+// Schema for the `PushAttachment` type.
+// Experimental: PushAttachment is part of an experimental API and may change or be removed.
+type PushAttachment interface {
+ pushAttachment()
+ Type() PushAttachmentType
+}
+
+type RawPushAttachmentData struct {
+ Discriminator PushAttachmentType
+ Raw json.RawMessage
+}
+
+func (RawPushAttachmentData) pushAttachment() {}
+func (r RawPushAttachmentData) Type() PushAttachmentType {
+ return r.Discriminator
+}
+
+// Slim input shape for extension_context attachments; identity fields are runtime-derived.
+// Experimental: ExtensionContextPushInput is part of an experimental API and may change or
+// be removed.
+type ExtensionContextPushInput struct {
+ // Caller-supplied JSON payload (required, may be null but not undefined)
+ Payload any `json:"payload"`
+ // Human-readable composer pill label
+ Title string `json:"title"`
+}
+
+func (ExtensionContextPushInput) pushAttachment() {}
+func (ExtensionContextPushInput) Type() PushAttachmentType {
+ return PushAttachmentTypeExtensionContext
+}
+
+// Blob attachment with inline base64-encoded data
+// Experimental: PushAttachmentBlob is part of an experimental API and may change or be
+// removed.
+type PushAttachmentBlob struct {
+ // Base64-encoded content
+ Data string `json:"data"`
+ // User-facing display name for the attachment
+ DisplayName *string `json:"displayName,omitempty"`
+ // MIME type of the inline data
+ MIMEType string `json:"mimeType"`
+}
+
+func (PushAttachmentBlob) pushAttachment() {}
+func (PushAttachmentBlob) Type() PushAttachmentType {
+ return PushAttachmentTypeBlob
+}
+
+// Directory attachment
+// Experimental: PushAttachmentDirectory is part of an experimental API and may change or be
+// removed.
+type PushAttachmentDirectory struct {
+ // User-facing display name for the attachment
+ DisplayName string `json:"displayName"`
+ // Absolute directory path
+ Path string `json:"path"`
+}
+
+func (PushAttachmentDirectory) pushAttachment() {}
+func (PushAttachmentDirectory) Type() PushAttachmentType {
+ return PushAttachmentTypeDirectory
+}
+
+// File attachment
+// Experimental: PushAttachmentFile is part of an experimental API and may change or be
+// removed.
+type PushAttachmentFile struct {
+ // User-facing display name for the attachment
+ DisplayName string `json:"displayName"`
+ // Optional line range to scope the attachment to a specific section of the file
+ LineRange *PushAttachmentFileLineRange `json:"lineRange,omitempty"`
+ // Absolute file path
+ Path string `json:"path"`
+}
+
+func (PushAttachmentFile) pushAttachment() {}
+func (PushAttachmentFile) Type() PushAttachmentType {
+ return PushAttachmentTypeFile
+}
+
+// GitHub issue, pull request, or discussion reference
+// Experimental: PushAttachmentGitHubReference is part of an experimental API and may change
+// or be removed.
+type PushAttachmentGitHubReference struct {
+ // Issue, pull request, or discussion number
+ Number int64 `json:"number"`
+ // Type of GitHub reference
+ ReferenceType PushAttachmentGitHubReferenceType `json:"referenceType"`
+ // Current state of the referenced item (e.g., open, closed, merged)
+ State string `json:"state"`
+ // Title of the referenced item
+ Title string `json:"title"`
+ // URL to the referenced item on GitHub
+ URL string `json:"url"`
+}
+
+func (PushAttachmentGitHubReference) pushAttachment() {}
+func (PushAttachmentGitHubReference) Type() PushAttachmentType {
+ return PushAttachmentTypeGitHubReference
+}
+
+// Code selection attachment from an editor
+// Experimental: PushAttachmentSelection is part of an experimental API and may change or be
+// removed.
+type PushAttachmentSelection struct {
+ // User-facing display name for the selection
+ DisplayName string `json:"displayName"`
+ // Absolute path to the file containing the selection
+ FilePath string `json:"filePath"`
+ // Position range of the selection within the file
+ Selection PushAttachmentSelectionDetails `json:"selection"`
+ // The selected text content
+ Text string `json:"text"`
+}
+
+func (PushAttachmentSelection) pushAttachment() {}
+func (PushAttachmentSelection) Type() PushAttachmentType {
+ return PushAttachmentTypeSelection
+}
+
+// Optional line range to scope the attachment to a specific section of the file
+// Experimental: PushAttachmentFileLineRange is part of an experimental API and may change
+// or be removed.
+type PushAttachmentFileLineRange struct {
+ // End line number (1-based, inclusive)
+ End int64 `json:"end"`
+ // Start line number (1-based)
+ Start int64 `json:"start"`
+}
+
+// Position range of the selection within the file
+// Experimental: PushAttachmentSelectionDetails is part of an experimental API and may
+// change or be removed.
+type PushAttachmentSelectionDetails struct {
+ // End position of the selection
+ End PushAttachmentSelectionDetailsEnd `json:"end"`
+ // Start position of the selection
+ Start PushAttachmentSelectionDetailsStart `json:"start"`
+}
+
+// End position of the selection
+// Experimental: PushAttachmentSelectionDetailsEnd is part of an experimental API and may
+// change or be removed.
+type PushAttachmentSelectionDetailsEnd struct {
+ // End character offset within the line (0-based)
+ Character int64 `json:"character"`
+ // End line number (0-based)
+ Line int64 `json:"line"`
+}
+
+// Start position of the selection
+// Experimental: PushAttachmentSelectionDetailsStart is part of an experimental API and may
+// change or be removed.
+type PushAttachmentSelectionDetailsStart struct {
+ // Start character offset within the line (0-based)
+ Character int64 `json:"character"`
+ // Start line number (0-based)
+ Line int64 `json:"line"`
+}
+
// Result of the queued command execution.
// Experimental: QueuedCommandResult is part of an experimental API and may change or be
// removed.
@@ -3844,6 +4184,9 @@ type RemoteSessionConnectionResult struct {
SessionID string `json:"sessionId"`
}
+type RuntimeShutdownResult struct {
+}
+
// Schema for the `ScheduleEntry` type.
// Experimental: ScheduleEntry is part of an experimental API and may change or be removed.
type ScheduleEntry struct {
@@ -3898,150 +4241,18 @@ type SecretsAddFilterValuesResult struct {
Ok bool `json:"ok"`
}
-// A user message attachment — a file, directory, code selection, blob, or GitHub reference
-// Experimental: SendAttachment is part of an experimental API and may change or be removed.
-type SendAttachment interface {
- sendAttachment()
- Type() SendAttachmentType
-}
-
-type RawSendAttachmentData struct {
- Discriminator SendAttachmentType
- Raw json.RawMessage
-}
-
-func (RawSendAttachmentData) sendAttachment() {}
-func (r RawSendAttachmentData) Type() SendAttachmentType {
- return r.Discriminator
-}
-
-// Blob attachment with inline base64-encoded data
-// Experimental: SendAttachmentBlob is part of an experimental API and may change or be
-// removed.
-type SendAttachmentBlob struct {
- // Base64-encoded content
- Data string `json:"data"`
- // User-facing display name for the attachment
- DisplayName *string `json:"displayName,omitempty"`
- // MIME type of the inline data
- MIMEType string `json:"mimeType"`
-}
-
-func (SendAttachmentBlob) sendAttachment() {}
-func (SendAttachmentBlob) Type() SendAttachmentType {
- return SendAttachmentTypeBlob
-}
-
-// Directory attachment
-// Experimental: SendAttachmentDirectory is part of an experimental API and may change or be
-// removed.
-type SendAttachmentDirectory struct {
- // User-facing display name for the attachment
- DisplayName string `json:"displayName"`
- // Absolute directory path
- Path string `json:"path"`
-}
-
-func (SendAttachmentDirectory) sendAttachment() {}
-func (SendAttachmentDirectory) Type() SendAttachmentType {
- return SendAttachmentTypeDirectory
-}
-
-// File attachment
-// Experimental: SendAttachmentFile is part of an experimental API and may change or be
-// removed.
-type SendAttachmentFile struct {
- // User-facing display name for the attachment
- DisplayName string `json:"displayName"`
- // Optional line range to scope the attachment to a specific section of the file
- LineRange *SendAttachmentFileLineRange `json:"lineRange,omitempty"`
- // Absolute file path
- Path string `json:"path"`
-}
-
-func (SendAttachmentFile) sendAttachment() {}
-func (SendAttachmentFile) Type() SendAttachmentType {
- return SendAttachmentTypeFile
-}
-
-// GitHub issue, pull request, or discussion reference
-// Experimental: SendAttachmentGithubReference is part of an experimental API and may change
-// or be removed.
-type SendAttachmentGithubReference struct {
- // Issue, pull request, or discussion number
- Number int64 `json:"number"`
- // Type of GitHub reference
- ReferenceType SendAttachmentGithubReferenceType `json:"referenceType"`
- // Current state of the referenced item (e.g., open, closed, merged)
- State string `json:"state"`
- // Title of the referenced item
- Title string `json:"title"`
- // URL to the referenced item on GitHub
- URL string `json:"url"`
-}
-
-func (SendAttachmentGithubReference) sendAttachment() {}
-func (SendAttachmentGithubReference) Type() SendAttachmentType {
- return SendAttachmentTypeGithubReference
-}
-
-// Code selection attachment from an editor
-// Experimental: SendAttachmentSelection is part of an experimental API and may change or be
-// removed.
-type SendAttachmentSelection struct {
- // User-facing display name for the selection
- DisplayName string `json:"displayName"`
- // Absolute path to the file containing the selection
- FilePath string `json:"filePath"`
- // Position range of the selection within the file
- Selection SendAttachmentSelectionDetails `json:"selection"`
- // The selected text content
- Text string `json:"text"`
-}
-
-func (SendAttachmentSelection) sendAttachment() {}
-func (SendAttachmentSelection) Type() SendAttachmentType {
- return SendAttachmentTypeSelection
-}
-
-// Optional line range to scope the attachment to a specific section of the file
-// Experimental: SendAttachmentFileLineRange is part of an experimental API and may change
-// or be removed.
-type SendAttachmentFileLineRange struct {
- // End line number (1-based, inclusive)
- End int64 `json:"end"`
- // Start line number (1-based)
- Start int64 `json:"start"`
-}
-
-// Position range of the selection within the file
-// Experimental: SendAttachmentSelectionDetails is part of an experimental API and may
+// Parameters for session.extensions.sendAttachmentsToMessage.
+// Experimental: SendAttachmentsToMessageParams is part of an experimental API and may
// change or be removed.
-type SendAttachmentSelectionDetails struct {
- // End position of the selection
- End SendAttachmentSelectionDetailsEnd `json:"end"`
- // Start position of the selection
- Start SendAttachmentSelectionDetailsStart `json:"start"`
-}
-
-// End position of the selection
-// Experimental: SendAttachmentSelectionDetailsEnd is part of an experimental API and may
-// change or be removed.
-type SendAttachmentSelectionDetailsEnd struct {
- // End character offset within the line (0-based)
- Character int64 `json:"character"`
- // End line number (0-based)
- Line int64 `json:"line"`
-}
-
-// Start position of the selection
-// Experimental: SendAttachmentSelectionDetailsStart is part of an experimental API and may
-// change or be removed.
-type SendAttachmentSelectionDetailsStart struct {
- // Start character offset within the line (0-based)
- Character int64 `json:"character"`
- // Start line number (0-based)
- Line int64 `json:"line"`
+type SendAttachmentsToMessageParams struct {
+ // Attachments to push into the next user-message turn. extension_context entries take the
+ // slim shape; standard variants take their full AttachmentSchema shape.
+ Attachments []PushAttachment `json:"attachments"`
+ // Optional canvas instance binding the push for provenance. When supplied, the runtime
+ // resolves the canvas, verifies it is owned by the calling extension, and stamps
+ // canvasId/instanceId onto each extension_context entry. When omitted, no resolution runs
+ // and those fields stay unset on the attachment.
+ InstanceID *string `json:"instanceId,omitempty"`
}
// Parameters for sending a user message to the session
@@ -4052,7 +4263,7 @@ type SendRequest struct {
AgentMode *SendAgentMode `json:"agentMode,omitempty"`
// Optional attachments (files, directories, selections, blobs, GitHub references) to
// include with the message
- Attachments []SendAttachment `json:"attachments,omitempty"`
+ Attachments []Attachment `json:"attachments,omitzero"`
// If false, this message will not trigger a Premium Request Unit charge. User messages
// default to billable.
Billable *bool `json:"billable,omitempty"`
@@ -4068,7 +4279,7 @@ type SendRequest struct {
// Custom HTTP headers to include in outbound model requests for this turn. Merged with
// session-level provider headers; per-turn headers augment and overwrite session-level
// headers with the same key.
- RequestHeaders map[string]string `json:"requestHeaders,omitempty"`
+ RequestHeaders map[string]string `json:"requestHeaders,omitzero"`
// If set, the request will fail if the named tool is not available when this message is
// among the user messages at the start of the current exchange
RequiredTool *string `json:"requiredTool,omitempty"`
@@ -4182,12 +4393,12 @@ type SessionContextInfo struct {
CompactionThreshold int64 `json:"compactionThreshold"`
// Tokens consumed by user/assistant/tool messages
ConversationTokens int64 `json:"conversationTokens"`
- // Total context limit for /context display. promptTokenLimit + min(32k or 64k,
- // outputTokenLimit) depending on model.
+ // Total context limit for /context display: promptTokenLimit + outputTokenLimit (the
+ // model's full max_output_tokens reserved on top of the prompt budget).
Limit int64 `json:"limit"`
// Tokens consumed by MCP tool definitions (subset of toolDefinitionsTokens, excludes
// deferred tools)
- McpToolsTokens int64 `json:"mcpToolsTokens"`
+ MCPToolsTokens int64 `json:"mcpToolsTokens"`
// The model used for token counting
ModelName string `json:"modelName"`
// Maximum prompt tokens allowed by the model (or DEFAULT_TOKEN_LIMIT if unspecified)
@@ -4225,11 +4436,16 @@ type SessionExtensionsEnableResult struct {
type SessionExtensionsReloadResult struct {
}
+// Experimental: SessionExtensionsSendAttachmentsToMessageResult is part of an experimental
+// API and may change or be removed.
+type SessionExtensionsSendAttachmentsToMessageResult struct {
+}
+
// File path, content to append, and optional mode for the client-provided session
// filesystem.
-// Experimental: SessionFsAppendFileRequest is part of an experimental API and may change or
+// Experimental: SessionFSAppendFileRequest is part of an experimental API and may change or
// be removed.
-type SessionFsAppendFileRequest struct {
+type SessionFSAppendFileRequest struct {
// Content to append
Content string `json:"content"`
// Optional POSIX-style mode for newly created files
@@ -4241,18 +4457,18 @@ type SessionFsAppendFileRequest struct {
}
// Describes a filesystem error.
-// Experimental: SessionFsError is part of an experimental API and may change or be removed.
-type SessionFsError struct {
+// Experimental: SessionFSError is part of an experimental API and may change or be removed.
+type SessionFSError struct {
// Error classification
- Code SessionFsErrorCode `json:"code"`
+ Code SessionFSErrorCode `json:"code"`
// Free-form detail about the error, for logging/diagnostics
Message *string `json:"message,omitempty"`
}
// Path to test for existence in the client-provided session filesystem.
-// Experimental: SessionFsExistsRequest is part of an experimental API and may change or be
+// Experimental: SessionFSExistsRequest is part of an experimental API and may change or be
// removed.
-type SessionFsExistsRequest struct {
+type SessionFSExistsRequest struct {
// Path using SessionFs conventions
Path string `json:"path"`
// Target session identifier
@@ -4260,18 +4476,18 @@ type SessionFsExistsRequest struct {
}
// Indicates whether the requested path exists in the client-provided session filesystem.
-// Experimental: SessionFsExistsResult is part of an experimental API and may change or be
+// Experimental: SessionFSExistsResult is part of an experimental API and may change or be
// removed.
-type SessionFsExistsResult struct {
+type SessionFSExistsResult struct {
// Whether the path exists
Exists bool `json:"exists"`
}
// Directory path to create in the client-provided session filesystem, with options for
// recursive creation and POSIX mode.
-// Experimental: SessionFsMkdirRequest is part of an experimental API and may change or be
+// Experimental: SessionFSMkdirRequest is part of an experimental API and may change or be
// removed.
-type SessionFsMkdirRequest struct {
+type SessionFSMkdirRequest struct {
// Optional POSIX-style mode for newly created directories
Mode *int64 `json:"mode,omitempty"`
// Path using SessionFs conventions
@@ -4283,9 +4499,9 @@ type SessionFsMkdirRequest struct {
}
// Directory path whose entries should be listed from the client-provided session filesystem.
-// Experimental: SessionFsReaddirRequest is part of an experimental API and may change or be
+// Experimental: SessionFSReaddirRequest is part of an experimental API and may change or be
// removed.
-type SessionFsReaddirRequest struct {
+type SessionFSReaddirRequest struct {
// Path using SessionFs conventions
Path string `json:"path"`
// Target session identifier
@@ -4293,30 +4509,30 @@ type SessionFsReaddirRequest struct {
}
// Names of entries in the requested directory, or a filesystem error if the read failed.
-// Experimental: SessionFsReaddirResult is part of an experimental API and may change or be
+// Experimental: SessionFSReaddirResult is part of an experimental API and may change or be
// removed.
-type SessionFsReaddirResult struct {
+type SessionFSReaddirResult struct {
// Entry names in the directory
Entries []string `json:"entries"`
// Describes a filesystem error.
- Error *SessionFsError `json:"error,omitempty"`
+ Error *SessionFSError `json:"error,omitempty"`
}
// Schema for the `SessionFsReaddirWithTypesEntry` type.
-// Experimental: SessionFsReaddirWithTypesEntry is part of an experimental API and may
+// Experimental: SessionFSReaddirWithTypesEntry is part of an experimental API and may
// change or be removed.
-type SessionFsReaddirWithTypesEntry struct {
+type SessionFSReaddirWithTypesEntry struct {
// Entry name
Name string `json:"name"`
// Entry type
- Type SessionFsReaddirWithTypesEntryType `json:"type"`
+ Type SessionFSReaddirWithTypesEntryType `json:"type"`
}
// Directory path whose entries (with type information) should be listed from the
// client-provided session filesystem.
-// Experimental: SessionFsReaddirWithTypesRequest is part of an experimental API and may
+// Experimental: SessionFSReaddirWithTypesRequest is part of an experimental API and may
// change or be removed.
-type SessionFsReaddirWithTypesRequest struct {
+type SessionFSReaddirWithTypesRequest struct {
// Path using SessionFs conventions
Path string `json:"path"`
// Target session identifier
@@ -4325,19 +4541,19 @@ type SessionFsReaddirWithTypesRequest struct {
// Entries in the requested directory paired with file/directory type information, or a
// filesystem error if the read failed.
-// Experimental: SessionFsReaddirWithTypesResult is part of an experimental API and may
+// Experimental: SessionFSReaddirWithTypesResult is part of an experimental API and may
// change or be removed.
-type SessionFsReaddirWithTypesResult struct {
+type SessionFSReaddirWithTypesResult struct {
// Directory entries with type information
- Entries []SessionFsReaddirWithTypesEntry `json:"entries"`
+ Entries []SessionFSReaddirWithTypesEntry `json:"entries"`
// Describes a filesystem error.
- Error *SessionFsError `json:"error,omitempty"`
+ Error *SessionFSError `json:"error,omitempty"`
}
// Path of the file to read from the client-provided session filesystem.
-// Experimental: SessionFsReadFileRequest is part of an experimental API and may change or
+// Experimental: SessionFSReadFileRequest is part of an experimental API and may change or
// be removed.
-type SessionFsReadFileRequest struct {
+type SessionFSReadFileRequest struct {
// Path using SessionFs conventions
Path string `json:"path"`
// Target session identifier
@@ -4345,20 +4561,20 @@ type SessionFsReadFileRequest struct {
}
// File content as a UTF-8 string, or a filesystem error if the read failed.
-// Experimental: SessionFsReadFileResult is part of an experimental API and may change or be
+// Experimental: SessionFSReadFileResult is part of an experimental API and may change or be
// removed.
-type SessionFsReadFileResult struct {
+type SessionFSReadFileResult struct {
// File content as UTF-8 string
Content string `json:"content"`
// Describes a filesystem error.
- Error *SessionFsError `json:"error,omitempty"`
+ Error *SessionFSError `json:"error,omitempty"`
}
// Source and destination paths for renaming or moving an entry in the client-provided
// session filesystem.
-// Experimental: SessionFsRenameRequest is part of an experimental API and may change or be
+// Experimental: SessionFSRenameRequest is part of an experimental API and may change or be
// removed.
-type SessionFsRenameRequest struct {
+type SessionFSRenameRequest struct {
// Destination path using SessionFs conventions
Dest string `json:"dest"`
// Target session identifier
@@ -4369,9 +4585,9 @@ type SessionFsRenameRequest struct {
// Path to remove from the client-provided session filesystem, with options for recursive
// removal and force.
-// Experimental: SessionFsRmRequest is part of an experimental API and may change or be
+// Experimental: SessionFSRmRequest is part of an experimental API and may change or be
// removed.
-type SessionFsRmRequest struct {
+type SessionFSRmRequest struct {
// Ignore errors if the path does not exist
Force *bool `json:"force,omitempty"`
// Path using SessionFs conventions
@@ -4383,18 +4599,18 @@ type SessionFsRmRequest struct {
}
// Optional capabilities declared by the provider
-type SessionFsSetProviderCapabilities struct {
+type SessionFSSetProviderCapabilities struct {
// Whether the provider supports SQLite query/exists operations
Sqlite *bool `json:"sqlite,omitempty"`
}
// Initial working directory, session-state path layout, and path conventions used to
// register the calling SDK client as the session filesystem provider.
-type SessionFsSetProviderRequest struct {
+type SessionFSSetProviderRequest struct {
// Optional capabilities declared by the provider
- Capabilities *SessionFsSetProviderCapabilities `json:"capabilities,omitempty"`
+ Capabilities *SessionFSSetProviderCapabilities `json:"capabilities,omitempty"`
// Path conventions used by this filesystem
- Conventions SessionFsSetProviderConventions `json:"conventions"`
+ Conventions SessionFSSetProviderConventions `json:"conventions"`
// Initial working directory for sessions
InitialCwd string `json:"initialCwd"`
// Path within each session's SessionFs where the runtime stores files for that session
@@ -4402,52 +4618,52 @@ type SessionFsSetProviderRequest struct {
}
// Indicates whether the calling client was registered as the session filesystem provider.
-type SessionFsSetProviderResult struct {
+type SessionFSSetProviderResult struct {
// Whether the provider was set successfully
Success bool `json:"success"`
}
// Identifies the target session.
-// Experimental: SessionFsSqliteExistsRequest is part of an experimental API and may change
+// Experimental: SessionFSSqliteExistsRequest is part of an experimental API and may change
// or be removed.
-type SessionFsSqliteExistsRequest struct {
+type SessionFSSqliteExistsRequest struct {
// Target session identifier
SessionID string `json:"sessionId"`
}
// Indicates whether the per-session SQLite database already exists.
-// Experimental: SessionFsSqliteExistsResult is part of an experimental API and may change
+// Experimental: SessionFSSqliteExistsResult is part of an experimental API and may change
// or be removed.
-type SessionFsSqliteExistsResult struct {
+type SessionFSSqliteExistsResult struct {
// Whether the session database already exists
Exists bool `json:"exists"`
}
// SQL query, query type, and optional bind parameters for executing a SQLite query against
// the per-session database.
-// Experimental: SessionFsSqliteQueryRequest is part of an experimental API and may change
+// Experimental: SessionFSSqliteQueryRequest is part of an experimental API and may change
// or be removed.
-type SessionFsSqliteQueryRequest struct {
+type SessionFSSqliteQueryRequest struct {
// Optional named bind parameters
- Params map[string]any `json:"params,omitempty"`
+ Params map[string]any `json:"params,omitzero"`
// SQL query to execute
Query string `json:"query"`
// How to execute the query: 'exec' for DDL/multi-statement (no results), 'query' for SELECT
// (returns rows), 'run' for INSERT/UPDATE/DELETE (returns rowsAffected)
- QueryType SessionFsSqliteQueryType `json:"queryType"`
+ QueryType SessionFSSqliteQueryType `json:"queryType"`
// Target session identifier
SessionID string `json:"sessionId"`
}
// Query results including rows, columns, and rows affected, or a filesystem error if
// execution failed.
-// Experimental: SessionFsSqliteQueryResult is part of an experimental API and may change or
+// Experimental: SessionFSSqliteQueryResult is part of an experimental API and may change or
// be removed.
-type SessionFsSqliteQueryResult struct {
+type SessionFSSqliteQueryResult struct {
// Column names from the result set
Columns []string `json:"columns"`
// Describes a filesystem error.
- Error *SessionFsError `json:"error,omitempty"`
+ Error *SessionFSError `json:"error,omitempty"`
// SQLite last_insert_rowid() value for INSERT.
LastInsertRowid *int64 `json:"lastInsertRowid,omitempty"`
// For SELECT: array of row objects. For others: empty array.
@@ -4457,9 +4673,9 @@ type SessionFsSqliteQueryResult struct {
}
// Path whose metadata should be returned from the client-provided session filesystem.
-// Experimental: SessionFsStatRequest is part of an experimental API and may change or be
+// Experimental: SessionFSStatRequest is part of an experimental API and may change or be
// removed.
-type SessionFsStatRequest struct {
+type SessionFSStatRequest struct {
// Path using SessionFs conventions
Path string `json:"path"`
// Target session identifier
@@ -4467,13 +4683,13 @@ type SessionFsStatRequest struct {
}
// Filesystem metadata for the requested path, or a filesystem error if the stat failed.
-// Experimental: SessionFsStatResult is part of an experimental API and may change or be
+// Experimental: SessionFSStatResult is part of an experimental API and may change or be
// removed.
-type SessionFsStatResult struct {
+type SessionFSStatResult struct {
// ISO 8601 timestamp of creation
Birthtime time.Time `json:"birthtime"`
// Describes a filesystem error.
- Error *SessionFsError `json:"error,omitempty"`
+ Error *SessionFSError `json:"error,omitempty"`
// Whether the path is a directory
IsDirectory bool `json:"isDirectory"`
// Whether the path is a file
@@ -4485,9 +4701,9 @@ type SessionFsStatResult struct {
}
// File path, content to write, and optional mode for the client-provided session filesystem.
-// Experimental: SessionFsWriteFileRequest is part of an experimental API and may change or
+// Experimental: SessionFSWriteFileRequest is part of an experimental API and may change or
// be removed.
-type SessionFsWriteFileRequest struct {
+type SessionFSWriteFileRequest struct {
// Content to write
Content string `json:"content"`
// Optional POSIX-style mode for newly created files
@@ -4522,21 +4738,21 @@ type SessionInstalledPlugin struct {
// Experimental: SessionInstalledPluginSource is part of an experimental API and may change
// or be removed.
type SessionInstalledPluginSource struct {
- SessionInstalledPluginSourceGithub *SessionInstalledPluginSourceGithub
+ SessionInstalledPluginSourceGitHub *SessionInstalledPluginSourceGitHub
SessionInstalledPluginSourceLocal *SessionInstalledPluginSourceLocal
SessionInstalledPluginSourceURL *SessionInstalledPluginSourceURL
String *string
}
-// Schema for the `SessionInstalledPluginSourceGithub` type.
-// Experimental: SessionInstalledPluginSourceGithub is part of an experimental API and may
+// Schema for the `SessionInstalledPluginSourceGitHub` type.
+// Experimental: SessionInstalledPluginSourceGitHub is part of an experimental API and may
// change or be removed.
-type SessionInstalledPluginSourceGithub struct {
+type SessionInstalledPluginSourceGitHub struct {
Path *string `json:"path,omitempty"`
Ref *string `json:"ref,omitempty"`
Repo string `json:"repo"`
// Constant value. Always "github".
- Source SessionInstalledPluginSourceGithubSource `json:"source"`
+ Source SessionInstalledPluginSourceGitHubSource `json:"source"`
}
// Schema for the `SessionInstalledPluginSourceLocal` type.
@@ -4598,28 +4814,28 @@ type SessionLspInitializeResult struct {
}
// Standard MCP CallToolResult
-// Experimental: SessionMcpAppsCallToolResult is part of an experimental API and may change
+// Experimental: SessionMCPAppsCallToolResult is part of an experimental API and may change
// or be removed.
-type SessionMcpAppsCallToolResult map[string]any
+type SessionMCPAppsCallToolResult map[string]any
-// Experimental: SessionMcpAppsSetHostContextResult is part of an experimental API and may
+// Experimental: SessionMCPAppsSetHostContextResult is part of an experimental API and may
// change or be removed.
-type SessionMcpAppsSetHostContextResult struct {
+type SessionMCPAppsSetHostContextResult struct {
}
-// Experimental: SessionMcpDisableResult is part of an experimental API and may change or be
+// Experimental: SessionMCPDisableResult is part of an experimental API and may change or be
// removed.
-type SessionMcpDisableResult struct {
+type SessionMCPDisableResult struct {
}
-// Experimental: SessionMcpEnableResult is part of an experimental API and may change or be
+// Experimental: SessionMCPEnableResult is part of an experimental API and may change or be
// removed.
-type SessionMcpEnableResult struct {
+type SessionMCPEnableResult struct {
}
-// Experimental: SessionMcpReloadResult is part of an experimental API and may change or be
+// Experimental: SessionMCPReloadResult is part of an experimental API and may change or be
// removed.
-type SessionMcpReloadResult struct {
+type SessionMCPReloadResult struct {
}
// Schema for the `SessionMetadata` type.
@@ -4700,7 +4916,7 @@ type SessionModelList struct {
// Available models, ordered with the most preferred default first.
List []any `json:"list"`
// Per-quota snapshots returned alongside the model list, keyed by quota type.
- QuotaSnapshots map[string]any `json:"quotaSnapshots,omitempty"`
+ QuotaSnapshots map[string]any `json:"quotaSnapshots,omitzero"`
}
// Experimental: SessionModeSetResult is part of an experimental API and may change or be
@@ -4755,7 +4971,7 @@ type SessionRemoteDisableResult struct {
// be removed.
type SessionsBulkDeleteRequest struct {
// Session IDs to close, deactivate, and delete from disk
- SessionIds []string `json:"sessionIds"`
+ SessionIDs []string `json:"sessionIds"`
}
// Session IDs to test for live in-use locks.
@@ -4763,7 +4979,7 @@ type SessionsBulkDeleteRequest struct {
// be removed.
type SessionsCheckInUseRequest struct {
// Session IDs to test for live in-use locks
- SessionIds []string `json:"sessionIds"`
+ SessionIDs []string `json:"sessionIds"`
}
// Session IDs from the input set that are currently in use by another process.
@@ -4986,7 +5202,7 @@ type SessionsPruneOldRequest struct {
// When true, only report what would be deleted without performing any deletion
DryRun *bool `json:"dryRun,omitempty"`
// Session IDs that should never be considered for pruning
- ExcludeSessionIds []string `json:"excludeSessionIds,omitempty"`
+ ExcludeSessionIDs []string `json:"excludeSessionIds,omitzero"`
// When true, named sessions (set via /rename) are also eligible for pruning
IncludeNamed *bool `json:"includeNamed,omitempty"`
// Delete sessions whose modifiedTime is at least this many days old
@@ -5077,13 +5293,13 @@ type SessionUpdateOptionsParams struct {
// shape; see `ContentExclusionApiResponse` in the runtime.
// Experimental: AdditionalContentExclusionPolicies is part of an experimental API and may
// change or be removed.
- AdditionalContentExclusionPolicies []any `json:"additionalContentExclusionPolicies,omitempty"`
+ AdditionalContentExclusionPolicies []any `json:"additionalContentExclusionPolicies,omitzero"`
// Runtime context discriminator (e.g., `cli`, `actions`).
AgentContext *string `json:"agentContext,omitempty"`
// Whether to disable the `ask_user` tool (encourages autonomous behavior).
AskUserDisabled *bool `json:"askUserDisabled,omitempty"`
// Allowlist of tool names available to this session.
- AvailableTools []string `json:"availableTools,omitempty"`
+ AvailableTools []string `json:"availableTools,omitzero"`
// Identifier of the client driving the session.
ClientName *string `json:"clientName,omitempty"`
// Whether to include the `Co-authored-by` trailer in commit messages.
@@ -5095,9 +5311,9 @@ type SessionUpdateOptionsParams struct {
// Whether to default custom agents to local-only execution.
CustomAgentsLocalOnly *bool `json:"customAgentsLocalOnly,omitempty"`
// Instruction source IDs to exclude from the system prompt.
- DisabledInstructionSources []string `json:"disabledInstructionSources,omitempty"`
+ DisabledInstructionSources []string `json:"disabledInstructionSources,omitzero"`
// Skill IDs that should be excluded from this session.
- DisabledSkills []string `json:"disabledSkills,omitempty"`
+ DisabledSkills []string `json:"disabledSkills,omitzero"`
// Whether to enable loading of `.github/hooks/` filesystem hooks. Separate from the SDK
// callback hook mechanism.
EnableFileHooks *bool `json:"enableFileHooks,omitempty"`
@@ -5126,12 +5342,12 @@ type SessionUpdateOptionsParams struct {
// log directory is used.
EventsLogDirectory *string `json:"eventsLogDirectory,omitempty"`
// Denylist of tool names for this session.
- ExcludedTools []string `json:"excludedTools,omitempty"`
+ ExcludedTools []string `json:"excludedTools,omitzero"`
// Map of feature-flag IDs to their boolean enabled state.
- FeatureFlags map[string]bool `json:"featureFlags,omitempty"`
+ FeatureFlags map[string]bool `json:"featureFlags,omitzero"`
// Full set of installed plugins for the session. Replaces the existing list; the runtime
// invalidates the skills cache only when the list materially changes.
- InstalledPlugins []SessionInstalledPlugin `json:"installedPlugins,omitempty"`
+ InstalledPlugins []SessionInstalledPlugin `json:"installedPlugins,omitzero"`
// Stable integration identifier used for analytics and rate-limit attribution.
IntegrationID *string `json:"integrationId,omitempty"`
// Whether experimental capabilities are enabled.
@@ -5162,13 +5378,17 @@ type SessionUpdateOptionsParams struct {
// Shell init profile (`None` or `NonInteractive`).
ShellInitProfile *string `json:"shellInitProfile,omitempty"`
// Per-shell process flags (e.g., `pwsh` arguments).
- ShellProcessFlags []string `json:"shellProcessFlags,omitempty"`
+ ShellProcessFlags []string `json:"shellProcessFlags,omitzero"`
// Additional directories to search for skills.
- SkillDirectories []string `json:"skillDirectories,omitempty"`
+ SkillDirectories []string `json:"skillDirectories,omitzero"`
// Whether to skip loading custom instruction sources.
SkipCustomInstructions *bool `json:"skipCustomInstructions,omitempty"`
// Whether to skip embedding retrieval pipeline initialization and execution.
SkipEmbeddingRetrieval *bool `json:"skipEmbeddingRetrieval,omitempty"`
+ // When true, the selected custom agent's prompt is not injected into the user message
+ // (skill context is still injected). Used by automation triggers where the agent prompt is
+ // already in the problem statement.
+ SuppressCustomAgentPrompt *bool `json:"suppressCustomAgentPrompt,omitempty"`
// Controls how availableTools (allowlist) and excludedTools (denylist) combine when both
// are set.
ToolFilterPrecedence *OptionsUpdateToolFilterPrecedence `json:"toolFilterPrecedence,omitempty"`
@@ -5309,9 +5529,9 @@ type SkillsDisableRequest struct {
// Optional project paths and additional skill directories to include in discovery.
type SkillsDiscoverRequest struct {
// Optional list of project directory paths to scan for project-scoped skills
- ProjectPaths []string `json:"projectPaths,omitempty"`
+ ProjectPaths []string `json:"projectPaths,omitzero"`
// Optional list of additional skill directory paths to include
- SkillDirectories []string `json:"skillDirectories,omitempty"`
+ SkillDirectories []string `json:"skillDirectories,omitzero"`
}
// Name of the skill to enable for the session.
@@ -5335,7 +5555,7 @@ type SkillsGetInvokedResult struct {
// removed.
type SkillsInvokedSkill struct {
// Tools that should be auto-approved when this skill is active, captured at invocation time
- AllowedTools []string `json:"allowedTools,omitempty"`
+ AllowedTools []string `json:"allowedTools,omitzero"`
// Full content of the skill file
Content string `json:"content"`
// Turn number when the skill was invoked
@@ -5361,7 +5581,7 @@ type SkillsLoadDiagnostics struct {
// removed.
type SlashCommandInfo struct {
// Canonical aliases without leading slashes
- Aliases []string `json:"aliases,omitempty"`
+ Aliases []string `json:"aliases,omitzero"`
// Whether the command may run while an agent turn is active
AllowDuringAgentExecution bool `json:"allowDuringAgentExecution"`
// Human-readable command description
@@ -5831,7 +6051,7 @@ type Tool struct {
// tools)
NamespacedName *string `json:"namespacedName,omitempty"`
// JSON Schema for the tool's input parameters
- Parameters map[string]any `json:"parameters,omitempty"`
+ Parameters map[string]any `json:"parameters,omitzero"`
}
// Built-in tools available for the requested model, with their parameters and instructions.
@@ -5895,24 +6115,24 @@ type UIElicitationArrayEnumFieldItems struct {
// Experimental: UIElicitationFieldValue is part of an experimental API and may change or be
// removed.
type UIElicitationFieldValue interface {
- uIElicitationFieldValue()
+ uiElicitationFieldValue()
}
type UIElicitationBooleanValue bool
-func (UIElicitationBooleanValue) uIElicitationFieldValue() {}
+func (UIElicitationBooleanValue) uiElicitationFieldValue() {}
type UIElicitationNumberValue float64
-func (UIElicitationNumberValue) uIElicitationFieldValue() {}
+func (UIElicitationNumberValue) uiElicitationFieldValue() {}
type UIElicitationStringArrayValue []string
-func (UIElicitationStringArrayValue) uIElicitationFieldValue() {}
+func (UIElicitationStringArrayValue) uiElicitationFieldValue() {}
type UIElicitationStringValue string
-func (UIElicitationStringValue) uIElicitationFieldValue() {}
+func (UIElicitationStringValue) uiElicitationFieldValue() {}
// Prompt message and JSON schema describing the form fields to elicit from the user.
// Experimental: UIElicitationRequest is part of an experimental API and may change or be
@@ -5931,7 +6151,7 @@ type UIElicitationResponse struct {
// The user's response: accept (submitted), decline (rejected), or cancel (dismissed)
Action UIElicitationResponseAction `json:"action"`
// The form values submitted by the user (present when action is 'accept')
- Content map[string]UIElicitationFieldValue `json:"content,omitempty"`
+ Content map[string]UIElicitationFieldValue `json:"content,omitzero"`
}
// The form values submitted by the user (present when action is 'accept')
@@ -5956,7 +6176,7 @@ type UIElicitationSchema struct {
// Form field definitions, keyed by field name
Properties map[string]UIElicitationSchemaProperty `json:"properties"`
// List of required field names
- Required []string `json:"required,omitempty"`
+ Required []string `json:"required,omitzero"`
// Schema type indicator (always 'object')
Type UIElicitationSchemaType `json:"type"`
}
@@ -5965,7 +6185,7 @@ type UIElicitationSchema struct {
// Experimental: UIElicitationSchemaProperty is part of an experimental API and may change
// or be removed.
type UIElicitationSchemaProperty interface {
- uIElicitationSchemaProperty()
+ uiElicitationSchemaProperty()
Type() UIElicitationSchemaPropertyType
}
@@ -5974,7 +6194,7 @@ type RawUIElicitationSchemaPropertyData struct {
Raw json.RawMessage
}
-func (RawUIElicitationSchemaPropertyData) uIElicitationSchemaProperty() {}
+func (RawUIElicitationSchemaPropertyData) uiElicitationSchemaProperty() {}
func (r RawUIElicitationSchemaPropertyData) Type() UIElicitationSchemaPropertyType {
return r.Discriminator
}
@@ -5984,7 +6204,7 @@ func (r RawUIElicitationSchemaPropertyData) Type() UIElicitationSchemaPropertyTy
// or be removed.
type UIElicitationArrayAnyOfField struct {
// Default values selected when the form is first shown.
- Default []string `json:"default,omitempty"`
+ Default []string `json:"default,omitzero"`
// Help text describing the field.
Description *string `json:"description,omitempty"`
// Schema applied to each item in the array.
@@ -5997,7 +6217,7 @@ type UIElicitationArrayAnyOfField struct {
Title *string `json:"title,omitempty"`
}
-func (UIElicitationArrayAnyOfField) uIElicitationSchemaProperty() {}
+func (UIElicitationArrayAnyOfField) uiElicitationSchemaProperty() {}
func (UIElicitationArrayAnyOfField) Type() UIElicitationSchemaPropertyType {
return UIElicitationSchemaPropertyTypeArray
}
@@ -6007,7 +6227,7 @@ func (UIElicitationArrayAnyOfField) Type() UIElicitationSchemaPropertyType {
// or be removed.
type UIElicitationArrayEnumField struct {
// Default values selected when the form is first shown.
- Default []string `json:"default,omitempty"`
+ Default []string `json:"default,omitzero"`
// Help text describing the field.
Description *string `json:"description,omitempty"`
// Schema applied to each item in the array.
@@ -6020,7 +6240,7 @@ type UIElicitationArrayEnumField struct {
Title *string `json:"title,omitempty"`
}
-func (UIElicitationArrayEnumField) uIElicitationSchemaProperty() {}
+func (UIElicitationArrayEnumField) uiElicitationSchemaProperty() {}
func (UIElicitationArrayEnumField) Type() UIElicitationSchemaPropertyType {
return UIElicitationSchemaPropertyTypeArray
}
@@ -6037,7 +6257,7 @@ type UIElicitationSchemaPropertyBoolean struct {
Title *string `json:"title,omitempty"`
}
-func (UIElicitationSchemaPropertyBoolean) uIElicitationSchemaProperty() {}
+func (UIElicitationSchemaPropertyBoolean) uiElicitationSchemaProperty() {}
func (UIElicitationSchemaPropertyBoolean) Type() UIElicitationSchemaPropertyType {
return UIElicitationSchemaPropertyTypeBoolean
}
@@ -6059,7 +6279,7 @@ type UIElicitationSchemaPropertyNumber struct {
Discriminator UIElicitationSchemaPropertyNumberType `json:"type,omitempty"`
}
-func (UIElicitationSchemaPropertyNumber) uIElicitationSchemaProperty() {}
+func (UIElicitationSchemaPropertyNumber) uiElicitationSchemaProperty() {}
func (r UIElicitationSchemaPropertyNumber) Type() UIElicitationSchemaPropertyType {
if r.Discriminator == "" {
return UIElicitationSchemaPropertyTypeNumber
@@ -6085,7 +6305,7 @@ type UIElicitationSchemaPropertyString struct {
Title *string `json:"title,omitempty"`
}
-func (UIElicitationSchemaPropertyString) uIElicitationSchemaProperty() {}
+func (UIElicitationSchemaPropertyString) uiElicitationSchemaProperty() {}
func (UIElicitationSchemaPropertyString) Type() UIElicitationSchemaPropertyType {
return UIElicitationSchemaPropertyTypeString
}
@@ -6101,12 +6321,12 @@ type UIElicitationStringEnumField struct {
// Allowed string values.
Enum []string `json:"enum"`
// Optional display labels for each enum value, in the same order as `enum`.
- EnumNames []string `json:"enumNames,omitempty"`
+ EnumNames []string `json:"enumNames,omitzero"`
// Human-readable label for the field.
Title *string `json:"title,omitempty"`
}
-func (UIElicitationStringEnumField) uIElicitationSchemaProperty() {}
+func (UIElicitationStringEnumField) uiElicitationSchemaProperty() {}
func (UIElicitationStringEnumField) Type() UIElicitationSchemaPropertyType {
return UIElicitationSchemaPropertyTypeString
}
@@ -6125,7 +6345,7 @@ type UIElicitationStringOneOfField struct {
Title *string `json:"title,omitempty"`
}
-func (UIElicitationStringOneOfField) uIElicitationSchemaProperty() {}
+func (UIElicitationStringOneOfField) uiElicitationSchemaProperty() {}
func (UIElicitationStringOneOfField) Type() UIElicitationSchemaPropertyType {
return UIElicitationSchemaPropertyTypeString
}
@@ -6286,7 +6506,7 @@ type UsageGetMetricsResult struct {
// ISO 8601 timestamp when the session started
SessionStartTime time.Time `json:"sessionStartTime"`
// Session-wide per-token-type accumulated token counts
- TokenDetails map[string]UsageMetricsTokenDetail `json:"tokenDetails,omitempty"`
+ TokenDetails map[string]UsageMetricsTokenDetail `json:"tokenDetails,omitzero"`
// Total time spent in model API calls (milliseconds)
TotalAPIDurationMs int64 `json:"totalApiDurationMs"`
// Session-wide accumulated nano-AI units cost
@@ -6319,7 +6539,7 @@ type UsageMetricsModelMetric struct {
// Request count and cost metrics for this model
Requests UsageMetricsModelMetricRequests `json:"requests"`
// Token count details per type
- TokenDetails map[string]UsageMetricsModelMetricTokenDetail `json:"tokenDetails,omitempty"`
+ TokenDetails map[string]UsageMetricsModelMetricTokenDetail `json:"tokenDetails,omitzero"`
// Accumulated nano-AI units cost for this model
TotalNanoAiu *float64 `json:"totalNanoAiu,omitempty"`
// Token usage metrics for this model
@@ -6442,18 +6662,18 @@ func (UserToolSessionApprovalExtensionPermissionAccess) Kind() UserToolSessionAp
}
// Schema for the `UserToolSessionApprovalMcp` type.
-// Experimental: UserToolSessionApprovalMcp is part of an experimental API and may change or
+// Experimental: UserToolSessionApprovalMCP is part of an experimental API and may change or
// be removed.
-type UserToolSessionApprovalMcp struct {
+type UserToolSessionApprovalMCP struct {
// MCP server name
ServerName string `json:"serverName"`
// Optional MCP tool name, or null for all tools on the server
ToolName *string `json:"toolName"`
}
-func (UserToolSessionApprovalMcp) userToolSessionApproval() {}
-func (UserToolSessionApprovalMcp) Kind() UserToolSessionApprovalKind {
- return UserToolSessionApprovalKindMcp
+func (UserToolSessionApprovalMCP) userToolSessionApproval() {}
+func (UserToolSessionApprovalMCP) Kind() UserToolSessionApprovalKind {
+ return UserToolSessionApprovalKindMCP
}
// Schema for the `UserToolSessionApprovalMemory` type.
@@ -6851,6 +7071,32 @@ const (
AgentRegistrySpawnValidationErrorReasonYoloNotAllowed AgentRegistrySpawnValidationErrorReason = "yolo-not-allowed"
)
+// Type of GitHub reference
+// Experimental: AttachmentGitHubReferenceType is part of an experimental API and may change
+// or be removed.
+type AttachmentGitHubReferenceType string
+
+const (
+ // GitHub discussion reference.
+ AttachmentGitHubReferenceTypeDiscussion AttachmentGitHubReferenceType = "discussion"
+ // GitHub issue reference.
+ AttachmentGitHubReferenceTypeIssue AttachmentGitHubReferenceType = "issue"
+ // GitHub pull request reference.
+ AttachmentGitHubReferenceTypePr AttachmentGitHubReferenceType = "pr"
+)
+
+// Type discriminator for Attachment.
+type AttachmentType string
+
+const (
+ AttachmentTypeBlob AttachmentType = "blob"
+ AttachmentTypeDirectory AttachmentType = "directory"
+ AttachmentTypeExtensionContext AttachmentType = "extension_context"
+ AttachmentTypeFile AttachmentType = "file"
+ AttachmentTypeGitHubReference AttachmentType = "github_reference"
+ AttachmentTypeSelection AttachmentType = "selection"
+)
+
// Type discriminator for AuthInfo.
// Experimental: AuthInfoType is part of an experimental API and may change or be removed.
type AuthInfoType string
@@ -6859,8 +7105,8 @@ const (
AuthInfoTypeAPIKey AuthInfoType = "api-key"
AuthInfoTypeCopilotAPIToken AuthInfoType = "copilot-api-token"
AuthInfoTypeEnv AuthInfoType = "env"
- AuthInfoTypeGhCli AuthInfoType = "gh-cli"
- AuthInfoTypeHmac AuthInfoType = "hmac"
+ AuthInfoTypeGhCLI AuthInfoType = "gh-cli"
+ AuthInfoTypeHMAC AuthInfoType = "hmac"
AuthInfoTypeToken AuthInfoType = "token"
AuthInfoTypeUser AuthInfoType = "user"
)
@@ -6905,25 +7151,36 @@ const (
ContentFilterModeNone ContentFilterMode = "none"
)
+// Context tier for models that support multiple context-window sizes.
+// Experimental: ContextTier is part of an experimental API and may change or be removed.
+type ContextTier string
+
+const (
+ // Use the model's default context window.
+ ContextTierDefault ContextTier = "default"
+ // Pin the session to the long-context tier when supported.
+ ContextTierLongContext ContextTier = "long_context"
+)
+
// Authentication host (always the public GitHub host).
type CopilotAPITokenAuthInfoHost string
const (
- CopilotAPITokenAuthInfoHostHTTPSGithubCom CopilotAPITokenAuthInfoHost = "https://github.com"
+ CopilotAPITokenAuthInfoHostHTTPSGitHubCom CopilotAPITokenAuthInfoHost = "https://github.com"
)
// Server transport type: stdio, http, sse (deprecated), or memory
-type DiscoveredMcpServerType string
+type DiscoveredMCPServerType string
const (
// Server communicates over streamable HTTP.
- DiscoveredMcpServerTypeHTTP DiscoveredMcpServerType = "http"
+ DiscoveredMCPServerTypeHTTP DiscoveredMCPServerType = "http"
// Server is backed by an in-memory runtime implementation.
- DiscoveredMcpServerTypeMemory DiscoveredMcpServerType = "memory"
+ DiscoveredMCPServerTypeMemory DiscoveredMCPServerType = "memory"
// Server communicates over Server-Sent Events (deprecated).
- DiscoveredMcpServerTypeSse DiscoveredMcpServerType = "sse"
+ DiscoveredMCPServerTypeSSE DiscoveredMCPServerType = "sse"
// Server communicates over stdio with a local child process.
- DiscoveredMcpServerTypeStdio DiscoveredMcpServerType = "stdio"
+ DiscoveredMCPServerTypeStdio DiscoveredMCPServerType = "stdio"
)
type EventLogTypesString string
@@ -7028,14 +7285,14 @@ const (
type HMACAuthInfoHost string
const (
- HMACAuthInfoHostHTTPSGithubCom HMACAuthInfoHost = "https://github.com"
+ HMACAuthInfoHostHTTPSGitHubCom HMACAuthInfoHost = "https://github.com"
)
// Constant value. Always "github".
-type InstalledPluginSourceGithubSource string
+type InstalledPluginSourceGitHubSource string
const (
- InstalledPluginSourceGithubSourceGithub InstalledPluginSourceGithubSource = "github"
+ InstalledPluginSourceGitHubSourceGitHub InstalledPluginSourceGitHubSource = "github"
)
// Constant value. Always "local".
@@ -7091,180 +7348,180 @@ const (
)
// Allowed values for the `McpAppsHostContextDetailsAvailableDisplayMode` enumeration.
-// Experimental: McpAppsHostContextDetailsAvailableDisplayMode is part of an experimental
+// Experimental: MCPAppsHostContextDetailsAvailableDisplayMode is part of an experimental
// API and may change or be removed.
-type McpAppsHostContextDetailsAvailableDisplayMode string
+type MCPAppsHostContextDetailsAvailableDisplayMode string
const (
// Rendered as a fullscreen overlay
- McpAppsHostContextDetailsAvailableDisplayModeFullscreen McpAppsHostContextDetailsAvailableDisplayMode = "fullscreen"
+ MCPAppsHostContextDetailsAvailableDisplayModeFullscreen MCPAppsHostContextDetailsAvailableDisplayMode = "fullscreen"
// Rendered inline within the host conversation surface
- McpAppsHostContextDetailsAvailableDisplayModeInline McpAppsHostContextDetailsAvailableDisplayMode = "inline"
+ MCPAppsHostContextDetailsAvailableDisplayModeInline MCPAppsHostContextDetailsAvailableDisplayMode = "inline"
// Rendered as a picture-in-picture floating panel
- McpAppsHostContextDetailsAvailableDisplayModePip McpAppsHostContextDetailsAvailableDisplayMode = "pip"
+ MCPAppsHostContextDetailsAvailableDisplayModePip MCPAppsHostContextDetailsAvailableDisplayMode = "pip"
)
// Current display mode (SEP-1865)
-// Experimental: McpAppsHostContextDetailsDisplayMode is part of an experimental API and may
+// Experimental: MCPAppsHostContextDetailsDisplayMode is part of an experimental API and may
// change or be removed.
-type McpAppsHostContextDetailsDisplayMode string
+type MCPAppsHostContextDetailsDisplayMode string
const (
// Rendered as a fullscreen overlay
- McpAppsHostContextDetailsDisplayModeFullscreen McpAppsHostContextDetailsDisplayMode = "fullscreen"
+ MCPAppsHostContextDetailsDisplayModeFullscreen MCPAppsHostContextDetailsDisplayMode = "fullscreen"
// Rendered inline within the host conversation surface
- McpAppsHostContextDetailsDisplayModeInline McpAppsHostContextDetailsDisplayMode = "inline"
+ MCPAppsHostContextDetailsDisplayModeInline MCPAppsHostContextDetailsDisplayMode = "inline"
// Rendered as a picture-in-picture floating panel
- McpAppsHostContextDetailsDisplayModePip McpAppsHostContextDetailsDisplayMode = "pip"
+ MCPAppsHostContextDetailsDisplayModePip MCPAppsHostContextDetailsDisplayMode = "pip"
)
// Platform type for responsive design
-// Experimental: McpAppsHostContextDetailsPlatform is part of an experimental API and may
+// Experimental: MCPAppsHostContextDetailsPlatform is part of an experimental API and may
// change or be removed.
-type McpAppsHostContextDetailsPlatform string
+type MCPAppsHostContextDetailsPlatform string
const (
// Host runs as a desktop application
- McpAppsHostContextDetailsPlatformDesktop McpAppsHostContextDetailsPlatform = "desktop"
+ MCPAppsHostContextDetailsPlatformDesktop MCPAppsHostContextDetailsPlatform = "desktop"
// Host runs on a mobile device
- McpAppsHostContextDetailsPlatformMobile McpAppsHostContextDetailsPlatform = "mobile"
+ MCPAppsHostContextDetailsPlatformMobile MCPAppsHostContextDetailsPlatform = "mobile"
// Host runs in a web browser
- McpAppsHostContextDetailsPlatformWeb McpAppsHostContextDetailsPlatform = "web"
+ MCPAppsHostContextDetailsPlatformWeb MCPAppsHostContextDetailsPlatform = "web"
)
// UI theme preference per SEP-1865
-// Experimental: McpAppsHostContextDetailsTheme is part of an experimental API and may
+// Experimental: MCPAppsHostContextDetailsTheme is part of an experimental API and may
// change or be removed.
-type McpAppsHostContextDetailsTheme string
+type MCPAppsHostContextDetailsTheme string
const (
// Dark UI theme
- McpAppsHostContextDetailsThemeDark McpAppsHostContextDetailsTheme = "dark"
+ MCPAppsHostContextDetailsThemeDark MCPAppsHostContextDetailsTheme = "dark"
// Light UI theme
- McpAppsHostContextDetailsThemeLight McpAppsHostContextDetailsTheme = "light"
+ MCPAppsHostContextDetailsThemeLight MCPAppsHostContextDetailsTheme = "light"
)
// Allowed values for the `McpAppsSetHostContextDetailsAvailableDisplayMode` enumeration.
-// Experimental: McpAppsSetHostContextDetailsAvailableDisplayMode is part of an experimental
+// Experimental: MCPAppsSetHostContextDetailsAvailableDisplayMode is part of an experimental
// API and may change or be removed.
-type McpAppsSetHostContextDetailsAvailableDisplayMode string
+type MCPAppsSetHostContextDetailsAvailableDisplayMode string
const (
// Rendered as a fullscreen overlay
- McpAppsSetHostContextDetailsAvailableDisplayModeFullscreen McpAppsSetHostContextDetailsAvailableDisplayMode = "fullscreen"
+ MCPAppsSetHostContextDetailsAvailableDisplayModeFullscreen MCPAppsSetHostContextDetailsAvailableDisplayMode = "fullscreen"
// Rendered inline within the host conversation surface
- McpAppsSetHostContextDetailsAvailableDisplayModeInline McpAppsSetHostContextDetailsAvailableDisplayMode = "inline"
+ MCPAppsSetHostContextDetailsAvailableDisplayModeInline MCPAppsSetHostContextDetailsAvailableDisplayMode = "inline"
// Rendered as a picture-in-picture floating panel
- McpAppsSetHostContextDetailsAvailableDisplayModePip McpAppsSetHostContextDetailsAvailableDisplayMode = "pip"
+ MCPAppsSetHostContextDetailsAvailableDisplayModePip MCPAppsSetHostContextDetailsAvailableDisplayMode = "pip"
)
// Current display mode (SEP-1865)
-// Experimental: McpAppsSetHostContextDetailsDisplayMode is part of an experimental API and
+// Experimental: MCPAppsSetHostContextDetailsDisplayMode is part of an experimental API and
// may change or be removed.
-type McpAppsSetHostContextDetailsDisplayMode string
+type MCPAppsSetHostContextDetailsDisplayMode string
const (
// Rendered as a fullscreen overlay
- McpAppsSetHostContextDetailsDisplayModeFullscreen McpAppsSetHostContextDetailsDisplayMode = "fullscreen"
+ MCPAppsSetHostContextDetailsDisplayModeFullscreen MCPAppsSetHostContextDetailsDisplayMode = "fullscreen"
// Rendered inline within the host conversation surface
- McpAppsSetHostContextDetailsDisplayModeInline McpAppsSetHostContextDetailsDisplayMode = "inline"
+ MCPAppsSetHostContextDetailsDisplayModeInline MCPAppsSetHostContextDetailsDisplayMode = "inline"
// Rendered as a picture-in-picture floating panel
- McpAppsSetHostContextDetailsDisplayModePip McpAppsSetHostContextDetailsDisplayMode = "pip"
+ MCPAppsSetHostContextDetailsDisplayModePip MCPAppsSetHostContextDetailsDisplayMode = "pip"
)
// Platform type for responsive design
-// Experimental: McpAppsSetHostContextDetailsPlatform is part of an experimental API and may
+// Experimental: MCPAppsSetHostContextDetailsPlatform is part of an experimental API and may
// change or be removed.
-type McpAppsSetHostContextDetailsPlatform string
+type MCPAppsSetHostContextDetailsPlatform string
const (
// Host runs as a desktop application
- McpAppsSetHostContextDetailsPlatformDesktop McpAppsSetHostContextDetailsPlatform = "desktop"
+ MCPAppsSetHostContextDetailsPlatformDesktop MCPAppsSetHostContextDetailsPlatform = "desktop"
// Host runs on a mobile device
- McpAppsSetHostContextDetailsPlatformMobile McpAppsSetHostContextDetailsPlatform = "mobile"
+ MCPAppsSetHostContextDetailsPlatformMobile MCPAppsSetHostContextDetailsPlatform = "mobile"
// Host runs in a web browser
- McpAppsSetHostContextDetailsPlatformWeb McpAppsSetHostContextDetailsPlatform = "web"
+ MCPAppsSetHostContextDetailsPlatformWeb MCPAppsSetHostContextDetailsPlatform = "web"
)
// UI theme preference per SEP-1865
-// Experimental: McpAppsSetHostContextDetailsTheme is part of an experimental API and may
+// Experimental: MCPAppsSetHostContextDetailsTheme is part of an experimental API and may
// change or be removed.
-type McpAppsSetHostContextDetailsTheme string
+type MCPAppsSetHostContextDetailsTheme string
const (
// Dark UI theme
- McpAppsSetHostContextDetailsThemeDark McpAppsSetHostContextDetailsTheme = "dark"
+ MCPAppsSetHostContextDetailsThemeDark MCPAppsSetHostContextDetailsTheme = "dark"
// Light UI theme
- McpAppsSetHostContextDetailsThemeLight McpAppsSetHostContextDetailsTheme = "light"
+ MCPAppsSetHostContextDetailsThemeLight MCPAppsSetHostContextDetailsTheme = "light"
)
// Outcome of the sampling inference. 'success' produced a response; 'failure' encountered
// an error (including agent-side rejection by content filter or criteria); 'cancelled' the
// caller cancelled this execution via cancelSamplingExecution.
-// Experimental: McpSamplingExecutionAction is part of an experimental API and may change or
+// Experimental: MCPSamplingExecutionAction is part of an experimental API and may change or
// be removed.
-type McpSamplingExecutionAction string
+type MCPSamplingExecutionAction string
const (
// The sampling inference was cancelled before completion.
- McpSamplingExecutionActionCancelled McpSamplingExecutionAction = "cancelled"
+ MCPSamplingExecutionActionCancelled MCPSamplingExecutionAction = "cancelled"
// The sampling inference failed or was rejected.
- McpSamplingExecutionActionFailure McpSamplingExecutionAction = "failure"
+ MCPSamplingExecutionActionFailure MCPSamplingExecutionAction = "failure"
// The sampling inference completed and produced a result.
- McpSamplingExecutionActionSuccess McpSamplingExecutionAction = "success"
+ MCPSamplingExecutionActionSuccess MCPSamplingExecutionAction = "success"
)
// OAuth grant type to use when authenticating to the remote MCP server.
-type McpServerConfigHTTPOauthGrantType string
+type MCPServerConfigHTTPOauthGrantType string
const (
// Interactive browser-based authorization code flow with PKCE.
- McpServerConfigHTTPOauthGrantTypeAuthorizationCode McpServerConfigHTTPOauthGrantType = "authorization_code"
+ MCPServerConfigHTTPOauthGrantTypeAuthorizationCode MCPServerConfigHTTPOauthGrantType = "authorization_code"
// Headless client credentials flow using the configured OAuth client.
- McpServerConfigHTTPOauthGrantTypeClientCredentials McpServerConfigHTTPOauthGrantType = "client_credentials"
+ MCPServerConfigHTTPOauthGrantTypeClientCredentials MCPServerConfigHTTPOauthGrantType = "client_credentials"
)
// Remote transport type. Defaults to "http" when omitted.
-type McpServerConfigHTTPType string
+type MCPServerConfigHTTPType string
const (
// Streamable HTTP transport.
- McpServerConfigHTTPTypeHTTP McpServerConfigHTTPType = "http"
+ MCPServerConfigHTTPTypeHTTP MCPServerConfigHTTPType = "http"
// Server-Sent Events transport.
- McpServerConfigHTTPTypeSse McpServerConfigHTTPType = "sse"
+ MCPServerConfigHTTPTypeSSE MCPServerConfigHTTPType = "sse"
)
// Configuration source: user, workspace, plugin, or builtin
-type McpServerSource string
+type MCPServerSource string
const (
// Server bundled with the runtime.
- McpServerSourceBuiltin McpServerSource = "builtin"
+ MCPServerSourceBuiltin MCPServerSource = "builtin"
// Server contributed by an installed plugin.
- McpServerSourcePlugin McpServerSource = "plugin"
+ MCPServerSourcePlugin MCPServerSource = "plugin"
// Server configured in the user's global MCP configuration.
- McpServerSourceUser McpServerSource = "user"
+ MCPServerSourceUser MCPServerSource = "user"
// Server configured by the current workspace.
- McpServerSourceWorkspace McpServerSource = "workspace"
+ MCPServerSourceWorkspace MCPServerSource = "workspace"
)
// Connection status: connected, failed, needs-auth, pending, disabled, or not_configured
-// Experimental: McpServerStatus is part of an experimental API and may change or be removed.
-type McpServerStatus string
+// Experimental: MCPServerStatus is part of an experimental API and may change or be removed.
+type MCPServerStatus string
const (
// The server is connected and available.
- McpServerStatusConnected McpServerStatus = "connected"
+ MCPServerStatusConnected MCPServerStatus = "connected"
// The server is configured but disabled.
- McpServerStatusDisabled McpServerStatus = "disabled"
+ MCPServerStatusDisabled MCPServerStatus = "disabled"
// The server failed to connect or initialize.
- McpServerStatusFailed McpServerStatus = "failed"
+ MCPServerStatusFailed MCPServerStatus = "failed"
// The server requires authentication before it can connect.
- McpServerStatusNeedsAuth McpServerStatus = "needs-auth"
+ MCPServerStatusNeedsAuth MCPServerStatus = "needs-auth"
// The server is not configured for this session.
- McpServerStatusNotConfigured McpServerStatus = "not_configured"
+ MCPServerStatusNotConfigured MCPServerStatus = "not_configured"
// The server connection is still being established.
- McpServerStatusPending McpServerStatus = "pending"
+ MCPServerStatusPending MCPServerStatus = "pending"
)
// How environment-variable values supplied to MCP servers are resolved. "direct" passes
@@ -7272,15 +7529,15 @@ const (
// variables on the host) that the runtime resolves before launch. Defaults to the runtime's
// startup mode; clients that intentionally launch MCP servers with literal values (e.g. CLI
// prompt mode and ACP) set this to "direct".
-// Experimental: McpSetEnvValueModeDetails is part of an experimental API and may change or
+// Experimental: MCPSetEnvValueModeDetails is part of an experimental API and may change or
// be removed.
-type McpSetEnvValueModeDetails string
+type MCPSetEnvValueModeDetails string
const (
// Treat MCP server environment values as literal strings.
- McpSetEnvValueModeDetailsDirect McpSetEnvValueModeDetails = "direct"
+ MCPSetEnvValueModeDetailsDirect MCPSetEnvValueModeDetails = "direct"
// Treat MCP server environment values as host-side references to resolve before launch.
- McpSetEnvValueModeDetailsIndirect McpSetEnvValueModeDetails = "indirect"
+ MCPSetEnvValueModeDetailsIndirect MCPSetEnvValueModeDetails = "indirect"
)
// The current agent mode for this session (e.g., 'interactive', 'plan', 'autopilot')
@@ -7307,7 +7564,7 @@ const (
// Remote task originated from Copilot Coding Agent.
MetadataSnapshotRemoteMetadataTaskTypeCca MetadataSnapshotRemoteMetadataTaskType = "cca"
// Remote task originated from a CLI remote-session invocation.
- MetadataSnapshotRemoteMetadataTaskTypeCli MetadataSnapshotRemoteMetadataTaskType = "cli"
+ MetadataSnapshotRemoteMetadataTaskTypeCLI MetadataSnapshotRemoteMetadataTaskType = "cli"
)
// Model capability category for grouping in the model picker
@@ -7348,15 +7605,6 @@ const (
ModelPolicyStateUnconfigured ModelPolicyState = "unconfigured"
)
-type ModelSwitchToRequestContextTier string
-
-const (
- // Use the model's default context window.
- ModelSwitchToRequestContextTierDefault ModelSwitchToRequestContextTier = "default"
- // Pin the session to the long-context tier when supported.
- ModelSwitchToRequestContextTierLongContext ModelSwitchToRequestContextTier = "long_context"
-)
-
// How env values are passed to MCP servers (`direct` inlines literal values; `indirect`
// resolves at launch).
// Experimental: OptionsUpdateEnvValueMode is part of an experimental API and may change or
@@ -7394,8 +7642,8 @@ const (
PermissionDecisionApproveForLocationApprovalKindCustomTool PermissionDecisionApproveForLocationApprovalKind = "custom-tool"
PermissionDecisionApproveForLocationApprovalKindExtensionManagement PermissionDecisionApproveForLocationApprovalKind = "extension-management"
PermissionDecisionApproveForLocationApprovalKindExtensionPermissionAccess PermissionDecisionApproveForLocationApprovalKind = "extension-permission-access"
- PermissionDecisionApproveForLocationApprovalKindMcp PermissionDecisionApproveForLocationApprovalKind = "mcp"
- PermissionDecisionApproveForLocationApprovalKindMcpSampling PermissionDecisionApproveForLocationApprovalKind = "mcp-sampling"
+ PermissionDecisionApproveForLocationApprovalKindMCP PermissionDecisionApproveForLocationApprovalKind = "mcp"
+ PermissionDecisionApproveForLocationApprovalKindMCPSampling PermissionDecisionApproveForLocationApprovalKind = "mcp-sampling"
PermissionDecisionApproveForLocationApprovalKindMemory PermissionDecisionApproveForLocationApprovalKind = "memory"
PermissionDecisionApproveForLocationApprovalKindRead PermissionDecisionApproveForLocationApprovalKind = "read"
PermissionDecisionApproveForLocationApprovalKindWrite PermissionDecisionApproveForLocationApprovalKind = "write"
@@ -7409,8 +7657,8 @@ const (
PermissionDecisionApproveForSessionApprovalKindCustomTool PermissionDecisionApproveForSessionApprovalKind = "custom-tool"
PermissionDecisionApproveForSessionApprovalKindExtensionManagement PermissionDecisionApproveForSessionApprovalKind = "extension-management"
PermissionDecisionApproveForSessionApprovalKindExtensionPermissionAccess PermissionDecisionApproveForSessionApprovalKind = "extension-permission-access"
- PermissionDecisionApproveForSessionApprovalKindMcp PermissionDecisionApproveForSessionApprovalKind = "mcp"
- PermissionDecisionApproveForSessionApprovalKindMcpSampling PermissionDecisionApproveForSessionApprovalKind = "mcp-sampling"
+ PermissionDecisionApproveForSessionApprovalKindMCP PermissionDecisionApproveForSessionApprovalKind = "mcp"
+ PermissionDecisionApproveForSessionApprovalKindMCPSampling PermissionDecisionApproveForSessionApprovalKind = "mcp-sampling"
PermissionDecisionApproveForSessionApprovalKindMemory PermissionDecisionApproveForSessionApprovalKind = "memory"
PermissionDecisionApproveForSessionApprovalKindRead PermissionDecisionApproveForSessionApprovalKind = "read"
PermissionDecisionApproveForSessionApprovalKindWrite PermissionDecisionApproveForSessionApprovalKind = "write"
@@ -7470,8 +7718,8 @@ const (
PermissionsLocationsAddToolApprovalDetailsKindCustomTool PermissionsLocationsAddToolApprovalDetailsKind = "custom-tool"
PermissionsLocationsAddToolApprovalDetailsKindExtensionManagement PermissionsLocationsAddToolApprovalDetailsKind = "extension-management"
PermissionsLocationsAddToolApprovalDetailsKindExtensionPermissionAccess PermissionsLocationsAddToolApprovalDetailsKind = "extension-permission-access"
- PermissionsLocationsAddToolApprovalDetailsKindMcp PermissionsLocationsAddToolApprovalDetailsKind = "mcp"
- PermissionsLocationsAddToolApprovalDetailsKindMcpSampling PermissionsLocationsAddToolApprovalDetailsKind = "mcp-sampling"
+ PermissionsLocationsAddToolApprovalDetailsKindMCP PermissionsLocationsAddToolApprovalDetailsKind = "mcp"
+ PermissionsLocationsAddToolApprovalDetailsKindMCPSampling PermissionsLocationsAddToolApprovalDetailsKind = "mcp-sampling"
PermissionsLocationsAddToolApprovalDetailsKindMemory PermissionsLocationsAddToolApprovalDetailsKind = "memory"
PermissionsLocationsAddToolApprovalDetailsKindRead PermissionsLocationsAddToolApprovalDetailsKind = "read"
PermissionsLocationsAddToolApprovalDetailsKindWrite PermissionsLocationsAddToolApprovalDetailsKind = "write"
@@ -7490,6 +7738,22 @@ const (
PermissionsModifyRulesScopeSession PermissionsModifyRulesScope = "session"
)
+// Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers.
+// Experimental: PermissionsSetAllowAllSource is part of an experimental API and may change
+// or be removed.
+type PermissionsSetAllowAllSource string
+
+const (
+ // Allow-all was enabled by confirming autopilot behavior.
+ PermissionsSetAllowAllSourceAutopilotConfirmation PermissionsSetAllowAllSource = "autopilot_confirmation"
+ // Allow-all was enabled from a CLI command-line flag.
+ PermissionsSetAllowAllSourceCLIFlag PermissionsSetAllowAllSource = "cli_flag"
+ // Allow-all was enabled through an RPC caller.
+ PermissionsSetAllowAllSourceRPC PermissionsSetAllowAllSource = "rpc"
+ // Allow-all was enabled by a slash command.
+ PermissionsSetAllowAllSourceSlashCommand PermissionsSetAllowAllSource = "slash_command"
+)
+
// Optional source for allow-all telemetry. Defaults to `rpc` when omitted for SDK callers.
// Experimental: PermissionsSetApproveAllSource is part of an experimental API and may
// change or be removed.
@@ -7499,13 +7763,39 @@ const (
// Allow-all was enabled by confirming autopilot behavior.
PermissionsSetApproveAllSourceAutopilotConfirmation PermissionsSetApproveAllSource = "autopilot_confirmation"
// Allow-all was enabled from a CLI command-line flag.
- PermissionsSetApproveAllSourceCliFlag PermissionsSetApproveAllSource = "cli_flag"
+ PermissionsSetApproveAllSourceCLIFlag PermissionsSetApproveAllSource = "cli_flag"
// Allow-all was enabled through an RPC caller.
PermissionsSetApproveAllSourceRPC PermissionsSetApproveAllSource = "rpc"
// Allow-all was enabled by a slash command.
PermissionsSetApproveAllSourceSlashCommand PermissionsSetApproveAllSource = "slash_command"
)
+// Type of GitHub reference
+// Experimental: PushAttachmentGitHubReferenceType is part of an experimental API and may
+// change or be removed.
+type PushAttachmentGitHubReferenceType string
+
+const (
+ // GitHub discussion reference.
+ PushAttachmentGitHubReferenceTypeDiscussion PushAttachmentGitHubReferenceType = "discussion"
+ // GitHub issue reference.
+ PushAttachmentGitHubReferenceTypeIssue PushAttachmentGitHubReferenceType = "issue"
+ // GitHub pull request reference.
+ PushAttachmentGitHubReferenceTypePr PushAttachmentGitHubReferenceType = "pr"
+)
+
+// Type discriminator for PushAttachment.
+type PushAttachmentType string
+
+const (
+ PushAttachmentTypeBlob PushAttachmentType = "blob"
+ PushAttachmentTypeDirectory PushAttachmentType = "directory"
+ PushAttachmentTypeExtensionContext PushAttachmentType = "extension_context"
+ PushAttachmentTypeFile PushAttachmentType = "file"
+ PushAttachmentTypeGitHubReference PushAttachmentType = "github_reference"
+ PushAttachmentTypeSelection PushAttachmentType = "selection"
+)
+
// Whether this item is a queued user message or a queued slash command / model change
// Experimental: QueuePendingItemsKind is part of an experimental API and may change or be
// removed.
@@ -7563,31 +7853,6 @@ const (
SendAgentModeShell SendAgentMode = "shell"
)
-// Type of GitHub reference
-// Experimental: SendAttachmentGithubReferenceType is part of an experimental API and may
-// change or be removed.
-type SendAttachmentGithubReferenceType string
-
-const (
- // GitHub discussion reference.
- SendAttachmentGithubReferenceTypeDiscussion SendAttachmentGithubReferenceType = "discussion"
- // GitHub issue reference.
- SendAttachmentGithubReferenceTypeIssue SendAttachmentGithubReferenceType = "issue"
- // GitHub pull request reference.
- SendAttachmentGithubReferenceTypePr SendAttachmentGithubReferenceType = "pr"
-)
-
-// Type discriminator for SendAttachment.
-type SendAttachmentType string
-
-const (
- SendAttachmentTypeBlob SendAttachmentType = "blob"
- SendAttachmentTypeDirectory SendAttachmentType = "directory"
- SendAttachmentTypeFile SendAttachmentType = "file"
- SendAttachmentTypeGithubReference SendAttachmentType = "github_reference"
- SendAttachmentTypeSelection SendAttachmentType = "selection"
-)
-
// How to deliver the message. `enqueue` (default) appends to the message queue. `immediate`
// interjects during an in-progress turn.
// Experimental: SendMode is part of an experimental API and may change or be removed.
@@ -7607,65 +7872,65 @@ type SessionContextHostType string
const (
// Session repository is hosted on Azure DevOps.
- SessionContextHostTypeAdo SessionContextHostType = "ado"
+ SessionContextHostTypeADO SessionContextHostType = "ado"
// Session repository is hosted on GitHub.
- SessionContextHostTypeGithub SessionContextHostType = "github"
+ SessionContextHostTypeGitHub SessionContextHostType = "github"
)
// Error classification
-// Experimental: SessionFsErrorCode is part of an experimental API and may change or be
+// Experimental: SessionFSErrorCode is part of an experimental API and may change or be
// removed.
-type SessionFsErrorCode string
+type SessionFSErrorCode string
const (
// The requested path does not exist.
- SessionFsErrorCodeENOENT SessionFsErrorCode = "ENOENT"
+ SessionFSErrorCodeENOENT SessionFSErrorCode = "ENOENT"
// The filesystem operation failed for an unspecified reason.
- SessionFsErrorCodeUNKNOWN SessionFsErrorCode = "UNKNOWN"
+ SessionFSErrorCodeUNKNOWN SessionFSErrorCode = "UNKNOWN"
)
// Entry type
-// Experimental: SessionFsReaddirWithTypesEntryType is part of an experimental API and may
+// Experimental: SessionFSReaddirWithTypesEntryType is part of an experimental API and may
// change or be removed.
-type SessionFsReaddirWithTypesEntryType string
+type SessionFSReaddirWithTypesEntryType string
const (
// The entry is a directory.
- SessionFsReaddirWithTypesEntryTypeDirectory SessionFsReaddirWithTypesEntryType = "directory"
+ SessionFSReaddirWithTypesEntryTypeDirectory SessionFSReaddirWithTypesEntryType = "directory"
// The entry is a file.
- SessionFsReaddirWithTypesEntryTypeFile SessionFsReaddirWithTypesEntryType = "file"
+ SessionFSReaddirWithTypesEntryTypeFile SessionFSReaddirWithTypesEntryType = "file"
)
// Path conventions used by this filesystem
-type SessionFsSetProviderConventions string
+type SessionFSSetProviderConventions string
const (
// Paths use POSIX path conventions.
- SessionFsSetProviderConventionsPosix SessionFsSetProviderConventions = "posix"
+ SessionFSSetProviderConventionsPosix SessionFSSetProviderConventions = "posix"
// Paths use Windows path conventions.
- SessionFsSetProviderConventionsWindows SessionFsSetProviderConventions = "windows"
+ SessionFSSetProviderConventionsWindows SessionFSSetProviderConventions = "windows"
)
// How to execute the query: 'exec' for DDL/multi-statement (no results), 'query' for SELECT
// (returns rows), 'run' for INSERT/UPDATE/DELETE (returns rowsAffected)
-// Experimental: SessionFsSqliteQueryType is part of an experimental API and may change or
+// Experimental: SessionFSSqliteQueryType is part of an experimental API and may change or
// be removed.
-type SessionFsSqliteQueryType string
+type SessionFSSqliteQueryType string
const (
// Execute DDL or multi-statement SQL without returning rows.
- SessionFsSqliteQueryTypeExec SessionFsSqliteQueryType = "exec"
+ SessionFSSqliteQueryTypeExec SessionFSSqliteQueryType = "exec"
// Execute a SELECT-style query and return rows.
- SessionFsSqliteQueryTypeQuery SessionFsSqliteQueryType = "query"
+ SessionFSSqliteQueryTypeQuery SessionFSSqliteQueryType = "query"
// Execute INSERT, UPDATE, or DELETE SQL and return affected-row metadata.
- SessionFsSqliteQueryTypeRun SessionFsSqliteQueryType = "run"
+ SessionFSSqliteQueryTypeRun SessionFSSqliteQueryType = "run"
)
// Constant value. Always "github".
-type SessionInstalledPluginSourceGithubSource string
+type SessionInstalledPluginSourceGitHubSource string
const (
- SessionInstalledPluginSourceGithubSourceGithub SessionInstalledPluginSourceGithubSource = "github"
+ SessionInstalledPluginSourceGitHubSourceGitHub SessionInstalledPluginSourceGitHubSource = "github"
)
// Constant value. Always "local".
@@ -7716,9 +7981,9 @@ type SessionWorkingDirectoryContextHostType string
const (
// The working directory repository is hosted on Azure DevOps.
- SessionWorkingDirectoryContextHostTypeAdo SessionWorkingDirectoryContextHostType = "ado"
+ SessionWorkingDirectoryContextHostTypeADO SessionWorkingDirectoryContextHostType = "ado"
// The working directory repository is hosted on GitHub.
- SessionWorkingDirectoryContextHostTypeGithub SessionWorkingDirectoryContextHostType = "github"
+ SessionWorkingDirectoryContextHostTypeGitHub SessionWorkingDirectoryContextHostType = "github"
)
// Signal to send (default: SIGTERM)
@@ -7965,7 +8230,7 @@ const (
UserToolSessionApprovalKindCustomTool UserToolSessionApprovalKind = "custom-tool"
UserToolSessionApprovalKindExtensionManagement UserToolSessionApprovalKind = "extension-management"
UserToolSessionApprovalKindExtensionPermissionAccess UserToolSessionApprovalKind = "extension-permission-access"
- UserToolSessionApprovalKindMcp UserToolSessionApprovalKind = "mcp"
+ UserToolSessionApprovalKindMCP UserToolSessionApprovalKind = "mcp"
UserToolSessionApprovalKindMemory UserToolSessionApprovalKind = "memory"
UserToolSessionApprovalKindRead UserToolSessionApprovalKind = "read"
UserToolSessionApprovalKindWrite UserToolSessionApprovalKind = "write"
@@ -8006,9 +8271,9 @@ type WorkspaceSummaryHostType string
const (
// Workspace summary repository is hosted on Azure DevOps.
- WorkspaceSummaryHostTypeAdo WorkspaceSummaryHostType = "ado"
+ WorkspaceSummaryHostTypeADO WorkspaceSummaryHostType = "ado"
// Workspace summary repository is hosted on GitHub.
- WorkspaceSummaryHostTypeGithub WorkspaceSummaryHostType = "github"
+ WorkspaceSummaryHostTypeGitHub WorkspaceSummaryHostType = "github"
)
// Allowed values for the `WorkspacesWorkspaceDetailsHostType` enumeration.
@@ -8018,16 +8283,16 @@ type WorkspacesWorkspaceDetailsHostType string
const (
// Workspace repository is hosted on Azure DevOps.
- WorkspacesWorkspaceDetailsHostTypeAdo WorkspacesWorkspaceDetailsHostType = "ado"
+ WorkspacesWorkspaceDetailsHostTypeADO WorkspacesWorkspaceDetailsHostType = "ado"
// Workspace repository is hosted on GitHub.
- WorkspacesWorkspaceDetailsHostTypeGithub WorkspacesWorkspaceDetailsHostType = "github"
+ WorkspacesWorkspaceDetailsHostTypeGitHub WorkspacesWorkspaceDetailsHostType = "github"
)
-type serverApi struct {
+type serverAPI struct {
client *jsonrpc2.Client
}
-type ServerAccountApi serverApi
+type ServerAccountAPI serverAPI
// GetQuota gets Copilot quota usage for the authenticated user or supplied GitHub token.
//
@@ -8037,7 +8302,7 @@ type ServerAccountApi serverApi
// the global auth context.
//
// Returns: Quota usage snapshots for the resolved user, keyed by quota type.
-func (a *ServerAccountApi) GetQuota(ctx context.Context, params *AccountGetQuotaRequest) (*AccountGetQuotaResult, error) {
+func (a *ServerAccountAPI) GetQuota(ctx context.Context, params *AccountGetQuotaRequest) (*AccountGetQuotaResult, error) {
raw, err := a.client.Request("account.getQuota", params)
if err != nil {
return nil, err
@@ -8049,9 +8314,9 @@ func (a *ServerAccountApi) GetQuota(ctx context.Context, params *AccountGetQuota
return &result, nil
}
-// Experimental: ServerAgentRegistryApi contains experimental APIs that may change or be
+// Experimental: ServerAgentRegistryAPI contains experimental APIs that may change or be
// removed.
-type ServerAgentRegistryApi serverApi
+type ServerAgentRegistryAPI serverAPI
// Spawns a managed-server child with the supplied configuration and returns a
// discriminated-union result. The caller (typically the CLI controller) is responsible for
@@ -8063,7 +8328,7 @@ type ServerAgentRegistryApi serverApi
// Parameters: Inputs to spawn a managed-server child via the controller's spawn delegate.
//
// Returns: Outcome of an agentRegistry.spawn call.
-func (a *ServerAgentRegistryApi) Spawn(ctx context.Context, params *AgentRegistrySpawnRequest) (AgentRegistrySpawnResult, error) {
+func (a *ServerAgentRegistryAPI) Spawn(ctx context.Context, params *AgentRegistrySpawnRequest) (AgentRegistrySpawnResult, error) {
raw, err := a.client.Request("agentRegistry.spawn", params)
if err != nil {
return nil, err
@@ -8075,7 +8340,7 @@ func (a *ServerAgentRegistryApi) Spawn(ctx context.Context, params *AgentRegistr
return result, nil
}
-type ServerMcpApi serverApi
+type ServerMCPAPI serverAPI
// Discovers MCP servers from user, workspace, plugin, and builtin sources.
//
@@ -8084,31 +8349,31 @@ type ServerMcpApi serverApi
// Parameters: Optional working directory used as context for MCP server discovery.
//
// Returns: MCP servers discovered from user, workspace, plugin, and built-in sources.
-func (a *ServerMcpApi) Discover(ctx context.Context, params *McpDiscoverRequest) (*McpDiscoverResult, error) {
+func (a *ServerMCPAPI) Discover(ctx context.Context, params *MCPDiscoverRequest) (*MCPDiscoverResult, error) {
raw, err := a.client.Request("mcp.discover", params)
if err != nil {
return nil, err
}
- var result McpDiscoverResult
+ var result MCPDiscoverResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
return &result, nil
}
-type ServerMcpConfigApi serverApi
+type ServerMCPConfigAPI serverAPI
// Adds an MCP server to user configuration.
//
// RPC method: mcp.config.add.
//
// Parameters: MCP server name and configuration to add to user configuration.
-func (a *ServerMcpConfigApi) Add(ctx context.Context, params *McpConfigAddRequest) (*McpConfigAddResult, error) {
+func (a *ServerMCPConfigAPI) Add(ctx context.Context, params *MCPConfigAddRequest) (*MCPConfigAddResult, error) {
raw, err := a.client.Request("mcp.config.add", params)
if err != nil {
return nil, err
}
- var result McpConfigAddResult
+ var result MCPConfigAddResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -8120,12 +8385,12 @@ func (a *ServerMcpConfigApi) Add(ctx context.Context, params *McpConfigAddReques
// RPC method: mcp.config.disable.
//
// Parameters: MCP server names to disable for new sessions.
-func (a *ServerMcpConfigApi) Disable(ctx context.Context, params *McpConfigDisableRequest) (*McpConfigDisableResult, error) {
+func (a *ServerMCPConfigAPI) Disable(ctx context.Context, params *MCPConfigDisableRequest) (*MCPConfigDisableResult, error) {
raw, err := a.client.Request("mcp.config.disable", params)
if err != nil {
return nil, err
}
- var result McpConfigDisableResult
+ var result MCPConfigDisableResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -8137,12 +8402,12 @@ func (a *ServerMcpConfigApi) Disable(ctx context.Context, params *McpConfigDisab
// RPC method: mcp.config.enable.
//
// Parameters: MCP server names to enable for new sessions.
-func (a *ServerMcpConfigApi) Enable(ctx context.Context, params *McpConfigEnableRequest) (*McpConfigEnableResult, error) {
+func (a *ServerMCPConfigAPI) Enable(ctx context.Context, params *MCPConfigEnableRequest) (*MCPConfigEnableResult, error) {
raw, err := a.client.Request("mcp.config.enable", params)
if err != nil {
return nil, err
}
- var result McpConfigEnableResult
+ var result MCPConfigEnableResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -8154,12 +8419,12 @@ func (a *ServerMcpConfigApi) Enable(ctx context.Context, params *McpConfigEnable
// RPC method: mcp.config.list.
//
// Returns: User-configured MCP servers, keyed by server name.
-func (a *ServerMcpConfigApi) List(ctx context.Context) (*McpConfigList, error) {
+func (a *ServerMCPConfigAPI) List(ctx context.Context) (*MCPConfigList, error) {
raw, err := a.client.Request("mcp.config.list", nil)
if err != nil {
return nil, err
}
- var result McpConfigList
+ var result MCPConfigList
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -8170,12 +8435,12 @@ func (a *ServerMcpConfigApi) List(ctx context.Context) (*McpConfigList, error) {
// config read observes disk.
//
// RPC method: mcp.config.reload.
-func (a *ServerMcpConfigApi) Reload(ctx context.Context) (*McpConfigReloadResult, error) {
+func (a *ServerMCPConfigAPI) Reload(ctx context.Context) (*MCPConfigReloadResult, error) {
raw, err := a.client.Request("mcp.config.reload", nil)
if err != nil {
return nil, err
}
- var result McpConfigReloadResult
+ var result MCPConfigReloadResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -8187,12 +8452,12 @@ func (a *ServerMcpConfigApi) Reload(ctx context.Context) (*McpConfigReloadResult
// RPC method: mcp.config.remove.
//
// Parameters: MCP server name to remove from user configuration.
-func (a *ServerMcpConfigApi) Remove(ctx context.Context, params *McpConfigRemoveRequest) (*McpConfigRemoveResult, error) {
+func (a *ServerMCPConfigAPI) Remove(ctx context.Context, params *MCPConfigRemoveRequest) (*MCPConfigRemoveResult, error) {
raw, err := a.client.Request("mcp.config.remove", params)
if err != nil {
return nil, err
}
- var result McpConfigRemoveResult
+ var result MCPConfigRemoveResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -8204,23 +8469,23 @@ func (a *ServerMcpConfigApi) Remove(ctx context.Context, params *McpConfigRemove
// RPC method: mcp.config.update.
//
// Parameters: MCP server name and replacement configuration to write to user configuration.
-func (a *ServerMcpConfigApi) Update(ctx context.Context, params *McpConfigUpdateRequest) (*McpConfigUpdateResult, error) {
+func (a *ServerMCPConfigAPI) Update(ctx context.Context, params *MCPConfigUpdateRequest) (*MCPConfigUpdateResult, error) {
raw, err := a.client.Request("mcp.config.update", params)
if err != nil {
return nil, err
}
- var result McpConfigUpdateResult
+ var result MCPConfigUpdateResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
return &result, nil
}
-func (s *ServerMcpApi) Config() *ServerMcpConfigApi {
- return (*ServerMcpConfigApi)(s)
+func (s *ServerMCPAPI) Config() *ServerMCPConfigAPI {
+ return (*ServerMCPConfigAPI)(s)
}
-type ServerModelsApi serverApi
+type ServerModelsAPI serverAPI
// Lists Copilot models available to the authenticated user.
//
@@ -8231,7 +8496,7 @@ type ServerModelsApi serverApi
//
// Returns: List of Copilot models available to the resolved user, including capabilities
// and billing metadata.
-func (a *ServerModelsApi) List(ctx context.Context, params *ModelsListRequest) (*ModelList, error) {
+func (a *ServerModelsAPI) List(ctx context.Context, params *ModelsListRequest) (*ModelList, error) {
raw, err := a.client.Request("models.list", params)
if err != nil {
return nil, err
@@ -8243,7 +8508,25 @@ func (a *ServerModelsApi) List(ctx context.Context, params *ModelsListRequest) (
return &result, nil
}
-type ServerSecretsApi serverApi
+type ServerRuntimeAPI serverAPI
+
+// Shutdown gracefully shuts down an SDK-owned runtime. The response is sent only after
+// cleanup completes; callers may then terminate the owned runtime process.
+//
+// RPC method: runtime.shutdown.
+func (a *ServerRuntimeAPI) Shutdown(ctx context.Context) (*RuntimeShutdownResult, error) {
+ raw, err := a.client.Request("runtime.shutdown", nil)
+ if err != nil {
+ return nil, err
+ }
+ var result RuntimeShutdownResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+type ServerSecretsAPI serverAPI
// AddFilterValues registers secret values for redaction in session logs and exports. The
// SDK calls this to inject dynamically generated secret values (e.g., OIDC tokens).
@@ -8253,7 +8536,7 @@ type ServerSecretsApi serverApi
// Parameters: Secret values to add to the redaction filter.
//
// Returns: Confirmation that the secret values were registered.
-func (a *ServerSecretsApi) AddFilterValues(ctx context.Context, params *SecretsAddFilterValuesRequest) (*SecretsAddFilterValuesResult, error) {
+func (a *ServerSecretsAPI) AddFilterValues(ctx context.Context, params *SecretsAddFilterValuesRequest) (*SecretsAddFilterValuesResult, error) {
raw, err := a.client.Request("secrets.addFilterValues", params)
if err != nil {
return nil, err
@@ -8265,7 +8548,7 @@ func (a *ServerSecretsApi) AddFilterValues(ctx context.Context, params *SecretsA
return &result, nil
}
-type ServerSessionFsApi serverApi
+type ServerSessionFSAPI serverAPI
// SetProvider registers an SDK client as the session filesystem provider.
//
@@ -8276,20 +8559,20 @@ type ServerSessionFsApi serverApi
//
// Returns: Indicates whether the calling client was registered as the session filesystem
// provider.
-func (a *ServerSessionFsApi) SetProvider(ctx context.Context, params *SessionFsSetProviderRequest) (*SessionFsSetProviderResult, error) {
+func (a *ServerSessionFSAPI) SetProvider(ctx context.Context, params *SessionFSSetProviderRequest) (*SessionFSSetProviderResult, error) {
raw, err := a.client.Request("sessionFs.setProvider", params)
if err != nil {
return nil, err
}
- var result SessionFsSetProviderResult
+ var result SessionFSSetProviderResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
return &result, nil
}
-// Experimental: ServerSessionsApi contains experimental APIs that may change or be removed.
-type ServerSessionsApi serverApi
+// Experimental: ServerSessionsAPI contains experimental APIs that may change or be removed.
+type ServerSessionsAPI serverAPI
// BulkDelete closes, deactivates, and deletes a set of sessions, returning the bytes freed
// per session.
@@ -8299,7 +8582,7 @@ type ServerSessionsApi serverApi
// Parameters: Session IDs to close, deactivate, and delete from disk.
//
// Returns: Map of sessionId -> bytes freed by removing the session's workspace directory.
-func (a *ServerSessionsApi) BulkDelete(ctx context.Context, params *SessionsBulkDeleteRequest) (*SessionBulkDeleteResult, error) {
+func (a *ServerSessionsAPI) BulkDelete(ctx context.Context, params *SessionsBulkDeleteRequest) (*SessionBulkDeleteResult, error) {
raw, err := a.client.Request("sessions.bulkDelete", params)
if err != nil {
return nil, err
@@ -8319,7 +8602,7 @@ func (a *ServerSessionsApi) BulkDelete(ctx context.Context, params *SessionsBulk
// Parameters: Session IDs to test for live in-use locks.
//
// Returns: Session IDs from the input set that are currently in use by another process.
-func (a *ServerSessionsApi) CheckInUse(ctx context.Context, params *SessionsCheckInUseRequest) (*SessionsCheckInUseResult, error) {
+func (a *ServerSessionsAPI) CheckInUse(ctx context.Context, params *SessionsCheckInUseRequest) (*SessionsCheckInUseResult, error) {
raw, err := a.client.Request("sessions.checkInUse", params)
if err != nil {
return nil, err
@@ -8341,7 +8624,7 @@ func (a *ServerSessionsApi) CheckInUse(ctx context.Context, params *SessionsChec
// Returns: Closes a session: emits shutdown, flushes pending events to disk, releases the
// in-use lock, disposes the active session. Idempotent: succeeds even if the session is not
// currently active.
-func (a *ServerSessionsApi) Close(ctx context.Context, params *SessionsCloseRequest) (*SessionsCloseResult, error) {
+func (a *ServerSessionsAPI) Close(ctx context.Context, params *SessionsCloseRequest) (*SessionsCloseResult, error) {
raw, err := a.client.Request("sessions.close", params)
if err != nil {
return nil, err
@@ -8360,7 +8643,7 @@ func (a *ServerSessionsApi) Close(ctx context.Context, params *SessionsCloseRequ
// Parameters: Remote session connection parameters.
//
// Returns: Remote session connection result.
-func (a *ServerSessionsApi) Connect(ctx context.Context, params *ConnectRemoteSessionParams) (*RemoteSessionConnectionResult, error) {
+func (a *ServerSessionsAPI) Connect(ctx context.Context, params *ConnectRemoteSessionParams) (*RemoteSessionConnectionResult, error) {
raw, err := a.client.Request("sessions.connect", params)
if err != nil {
return nil, err
@@ -8381,7 +8664,7 @@ func (a *ServerSessionsApi) Connect(ctx context.Context, params *ConnectRemoteSe
//
// Returns: The enriched metadata records, with summary and context fields backfilled where
// available. Sessions confirmed empty and unnamed are omitted.
-func (a *ServerSessionsApi) EnrichMetadata(ctx context.Context, params *SessionsEnrichMetadataRequest) (*SessionEnrichMetadataResult, error) {
+func (a *ServerSessionsAPI) EnrichMetadata(ctx context.Context, params *SessionsEnrichMetadataRequest) (*SessionEnrichMetadataResult, error) {
raw, err := a.client.Request("sessions.enrichMetadata", params)
if err != nil {
return nil, err
@@ -8401,7 +8684,7 @@ func (a *ServerSessionsApi) EnrichMetadata(ctx context.Context, params *Sessions
// Parameters: UUID prefix to resolve to a unique session ID.
//
// Returns: Session ID matching the prefix, omitted when no unique match exists.
-func (a *ServerSessionsApi) FindByPrefix(ctx context.Context, params *SessionsFindByPrefixRequest) (*SessionsFindByPrefixResult, error) {
+func (a *ServerSessionsAPI) FindByPrefix(ctx context.Context, params *SessionsFindByPrefixRequest) (*SessionsFindByPrefixResult, error) {
raw, err := a.client.Request("sessions.findByPrefix", params)
if err != nil {
return nil, err
@@ -8420,7 +8703,7 @@ func (a *ServerSessionsApi) FindByPrefix(ctx context.Context, params *SessionsFi
// Parameters: GitHub task ID to look up.
//
// Returns: ID of the local session bound to the given GitHub task, or omitted when none.
-func (a *ServerSessionsApi) FindByTaskId(ctx context.Context, params *SessionsFindByTaskIDRequest) (*SessionsFindByTaskIDResult, error) {
+func (a *ServerSessionsAPI) FindByTaskId(ctx context.Context, params *SessionsFindByTaskIDRequest) (*SessionsFindByTaskIDResult, error) {
raw, err := a.client.Request("sessions.findByTaskId", params)
if err != nil {
return nil, err
@@ -8440,7 +8723,7 @@ func (a *ServerSessionsApi) FindByTaskId(ctx context.Context, params *SessionsFi
// optional friendly name for the new session.
//
// Returns: Identifier and optional friendly name assigned to the newly forked session.
-func (a *ServerSessionsApi) Fork(ctx context.Context, params *SessionsForkRequest) (*SessionsForkResult, error) {
+func (a *ServerSessionsAPI) Fork(ctx context.Context, params *SessionsForkRequest) (*SessionsForkResult, error) {
raw, err := a.client.Request("sessions.fork", params)
if err != nil {
return nil, err
@@ -8459,7 +8742,7 @@ func (a *ServerSessionsApi) Fork(ctx context.Context, params *SessionsForkReques
// Parameters: Session ID whose event-log file path to compute.
//
// Returns: Absolute path to the session's events.jsonl file on disk.
-func (a *ServerSessionsApi) GetEventFilePath(ctx context.Context, params *SessionsGetEventFilePathRequest) (*SessionsGetEventFilePathResult, error) {
+func (a *ServerSessionsAPI) GetEventFilePath(ctx context.Context, params *SessionsGetEventFilePathRequest) (*SessionsGetEventFilePathResult, error) {
raw, err := a.client.Request("sessions.getEventFilePath", params)
if err != nil {
return nil, err
@@ -8480,7 +8763,7 @@ func (a *ServerSessionsApi) GetEventFilePath(ctx context.Context, params *Sessio
//
// Returns: Most-relevant session ID for the supplied context, or omitted when no sessions
// exist.
-func (a *ServerSessionsApi) GetLastForContext(ctx context.Context, params *SessionsGetLastForContextRequest) (*SessionsGetLastForContextResult, error) {
+func (a *ServerSessionsAPI) GetLastForContext(ctx context.Context, params *SessionsGetLastForContextRequest) (*SessionsGetLastForContextResult, error) {
raw, err := a.client.Request("sessions.getLastForContext", params)
if err != nil {
return nil, err
@@ -8501,7 +8784,7 @@ func (a *ServerSessionsApi) GetLastForContext(ctx context.Context, params *Sessi
//
// Returns: The session's persisted remote-steerable flag, or omitted when no value has been
// persisted.
-func (a *ServerSessionsApi) GetPersistedRemoteSteerable(ctx context.Context, params *SessionsGetPersistedRemoteSteerableRequest) (*SessionsGetPersistedRemoteSteerableResult, error) {
+func (a *ServerSessionsAPI) GetPersistedRemoteSteerable(ctx context.Context, params *SessionsGetPersistedRemoteSteerableRequest) (*SessionsGetPersistedRemoteSteerableResult, error) {
raw, err := a.client.Request("sessions.getPersistedRemoteSteerable", params)
if err != nil {
return nil, err
@@ -8518,7 +8801,7 @@ func (a *ServerSessionsApi) GetPersistedRemoteSteerable(ctx context.Context, par
// RPC method: sessions.getSizes.
//
// Returns: Map of sessionId -> on-disk size in bytes for each session's workspace directory.
-func (a *ServerSessionsApi) GetSizes(ctx context.Context) (*SessionSizes, error) {
+func (a *ServerSessionsAPI) GetSizes(ctx context.Context) (*SessionSizes, error) {
raw, err := a.client.Request("sessions.getSizes", nil)
if err != nil {
return nil, err
@@ -8537,7 +8820,7 @@ func (a *ServerSessionsApi) GetSizes(ctx context.Context) (*SessionSizes, error)
// Parameters: Optional metadata-load limit and filters applied to the returned sessions.
//
// Returns: Persisted sessions matching the filter, ordered most-recently-modified first.
-func (a *ServerSessionsApi) List(ctx context.Context, params *SessionsListRequest) (*SessionList, error) {
+func (a *ServerSessionsAPI) List(ctx context.Context, params *SessionsListRequest) (*SessionList, error) {
raw, err := a.client.Request("sessions.list", params)
if err != nil {
return nil, err
@@ -8557,7 +8840,7 @@ func (a *ServerSessionsApi) List(ctx context.Context, params *SessionsListReques
// Parameters: Active session ID whose deferred repo-level hooks should be loaded.
//
// Returns: Queued repo-level startup prompts and the total hook command count after loading.
-func (a *ServerSessionsApi) LoadDeferredRepoHooks(ctx context.Context, params *SessionsLoadDeferredRepoHooksRequest) (*SessionLoadDeferredRepoHooksResult, error) {
+func (a *ServerSessionsAPI) LoadDeferredRepoHooks(ctx context.Context, params *SessionsLoadDeferredRepoHooksRequest) (*SessionLoadDeferredRepoHooksResult, error) {
raw, err := a.client.Request("sessions.loadDeferredRepoHooks", params)
if err != nil {
return nil, err
@@ -8579,7 +8862,7 @@ func (a *ServerSessionsApi) LoadDeferredRepoHooks(ctx context.Context, params *S
//
// Returns: Outcome of the prune operation: deleted IDs, dry-run candidates, skipped IDs,
// total bytes freed, and the dry-run flag.
-func (a *ServerSessionsApi) PruneOld(ctx context.Context, params *SessionsPruneOldRequest) (*SessionPruneResult, error) {
+func (a *ServerSessionsAPI) PruneOld(ctx context.Context, params *SessionsPruneOldRequest) (*SessionPruneResult, error) {
raw, err := a.client.Request("sessions.pruneOld", params)
if err != nil {
return nil, err
@@ -8599,7 +8882,7 @@ func (a *ServerSessionsApi) PruneOld(ctx context.Context, params *SessionsPruneO
//
// Returns: Release the in-use lock held by this process for the given session. No-op when
// this process does not currently hold a lock for the session.
-func (a *ServerSessionsApi) ReleaseLock(ctx context.Context, params *SessionsReleaseLockRequest) (*SessionsReleaseLockResult, error) {
+func (a *ServerSessionsAPI) ReleaseLock(ctx context.Context, params *SessionsReleaseLockRequest) (*SessionsReleaseLockResult, error) {
raw, err := a.client.Request("sessions.releaseLock", params)
if err != nil {
return nil, err
@@ -8621,7 +8904,7 @@ func (a *ServerSessionsApi) ReleaseLock(ctx context.Context, params *SessionsRel
// Returns: Reload all hooks (user, plugin, optionally repo) and apply them to the active
// session. Call after installing or removing plugins so their hooks take effect
// immediately. No-op when no active session matches the given sessionId.
-func (a *ServerSessionsApi) ReloadPluginHooks(ctx context.Context, params *SessionsReloadPluginHooksRequest) (*SessionsReloadPluginHooksResult, error) {
+func (a *ServerSessionsAPI) ReloadPluginHooks(ctx context.Context, params *SessionsReloadPluginHooksRequest) (*SessionsReloadPluginHooksResult, error) {
raw, err := a.client.Request("sessions.reloadPluginHooks", params)
if err != nil {
return nil, err
@@ -8641,7 +8924,7 @@ func (a *ServerSessionsApi) ReloadPluginHooks(ctx context.Context, params *Sessi
//
// Returns: Flush a session's pending events to disk. No-op when no writer exists for the
// session (e.g., already closed).
-func (a *ServerSessionsApi) Save(ctx context.Context, params *SessionsSaveRequest) (*SessionsSaveResult, error) {
+func (a *ServerSessionsAPI) Save(ctx context.Context, params *SessionsSaveRequest) (*SessionsSaveResult, error) {
raw, err := a.client.Request("sessions.save", params)
if err != nil {
return nil, err
@@ -8664,7 +8947,7 @@ func (a *ServerSessionsApi) Save(ctx context.Context, params *SessionsSaveReques
// Returns: Replace the manager-wide additional plugins. New session creations and
// subsequent hook reloads see the new set; already-running sessions keep their existing
// hook installation until the next reload.
-func (a *ServerSessionsApi) SetAdditionalPlugins(ctx context.Context, params *SessionsSetAdditionalPluginsRequest) (*SessionsSetAdditionalPluginsResult, error) {
+func (a *ServerSessionsAPI) SetAdditionalPlugins(ctx context.Context, params *SessionsSetAdditionalPluginsRequest) (*SessionsSetAdditionalPluginsResult, error) {
raw, err := a.client.Request("sessions.setAdditionalPlugins", params)
if err != nil {
return nil, err
@@ -8676,7 +8959,7 @@ func (a *ServerSessionsApi) SetAdditionalPlugins(ctx context.Context, params *Se
return &result, nil
}
-type ServerSkillsApi serverApi
+type ServerSkillsAPI serverAPI
// Discovers skills across global and project sources.
//
@@ -8686,7 +8969,7 @@ type ServerSkillsApi serverApi
// discovery.
//
// Returns: Skills discovered across global and project sources.
-func (a *ServerSkillsApi) Discover(ctx context.Context, params *SkillsDiscoverRequest) (*ServerSkillList, error) {
+func (a *ServerSkillsAPI) Discover(ctx context.Context, params *SkillsDiscoverRequest) (*ServerSkillList, error) {
raw, err := a.client.Request("skills.discover", params)
if err != nil {
return nil, err
@@ -8698,7 +8981,7 @@ func (a *ServerSkillsApi) Discover(ctx context.Context, params *SkillsDiscoverRe
return &result, nil
}
-type ServerSkillsConfigApi serverApi
+type ServerSkillsConfigAPI serverAPI
// SetDisabledSkills replaces the global list of disabled skills.
//
@@ -8706,7 +8989,7 @@ type ServerSkillsConfigApi serverApi
//
// Parameters: Skill names to mark as disabled in global configuration, replacing any
// previous list.
-func (a *ServerSkillsConfigApi) SetDisabledSkills(ctx context.Context, params *SkillsConfigSetDisabledSkillsRequest) (*SkillsConfigSetDisabledSkillsResult, error) {
+func (a *ServerSkillsConfigAPI) SetDisabledSkills(ctx context.Context, params *SkillsConfigSetDisabledSkillsRequest) (*SkillsConfigSetDisabledSkillsResult, error) {
raw, err := a.client.Request("skills.config.setDisabledSkills", params)
if err != nil {
return nil, err
@@ -8718,11 +9001,11 @@ func (a *ServerSkillsConfigApi) SetDisabledSkills(ctx context.Context, params *S
return &result, nil
}
-func (s *ServerSkillsApi) Config() *ServerSkillsConfigApi {
- return (*ServerSkillsConfigApi)(s)
+func (s *ServerSkillsAPI) Config() *ServerSkillsConfigAPI {
+ return (*ServerSkillsConfigAPI)(s)
}
-type ServerToolsApi serverApi
+type ServerToolsAPI serverAPI
// Lists built-in tools available for a model.
//
@@ -8733,7 +9016,7 @@ type ServerToolsApi serverApi
//
// Returns: Built-in tools available for the requested model, with their parameters and
// instructions.
-func (a *ServerToolsApi) List(ctx context.Context, params *ToolsListRequest) (*ToolList, error) {
+func (a *ServerToolsAPI) List(ctx context.Context, params *ToolsListRequest) (*ToolList, error) {
raw, err := a.client.Request("tools.list", params)
if err != nil {
return nil, err
@@ -8745,15 +9028,15 @@ func (a *ServerToolsApi) List(ctx context.Context, params *ToolsListRequest) (*T
return &result, nil
}
-type ServerUserApi serverApi
+type ServerUserAPI serverAPI
-type ServerUserSettingsApi serverApi
+type ServerUserSettingsAPI serverAPI
// Reload drops this runtime process's in-memory user settings cache so the next settings
// read observes disk.
//
// RPC method: user.settings.reload.
-func (a *ServerUserSettingsApi) Reload(ctx context.Context) (*UserSettingsReloadResult, error) {
+func (a *ServerUserSettingsAPI) Reload(ctx context.Context) (*UserSettingsReloadResult, error) {
raw, err := a.client.Request("user.settings.reload", nil)
if err != nil {
return nil, err
@@ -8765,25 +9048,26 @@ func (a *ServerUserSettingsApi) Reload(ctx context.Context) (*UserSettingsReload
return &result, nil
}
-func (s *ServerUserApi) Settings() *ServerUserSettingsApi {
- return (*ServerUserSettingsApi)(s)
+func (s *ServerUserAPI) Settings() *ServerUserSettingsAPI {
+ return (*ServerUserSettingsAPI)(s)
}
-// ServerRpc provides typed server-scoped RPC methods.
-type ServerRpc struct {
+// ServerRPC provides typed server-scoped RPC methods.
+type ServerRPC struct {
// Reuse a single struct instead of allocating one for each service on the heap.
- common serverApi
+ common serverAPI
- Account *ServerAccountApi
- AgentRegistry *ServerAgentRegistryApi
- Mcp *ServerMcpApi
- Models *ServerModelsApi
- Secrets *ServerSecretsApi
- SessionFs *ServerSessionFsApi
- Sessions *ServerSessionsApi
- Skills *ServerSkillsApi
- Tools *ServerToolsApi
- User *ServerUserApi
+ Account *ServerAccountAPI
+ AgentRegistry *ServerAgentRegistryAPI
+ MCP *ServerMCPAPI
+ Models *ServerModelsAPI
+ Runtime *ServerRuntimeAPI
+ Secrets *ServerSecretsAPI
+ SessionFS *ServerSessionFSAPI
+ Sessions *ServerSessionsAPI
+ Skills *ServerSkillsAPI
+ Tools *ServerToolsAPI
+ User *ServerUserAPI
}
// Ping checks server responsiveness and returns protocol information.
@@ -8794,7 +9078,7 @@ type ServerRpc struct {
//
// Returns: Server liveness response, including the echoed message, current server
// timestamp, and protocol version.
-func (a *ServerRpc) Ping(ctx context.Context, params *PingRequest) (*PingResult, error) {
+func (a *ServerRPC) Ping(ctx context.Context, params *PingRequest) (*PingResult, error) {
raw, err := a.common.client.Request("ping", params)
if err != nil {
return nil, err
@@ -8806,31 +9090,32 @@ func (a *ServerRpc) Ping(ctx context.Context, params *PingRequest) (*PingResult,
return &result, nil
}
-func NewServerRpc(client *jsonrpc2.Client) *ServerRpc {
- r := &ServerRpc{}
- r.common = serverApi{client: client}
- r.Account = (*ServerAccountApi)(&r.common)
- r.AgentRegistry = (*ServerAgentRegistryApi)(&r.common)
- r.Mcp = (*ServerMcpApi)(&r.common)
- r.Models = (*ServerModelsApi)(&r.common)
- r.Secrets = (*ServerSecretsApi)(&r.common)
- r.SessionFs = (*ServerSessionFsApi)(&r.common)
- r.Sessions = (*ServerSessionsApi)(&r.common)
- r.Skills = (*ServerSkillsApi)(&r.common)
- r.Tools = (*ServerToolsApi)(&r.common)
- r.User = (*ServerUserApi)(&r.common)
+func NewServerRPC(client *jsonrpc2.Client) *ServerRPC {
+ r := &ServerRPC{}
+ r.common = serverAPI{client: client}
+ r.Account = (*ServerAccountAPI)(&r.common)
+ r.AgentRegistry = (*ServerAgentRegistryAPI)(&r.common)
+ r.MCP = (*ServerMCPAPI)(&r.common)
+ r.Models = (*ServerModelsAPI)(&r.common)
+ r.Runtime = (*ServerRuntimeAPI)(&r.common)
+ r.Secrets = (*ServerSecretsAPI)(&r.common)
+ r.SessionFS = (*ServerSessionFSAPI)(&r.common)
+ r.Sessions = (*ServerSessionsAPI)(&r.common)
+ r.Skills = (*ServerSkillsAPI)(&r.common)
+ r.Tools = (*ServerToolsAPI)(&r.common)
+ r.User = (*ServerUserAPI)(&r.common)
return r
}
-type internalServerApi struct {
+type internalServerAPI struct {
client *jsonrpc2.Client
}
-// InternalServerRpc provides internal SDK server-scoped RPC methods (handshake helpers
+// InternalServerRPC provides internal SDK server-scoped RPC methods (handshake helpers
// etc.). Not part of the public API.
-type InternalServerRpc struct {
+type InternalServerRPC struct {
// Reuse a single struct instead of allocating one for each service on the heap.
- common internalServerApi
+ common internalServerAPI
}
// Connect performs the SDK server connection handshake and validates the optional
@@ -8844,7 +9129,7 @@ type InternalServerRpc struct {
// success.
// Internal: Connect is part of the SDK's internal handshake/plumbing; external callers
// should not use it.
-func (a *InternalServerRpc) Connect(ctx context.Context, params *ConnectRequest) (*ConnectResult, error) {
+func (a *InternalServerRPC) Connect(ctx context.Context, params *ConnectRequest) (*ConnectResult, error) {
raw, err := a.common.client.Request("connect", params)
if err != nil {
return nil, err
@@ -8856,24 +9141,24 @@ func (a *InternalServerRpc) Connect(ctx context.Context, params *ConnectRequest)
return &result, nil
}
-func NewInternalServerRpc(client *jsonrpc2.Client) *InternalServerRpc {
- r := &InternalServerRpc{}
- r.common = internalServerApi{client: client}
+func NewInternalServerRPC(client *jsonrpc2.Client) *InternalServerRPC {
+ r := &InternalServerRPC{}
+ r.common = internalServerAPI{client: client}
return r
}
-type sessionApi struct {
+type sessionAPI struct {
client *jsonrpc2.Client
sessionID string
}
-// Experimental: AgentApi contains experimental APIs that may change or be removed.
-type AgentApi sessionApi
+// Experimental: AgentAPI contains experimental APIs that may change or be removed.
+type AgentAPI sessionAPI
// Deselect clears the selected custom agent and returns the session to the default agent.
//
// RPC method: session.agent.deselect.
-func (a *AgentApi) Deselect(ctx context.Context) (*SessionAgentDeselectResult, error) {
+func (a *AgentAPI) Deselect(ctx context.Context) (*SessionAgentDeselectResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.agent.deselect", req)
if err != nil {
@@ -8891,7 +9176,7 @@ func (a *AgentApi) Deselect(ctx context.Context) (*SessionAgentDeselectResult, e
// RPC method: session.agent.getCurrent.
//
// Returns: The currently selected custom agent, or null when using the default agent.
-func (a *AgentApi) GetCurrent(ctx context.Context) (*AgentGetCurrentResult, error) {
+func (a *AgentAPI) GetCurrent(ctx context.Context) (*AgentGetCurrentResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.agent.getCurrent", req)
if err != nil {
@@ -8909,7 +9194,7 @@ func (a *AgentApi) GetCurrent(ctx context.Context) (*AgentGetCurrentResult, erro
// RPC method: session.agent.list.
//
// Returns: Custom agents available to the session.
-func (a *AgentApi) List(ctx context.Context) (*AgentList, error) {
+func (a *AgentAPI) List(ctx context.Context) (*AgentList, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.agent.list", req)
if err != nil {
@@ -8927,7 +9212,7 @@ func (a *AgentApi) List(ctx context.Context) (*AgentList, error) {
// RPC method: session.agent.reload.
//
// Returns: Custom agents available to the session after reloading definitions from disk.
-func (a *AgentApi) Reload(ctx context.Context) (*AgentReloadResult, error) {
+func (a *AgentAPI) Reload(ctx context.Context) (*AgentReloadResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.agent.reload", req)
if err != nil {
@@ -8947,7 +9232,7 @@ func (a *AgentApi) Reload(ctx context.Context) (*AgentReloadResult, error) {
// Parameters: Name of the custom agent to select for subsequent turns.
//
// Returns: The newly selected custom agent.
-func (a *AgentApi) Select(ctx context.Context, params *AgentSelectRequest) (*AgentSelectResult, error) {
+func (a *AgentAPI) Select(ctx context.Context, params *AgentSelectRequest) (*AgentSelectResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["name"] = params.Name
@@ -8963,15 +9248,15 @@ func (a *AgentApi) Select(ctx context.Context, params *AgentSelectRequest) (*Age
return &result, nil
}
-// Experimental: AuthApi contains experimental APIs that may change or be removed.
-type AuthApi sessionApi
+// Experimental: AuthAPI contains experimental APIs that may change or be removed.
+type AuthAPI sessionAPI
// GetStatus gets authentication status and account metadata for the session.
//
// RPC method: session.auth.getStatus.
//
// Returns: Authentication status and account metadata for the session.
-func (a *AuthApi) GetStatus(ctx context.Context) (*SessionAuthStatus, error) {
+func (a *AuthAPI) GetStatus(ctx context.Context) (*SessionAuthStatus, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.auth.getStatus", req)
if err != nil {
@@ -8993,7 +9278,7 @@ func (a *AuthApi) GetStatus(ctx context.Context) (*SessionAuthStatus, error) {
// unchanged.
//
// Returns: Indicates whether the credential update succeeded.
-func (a *AuthApi) SetCredentials(ctx context.Context, params *SessionSetCredentialsParams) (*SessionSetCredentialsResult, error) {
+func (a *AuthAPI) SetCredentials(ctx context.Context, params *SessionSetCredentialsParams) (*SessionSetCredentialsResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
if params.Credentials != nil {
@@ -9011,15 +9296,15 @@ func (a *AuthApi) SetCredentials(ctx context.Context, params *SessionSetCredenti
return &result, nil
}
-// Experimental: CanvasApi contains experimental APIs that may change or be removed.
-type CanvasApi sessionApi
+// Experimental: CanvasAPI contains experimental APIs that may change or be removed.
+type CanvasAPI sessionAPI
// Closes an open canvas instance.
//
// RPC method: session.canvas.close.
//
// Parameters: Canvas close parameters.
-func (a *CanvasApi) Close(ctx context.Context, params *CanvasCloseRequest) (*SessionCanvasCloseResult, error) {
+func (a *CanvasAPI) Close(ctx context.Context, params *CanvasCloseRequest) (*SessionCanvasCloseResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["instanceId"] = params.InstanceID
@@ -9040,7 +9325,7 @@ func (a *CanvasApi) Close(ctx context.Context, params *CanvasCloseRequest) (*Ses
// RPC method: session.canvas.list.
//
// Returns: Declared canvases available in this session.
-func (a *CanvasApi) List(ctx context.Context) (*CanvasList, error) {
+func (a *CanvasAPI) List(ctx context.Context) (*CanvasList, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.canvas.list", req)
if err != nil {
@@ -9058,7 +9343,7 @@ func (a *CanvasApi) List(ctx context.Context) (*CanvasList, error) {
// RPC method: session.canvas.listOpen.
//
// Returns: Live open-canvas snapshot.
-func (a *CanvasApi) ListOpen(ctx context.Context) (*CanvasListOpenResult, error) {
+func (a *CanvasAPI) ListOpen(ctx context.Context) (*CanvasListOpenResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.canvas.listOpen", req)
if err != nil {
@@ -9078,7 +9363,7 @@ func (a *CanvasApi) ListOpen(ctx context.Context) (*CanvasListOpenResult, error)
// Parameters: Canvas open parameters.
//
// Returns: Open canvas instance snapshot.
-func (a *CanvasApi) Open(ctx context.Context, params *CanvasOpenRequest) (*OpenCanvasInstance, error) {
+func (a *CanvasAPI) Open(ctx context.Context, params *CanvasOpenRequest) (*OpenCanvasInstance, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["canvasId"] = params.CanvasID
@@ -9101,8 +9386,8 @@ func (a *CanvasApi) Open(ctx context.Context, params *CanvasOpenRequest) (*OpenC
return &result, nil
}
-// Experimental: CanvasActionApi contains experimental APIs that may change or be removed.
-type CanvasActionApi sessionApi
+// Experimental: CanvasActionAPI contains experimental APIs that may change or be removed.
+type CanvasActionAPI sessionAPI
// Invokes an action on an open canvas instance.
//
@@ -9111,7 +9396,7 @@ type CanvasActionApi sessionApi
// Parameters: Canvas action invocation parameters.
//
// Returns: Canvas action invocation result.
-func (a *CanvasActionApi) Invoke(ctx context.Context, params *CanvasActionInvokeRequest) (*CanvasActionInvokeResult, error) {
+func (a *CanvasActionAPI) Invoke(ctx context.Context, params *CanvasActionInvokeRequest) (*CanvasActionInvokeResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["actionName"] = params.ActionName
@@ -9132,12 +9417,12 @@ func (a *CanvasActionApi) Invoke(ctx context.Context, params *CanvasActionInvoke
}
// Experimental: Action returns experimental APIs that may change or be removed.
-func (s *CanvasApi) Action() *CanvasActionApi {
- return (*CanvasActionApi)(s)
+func (s *CanvasAPI) Action() *CanvasActionAPI {
+ return (*CanvasActionAPI)(s)
}
-// Experimental: CommandsApi contains experimental APIs that may change or be removed.
-type CommandsApi sessionApi
+// Experimental: CommandsAPI contains experimental APIs that may change or be removed.
+type CommandsAPI sessionAPI
// Enqueues a slash command for FIFO processing on the local session.
//
@@ -9146,7 +9431,7 @@ type CommandsApi sessionApi
// Parameters: Slash-prefixed command string to enqueue for FIFO processing.
//
// Returns: Indicates whether the command was accepted into the local execution queue.
-func (a *CommandsApi) Enqueue(ctx context.Context, params *EnqueueCommandParams) (*EnqueueCommandResult, error) {
+func (a *CommandsAPI) Enqueue(ctx context.Context, params *EnqueueCommandParams) (*EnqueueCommandResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["command"] = params.Command
@@ -9169,7 +9454,7 @@ func (a *CommandsApi) Enqueue(ctx context.Context, params *EnqueueCommandParams)
// Parameters: Slash command name and argument string to execute synchronously.
//
// Returns: Error message produced while executing the command, if any.
-func (a *CommandsApi) Execute(ctx context.Context, params *ExecuteCommandParams) (*ExecuteCommandResult, error) {
+func (a *CommandsAPI) Execute(ctx context.Context, params *ExecuteCommandParams) (*ExecuteCommandResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["args"] = params.Args
@@ -9193,7 +9478,7 @@ func (a *CommandsApi) Execute(ctx context.Context, params *ExecuteCommandParams)
// Parameters: Pending command request ID and an optional error if the client handler failed.
//
// Returns: Indicates whether the pending client-handled command was completed successfully.
-func (a *CommandsApi) HandlePendingCommand(ctx context.Context, params *CommandsHandlePendingCommandRequest) (*CommandsHandlePendingCommandResult, error) {
+func (a *CommandsAPI) HandlePendingCommand(ctx context.Context, params *CommandsHandlePendingCommandRequest) (*CommandsHandlePendingCommandResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
if params.Error != nil {
@@ -9220,7 +9505,7 @@ func (a *CommandsApi) HandlePendingCommand(ctx context.Context, params *Commands
//
// Returns: Result of invoking the slash command (text output, prompt to send to the agent,
// or completion).
-func (a *CommandsApi) Invoke(ctx context.Context, params *CommandsInvokeRequest) (SlashCommandInvocationResult, error) {
+func (a *CommandsAPI) Invoke(ctx context.Context, params *CommandsInvokeRequest) (SlashCommandInvocationResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
if params.Input != nil {
@@ -9247,7 +9532,7 @@ func (a *CommandsApi) Invoke(ctx context.Context, params *CommandsInvokeRequest)
//
// Returns: Slash commands available in the session, after applying any include/exclude
// filters.
-func (a *CommandsApi) List(ctx context.Context, params ...*CommandsListRequest) (*CommandList, error) {
+func (a *CommandsAPI) List(ctx context.Context, params ...*CommandsListRequest) (*CommandList, error) {
var requestParams *CommandsListRequest
if len(params) > 0 {
requestParams = params[0]
@@ -9284,7 +9569,7 @@ func (a *CommandsApi) List(ctx context.Context, params ...*CommandsListRequest)
// it (and whether to stop processing further queued commands).
//
// Returns: Indicates whether the queued-command response was matched to a pending request.
-func (a *CommandsApi) RespondToQueuedCommand(ctx context.Context, params *CommandsRespondToQueuedCommandRequest) (*CommandsRespondToQueuedCommandResult, error) {
+func (a *CommandsAPI) RespondToQueuedCommand(ctx context.Context, params *CommandsRespondToQueuedCommandRequest) (*CommandsRespondToQueuedCommandResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["requestId"] = params.RequestID
@@ -9301,8 +9586,8 @@ func (a *CommandsApi) RespondToQueuedCommand(ctx context.Context, params *Comman
return &result, nil
}
-// Experimental: EventLogApi contains experimental APIs that may change or be removed.
-type EventLogApi sessionApi
+// Experimental: EventLogAPI contains experimental APIs that may change or be removed.
+type EventLogAPI sessionAPI
// Reads a batch of session events from a cursor, optionally waiting for new events.
//
@@ -9313,7 +9598,7 @@ type EventLogApi sessionApi
//
// Returns: Batch of session events returned by a read, with cursor and continuation
// metadata.
-func (a *EventLogApi) Read(ctx context.Context, params *EventLogReadRequest) (*EventsReadResult, error) {
+func (a *EventLogAPI) Read(ctx context.Context, params *EventLogReadRequest) (*EventsReadResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
if params.AgentScope != nil {
@@ -9350,7 +9635,7 @@ func (a *EventLogApi) Read(ctx context.Context, params *EventLogReadRequest) (*E
// Parameters: Event type to register consumer interest for, used by runtime gating logic.
//
// Returns: Opaque handle representing an event-type interest registration.
-func (a *EventLogApi) RegisterInterest(ctx context.Context, params *RegisterEventInterestParams) (*RegisterEventInterestResult, error) {
+func (a *EventLogAPI) RegisterInterest(ctx context.Context, params *RegisterEventInterestParams) (*RegisterEventInterestResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["eventType"] = params.EventType
@@ -9373,7 +9658,7 @@ func (a *EventLogApi) RegisterInterest(ctx context.Context, params *RegisterEven
// Parameters: Opaque handle previously returned by `registerInterest` to release.
//
// Returns: Indicates whether the operation succeeded.
-func (a *EventLogApi) ReleaseInterest(ctx context.Context, params *ReleaseEventInterestParams) (*EventLogReleaseInterestResult, error) {
+func (a *EventLogAPI) ReleaseInterest(ctx context.Context, params *ReleaseEventInterestParams) (*EventLogReleaseInterestResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["handle"] = params.Handle
@@ -9397,7 +9682,7 @@ func (a *EventLogApi) ReleaseInterest(ctx context.Context, params *ReleaseEventI
// a consumer wants to subscribe to live events going forward without first paginating
// through the entire persisted history (which would happen if `read` were called without a
// cursor on a long-lived session).
-func (a *EventLogApi) Tail(ctx context.Context) (*EventLogTailResult, error) {
+func (a *EventLogAPI) Tail(ctx context.Context) (*EventLogTailResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.eventLog.tail", req)
if err != nil {
@@ -9410,15 +9695,15 @@ func (a *EventLogApi) Tail(ctx context.Context) (*EventLogTailResult, error) {
return &result, nil
}
-// Experimental: ExtensionsApi contains experimental APIs that may change or be removed.
-type ExtensionsApi sessionApi
+// Experimental: ExtensionsAPI contains experimental APIs that may change or be removed.
+type ExtensionsAPI sessionAPI
// Disables an extension for the session.
//
// RPC method: session.extensions.disable.
//
// Parameters: Source-qualified extension identifier to disable for the session.
-func (a *ExtensionsApi) Disable(ctx context.Context, params *ExtensionsDisableRequest) (*SessionExtensionsDisableResult, error) {
+func (a *ExtensionsAPI) Disable(ctx context.Context, params *ExtensionsDisableRequest) (*SessionExtensionsDisableResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["id"] = params.ID
@@ -9439,7 +9724,7 @@ func (a *ExtensionsApi) Disable(ctx context.Context, params *ExtensionsDisableRe
// RPC method: session.extensions.enable.
//
// Parameters: Source-qualified extension identifier to enable for the session.
-func (a *ExtensionsApi) Enable(ctx context.Context, params *ExtensionsEnableRequest) (*SessionExtensionsEnableResult, error) {
+func (a *ExtensionsAPI) Enable(ctx context.Context, params *ExtensionsEnableRequest) (*SessionExtensionsEnableResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["id"] = params.ID
@@ -9460,7 +9745,7 @@ func (a *ExtensionsApi) Enable(ctx context.Context, params *ExtensionsEnableRequ
// RPC method: session.extensions.list.
//
// Returns: Extensions discovered for the session, with their current status.
-func (a *ExtensionsApi) List(ctx context.Context) (*ExtensionList, error) {
+func (a *ExtensionsAPI) List(ctx context.Context) (*ExtensionList, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.extensions.list", req)
if err != nil {
@@ -9476,7 +9761,7 @@ func (a *ExtensionsApi) List(ctx context.Context) (*ExtensionList, error) {
// Reloads extension definitions and processes for the session.
//
// RPC method: session.extensions.reload.
-func (a *ExtensionsApi) Reload(ctx context.Context) (*SessionExtensionsReloadResult, error) {
+func (a *ExtensionsAPI) Reload(ctx context.Context) (*SessionExtensionsReloadResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.extensions.reload", req)
if err != nil {
@@ -9489,8 +9774,34 @@ func (a *ExtensionsApi) Reload(ctx context.Context) (*SessionExtensionsReloadRes
return &result, nil
}
-// Experimental: FleetApi contains experimental APIs that may change or be removed.
-type FleetApi sessionApi
+// SendAttachmentsToMessage push attachments into the next user-message turn from an
+// extension. The host should surface them as composer pills and forward them via the next
+// session.send call. Callable only by extension-owned connections.
+//
+// RPC method: session.extensions.sendAttachmentsToMessage.
+//
+// Parameters: Parameters for session.extensions.sendAttachmentsToMessage.
+func (a *ExtensionsAPI) SendAttachmentsToMessage(ctx context.Context, params *SendAttachmentsToMessageParams) (*SessionExtensionsSendAttachmentsToMessageResult, error) {
+ req := map[string]any{"sessionId": a.sessionID}
+ if params != nil {
+ req["attachments"] = params.Attachments
+ if params.InstanceID != nil {
+ req["instanceId"] = *params.InstanceID
+ }
+ }
+ raw, err := a.client.Request("session.extensions.sendAttachmentsToMessage", req)
+ if err != nil {
+ return nil, err
+ }
+ var result SessionExtensionsSendAttachmentsToMessageResult
+ if err := json.Unmarshal(raw, &result); err != nil {
+ return nil, err
+ }
+ return &result, nil
+}
+
+// Experimental: FleetAPI contains experimental APIs that may change or be removed.
+type FleetAPI sessionAPI
// Starts fleet mode by submitting the fleet orchestration prompt to the session.
//
@@ -9499,7 +9810,7 @@ type FleetApi sessionApi
// Parameters: Optional user prompt to combine with the fleet orchestration instructions.
//
// Returns: Indicates whether fleet mode was successfully activated.
-func (a *FleetApi) Start(ctx context.Context, params *FleetStartRequest) (*FleetStartResult, error) {
+func (a *FleetAPI) Start(ctx context.Context, params *FleetStartRequest) (*FleetStartResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
if params.Prompt != nil {
@@ -9517,15 +9828,15 @@ func (a *FleetApi) Start(ctx context.Context, params *FleetStartRequest) (*Fleet
return &result, nil
}
-// Experimental: HistoryApi contains experimental APIs that may change or be removed.
-type HistoryApi sessionApi
+// Experimental: HistoryAPI contains experimental APIs that may change or be removed.
+type HistoryAPI sessionAPI
// AbortManualCompaction aborts any in-progress manual compaction on a local session.
//
// RPC method: session.history.abortManualCompaction.
//
// Returns: Indicates whether an in-progress manual compaction was aborted.
-func (a *HistoryApi) AbortManualCompaction(ctx context.Context) (*HistoryAbortManualCompactionResult, error) {
+func (a *HistoryAPI) AbortManualCompaction(ctx context.Context) (*HistoryAbortManualCompactionResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.history.abortManualCompaction", req)
if err != nil {
@@ -9544,7 +9855,7 @@ func (a *HistoryApi) AbortManualCompaction(ctx context.Context) (*HistoryAbortMa
// RPC method: session.history.cancelBackgroundCompaction.
//
// Returns: Indicates whether an in-progress background compaction was cancelled.
-func (a *HistoryApi) CancelBackgroundCompaction(ctx context.Context) (*HistoryCancelBackgroundCompactionResult, error) {
+func (a *HistoryAPI) CancelBackgroundCompaction(ctx context.Context) (*HistoryCancelBackgroundCompactionResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.history.cancelBackgroundCompaction", req)
if err != nil {
@@ -9565,7 +9876,7 @@ func (a *HistoryApi) CancelBackgroundCompaction(ctx context.Context) (*HistoryCa
//
// Returns: Compaction outcome with the number of tokens and messages removed, summary text,
// and the resulting context window breakdown.
-func (a *HistoryApi) Compact(ctx context.Context, params ...*HistoryCompactRequest) (*HistoryCompactResult, error) {
+func (a *HistoryAPI) Compact(ctx context.Context, params ...*HistoryCompactRequest) (*HistoryCompactResult, error) {
var requestParams *HistoryCompactRequest
if len(params) > 0 {
requestParams = params[0]
@@ -9593,7 +9904,7 @@ func (a *HistoryApi) Compact(ctx context.Context, params ...*HistoryCompactReque
// RPC method: session.history.summarizeForHandoff.
//
// Returns: Markdown summary of the conversation context (empty when not available).
-func (a *HistoryApi) SummarizeForHandoff(ctx context.Context) (*HistorySummarizeForHandoffResult, error) {
+func (a *HistoryAPI) SummarizeForHandoff(ctx context.Context) (*HistorySummarizeForHandoffResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.history.summarizeForHandoff", req)
if err != nil {
@@ -9614,7 +9925,7 @@ func (a *HistoryApi) SummarizeForHandoff(ctx context.Context) (*HistorySummarize
// removed.
//
// Returns: Number of events that were removed by the truncation.
-func (a *HistoryApi) Truncate(ctx context.Context, params *HistoryTruncateRequest) (*HistoryTruncateResult, error) {
+func (a *HistoryAPI) Truncate(ctx context.Context, params *HistoryTruncateRequest) (*HistoryTruncateResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["eventId"] = params.EventID
@@ -9630,15 +9941,15 @@ func (a *HistoryApi) Truncate(ctx context.Context, params *HistoryTruncateReques
return &result, nil
}
-// Experimental: InstructionsApi contains experimental APIs that may change or be removed.
-type InstructionsApi sessionApi
+// Experimental: InstructionsAPI contains experimental APIs that may change or be removed.
+type InstructionsAPI sessionAPI
// GetSources gets instruction sources loaded for the session.
//
// RPC method: session.instructions.getSources.
//
// Returns: Instruction sources loaded for the session, in merge order.
-func (a *InstructionsApi) GetSources(ctx context.Context) (*InstructionsGetSourcesResult, error) {
+func (a *InstructionsAPI) GetSources(ctx context.Context) (*InstructionsGetSourcesResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.instructions.getSources", req)
if err != nil {
@@ -9651,15 +9962,15 @@ func (a *InstructionsApi) GetSources(ctx context.Context) (*InstructionsGetSourc
return &result, nil
}
-// Experimental: LspApi contains experimental APIs that may change or be removed.
-type LspApi sessionApi
+// Experimental: LspAPI contains experimental APIs that may change or be removed.
+type LspAPI sessionAPI
// Initialize loads the merged LSP configuration set for the session's working directory.
//
// RPC method: session.lsp.initialize.
//
// Parameters: Parameters for (re)loading the merged LSP configuration set.
-func (a *LspApi) Initialize(ctx context.Context, params *LspInitializeRequest) (*SessionLspInitializeResult, error) {
+func (a *LspAPI) Initialize(ctx context.Context, params *LspInitializeRequest) (*SessionLspInitializeResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
if params.Force != nil {
@@ -9683,8 +9994,8 @@ func (a *LspApi) Initialize(ctx context.Context, params *LspInitializeRequest) (
return &result, nil
}
-// Experimental: McpApi contains experimental APIs that may change or be removed.
-type McpApi sessionApi
+// Experimental: MCPAPI contains experimental APIs that may change or be removed.
+type MCPAPI sessionAPI
// CancelSamplingExecution cancels an in-flight MCP sampling execution by request ID.
//
@@ -9694,7 +10005,7 @@ type McpApi sessionApi
//
// Returns: Indicates whether an in-flight sampling execution with the given requestId was
// found and cancelled.
-func (a *McpApi) CancelSamplingExecution(ctx context.Context, params *McpCancelSamplingExecutionParams) (*McpCancelSamplingExecutionResult, error) {
+func (a *MCPAPI) CancelSamplingExecution(ctx context.Context, params *MCPCancelSamplingExecutionParams) (*MCPCancelSamplingExecutionResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["requestId"] = params.RequestID
@@ -9703,7 +10014,7 @@ func (a *McpApi) CancelSamplingExecution(ctx context.Context, params *McpCancelS
if err != nil {
return nil, err
}
- var result McpCancelSamplingExecutionResult
+ var result MCPCancelSamplingExecutionResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -9715,7 +10026,7 @@ func (a *McpApi) CancelSamplingExecution(ctx context.Context, params *McpCancelS
// RPC method: session.mcp.disable.
//
// Parameters: Name of the MCP server to disable for the session.
-func (a *McpApi) Disable(ctx context.Context, params *McpDisableRequest) (*SessionMcpDisableResult, error) {
+func (a *MCPAPI) Disable(ctx context.Context, params *MCPDisableRequest) (*SessionMCPDisableResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["serverName"] = params.ServerName
@@ -9724,7 +10035,7 @@ func (a *McpApi) Disable(ctx context.Context, params *McpDisableRequest) (*Sessi
if err != nil {
return nil, err
}
- var result SessionMcpDisableResult
+ var result SessionMCPDisableResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -9736,7 +10047,7 @@ func (a *McpApi) Disable(ctx context.Context, params *McpDisableRequest) (*Sessi
// RPC method: session.mcp.enable.
//
// Parameters: Name of the MCP server to enable for the session.
-func (a *McpApi) Enable(ctx context.Context, params *McpEnableRequest) (*SessionMcpEnableResult, error) {
+func (a *MCPAPI) Enable(ctx context.Context, params *MCPEnableRequest) (*SessionMCPEnableResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["serverName"] = params.ServerName
@@ -9745,7 +10056,7 @@ func (a *McpApi) Enable(ctx context.Context, params *McpEnableRequest) (*Session
if err != nil {
return nil, err
}
- var result SessionMcpEnableResult
+ var result SessionMCPEnableResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -9761,10 +10072,10 @@ func (a *McpApi) Enable(ctx context.Context, params *McpEnableRequest) (*Session
//
// Returns: Outcome of an MCP sampling execution: success result, failure error, or
// cancellation.
-func (a *McpApi) ExecuteSampling(ctx context.Context, params *McpExecuteSamplingParams) (*McpSamplingExecutionResult, error) {
+func (a *MCPAPI) ExecuteSampling(ctx context.Context, params *MCPExecuteSamplingParams) (*MCPSamplingExecutionResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
- req["mcpRequestId"] = params.McpRequestID
+ req["mcpRequestId"] = params.MCPRequestID
req["request"] = params.Request
req["requestId"] = params.RequestID
req["serverName"] = params.ServerName
@@ -9773,7 +10084,7 @@ func (a *McpApi) ExecuteSampling(ctx context.Context, params *McpExecuteSampling
if err != nil {
return nil, err
}
- var result McpSamplingExecutionResult
+ var result MCPSamplingExecutionResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -9785,13 +10096,13 @@ func (a *McpApi) ExecuteSampling(ctx context.Context, params *McpExecuteSampling
// RPC method: session.mcp.list.
//
// Returns: MCP servers configured for the session, with their connection status.
-func (a *McpApi) List(ctx context.Context) (*McpServerList, error) {
+func (a *MCPAPI) List(ctx context.Context) (*MCPServerList, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.mcp.list", req)
if err != nil {
return nil, err
}
- var result McpServerList
+ var result MCPServerList
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -9801,13 +10112,13 @@ func (a *McpApi) List(ctx context.Context) (*McpServerList, error) {
// Reloads MCP server connections for the session.
//
// RPC method: session.mcp.reload.
-func (a *McpApi) Reload(ctx context.Context) (*SessionMcpReloadResult, error) {
+func (a *MCPAPI) Reload(ctx context.Context) (*SessionMCPReloadResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.mcp.reload", req)
if err != nil {
return nil, err
}
- var result SessionMcpReloadResult
+ var result SessionMCPReloadResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -9820,13 +10131,13 @@ func (a *McpApi) Reload(ctx context.Context) (*SessionMcpReloadResult, error) {
//
// Returns: Indicates whether the auto-managed `github` MCP server was removed (false when
// nothing to remove).
-func (a *McpApi) RemoveGitHub(ctx context.Context) (*McpRemoveGitHubResult, error) {
+func (a *MCPAPI) RemoveGitHub(ctx context.Context) (*MCPRemoveGitHubResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.mcp.removeGitHub", req)
if err != nil {
return nil, err
}
- var result McpRemoveGitHubResult
+ var result MCPRemoveGitHubResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -9842,7 +10153,7 @@ func (a *McpApi) RemoveGitHub(ctx context.Context) (*McpRemoveGitHubResult, erro
// `indirect`).
//
// Returns: Env-value mode recorded on the session after the update.
-func (a *McpApi) SetEnvValueMode(ctx context.Context, params *McpSetEnvValueModeParams) (*McpSetEnvValueModeResult, error) {
+func (a *MCPAPI) SetEnvValueMode(ctx context.Context, params *MCPSetEnvValueModeParams) (*MCPSetEnvValueModeResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["mode"] = params.Mode
@@ -9851,15 +10162,15 @@ func (a *McpApi) SetEnvValueMode(ctx context.Context, params *McpSetEnvValueMode
if err != nil {
return nil, err
}
- var result McpSetEnvValueModeResult
+ var result MCPSetEnvValueModeResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
return &result, nil
}
-// Experimental: McpAppsApi contains experimental APIs that may change or be removed.
-type McpAppsApi sessionApi
+// Experimental: MCPAppsAPI contains experimental APIs that may change or be removed.
+type MCPAppsAPI sessionAPI
// CallTool call an MCP tool from an MCP App view (SEP-1865). Enforces the visibility check
// that prevents an app iframe from invoking model-only tools. Returns the standard MCP
@@ -9870,7 +10181,7 @@ type McpAppsApi sessionApi
// Parameters: MCP server, tool name, and arguments to invoke from an MCP App view.
//
// Returns: Standard MCP CallToolResult
-func (a *McpAppsApi) CallTool(ctx context.Context, params *McpAppsCallToolRequest) (*SessionMcpAppsCallToolResult, error) {
+func (a *MCPAppsAPI) CallTool(ctx context.Context, params *MCPAppsCallToolRequest) (*SessionMCPAppsCallToolResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
if params.Arguments != nil {
@@ -9884,7 +10195,7 @@ func (a *McpAppsApi) CallTool(ctx context.Context, params *McpAppsCallToolReques
if err != nil {
return nil, err
}
- var result SessionMcpAppsCallToolResult
+ var result SessionMCPAppsCallToolResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -9899,7 +10210,7 @@ func (a *McpAppsApi) CallTool(ctx context.Context, params *McpAppsCallToolReques
// Parameters: MCP server to diagnose MCP Apps wiring for.
//
// Returns: Diagnostic snapshot of MCP Apps wiring for the named server.
-func (a *McpAppsApi) Diagnose(ctx context.Context, params *McpAppsDiagnoseRequest) (*McpAppsDiagnoseResult, error) {
+func (a *MCPAppsAPI) Diagnose(ctx context.Context, params *MCPAppsDiagnoseRequest) (*MCPAppsDiagnoseResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["serverName"] = params.ServerName
@@ -9908,7 +10219,7 @@ func (a *McpAppsApi) Diagnose(ctx context.Context, params *McpAppsDiagnoseReques
if err != nil {
return nil, err
}
- var result McpAppsDiagnoseResult
+ var result MCPAppsDiagnoseResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -9920,13 +10231,13 @@ func (a *McpAppsApi) Diagnose(ctx context.Context, params *McpAppsDiagnoseReques
// RPC method: session.mcp.apps.getHostContext.
//
// Returns: Current host context advertised to MCP App guests.
-func (a *McpAppsApi) GetHostContext(ctx context.Context) (*McpAppsHostContext, error) {
+func (a *MCPAppsAPI) GetHostContext(ctx context.Context) (*MCPAppsHostContext, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.mcp.apps.getHostContext", req)
if err != nil {
return nil, err
}
- var result McpAppsHostContext
+ var result MCPAppsHostContext
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -9942,7 +10253,7 @@ func (a *McpAppsApi) GetHostContext(ctx context.Context) (*McpAppsHostContext, e
// Parameters: MCP server to list app-callable tools for.
//
// Returns: App-callable tools from the named MCP server.
-func (a *McpAppsApi) ListTools(ctx context.Context, params *McpAppsListToolsRequest) (*McpAppsListToolsResult, error) {
+func (a *MCPAppsAPI) ListTools(ctx context.Context, params *MCPAppsListToolsRequest) (*MCPAppsListToolsResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["originServerName"] = params.OriginServerName
@@ -9952,7 +10263,7 @@ func (a *McpAppsApi) ListTools(ctx context.Context, params *McpAppsListToolsRequ
if err != nil {
return nil, err
}
- var result McpAppsListToolsResult
+ var result MCPAppsListToolsResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -9967,7 +10278,7 @@ func (a *McpAppsApi) ListTools(ctx context.Context, params *McpAppsListToolsRequ
// Parameters: MCP server and resource URI to fetch.
//
// Returns: Resource contents returned by the MCP server.
-func (a *McpAppsApi) ReadResource(ctx context.Context, params *McpAppsReadResourceRequest) (*McpAppsReadResourceResult, error) {
+func (a *MCPAppsAPI) ReadResource(ctx context.Context, params *MCPAppsReadResourceRequest) (*MCPAppsReadResourceResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["serverName"] = params.ServerName
@@ -9977,7 +10288,7 @@ func (a *McpAppsApi) ReadResource(ctx context.Context, params *McpAppsReadResour
if err != nil {
return nil, err
}
- var result McpAppsReadResourceResult
+ var result MCPAppsReadResourceResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -9990,7 +10301,7 @@ func (a *McpAppsApi) ReadResource(ctx context.Context, params *McpAppsReadResour
// RPC method: session.mcp.apps.setHostContext.
//
// Parameters: Host context to advertise to MCP App guests.
-func (a *McpAppsApi) SetHostContext(ctx context.Context, params *McpAppsSetHostContextRequest) (*SessionMcpAppsSetHostContextResult, error) {
+func (a *MCPAppsAPI) SetHostContext(ctx context.Context, params *MCPAppsSetHostContextRequest) (*SessionMCPAppsSetHostContextResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["context"] = params.Context
@@ -9999,7 +10310,7 @@ func (a *McpAppsApi) SetHostContext(ctx context.Context, params *McpAppsSetHostC
if err != nil {
return nil, err
}
- var result SessionMcpAppsSetHostContextResult
+ var result SessionMCPAppsSetHostContextResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -10007,12 +10318,12 @@ func (a *McpAppsApi) SetHostContext(ctx context.Context, params *McpAppsSetHostC
}
// Experimental: Apps returns experimental APIs that may change or be removed.
-func (s *McpApi) Apps() *McpAppsApi {
- return (*McpAppsApi)(s)
+func (s *MCPAPI) Apps() *MCPAppsAPI {
+ return (*MCPAppsAPI)(s)
}
-// Experimental: McpOauthApi contains experimental APIs that may change or be removed.
-type McpOauthApi sessionApi
+// Experimental: MCPOauthAPI contains experimental APIs that may change or be removed.
+type MCPOauthAPI sessionAPI
// Login starts OAuth authentication for a remote MCP server.
//
@@ -10023,7 +10334,7 @@ type McpOauthApi sessionApi
//
// Returns: OAuth authorization URL the caller should open, or empty when cached tokens
// already authenticated the server.
-func (a *McpOauthApi) Login(ctx context.Context, params *McpOauthLoginRequest) (*McpOauthLoginResult, error) {
+func (a *MCPOauthAPI) Login(ctx context.Context, params *MCPOauthLoginRequest) (*MCPOauthLoginResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
if params.CallbackSuccessMessage != nil {
@@ -10041,7 +10352,7 @@ func (a *McpOauthApi) Login(ctx context.Context, params *McpOauthLoginRequest) (
if err != nil {
return nil, err
}
- var result McpOauthLoginResult
+ var result MCPOauthLoginResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
@@ -10049,12 +10360,12 @@ func (a *McpOauthApi) Login(ctx context.Context, params *McpOauthLoginRequest) (
}
// Experimental: Oauth returns experimental APIs that may change or be removed.
-func (s *McpApi) Oauth() *McpOauthApi {
- return (*McpOauthApi)(s)
+func (s *MCPAPI) Oauth() *MCPOauthAPI {
+ return (*MCPOauthAPI)(s)
}
-// Experimental: MetadataApi contains experimental APIs that may change or be removed.
-type MetadataApi sessionApi
+// Experimental: MetadataAPI contains experimental APIs that may change or be removed.
+type MetadataAPI sessionAPI
// ContextInfo returns the token breakdown for the session's current context window for a
// given model.
@@ -10065,7 +10376,7 @@ type MetadataApi sessionApi
//
// Returns: Token breakdown for the session's current context window, or null if
// uninitialized.
-func (a *MetadataApi) ContextInfo(ctx context.Context, params *MetadataContextInfoRequest) (*MetadataContextInfoResult, error) {
+func (a *MetadataAPI) ContextInfo(ctx context.Context, params *MetadataContextInfoRequest) (*MetadataContextInfoResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["outputTokenLimit"] = params.OutputTokenLimit
@@ -10092,7 +10403,7 @@ func (a *MetadataApi) ContextInfo(ctx context.Context, params *MetadataContextIn
//
// Returns: Indicates whether the local session is currently processing a turn or background
// continuation.
-func (a *MetadataApi) IsProcessing(ctx context.Context) (*MetadataIsProcessingResult, error) {
+func (a *MetadataAPI) IsProcessing(ctx context.Context) (*MetadataIsProcessingResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.metadata.isProcessing", req)
if err != nil {
@@ -10116,7 +10427,7 @@ func (a *MetadataApi) IsProcessing(ctx context.Context) (*MetadataIsProcessingRe
// token totals. Useful for hosts that want an initial estimate of context usage on session
// resume, before the next agent turn fires `session.context_info_changed` events. Returns
// zeros for an empty session.
-func (a *MetadataApi) RecomputeContextTokens(ctx context.Context, params *MetadataRecomputeContextTokensRequest) (*MetadataRecomputeContextTokensResult, error) {
+func (a *MetadataAPI) RecomputeContextTokens(ctx context.Context, params *MetadataRecomputeContextTokensRequest) (*MetadataRecomputeContextTokensResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["modelId"] = params.ModelID
@@ -10143,7 +10454,7 @@ func (a *MetadataApi) RecomputeContextTokens(ctx context.Context, params *Metada
// `session.context_changed` event so consumers (telemetry, OTel tracker, ACP, the timeline
// UI) can react. Use this when the host has detected a cwd/branch/repo change outside the
// session's normal lifecycle (e.g., after a shell command in interactive mode).
-func (a *MetadataApi) RecordContextChange(ctx context.Context, params *MetadataRecordContextChangeRequest) (*MetadataRecordContextChangeResult, error) {
+func (a *MetadataAPI) RecordContextChange(ctx context.Context, params *MetadataRecordContextChangeRequest) (*MetadataRecordContextChangeResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["context"] = params.Context
@@ -10169,7 +10480,7 @@ func (a *MetadataApi) RecordContextChange(ctx context.Context, params *MetadataR
// explicitly changes cwd (e.g., the `/cd` slash command). The host is responsible for
// `process.chdir` and any related side-effects (file index, etc.); this method only updates
// the session's own recorded path.
-func (a *MetadataApi) SetWorkingDirectory(ctx context.Context, params *MetadataSetWorkingDirectoryRequest) (*MetadataSetWorkingDirectoryResult, error) {
+func (a *MetadataAPI) SetWorkingDirectory(ctx context.Context, params *MetadataSetWorkingDirectoryRequest) (*MetadataSetWorkingDirectoryResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["workingDirectory"] = params.WorkingDirectory
@@ -10191,7 +10502,7 @@ func (a *MetadataApi) SetWorkingDirectory(ctx context.Context, params *MetadataS
// RPC method: session.metadata.snapshot.
//
// Returns: Point-in-time snapshot of slow-changing session identifier and state fields
-func (a *MetadataApi) Snapshot(ctx context.Context) (*SessionMetadataSnapshot, error) {
+func (a *MetadataAPI) Snapshot(ctx context.Context) (*SessionMetadataSnapshot, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.metadata.snapshot", req)
if err != nil {
@@ -10204,15 +10515,15 @@ func (a *MetadataApi) Snapshot(ctx context.Context) (*SessionMetadataSnapshot, e
return &result, nil
}
-// Experimental: ModeApi contains experimental APIs that may change or be removed.
-type ModeApi sessionApi
+// Experimental: ModeAPI contains experimental APIs that may change or be removed.
+type ModeAPI sessionAPI
// Gets the current agent interaction mode.
//
// RPC method: session.mode.get.
//
// Returns: The session mode the agent is operating in
-func (a *ModeApi) Get(ctx context.Context) (*SessionMode, error) {
+func (a *ModeAPI) Get(ctx context.Context) (*SessionMode, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.mode.get", req)
if err != nil {
@@ -10230,7 +10541,7 @@ func (a *ModeApi) Get(ctx context.Context) (*SessionMode, error) {
// RPC method: session.mode.set.
//
// Parameters: Agent interaction mode to apply to the session.
-func (a *ModeApi) Set(ctx context.Context, params *ModeSetRequest) (*SessionModeSetResult, error) {
+func (a *ModeAPI) Set(ctx context.Context, params *ModeSetRequest) (*SessionModeSetResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["mode"] = params.Mode
@@ -10246,15 +10557,17 @@ func (a *ModeApi) Set(ctx context.Context, params *ModeSetRequest) (*SessionMode
return &result, nil
}
-// Experimental: ModelApi contains experimental APIs that may change or be removed.
-type ModelApi sessionApi
+// Experimental: ModelAPI contains experimental APIs that may change or be removed.
+type ModelAPI sessionAPI
// GetCurrent gets the currently selected model for the session.
//
// RPC method: session.model.getCurrent.
//
-// Returns: The currently selected model and reasoning effort for the session.
-func (a *ModelApi) GetCurrent(ctx context.Context) (*CurrentModel, error) {
+// Returns: The currently selected model, reasoning effort, and context tier for the
+// session. The context tier reflects `Session.getContextTier()`, restored from the session
+// journal on resume.
+func (a *ModelAPI) GetCurrent(ctx context.Context) (*CurrentModel, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.model.getCurrent", req)
if err != nil {
@@ -10276,7 +10589,7 @@ func (a *ModelApi) GetCurrent(ctx context.Context) (*CurrentModel, error) {
// Parameters: Optional listing options.
//
// Returns: The list of models available to this session.
-func (a *ModelApi) List(ctx context.Context, params ...*ModelListRequest) (*SessionModelList, error) {
+func (a *ModelAPI) List(ctx context.Context, params ...*ModelListRequest) (*SessionModelList, error) {
var requestParams *ModelListRequest
if len(params) > 0 {
requestParams = params[0]
@@ -10308,7 +10621,7 @@ func (a *ModelApi) List(ctx context.Context, params ...*ModelListRequest) (*Sess
// Returns: Update the session's reasoning effort without changing the selected model. Use
// `switchTo` instead when you also need to change the model. The runtime stores the effort
// on the session and applies it to subsequent turns.
-func (a *ModelApi) SetReasoningEffort(ctx context.Context, params *ModelSetReasoningEffortRequest) (*ModelSetReasoningEffortResult, error) {
+func (a *ModelAPI) SetReasoningEffort(ctx context.Context, params *ModelSetReasoningEffortRequest) (*ModelSetReasoningEffortResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["reasoningEffort"] = params.ReasoningEffort
@@ -10332,7 +10645,7 @@ func (a *ModelApi) SetReasoningEffort(ctx context.Context, params *ModelSetReaso
// overrides, and context tier.
//
// Returns: The model identifier active on the session after the switch.
-func (a *ModelApi) SwitchTo(ctx context.Context, params *ModelSwitchToRequest) (*ModelSwitchToResult, error) {
+func (a *ModelAPI) SwitchTo(ctx context.Context, params *ModelSwitchToRequest) (*ModelSwitchToResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
if params.ContextTier != nil {
@@ -10360,15 +10673,15 @@ func (a *ModelApi) SwitchTo(ctx context.Context, params *ModelSwitchToRequest) (
return &result, nil
}
-// Experimental: NameApi contains experimental APIs that may change or be removed.
-type NameApi sessionApi
+// Experimental: NameAPI contains experimental APIs that may change or be removed.
+type NameAPI sessionAPI
// Gets the session's friendly name.
//
// RPC method: session.name.get.
//
// Returns: The session's friendly name, or null when not yet set.
-func (a *NameApi) Get(ctx context.Context) (*NameGetResult, error) {
+func (a *NameAPI) Get(ctx context.Context) (*NameGetResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.name.get", req)
if err != nil {
@@ -10386,7 +10699,7 @@ func (a *NameApi) Get(ctx context.Context) (*NameGetResult, error) {
// RPC method: session.name.set.
//
// Parameters: New friendly name to apply to the session.
-func (a *NameApi) Set(ctx context.Context, params *NameSetRequest) (*SessionNameSetResult, error) {
+func (a *NameAPI) Set(ctx context.Context, params *NameSetRequest) (*SessionNameSetResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["name"] = params.Name
@@ -10411,7 +10724,7 @@ func (a *NameApi) Set(ctx context.Context, params *NameSetRequest) (*SessionName
// user-set name exists.
//
// Returns: Indicates whether the auto-generated summary was applied as the session's name.
-func (a *NameApi) SetAuto(ctx context.Context, params *NameSetAutoRequest) (*NameSetAutoResult, error) {
+func (a *NameAPI) SetAuto(ctx context.Context, params *NameSetAutoRequest) (*NameSetAutoResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["summary"] = params.Summary
@@ -10427,8 +10740,8 @@ func (a *NameApi) SetAuto(ctx context.Context, params *NameSetAutoRequest) (*Nam
return &result, nil
}
-// Experimental: OptionsApi contains experimental APIs that may change or be removed.
-type OptionsApi sessionApi
+// Experimental: OptionsAPI contains experimental APIs that may change or be removed.
+type OptionsAPI sessionAPI
// Update patches the genuinely-mutable subset of session options.
//
@@ -10437,7 +10750,7 @@ type OptionsApi sessionApi
// Parameters: Patch of mutable session options to apply to the running session.
//
// Returns: Indicates whether the session options patch was applied successfully.
-func (a *OptionsApi) Update(ctx context.Context, params *SessionUpdateOptionsParams) (*SessionUpdateOptionsResult, error) {
+func (a *OptionsAPI) Update(ctx context.Context, params *SessionUpdateOptionsParams) (*SessionUpdateOptionsResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
if params.AdditionalContentExclusionPolicies != nil {
@@ -10560,6 +10873,9 @@ func (a *OptionsApi) Update(ctx context.Context, params *SessionUpdateOptionsPar
if params.SkipEmbeddingRetrieval != nil {
req["skipEmbeddingRetrieval"] = *params.SkipEmbeddingRetrieval
}
+ if params.SuppressCustomAgentPrompt != nil {
+ req["suppressCustomAgentPrompt"] = *params.SuppressCustomAgentPrompt
+ }
if params.ToolFilterPrecedence != nil {
req["toolFilterPrecedence"] = *params.ToolFilterPrecedence
}
@@ -10581,8 +10897,8 @@ func (a *OptionsApi) Update(ctx context.Context, params *SessionUpdateOptionsPar
return &result, nil
}
-// Experimental: PermissionsApi contains experimental APIs that may change or be removed.
-type PermissionsApi sessionApi
+// Experimental: PermissionsAPI contains experimental APIs that may change or be removed.
+type PermissionsAPI sessionAPI
// Configure replaces selected permission policy fields (rules, paths, URLs, exclusions,
// allow-all flags) on the session.
@@ -10593,7 +10909,7 @@ type PermissionsApi sessionApi
// unchanged).
//
// Returns: Indicates whether the operation succeeded.
-func (a *PermissionsApi) Configure(ctx context.Context, params *PermissionsConfigureParams) (*PermissionsConfigureResult, error) {
+func (a *PermissionsAPI) Configure(ctx context.Context, params *PermissionsConfigureParams) (*PermissionsConfigureResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
if params.AdditionalContentExclusionPolicies != nil {
@@ -10611,8 +10927,8 @@ func (a *PermissionsApi) Configure(ctx context.Context, params *PermissionsConfi
if params.Rules != nil {
req["rules"] = *params.Rules
}
- if params.Urls != nil {
- req["urls"] = *params.Urls
+ if params.URLs != nil {
+ req["urls"] = *params.URLs
}
}
raw, err := a.client.Request("session.permissions.configure", req)
@@ -10632,7 +10948,7 @@ func (a *PermissionsApi) Configure(ctx context.Context, params *PermissionsConfi
// RPC method: session.permissions.getAllowAll.
//
// Returns: Current full allow-all permission state.
-func (a *PermissionsApi) GetAllowAll(ctx context.Context) (*AllowAllPermissionState, error) {
+func (a *PermissionsAPI) GetAllowAll(ctx context.Context) (*AllowAllPermissionState, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.permissions.getAllowAll", req)
if err != nil {
@@ -10654,7 +10970,7 @@ func (a *PermissionsApi) GetAllowAll(ctx context.Context) (*AllowAllPermissionSt
//
// Returns: Indicates whether the permission decision was applied; false when the request
// was already resolved.
-func (a *PermissionsApi) HandlePendingPermissionRequest(ctx context.Context, params *PermissionDecisionRequest) (*PermissionRequestResult, error) {
+func (a *PermissionsAPI) HandlePendingPermissionRequest(ctx context.Context, params *PermissionDecisionRequest) (*PermissionRequestResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["requestId"] = params.RequestID
@@ -10679,7 +10995,7 @@ func (a *PermissionsApi) HandlePendingPermissionRequest(ctx context.Context, par
// permission rules.
//
// Returns: Indicates whether the operation succeeded.
-func (a *PermissionsApi) ModifyRules(ctx context.Context, params *PermissionsModifyRulesParams) (*PermissionsModifyRulesResult, error) {
+func (a *PermissionsAPI) ModifyRules(ctx context.Context, params *PermissionsModifyRulesParams) (*PermissionsModifyRulesResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
if params.Add != nil {
@@ -10713,7 +11029,7 @@ func (a *PermissionsApi) ModifyRules(ctx context.Context, params *PermissionsMod
// rendered.
//
// Returns: Indicates whether the operation succeeded.
-func (a *PermissionsApi) NotifyPromptShown(ctx context.Context, params *PermissionPromptShownNotification) (*PermissionsNotifyPromptShownResult, error) {
+func (a *PermissionsAPI) NotifyPromptShown(ctx context.Context, params *PermissionPromptShownNotification) (*PermissionsNotifyPromptShownResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["message"] = params.Message
@@ -10735,7 +11051,7 @@ func (a *PermissionsApi) NotifyPromptShown(ctx context.Context, params *Permissi
// RPC method: session.permissions.pendingRequests.
//
// Returns: List of pending permission requests reconstructed from event history.
-func (a *PermissionsApi) PendingRequests(ctx context.Context) (*PendingPermissionRequestList, error) {
+func (a *PermissionsAPI) PendingRequests(ctx context.Context) (*PendingPermissionRequestList, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.permissions.pendingRequests", req)
if err != nil {
@@ -10753,7 +11069,7 @@ func (a *PermissionsApi) PendingRequests(ctx context.Context) (*PendingPermissio
// RPC method: session.permissions.resetSessionApprovals.
//
// Returns: Indicates whether the operation succeeded.
-func (a *PermissionsApi) ResetSessionApprovals(ctx context.Context) (*PermissionsResetSessionApprovalsResult, error) {
+func (a *PermissionsAPI) ResetSessionApprovals(ctx context.Context) (*PermissionsResetSessionApprovalsResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.permissions.resetSessionApprovals", req)
if err != nil {
@@ -10779,10 +11095,13 @@ func (a *PermissionsApi) ResetSessionApprovals(ctx context.Context) (*Permission
// Parameters: Whether to enable full allow-all permissions for the session.
//
// Returns: Indicates whether the operation succeeded and reports the post-mutation state.
-func (a *PermissionsApi) SetAllowAll(ctx context.Context, params *PermissionsSetAllowAllRequest) (*AllowAllPermissionSetResult, error) {
+func (a *PermissionsAPI) SetAllowAll(ctx context.Context, params *PermissionsSetAllowAllRequest) (*AllowAllPermissionSetResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["enabled"] = params.Enabled
+ if params.Source != nil {
+ req["source"] = *params.Source
+ }
}
raw, err := a.client.Request("session.permissions.setAllowAll", req)
if err != nil {
@@ -10804,7 +11123,7 @@ func (a *PermissionsApi) SetAllowAll(ctx context.Context, params *PermissionsSet
// source.
//
// Returns: Indicates whether the operation succeeded.
-func (a *PermissionsApi) SetApproveAll(ctx context.Context, params *PermissionsSetApproveAllRequest) (*PermissionsSetApproveAllResult, error) {
+func (a *PermissionsAPI) SetApproveAll(ctx context.Context, params *PermissionsSetApproveAllRequest) (*PermissionsSetApproveAllResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["enabled"] = params.Enabled
@@ -10831,7 +11150,7 @@ func (a *PermissionsApi) SetApproveAll(ctx context.Context, params *PermissionsS
// this client.
//
// Returns: Indicates whether the operation succeeded.
-func (a *PermissionsApi) SetRequired(ctx context.Context, params *PermissionsSetRequiredRequest) (*PermissionsSetRequiredResult, error) {
+func (a *PermissionsAPI) SetRequired(ctx context.Context, params *PermissionsSetRequiredRequest) (*PermissionsSetRequiredResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["required"] = params.Required
@@ -10847,9 +11166,9 @@ func (a *PermissionsApi) SetRequired(ctx context.Context, params *PermissionsSet
return &result, nil
}
-// Experimental: PermissionsFolderTrustApi contains experimental APIs that may change or be
+// Experimental: PermissionsFolderTrustAPI contains experimental APIs that may change or be
// removed.
-type PermissionsFolderTrustApi sessionApi
+type PermissionsFolderTrustAPI sessionAPI
// AddTrusted adds a folder to the user's trusted folders list.
//
@@ -10858,7 +11177,7 @@ type PermissionsFolderTrustApi sessionApi
// Parameters: Folder path to add to trusted folders.
//
// Returns: Indicates whether the operation succeeded.
-func (a *PermissionsFolderTrustApi) AddTrusted(ctx context.Context, params *FolderTrustAddParams) (*PermissionsFolderTrustAddTrustedResult, error) {
+func (a *PermissionsFolderTrustAPI) AddTrusted(ctx context.Context, params *FolderTrustAddParams) (*PermissionsFolderTrustAddTrustedResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["path"] = params.Path
@@ -10881,7 +11200,7 @@ func (a *PermissionsFolderTrustApi) AddTrusted(ctx context.Context, params *Fold
// Parameters: Folder path to check for trust.
//
// Returns: Folder trust check result.
-func (a *PermissionsFolderTrustApi) IsTrusted(ctx context.Context, params *FolderTrustCheckParams) (*FolderTrustCheckResult, error) {
+func (a *PermissionsFolderTrustAPI) IsTrusted(ctx context.Context, params *FolderTrustCheckParams) (*FolderTrustCheckResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["path"] = params.Path
@@ -10898,13 +11217,13 @@ func (a *PermissionsFolderTrustApi) IsTrusted(ctx context.Context, params *Folde
}
// Experimental: FolderTrust returns experimental APIs that may change or be removed.
-func (s *PermissionsApi) FolderTrust() *PermissionsFolderTrustApi {
- return (*PermissionsFolderTrustApi)(s)
+func (s *PermissionsAPI) FolderTrust() *PermissionsFolderTrustAPI {
+ return (*PermissionsFolderTrustAPI)(s)
}
-// Experimental: PermissionsLocationsApi contains experimental APIs that may change or be
+// Experimental: PermissionsLocationsAPI contains experimental APIs that may change or be
// removed.
-type PermissionsLocationsApi sessionApi
+type PermissionsLocationsAPI sessionAPI
// AddToolApproval persists a tool approval for a permission location and applies its rules
// to this session's live permission service.
@@ -10914,7 +11233,7 @@ type PermissionsLocationsApi sessionApi
// Parameters: Location-scoped tool approval to persist.
//
// Returns: Indicates whether the operation succeeded.
-func (a *PermissionsLocationsApi) AddToolApproval(ctx context.Context, params *PermissionLocationAddToolApprovalParams) (*PermissionsLocationsAddToolApprovalResult, error) {
+func (a *PermissionsLocationsAPI) AddToolApproval(ctx context.Context, params *PermissionLocationAddToolApprovalParams) (*PermissionsLocationsAddToolApprovalResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["approval"] = params.Approval
@@ -10939,7 +11258,7 @@ func (a *PermissionsLocationsApi) AddToolApproval(ctx context.Context, params *P
// Parameters: Working directory to load persisted location permissions for.
//
// Returns: Summary of persisted location permissions applied to the session.
-func (a *PermissionsLocationsApi) Apply(ctx context.Context, params *PermissionLocationApplyParams) (*PermissionLocationApplyResult, error) {
+func (a *PermissionsLocationsAPI) Apply(ctx context.Context, params *PermissionLocationApplyParams) (*PermissionLocationApplyResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["workingDirectory"] = params.WorkingDirectory
@@ -10962,7 +11281,7 @@ func (a *PermissionsLocationsApi) Apply(ctx context.Context, params *PermissionL
// Parameters: Working directory to resolve into a location-permissions key.
//
// Returns: Resolved location-permissions key and type.
-func (a *PermissionsLocationsApi) Resolve(ctx context.Context, params *PermissionLocationResolveParams) (*PermissionLocationResolveResult, error) {
+func (a *PermissionsLocationsAPI) Resolve(ctx context.Context, params *PermissionLocationResolveParams) (*PermissionLocationResolveResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["workingDirectory"] = params.WorkingDirectory
@@ -10979,13 +11298,13 @@ func (a *PermissionsLocationsApi) Resolve(ctx context.Context, params *Permissio
}
// Experimental: Locations returns experimental APIs that may change or be removed.
-func (s *PermissionsApi) Locations() *PermissionsLocationsApi {
- return (*PermissionsLocationsApi)(s)
+func (s *PermissionsAPI) Locations() *PermissionsLocationsAPI {
+ return (*PermissionsLocationsAPI)(s)
}
-// Experimental: PermissionsPathsApi contains experimental APIs that may change or be
+// Experimental: PermissionsPathsAPI contains experimental APIs that may change or be
// removed.
-type PermissionsPathsApi sessionApi
+type PermissionsPathsAPI sessionAPI
// Adds a directory to the session's allow-list.
//
@@ -10994,7 +11313,7 @@ type PermissionsPathsApi sessionApi
// Parameters: Directory path to add to the session's allowed directories.
//
// Returns: Indicates whether the operation succeeded.
-func (a *PermissionsPathsApi) Add(ctx context.Context, params *PermissionPathsAddParams) (*PermissionsPathsAddResult, error) {
+func (a *PermissionsPathsAPI) Add(ctx context.Context, params *PermissionPathsAddParams) (*PermissionsPathsAddResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["path"] = params.Path
@@ -11018,7 +11337,7 @@ func (a *PermissionsPathsApi) Add(ctx context.Context, params *PermissionPathsAd
// Parameters: Path to evaluate against the session's allowed directories.
//
// Returns: Indicates whether the supplied path is within the session's allowed directories.
-func (a *PermissionsPathsApi) IsPathWithinAllowedDirectories(ctx context.Context, params *PermissionPathsAllowedCheckParams) (*PermissionPathsAllowedCheckResult, error) {
+func (a *PermissionsPathsAPI) IsPathWithinAllowedDirectories(ctx context.Context, params *PermissionPathsAllowedCheckParams) (*PermissionPathsAllowedCheckResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["path"] = params.Path
@@ -11042,7 +11361,7 @@ func (a *PermissionsPathsApi) IsPathWithinAllowedDirectories(ctx context.Context
// Parameters: Path to evaluate against the session's workspace (primary) directory.
//
// Returns: Indicates whether the supplied path is within the session's workspace directory.
-func (a *PermissionsPathsApi) IsPathWithinWorkspace(ctx context.Context, params *PermissionPathsWorkspaceCheckParams) (*PermissionPathsWorkspaceCheckResult, error) {
+func (a *PermissionsPathsAPI) IsPathWithinWorkspace(ctx context.Context, params *PermissionPathsWorkspaceCheckParams) (*PermissionPathsWorkspaceCheckResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["path"] = params.Path
@@ -11063,7 +11382,7 @@ func (a *PermissionsPathsApi) IsPathWithinWorkspace(ctx context.Context, params
// RPC method: session.permissions.paths.list.
//
// Returns: Snapshot of the session's allow-listed directories and primary working directory.
-func (a *PermissionsPathsApi) List(ctx context.Context) (*PermissionPathsList, error) {
+func (a *PermissionsPathsAPI) List(ctx context.Context) (*PermissionPathsList, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.permissions.paths.list", req)
if err != nil {
@@ -11084,7 +11403,7 @@ func (a *PermissionsPathsApi) List(ctx context.Context) (*PermissionPathsList, e
// Parameters: Directory path to set as the session's new primary working directory.
//
// Returns: Indicates whether the operation succeeded.
-func (a *PermissionsPathsApi) UpdatePrimary(ctx context.Context, params *PermissionPathsUpdatePrimaryParams) (*PermissionsPathsUpdatePrimaryResult, error) {
+func (a *PermissionsPathsAPI) UpdatePrimary(ctx context.Context, params *PermissionPathsUpdatePrimaryParams) (*PermissionsPathsUpdatePrimaryResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["path"] = params.Path
@@ -11101,12 +11420,12 @@ func (a *PermissionsPathsApi) UpdatePrimary(ctx context.Context, params *Permiss
}
// Experimental: Paths returns experimental APIs that may change or be removed.
-func (s *PermissionsApi) Paths() *PermissionsPathsApi {
- return (*PermissionsPathsApi)(s)
+func (s *PermissionsAPI) Paths() *PermissionsPathsAPI {
+ return (*PermissionsPathsAPI)(s)
}
-// Experimental: PermissionsUrlsApi contains experimental APIs that may change or be removed.
-type PermissionsUrlsApi sessionApi
+// Experimental: PermissionsURLsAPI contains experimental APIs that may change or be removed.
+type PermissionsURLsAPI sessionAPI
// SetUnrestrictedMode toggles the runtime's URL-permission policy between unrestricted and
// restricted modes.
@@ -11116,7 +11435,7 @@ type PermissionsUrlsApi sessionApi
// Parameters: Whether the URL-permission policy should run in unrestricted mode.
//
// Returns: Indicates whether the operation succeeded.
-func (a *PermissionsUrlsApi) SetUnrestrictedMode(ctx context.Context, params *PermissionUrlsSetUnrestrictedModeParams) (*PermissionsUrlsSetUnrestrictedModeResult, error) {
+func (a *PermissionsURLsAPI) SetUnrestrictedMode(ctx context.Context, params *PermissionURLsSetUnrestrictedModeParams) (*PermissionsURLsSetUnrestrictedModeResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["enabled"] = params.Enabled
@@ -11125,25 +11444,25 @@ func (a *PermissionsUrlsApi) SetUnrestrictedMode(ctx context.Context, params *Pe
if err != nil {
return nil, err
}
- var result PermissionsUrlsSetUnrestrictedModeResult
+ var result PermissionsURLsSetUnrestrictedModeResult
if err := json.Unmarshal(raw, &result); err != nil {
return nil, err
}
return &result, nil
}
-// Experimental: Urls returns experimental APIs that may change or be removed.
-func (s *PermissionsApi) Urls() *PermissionsUrlsApi {
- return (*PermissionsUrlsApi)(s)
+// Experimental: URLs returns experimental APIs that may change or be removed.
+func (s *PermissionsAPI) URLs() *PermissionsURLsAPI {
+ return (*PermissionsURLsAPI)(s)
}
-// Experimental: PlanApi contains experimental APIs that may change or be removed.
-type PlanApi sessionApi
+// Experimental: PlanAPI contains experimental APIs that may change or be removed.
+type PlanAPI sessionAPI
// Deletes the session plan file from the workspace.
//
// RPC method: session.plan.delete.
-func (a *PlanApi) Delete(ctx context.Context) (*SessionPlanDeleteResult, error) {
+func (a *PlanAPI) Delete(ctx context.Context) (*SessionPlanDeleteResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.plan.delete", req)
if err != nil {
@@ -11161,7 +11480,7 @@ func (a *PlanApi) Delete(ctx context.Context) (*SessionPlanDeleteResult, error)
// RPC method: session.plan.read.
//
// Returns: Existence, contents, and resolved path of the session plan file.
-func (a *PlanApi) Read(ctx context.Context) (*PlanReadResult, error) {
+func (a *PlanAPI) Read(ctx context.Context) (*PlanReadResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.plan.read", req)
if err != nil {
@@ -11179,7 +11498,7 @@ func (a *PlanApi) Read(ctx context.Context) (*PlanReadResult, error) {
// RPC method: session.plan.update.
//
// Parameters: Replacement contents to write to the session plan file.
-func (a *PlanApi) Update(ctx context.Context, params *PlanUpdateRequest) (*SessionPlanUpdateResult, error) {
+func (a *PlanAPI) Update(ctx context.Context, params *PlanUpdateRequest) (*SessionPlanUpdateResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["content"] = params.Content
@@ -11195,15 +11514,15 @@ func (a *PlanApi) Update(ctx context.Context, params *PlanUpdateRequest) (*Sessi
return &result, nil
}
-// Experimental: PluginsApi contains experimental APIs that may change or be removed.
-type PluginsApi sessionApi
+// Experimental: PluginsAPI contains experimental APIs that may change or be removed.
+type PluginsAPI sessionAPI
// Lists plugins installed for the session.
//
// RPC method: session.plugins.list.
//
// Returns: Plugins installed for the session, with their enabled state and version metadata.
-func (a *PluginsApi) List(ctx context.Context) (*PluginList, error) {
+func (a *PluginsAPI) List(ctx context.Context) (*PluginList, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.plugins.list", req)
if err != nil {
@@ -11216,13 +11535,13 @@ func (a *PluginsApi) List(ctx context.Context) (*PluginList, error) {
return &result, nil
}
-// Experimental: QueueApi contains experimental APIs that may change or be removed.
-type QueueApi sessionApi
+// Experimental: QueueAPI contains experimental APIs that may change or be removed.
+type QueueAPI sessionAPI
// Clears all pending queued items on the local session.
//
// RPC method: session.queue.clear.
-func (a *QueueApi) Clear(ctx context.Context) (*SessionQueueClearResult, error) {
+func (a *QueueAPI) Clear(ctx context.Context) (*SessionQueueClearResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.queue.clear", req)
if err != nil {
@@ -11241,7 +11560,7 @@ func (a *QueueApi) Clear(ctx context.Context) (*SessionQueueClearResult, error)
// RPC method: session.queue.pendingItems.
//
// Returns: Snapshot of the session's pending queued items and immediate-steering messages.
-func (a *QueueApi) PendingItems(ctx context.Context) (*QueuePendingItemsResult, error) {
+func (a *QueueAPI) PendingItems(ctx context.Context) (*QueuePendingItemsResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.queue.pendingItems", req)
if err != nil {
@@ -11259,7 +11578,7 @@ func (a *QueueApi) PendingItems(ctx context.Context) (*QueuePendingItemsResult,
// RPC method: session.queue.removeMostRecent.
//
// Returns: Indicates whether a user-facing pending item was removed.
-func (a *QueueApi) RemoveMostRecent(ctx context.Context) (*QueueRemoveMostRecentResult, error) {
+func (a *QueueAPI) RemoveMostRecent(ctx context.Context) (*QueueRemoveMostRecentResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.queue.removeMostRecent", req)
if err != nil {
@@ -11272,13 +11591,13 @@ func (a *QueueApi) RemoveMostRecent(ctx context.Context) (*QueueRemoveMostRecent
return &result, nil
}
-// Experimental: RemoteApi contains experimental APIs that may change or be removed.
-type RemoteApi sessionApi
+// Experimental: RemoteAPI contains experimental APIs that may change or be removed.
+type RemoteAPI sessionAPI
// Disables remote session export and steering.
//
// RPC method: session.remote.disable.
-func (a *RemoteApi) Disable(ctx context.Context) (*SessionRemoteDisableResult, error) {
+func (a *RemoteAPI) Disable(ctx context.Context) (*SessionRemoteDisableResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.remote.disable", req)
if err != nil {
@@ -11300,7 +11619,7 @@ func (a *RemoteApi) Disable(ctx context.Context) (*SessionRemoteDisableResult, e
//
// Returns: GitHub URL for the session and a flag indicating whether remote steering is
// enabled.
-func (a *RemoteApi) Enable(ctx context.Context, params *RemoteEnableRequest) (*RemoteEnableResult, error) {
+func (a *RemoteAPI) Enable(ctx context.Context, params *RemoteEnableRequest) (*RemoteEnableResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
if params.Mode != nil {
@@ -11329,7 +11648,7 @@ func (a *RemoteApi) Enable(ctx context.Context, params *RemoteEnableRequest) (*R
// Returns: Persist a steerability change as a `session.remote_steerable_changed` event.
// Used by the host (CLI / SDK consumer) when it has just finished enabling or disabling
// steering on a remote exporter that the runtime does not directly own.
-func (a *RemoteApi) NotifySteerableChanged(ctx context.Context, params *RemoteNotifySteerableChangedRequest) (*RemoteNotifySteerableChangedResult, error) {
+func (a *RemoteAPI) NotifySteerableChanged(ctx context.Context, params *RemoteNotifySteerableChangedRequest) (*RemoteNotifySteerableChangedResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["remoteSteerable"] = params.RemoteSteerable
@@ -11345,15 +11664,15 @@ func (a *RemoteApi) NotifySteerableChanged(ctx context.Context, params *RemoteNo
return &result, nil
}
-// Experimental: ScheduleApi contains experimental APIs that may change or be removed.
-type ScheduleApi sessionApi
+// Experimental: ScheduleAPI contains experimental APIs that may change or be removed.
+type ScheduleAPI sessionAPI
// Lists the session's currently active scheduled prompts.
//
// RPC method: session.schedule.list.
//
// Returns: Snapshot of the currently active recurring prompts for this session.
-func (a *ScheduleApi) List(ctx context.Context) (*ScheduleList, error) {
+func (a *ScheduleAPI) List(ctx context.Context) (*ScheduleList, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.schedule.list", req)
if err != nil {
@@ -11374,7 +11693,7 @@ func (a *ScheduleApi) List(ctx context.Context) (*ScheduleList, error) {
//
// Returns: Remove a scheduled prompt by id. The result entry is omitted if the id was
// unknown.
-func (a *ScheduleApi) Stop(ctx context.Context, params *ScheduleStopRequest) (*ScheduleStopResult, error) {
+func (a *ScheduleAPI) Stop(ctx context.Context, params *ScheduleStopRequest) (*ScheduleStopResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["id"] = params.ID
@@ -11390,8 +11709,8 @@ func (a *ScheduleApi) Stop(ctx context.Context, params *ScheduleStopRequest) (*S
return &result, nil
}
-// Experimental: ShellApi contains experimental APIs that may change or be removed.
-type ShellApi sessionApi
+// Experimental: ShellAPI contains experimental APIs that may change or be removed.
+type ShellAPI sessionAPI
// Exec starts a shell command and streams output through session notifications.
//
@@ -11402,7 +11721,7 @@ type ShellApi sessionApi
//
// Returns: Identifier of the spawned process, used to correlate streamed output and exit
// notifications.
-func (a *ShellApi) Exec(ctx context.Context, params *ShellExecRequest) (*ShellExecResult, error) {
+func (a *ShellAPI) Exec(ctx context.Context, params *ShellExecRequest) (*ShellExecResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["command"] = params.Command
@@ -11433,7 +11752,7 @@ func (a *ShellApi) Exec(ctx context.Context, params *ShellExecRequest) (*ShellEx
//
// Returns: Indicates whether the signal was delivered; false if the process was unknown or
// already exited.
-func (a *ShellApi) Kill(ctx context.Context, params *ShellKillRequest) (*ShellKillResult, error) {
+func (a *ShellAPI) Kill(ctx context.Context, params *ShellKillRequest) (*ShellKillResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["processId"] = params.ProcessID
@@ -11452,15 +11771,15 @@ func (a *ShellApi) Kill(ctx context.Context, params *ShellKillRequest) (*ShellKi
return &result, nil
}
-// Experimental: SkillsApi contains experimental APIs that may change or be removed.
-type SkillsApi sessionApi
+// Experimental: SkillsAPI contains experimental APIs that may change or be removed.
+type SkillsAPI sessionAPI
// Disables a skill for the session.
//
// RPC method: session.skills.disable.
//
// Parameters: Name of the skill to disable for the session.
-func (a *SkillsApi) Disable(ctx context.Context, params *SkillsDisableRequest) (*SessionSkillsDisableResult, error) {
+func (a *SkillsAPI) Disable(ctx context.Context, params *SkillsDisableRequest) (*SessionSkillsDisableResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["name"] = params.Name
@@ -11481,7 +11800,7 @@ func (a *SkillsApi) Disable(ctx context.Context, params *SkillsDisableRequest) (
// RPC method: session.skills.enable.
//
// Parameters: Name of the skill to enable for the session.
-func (a *SkillsApi) Enable(ctx context.Context, params *SkillsEnableRequest) (*SessionSkillsEnableResult, error) {
+func (a *SkillsAPI) Enable(ctx context.Context, params *SkillsEnableRequest) (*SessionSkillsEnableResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["name"] = params.Name
@@ -11500,7 +11819,7 @@ func (a *SkillsApi) Enable(ctx context.Context, params *SkillsEnableRequest) (*S
// EnsureLoaded ensures the session's skill definitions have been loaded from disk.
//
// RPC method: session.skills.ensureLoaded.
-func (a *SkillsApi) EnsureLoaded(ctx context.Context) (*SessionSkillsEnsureLoadedResult, error) {
+func (a *SkillsAPI) EnsureLoaded(ctx context.Context) (*SessionSkillsEnsureLoadedResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.skills.ensureLoaded", req)
if err != nil {
@@ -11519,7 +11838,7 @@ func (a *SkillsApi) EnsureLoaded(ctx context.Context) (*SessionSkillsEnsureLoade
//
// Returns: Skills invoked during this session, ordered by invocation time (most recent
// last).
-func (a *SkillsApi) GetInvoked(ctx context.Context) (*SkillsGetInvokedResult, error) {
+func (a *SkillsAPI) GetInvoked(ctx context.Context) (*SkillsGetInvokedResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.skills.getInvoked", req)
if err != nil {
@@ -11537,7 +11856,7 @@ func (a *SkillsApi) GetInvoked(ctx context.Context) (*SkillsGetInvokedResult, er
// RPC method: session.skills.list.
//
// Returns: Skills available to the session, with their enabled state.
-func (a *SkillsApi) List(ctx context.Context) (*SkillList, error) {
+func (a *SkillsAPI) List(ctx context.Context) (*SkillList, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.skills.list", req)
if err != nil {
@@ -11556,7 +11875,7 @@ func (a *SkillsApi) List(ctx context.Context) (*SkillList, error) {
//
// Returns: Diagnostics from reloading skill definitions, with warnings and errors as
// separate lists.
-func (a *SkillsApi) Reload(ctx context.Context) (*SkillsLoadDiagnostics, error) {
+func (a *SkillsAPI) Reload(ctx context.Context) (*SkillsLoadDiagnostics, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.skills.reload", req)
if err != nil {
@@ -11569,8 +11888,8 @@ func (a *SkillsApi) Reload(ctx context.Context) (*SkillsLoadDiagnostics, error)
return &result, nil
}
-// Experimental: TasksApi contains experimental APIs that may change or be removed.
-type TasksApi sessionApi
+// Experimental: TasksAPI contains experimental APIs that may change or be removed.
+type TasksAPI sessionAPI
// Cancels a background task.
//
@@ -11579,7 +11898,7 @@ type TasksApi sessionApi
// Parameters: Identifier of the background task to cancel.
//
// Returns: Indicates whether the background task was successfully cancelled.
-func (a *TasksApi) Cancel(ctx context.Context, params *TasksCancelRequest) (*TasksCancelResult, error) {
+func (a *TasksAPI) Cancel(ctx context.Context, params *TasksCancelRequest) (*TasksCancelResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["id"] = params.ID
@@ -11601,7 +11920,7 @@ func (a *TasksApi) Cancel(ctx context.Context, params *TasksCancelRequest) (*Tas
// RPC method: session.tasks.getCurrentPromotable.
//
// Returns: The first sync-waiting task that can currently be promoted to background mode.
-func (a *TasksApi) GetCurrentPromotable(ctx context.Context) (*TasksGetCurrentPromotableResult, error) {
+func (a *TasksAPI) GetCurrentPromotable(ctx context.Context) (*TasksGetCurrentPromotableResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.tasks.getCurrentPromotable", req)
if err != nil {
@@ -11621,7 +11940,7 @@ func (a *TasksApi) GetCurrentPromotable(ctx context.Context) (*TasksGetCurrentPr
// Parameters: Identifier of the background task to fetch progress for.
//
// Returns: Progress information for the task, or null when no task with that ID is tracked.
-func (a *TasksApi) GetProgress(ctx context.Context, params *TasksGetProgressRequest) (*TasksGetProgressResult, error) {
+func (a *TasksAPI) GetProgress(ctx context.Context, params *TasksGetProgressRequest) (*TasksGetProgressResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["id"] = params.ID
@@ -11642,7 +11961,7 @@ func (a *TasksApi) GetProgress(ctx context.Context, params *TasksGetProgressRequ
// RPC method: session.tasks.list.
//
// Returns: Background tasks currently tracked by the session.
-func (a *TasksApi) List(ctx context.Context) (*TaskList, error) {
+func (a *TasksAPI) List(ctx context.Context) (*TaskList, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.tasks.list", req)
if err != nil {
@@ -11662,7 +11981,7 @@ func (a *TasksApi) List(ctx context.Context) (*TaskList, error) {
//
// Returns: The promoted task as it now exists in background mode, omitted if no promotable
// task was waiting.
-func (a *TasksApi) PromoteCurrentToBackground(ctx context.Context) (*TasksPromoteCurrentToBackgroundResult, error) {
+func (a *TasksAPI) PromoteCurrentToBackground(ctx context.Context) (*TasksPromoteCurrentToBackgroundResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.tasks.promoteCurrentToBackground", req)
if err != nil {
@@ -11683,7 +12002,7 @@ func (a *TasksApi) PromoteCurrentToBackground(ctx context.Context) (*TasksPromot
// Parameters: Identifier of the task to promote to background mode.
//
// Returns: Indicates whether the task was successfully promoted to background mode.
-func (a *TasksApi) PromoteToBackground(ctx context.Context, params *TasksPromoteToBackgroundRequest) (*TasksPromoteToBackgroundResult, error) {
+func (a *TasksAPI) PromoteToBackground(ctx context.Context, params *TasksPromoteToBackgroundRequest) (*TasksPromoteToBackgroundResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["id"] = params.ID
@@ -11705,7 +12024,7 @@ func (a *TasksApi) PromoteToBackground(ctx context.Context, params *TasksPromote
//
// Returns: Refresh metadata for any detached background shells the runtime knows about. Use
// after a long pause to pick up exit/output state for shells running outside the agent loop.
-func (a *TasksApi) Refresh(ctx context.Context) (*TasksRefreshResult, error) {
+func (a *TasksAPI) Refresh(ctx context.Context) (*TasksRefreshResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.tasks.refresh", req)
if err != nil {
@@ -11726,7 +12045,7 @@ func (a *TasksApi) Refresh(ctx context.Context) (*TasksRefreshResult, error) {
//
// Returns: Indicates whether the task was removed. False when the task does not exist or is
// still running/idle.
-func (a *TasksApi) Remove(ctx context.Context, params *TasksRemoveRequest) (*TasksRemoveResult, error) {
+func (a *TasksAPI) Remove(ctx context.Context, params *TasksRemoveRequest) (*TasksRemoveResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["id"] = params.ID
@@ -11751,7 +12070,7 @@ func (a *TasksApi) Remove(ctx context.Context, params *TasksRemoveRequest) (*Tas
//
// Returns: Indicates whether the message was delivered, with an error message when delivery
// failed.
-func (a *TasksApi) SendMessage(ctx context.Context, params *TasksSendMessageRequest) (*TasksSendMessageResult, error) {
+func (a *TasksAPI) SendMessage(ctx context.Context, params *TasksSendMessageRequest) (*TasksSendMessageResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
if params.FromAgentID != nil {
@@ -11779,7 +12098,7 @@ func (a *TasksApi) SendMessage(ctx context.Context, params *TasksSendMessageRequ
// new task.
//
// Returns: Identifier assigned to the newly started background agent task.
-func (a *TasksApi) StartAgent(ctx context.Context, params *TasksStartAgentRequest) (*TasksStartAgentResult, error) {
+func (a *TasksAPI) StartAgent(ctx context.Context, params *TasksStartAgentRequest) (*TasksStartAgentResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["agentType"] = params.AgentType
@@ -11811,7 +12130,7 @@ func (a *TasksApi) StartAgent(ctx context.Context, params *TasksStartAgentReques
// turns scheduled by their completions have settled. Returns when the runtime is fully
// drained or after an internal timeout (default 10 minutes; configurable via
// COPILOT_TASK_WAIT_TIMEOUT_SECONDS).
-func (a *TasksApi) WaitForPending(ctx context.Context) (*TasksWaitForPendingResult, error) {
+func (a *TasksAPI) WaitForPending(ctx context.Context) (*TasksWaitForPendingResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.tasks.waitForPending", req)
if err != nil {
@@ -11824,8 +12143,8 @@ func (a *TasksApi) WaitForPending(ctx context.Context) (*TasksWaitForPendingResu
return &result, nil
}
-// Experimental: TelemetryApi contains experimental APIs that may change or be removed.
-type TelemetryApi sessionApi
+// Experimental: TelemetryAPI contains experimental APIs that may change or be removed.
+type TelemetryAPI sessionAPI
// SetFeatureOverrides sets feature override key/value pairs to attach to subsequent
// telemetry events for the session.
@@ -11834,7 +12153,7 @@ type TelemetryApi sessionApi
//
// Parameters: Feature override key/value pairs to attach to subsequent telemetry events
// from this session.
-func (a *TelemetryApi) SetFeatureOverrides(ctx context.Context, params *TelemetrySetFeatureOverridesRequest) (*SessionTelemetrySetFeatureOverridesResult, error) {
+func (a *TelemetryAPI) SetFeatureOverrides(ctx context.Context, params *TelemetrySetFeatureOverridesRequest) (*SessionTelemetrySetFeatureOverridesResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["features"] = params.Features
@@ -11850,8 +12169,8 @@ func (a *TelemetryApi) SetFeatureOverrides(ctx context.Context, params *Telemetr
return &result, nil
}
-// Experimental: ToolsApi contains experimental APIs that may change or be removed.
-type ToolsApi sessionApi
+// Experimental: ToolsAPI contains experimental APIs that may change or be removed.
+type ToolsAPI sessionAPI
// GetCurrentMetadata returns lightweight metadata for the session's currently initialized
// tools.
@@ -11859,7 +12178,7 @@ type ToolsApi sessionApi
// RPC method: session.tools.getCurrentMetadata.
//
// Returns: Current lightweight tool metadata snapshot for the session.
-func (a *ToolsApi) GetCurrentMetadata(ctx context.Context) (*ToolsGetCurrentMetadataResult, error) {
+func (a *ToolsAPI) GetCurrentMetadata(ctx context.Context) (*ToolsGetCurrentMetadataResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.tools.getCurrentMetadata", req)
if err != nil {
@@ -11880,7 +12199,7 @@ func (a *ToolsApi) GetCurrentMetadata(ctx context.Context) (*ToolsGetCurrentMeta
// describing why it failed.
//
// Returns: Indicates whether the external tool call result was handled successfully.
-func (a *ToolsApi) HandlePendingToolCall(ctx context.Context, params *HandlePendingToolCallRequest) (*HandlePendingToolCallResult, error) {
+func (a *ToolsAPI) HandlePendingToolCall(ctx context.Context, params *HandlePendingToolCallRequest) (*HandlePendingToolCallResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
if params.Error != nil {
@@ -11911,7 +12230,7 @@ func (a *ToolsApi) HandlePendingToolCall(ctx context.Context, params *HandlePend
// sessions and consumer flows that need an initialized tool set before `send` invoke this.
// Default base-class implementation is a no-op for sessions that don't support tool
// validation.
-func (a *ToolsApi) InitializeAndValidate(ctx context.Context) (*ToolsInitializeAndValidateResult, error) {
+func (a *ToolsAPI) InitializeAndValidate(ctx context.Context) (*ToolsInitializeAndValidateResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.tools.initializeAndValidate", req)
if err != nil {
@@ -11924,8 +12243,8 @@ func (a *ToolsApi) InitializeAndValidate(ctx context.Context) (*ToolsInitializeA
return &result, nil
}
-// Experimental: UIApi contains experimental APIs that may change or be removed.
-type UIApi sessionApi
+// Experimental: UIAPI contains experimental APIs that may change or be removed.
+type UIAPI sessionAPI
// Elicitation requests structured input from a UI-capable client.
//
@@ -11935,7 +12254,7 @@ type UIApi sessionApi
// user.
//
// Returns: The elicitation response (accept with form values, decline, or cancel)
-func (a *UIApi) Elicitation(ctx context.Context, params *UIElicitationRequest) (*UIElicitationResponse, error) {
+func (a *UIAPI) Elicitation(ctx context.Context, params *UIElicitationRequest) (*UIElicitationResponse, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["message"] = params.Message
@@ -11961,7 +12280,7 @@ func (a *UIApi) Elicitation(ctx context.Context, params *UIElicitationRequest) (
// response.
//
// Returns: Indicates whether the pending UI request was resolved by this call.
-func (a *UIApi) HandlePendingAutoModeSwitch(ctx context.Context, params *UIHandlePendingAutoModeSwitchRequest) (*UIHandlePendingResult, error) {
+func (a *UIAPI) HandlePendingAutoModeSwitch(ctx context.Context, params *UIHandlePendingAutoModeSwitchRequest) (*UIHandlePendingResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["requestId"] = params.RequestID
@@ -11987,7 +12306,7 @@ func (a *UIApi) HandlePendingAutoModeSwitch(ctx context.Context, params *UIHandl
//
// Returns: Indicates whether the elicitation response was accepted; false if it was already
// resolved by another client.
-func (a *UIApi) HandlePendingElicitation(ctx context.Context, params *UIHandlePendingElicitationRequest) (*UIElicitationResult, error) {
+func (a *UIAPI) HandlePendingElicitation(ctx context.Context, params *UIHandlePendingElicitationRequest) (*UIElicitationResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["requestId"] = params.RequestID
@@ -12013,7 +12332,7 @@ func (a *UIApi) HandlePendingElicitation(ctx context.Context, params *UIHandlePe
// response.
//
// Returns: Indicates whether the pending UI request was resolved by this call.
-func (a *UIApi) HandlePendingExitPlanMode(ctx context.Context, params *UIHandlePendingExitPlanModeRequest) (*UIHandlePendingResult, error) {
+func (a *UIAPI) HandlePendingExitPlanMode(ctx context.Context, params *UIHandlePendingExitPlanModeRequest) (*UIHandlePendingResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["requestId"] = params.RequestID
@@ -12039,7 +12358,7 @@ func (a *UIApi) HandlePendingExitPlanMode(ctx context.Context, params *UIHandleP
// result payload (omit to reject).
//
// Returns: Indicates whether the pending UI request was resolved by this call.
-func (a *UIApi) HandlePendingSampling(ctx context.Context, params *UIHandlePendingSamplingRequest) (*UIHandlePendingResult, error) {
+func (a *UIAPI) HandlePendingSampling(ctx context.Context, params *UIHandlePendingSamplingRequest) (*UIHandlePendingResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["requestId"] = params.RequestID
@@ -12066,7 +12385,7 @@ func (a *UIApi) HandlePendingSampling(ctx context.Context, params *UIHandlePendi
// Parameters: Request ID of a pending `user_input.requested` event and the user's response.
//
// Returns: Indicates whether the pending UI request was resolved by this call.
-func (a *UIApi) HandlePendingUserInput(ctx context.Context, params *UIHandlePendingUserInputRequest) (*UIHandlePendingResult, error) {
+func (a *UIAPI) HandlePendingUserInput(ctx context.Context, params *UIHandlePendingUserInputRequest) (*UIHandlePendingResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["requestId"] = params.RequestID
@@ -12092,7 +12411,7 @@ func (a *UIApi) HandlePendingUserInput(ctx context.Context, params *UIHandlePend
// caller still attaches the actual listener via the standard event-subscription mechanism;
// this registration solely tells the server bridge to skip its own dispatch (so a remote
// client doesn't race the in-process handler for the same requestId).
-func (a *UIApi) RegisterDirectAutoModeSwitchHandler(ctx context.Context) (*UIRegisterDirectAutoModeSwitchHandlerResult, error) {
+func (a *UIAPI) RegisterDirectAutoModeSwitchHandler(ctx context.Context) (*UIRegisterDirectAutoModeSwitchHandlerResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.ui.registerDirectAutoModeSwitchHandler", req)
if err != nil {
@@ -12115,7 +12434,7 @@ func (a *UIApi) RegisterDirectAutoModeSwitchHandler(ctx context.Context) (*UIReg
//
// Returns: Indicates whether the handle was active and the registration count was
// decremented.
-func (a *UIApi) UnregisterDirectAutoModeSwitchHandler(ctx context.Context, params *UIUnregisterDirectAutoModeSwitchHandlerRequest) (*UIUnregisterDirectAutoModeSwitchHandlerResult, error) {
+func (a *UIAPI) UnregisterDirectAutoModeSwitchHandler(ctx context.Context, params *UIUnregisterDirectAutoModeSwitchHandlerRequest) (*UIUnregisterDirectAutoModeSwitchHandlerResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["handle"] = params.Handle
@@ -12131,8 +12450,8 @@ func (a *UIApi) UnregisterDirectAutoModeSwitchHandler(ctx context.Context, param
return &result, nil
}
-// Experimental: UsageApi contains experimental APIs that may change or be removed.
-type UsageApi sessionApi
+// Experimental: UsageAPI contains experimental APIs that may change or be removed.
+type UsageAPI sessionAPI
// GetMetrics gets accumulated usage metrics for the session.
//
@@ -12140,7 +12459,7 @@ type UsageApi sessionApi
//
// Returns: Accumulated session usage metrics, including premium request cost, token counts,
// model breakdown, and code-change totals.
-func (a *UsageApi) GetMetrics(ctx context.Context) (*UsageGetMetricsResult, error) {
+func (a *UsageAPI) GetMetrics(ctx context.Context) (*UsageGetMetricsResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.usage.getMetrics", req)
if err != nil {
@@ -12153,15 +12472,15 @@ func (a *UsageApi) GetMetrics(ctx context.Context) (*UsageGetMetricsResult, erro
return &result, nil
}
-// Experimental: WorkspacesApi contains experimental APIs that may change or be removed.
-type WorkspacesApi sessionApi
+// Experimental: WorkspacesAPI contains experimental APIs that may change or be removed.
+type WorkspacesAPI sessionAPI
// CreateFile creates or overwrites a file in the session workspace files directory.
//
// RPC method: session.workspaces.createFile.
//
// Parameters: Relative path and UTF-8 content for the workspace file to create or overwrite.
-func (a *WorkspacesApi) CreateFile(ctx context.Context, params *WorkspacesCreateFileRequest) (*SessionWorkspacesCreateFileResult, error) {
+func (a *WorkspacesAPI) CreateFile(ctx context.Context, params *WorkspacesCreateFileRequest) (*SessionWorkspacesCreateFileResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["content"] = params.Content
@@ -12185,7 +12504,7 @@ func (a *WorkspacesApi) CreateFile(ctx context.Context, params *WorkspacesCreate
// Parameters: Parameters for computing a workspace diff.
//
// Returns: Workspace diff result for the requested mode.
-func (a *WorkspacesApi) Diff(ctx context.Context, params *WorkspacesDiffRequest) (*WorkspaceDiffResult, error) {
+func (a *WorkspacesAPI) Diff(ctx context.Context, params *WorkspacesDiffRequest) (*WorkspaceDiffResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["mode"] = params.Mode
@@ -12207,7 +12526,7 @@ func (a *WorkspacesApi) Diff(ctx context.Context, params *WorkspacesDiffRequest)
//
// Returns: Current workspace metadata for the session, including its absolute filesystem
// path when available.
-func (a *WorkspacesApi) GetWorkspace(ctx context.Context) (*WorkspacesGetWorkspaceResult, error) {
+func (a *WorkspacesAPI) GetWorkspace(ctx context.Context) (*WorkspacesGetWorkspaceResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.workspaces.getWorkspace", req)
if err != nil {
@@ -12226,7 +12545,7 @@ func (a *WorkspacesApi) GetWorkspace(ctx context.Context) (*WorkspacesGetWorkspa
//
// Returns: Workspace checkpoints in chronological order; empty when the workspace is not
// enabled.
-func (a *WorkspacesApi) ListCheckpoints(ctx context.Context) (*WorkspacesListCheckpointsResult, error) {
+func (a *WorkspacesAPI) ListCheckpoints(ctx context.Context) (*WorkspacesListCheckpointsResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.workspaces.listCheckpoints", req)
if err != nil {
@@ -12244,7 +12563,7 @@ func (a *WorkspacesApi) ListCheckpoints(ctx context.Context) (*WorkspacesListChe
// RPC method: session.workspaces.listFiles.
//
// Returns: Relative paths of files stored in the session workspace files directory.
-func (a *WorkspacesApi) ListFiles(ctx context.Context) (*WorkspacesListFilesResult, error) {
+func (a *WorkspacesAPI) ListFiles(ctx context.Context) (*WorkspacesListFilesResult, error) {
req := map[string]any{"sessionId": a.sessionID}
raw, err := a.client.Request("session.workspaces.listFiles", req)
if err != nil {
@@ -12265,7 +12584,7 @@ func (a *WorkspacesApi) ListFiles(ctx context.Context) (*WorkspacesListFilesResu
//
// Returns: Checkpoint content as a UTF-8 string, or null when the checkpoint or workspace
// is missing.
-func (a *WorkspacesApi) ReadCheckpoint(ctx context.Context, params *WorkspacesReadCheckpointRequest) (*WorkspacesReadCheckpointResult, error) {
+func (a *WorkspacesAPI) ReadCheckpoint(ctx context.Context, params *WorkspacesReadCheckpointRequest) (*WorkspacesReadCheckpointResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["number"] = params.Number
@@ -12288,7 +12607,7 @@ func (a *WorkspacesApi) ReadCheckpoint(ctx context.Context, params *WorkspacesRe
// Parameters: Relative path of the workspace file to read.
//
// Returns: Contents of the requested workspace file as a UTF-8 string.
-func (a *WorkspacesApi) ReadFile(ctx context.Context, params *WorkspacesReadFileRequest) (*WorkspacesReadFileResult, error) {
+func (a *WorkspacesAPI) ReadFile(ctx context.Context, params *WorkspacesReadFileRequest) (*WorkspacesReadFileResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["path"] = params.Path
@@ -12311,7 +12630,7 @@ func (a *WorkspacesApi) ReadFile(ctx context.Context, params *WorkspacesReadFile
// Parameters: Pasted content to save as a UTF-8 file in the session workspace.
//
// Returns: Descriptor for the saved paste file, or null when the workspace is unavailable.
-func (a *WorkspacesApi) SaveLargePaste(ctx context.Context, params *WorkspacesSaveLargePasteRequest) (*WorkspacesSaveLargePasteResult, error) {
+func (a *WorkspacesAPI) SaveLargePaste(ctx context.Context, params *WorkspacesSaveLargePasteRequest) (*WorkspacesSaveLargePasteResult, error) {
req := map[string]any{"sessionId": a.sessionID}
if params != nil {
req["content"] = params.Content
@@ -12327,41 +12646,41 @@ func (a *WorkspacesApi) SaveLargePaste(ctx context.Context, params *WorkspacesSa
return &result, nil
}
-// SessionRpc provides typed session-scoped RPC methods.
-type SessionRpc struct {
+// SessionRPC provides typed session-scoped RPC methods.
+type SessionRPC struct {
// Reuse a single struct instead of allocating one for each service on the heap.
- common sessionApi
-
- Agent *AgentApi
- Auth *AuthApi
- Canvas *CanvasApi
- Commands *CommandsApi
- EventLog *EventLogApi
- Extensions *ExtensionsApi
- Fleet *FleetApi
- History *HistoryApi
- Instructions *InstructionsApi
- Lsp *LspApi
- Mcp *McpApi
- Metadata *MetadataApi
- Mode *ModeApi
- Model *ModelApi
- Name *NameApi
- Options *OptionsApi
- Permissions *PermissionsApi
- Plan *PlanApi
- Plugins *PluginsApi
- Queue *QueueApi
- Remote *RemoteApi
- Schedule *ScheduleApi
- Shell *ShellApi
- Skills *SkillsApi
- Tasks *TasksApi
- Telemetry *TelemetryApi
- Tools *ToolsApi
- UI *UIApi
- Usage *UsageApi
- Workspaces *WorkspacesApi
+ common sessionAPI
+
+ Agent *AgentAPI
+ Auth *AuthAPI
+ Canvas *CanvasAPI
+ Commands *CommandsAPI
+ EventLog *EventLogAPI
+ Extensions *ExtensionsAPI
+ Fleet *FleetAPI
+ History *HistoryAPI
+ Instructions *InstructionsAPI
+ Lsp *LspAPI
+ MCP *MCPAPI
+ Metadata *MetadataAPI
+ Mode *ModeAPI
+ Model *ModelAPI
+ Name *NameAPI
+ Options *OptionsAPI
+ Permissions *PermissionsAPI
+ Plan *PlanAPI
+ Plugins *PluginsAPI
+ Queue *QueueAPI
+ Remote *RemoteAPI
+ Schedule *ScheduleAPI
+ Shell *ShellAPI
+ Skills *SkillsAPI
+ Tasks *TasksAPI
+ Telemetry *TelemetryAPI
+ Tools *ToolsAPI
+ UI *UIAPI
+ Usage *UsageAPI
+ Workspaces *WorkspacesAPI
}
// Aborts the current agent turn.
@@ -12373,7 +12692,7 @@ type SessionRpc struct {
// Returns: Result of aborting the current turn
// Experimental: Abort is an experimental API and may change or be removed in future
// versions.
-func (a *SessionRpc) Abort(ctx context.Context, params *AbortRequest) (*AbortResult, error) {
+func (a *SessionRPC) Abort(ctx context.Context, params *AbortRequest) (*AbortResult, error) {
req := map[string]any{"sessionId": a.common.sessionID}
if params != nil {
if params.Reason != nil {
@@ -12400,7 +12719,7 @@ func (a *SessionRpc) Abort(ctx context.Context, params *AbortRequest) (*AbortRes
//
// Returns: Identifier of the session event that was emitted for the log message.
// Experimental: Log is an experimental API and may change or be removed in future versions.
-func (a *SessionRpc) Log(ctx context.Context, params *LogRequest) (*LogResult, error) {
+func (a *SessionRPC) Log(ctx context.Context, params *LogRequest) (*LogResult, error) {
req := map[string]any{"sessionId": a.common.sessionID}
if params != nil {
if params.Ephemeral != nil {
@@ -12439,7 +12758,7 @@ func (a *SessionRpc) Log(ctx context.Context, params *LogRequest) (*LogResult, e
//
// Returns: Result of sending a user message
// Experimental: Send is an experimental API and may change or be removed in future versions.
-func (a *SessionRpc) Send(ctx context.Context, params *SendRequest) (*SendResult, error) {
+func (a *SessionRPC) Send(ctx context.Context, params *SendRequest) (*SendResult, error) {
req := map[string]any{"sessionId": a.common.sessionID}
if params != nil {
if params.AgentMode != nil {
@@ -12500,7 +12819,7 @@ func (a *SessionRpc) Send(ctx context.Context, params *SendRequest) (*SendResult
// Parameters: Parameters for shutting down the session
// Experimental: Shutdown is an experimental API and may change or be removed in future
// versions.
-func (a *SessionRpc) Shutdown(ctx context.Context, params *ShutdownRequest) (*SessionShutdownResult, error) {
+func (a *SessionRPC) Shutdown(ctx context.Context, params *ShutdownRequest) (*SessionShutdownResult, error) {
req := map[string]any{"sessionId": a.common.sessionID}
if params != nil {
if params.Reason != nil {
@@ -12526,7 +12845,7 @@ func (a *SessionRpc) Shutdown(ctx context.Context, params *ShutdownRequest) (*Se
// RPC method: session.suspend.
// Experimental: Suspend is an experimental API and may change or be removed in future
// versions.
-func (a *SessionRpc) Suspend(ctx context.Context) (*SessionSuspendResult, error) {
+func (a *SessionRPC) Suspend(ctx context.Context) (*SessionSuspendResult, error) {
req := map[string]any{"sessionId": a.common.sessionID}
raw, err := a.common.client.Request("session.suspend", req)
if err != nil {
@@ -12539,39 +12858,39 @@ func (a *SessionRpc) Suspend(ctx context.Context) (*SessionSuspendResult, error)
return &result, nil
}
-func NewSessionRpc(client *jsonrpc2.Client, sessionID string) *SessionRpc {
- r := &SessionRpc{}
- r.common = sessionApi{client: client, sessionID: sessionID}
- r.Agent = (*AgentApi)(&r.common)
- r.Auth = (*AuthApi)(&r.common)
- r.Canvas = (*CanvasApi)(&r.common)
- r.Commands = (*CommandsApi)(&r.common)
- r.EventLog = (*EventLogApi)(&r.common)
- r.Extensions = (*ExtensionsApi)(&r.common)
- r.Fleet = (*FleetApi)(&r.common)
- r.History = (*HistoryApi)(&r.common)
- r.Instructions = (*InstructionsApi)(&r.common)
- r.Lsp = (*LspApi)(&r.common)
- r.Mcp = (*McpApi)(&r.common)
- r.Metadata = (*MetadataApi)(&r.common)
- r.Mode = (*ModeApi)(&r.common)
- r.Model = (*ModelApi)(&r.common)
- r.Name = (*NameApi)(&r.common)
- r.Options = (*OptionsApi)(&r.common)
- r.Permissions = (*PermissionsApi)(&r.common)
- r.Plan = (*PlanApi)(&r.common)
- r.Plugins = (*PluginsApi)(&r.common)
- r.Queue = (*QueueApi)(&r.common)
- r.Remote = (*RemoteApi)(&r.common)
- r.Schedule = (*ScheduleApi)(&r.common)
- r.Shell = (*ShellApi)(&r.common)
- r.Skills = (*SkillsApi)(&r.common)
- r.Tasks = (*TasksApi)(&r.common)
- r.Telemetry = (*TelemetryApi)(&r.common)
- r.Tools = (*ToolsApi)(&r.common)
- r.UI = (*UIApi)(&r.common)
- r.Usage = (*UsageApi)(&r.common)
- r.Workspaces = (*WorkspacesApi)(&r.common)
+func NewSessionRPC(client *jsonrpc2.Client, sessionID string) *SessionRPC {
+ r := &SessionRPC{}
+ r.common = sessionAPI{client: client, sessionID: sessionID}
+ r.Agent = (*AgentAPI)(&r.common)
+ r.Auth = (*AuthAPI)(&r.common)
+ r.Canvas = (*CanvasAPI)(&r.common)
+ r.Commands = (*CommandsAPI)(&r.common)
+ r.EventLog = (*EventLogAPI)(&r.common)
+ r.Extensions = (*ExtensionsAPI)(&r.common)
+ r.Fleet = (*FleetAPI)(&r.common)
+ r.History = (*HistoryAPI)(&r.common)
+ r.Instructions = (*InstructionsAPI)(&r.common)
+ r.Lsp = (*LspAPI)(&r.common)
+ r.MCP = (*MCPAPI)(&r.common)
+ r.Metadata = (*MetadataAPI)(&r.common)
+ r.Mode = (*ModeAPI)(&r.common)
+ r.Model = (*ModelAPI)(&r.common)
+ r.Name = (*NameAPI)(&r.common)
+ r.Options = (*OptionsAPI)(&r.common)
+ r.Permissions = (*PermissionsAPI)(&r.common)
+ r.Plan = (*PlanAPI)(&r.common)
+ r.Plugins = (*PluginsAPI)(&r.common)
+ r.Queue = (*QueueAPI)(&r.common)
+ r.Remote = (*RemoteAPI)(&r.common)
+ r.Schedule = (*ScheduleAPI)(&r.common)
+ r.Shell = (*ShellAPI)(&r.common)
+ r.Skills = (*SkillsAPI)(&r.common)
+ r.Tasks = (*TasksAPI)(&r.common)
+ r.Telemetry = (*TelemetryAPI)(&r.common)
+ r.Tools = (*ToolsAPI)(&r.common)
+ r.UI = (*UIAPI)(&r.common)
+ r.Usage = (*UsageAPI)(&r.common)
+ r.Workspaces = (*WorkspacesAPI)(&r.common)
return r
}
@@ -12601,8 +12920,8 @@ type CanvasHandler interface {
Open(request *CanvasProviderOpenRequest) (*CanvasProviderOpenResult, error)
}
-// Experimental: SessionFsHandler contains experimental APIs that may change or be removed.
-type SessionFsHandler interface {
+// Experimental: SessionFSHandler contains experimental APIs that may change or be removed.
+type SessionFSHandler interface {
// AppendFile appends content to a file in the client-provided session filesystem.
//
// RPC method: sessionFs.appendFile.
@@ -12611,7 +12930,7 @@ type SessionFsHandler interface {
// session filesystem.
//
// Returns: Describes a filesystem error.
- AppendFile(request *SessionFsAppendFileRequest) (*SessionFsError, error)
+ AppendFile(request *SessionFSAppendFileRequest) (*SessionFSError, error)
// Exists checks whether a path exists in the client-provided session filesystem.
//
// RPC method: sessionFs.exists.
@@ -12620,7 +12939,7 @@ type SessionFsHandler interface {
//
// Returns: Indicates whether the requested path exists in the client-provided session
// filesystem.
- Exists(request *SessionFsExistsRequest) (*SessionFsExistsResult, error)
+ Exists(request *SessionFSExistsRequest) (*SessionFSExistsResult, error)
// Mkdir creates a directory in the client-provided session filesystem.
//
// RPC method: sessionFs.mkdir.
@@ -12629,7 +12948,7 @@ type SessionFsHandler interface {
// options for recursive creation and POSIX mode.
//
// Returns: Describes a filesystem error.
- Mkdir(request *SessionFsMkdirRequest) (*SessionFsError, error)
+ Mkdir(request *SessionFSMkdirRequest) (*SessionFSError, error)
// Readdir lists entry names in a directory from the client-provided session filesystem.
//
// RPC method: sessionFs.readdir.
@@ -12639,7 +12958,7 @@ type SessionFsHandler interface {
//
// Returns: Names of entries in the requested directory, or a filesystem error if the read
// failed.
- Readdir(request *SessionFsReaddirRequest) (*SessionFsReaddirResult, error)
+ Readdir(request *SessionFSReaddirRequest) (*SessionFSReaddirResult, error)
// ReaddirWithTypes lists directory entries with type information from the client-provided
// session filesystem.
//
@@ -12650,7 +12969,7 @@ type SessionFsHandler interface {
//
// Returns: Entries in the requested directory paired with file/directory type information,
// or a filesystem error if the read failed.
- ReaddirWithTypes(request *SessionFsReaddirWithTypesRequest) (*SessionFsReaddirWithTypesResult, error)
+ ReaddirWithTypes(request *SessionFSReaddirWithTypesRequest) (*SessionFSReaddirWithTypesResult, error)
// ReadFile reads a file from the client-provided session filesystem.
//
// RPC method: sessionFs.readFile.
@@ -12658,7 +12977,7 @@ type SessionFsHandler interface {
// Parameters: Path of the file to read from the client-provided session filesystem.
//
// Returns: File content as a UTF-8 string, or a filesystem error if the read failed.
- ReadFile(request *SessionFsReadFileRequest) (*SessionFsReadFileResult, error)
+ ReadFile(request *SessionFSReadFileRequest) (*SessionFSReadFileResult, error)
// Renames or moves a path in the client-provided session filesystem.
//
// RPC method: sessionFs.rename.
@@ -12667,7 +12986,7 @@ type SessionFsHandler interface {
// client-provided session filesystem.
//
// Returns: Describes a filesystem error.
- Rename(request *SessionFsRenameRequest) (*SessionFsError, error)
+ Rename(request *SessionFSRenameRequest) (*SessionFSError, error)
// Rm removes a file or directory from the client-provided session filesystem.
//
// RPC method: sessionFs.rm.
@@ -12676,7 +12995,7 @@ type SessionFsHandler interface {
// recursive removal and force.
//
// Returns: Describes a filesystem error.
- Rm(request *SessionFsRmRequest) (*SessionFsError, error)
+ Rm(request *SessionFSRmRequest) (*SessionFSError, error)
// SqliteExists checks whether the per-session SQLite database already exists, without
// creating it.
//
@@ -12685,7 +13004,7 @@ type SessionFsHandler interface {
// Parameters: Identifies the target session.
//
// Returns: Indicates whether the per-session SQLite database already exists.
- SqliteExists(request *SessionFsSqliteExistsRequest) (*SessionFsSqliteExistsResult, error)
+ SqliteExists(request *SessionFSSqliteExistsRequest) (*SessionFSSqliteExistsResult, error)
// SqliteQuery executes a SQLite query against the per-session database.
//
// RPC method: sessionFs.sqliteQuery.
@@ -12695,7 +13014,7 @@ type SessionFsHandler interface {
//
// Returns: Query results including rows, columns, and rows affected, or a filesystem error
// if execution failed.
- SqliteQuery(request *SessionFsSqliteQueryRequest) (*SessionFsSqliteQueryResult, error)
+ SqliteQuery(request *SessionFSSqliteQueryRequest) (*SessionFSSqliteQueryResult, error)
// Stat gets metadata for a path in the client-provided session filesystem.
//
// RPC method: sessionFs.stat.
@@ -12705,7 +13024,7 @@ type SessionFsHandler interface {
//
// Returns: Filesystem metadata for the requested path, or a filesystem error if the stat
// failed.
- Stat(request *SessionFsStatRequest) (*SessionFsStatResult, error)
+ Stat(request *SessionFSStatRequest) (*SessionFSStatResult, error)
// WriteFile writes a file in the client-provided session filesystem.
//
// RPC method: sessionFs.writeFile.
@@ -12714,13 +13033,13 @@ type SessionFsHandler interface {
// session filesystem.
//
// Returns: Describes a filesystem error.
- WriteFile(request *SessionFsWriteFileRequest) (*SessionFsError, error)
+ WriteFile(request *SessionFSWriteFileRequest) (*SessionFSError, error)
}
-// ClientSessionApiHandlers provides all client session API handler groups for a session.
-type ClientSessionApiHandlers struct {
+// ClientSessionAPIHandlers provides all client session API handler groups for a session.
+type ClientSessionAPIHandlers struct {
Canvas CanvasHandler
- SessionFs SessionFsHandler
+ SessionFS SessionFSHandler
}
func clientSessionHandlerError(err error) *jsonrpc2.Error {
@@ -12734,9 +13053,9 @@ func clientSessionHandlerError(err error) *jsonrpc2.Error {
return &jsonrpc2.Error{Code: -32603, Message: err.Error()}
}
-// RegisterClientSessionApiHandlers registers handlers for server-to-client session API
+// RegisterClientSessionAPIHandlers registers handlers for server-to-client session API
// calls.
-func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func(sessionID string) *ClientSessionApiHandlers) {
+func RegisterClientSessionAPIHandlers(client *jsonrpc2.Client, getHandlers func(sessionID string) *ClientSessionAPIHandlers) {
client.SetRequestHandler("canvas.close", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
var request CanvasProviderCloseRequest
if err := json.Unmarshal(params, &request); err != nil {
@@ -12795,15 +13114,15 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func(
return raw, nil
})
client.SetRequestHandler("sessionFs.appendFile", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
- var request SessionFsAppendFileRequest
+ var request SessionFSAppendFileRequest
if err := json.Unmarshal(params, &request); err != nil {
return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)}
}
handlers := getHandlers(request.SessionID)
- if handlers == nil || handlers.SessionFs == nil {
+ if handlers == nil || handlers.SessionFS == nil {
return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)}
}
- result, err := handlers.SessionFs.AppendFile(&request)
+ result, err := handlers.SessionFS.AppendFile(&request)
if err != nil {
return nil, clientSessionHandlerError(err)
}
@@ -12814,15 +13133,15 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func(
return raw, nil
})
client.SetRequestHandler("sessionFs.exists", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
- var request SessionFsExistsRequest
+ var request SessionFSExistsRequest
if err := json.Unmarshal(params, &request); err != nil {
return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)}
}
handlers := getHandlers(request.SessionID)
- if handlers == nil || handlers.SessionFs == nil {
+ if handlers == nil || handlers.SessionFS == nil {
return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)}
}
- result, err := handlers.SessionFs.Exists(&request)
+ result, err := handlers.SessionFS.Exists(&request)
if err != nil {
return nil, clientSessionHandlerError(err)
}
@@ -12833,15 +13152,15 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func(
return raw, nil
})
client.SetRequestHandler("sessionFs.mkdir", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
- var request SessionFsMkdirRequest
+ var request SessionFSMkdirRequest
if err := json.Unmarshal(params, &request); err != nil {
return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)}
}
handlers := getHandlers(request.SessionID)
- if handlers == nil || handlers.SessionFs == nil {
+ if handlers == nil || handlers.SessionFS == nil {
return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)}
}
- result, err := handlers.SessionFs.Mkdir(&request)
+ result, err := handlers.SessionFS.Mkdir(&request)
if err != nil {
return nil, clientSessionHandlerError(err)
}
@@ -12852,15 +13171,15 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func(
return raw, nil
})
client.SetRequestHandler("sessionFs.readdir", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
- var request SessionFsReaddirRequest
+ var request SessionFSReaddirRequest
if err := json.Unmarshal(params, &request); err != nil {
return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)}
}
handlers := getHandlers(request.SessionID)
- if handlers == nil || handlers.SessionFs == nil {
+ if handlers == nil || handlers.SessionFS == nil {
return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)}
}
- result, err := handlers.SessionFs.Readdir(&request)
+ result, err := handlers.SessionFS.Readdir(&request)
if err != nil {
return nil, clientSessionHandlerError(err)
}
@@ -12871,15 +13190,15 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func(
return raw, nil
})
client.SetRequestHandler("sessionFs.readdirWithTypes", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
- var request SessionFsReaddirWithTypesRequest
+ var request SessionFSReaddirWithTypesRequest
if err := json.Unmarshal(params, &request); err != nil {
return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)}
}
handlers := getHandlers(request.SessionID)
- if handlers == nil || handlers.SessionFs == nil {
+ if handlers == nil || handlers.SessionFS == nil {
return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)}
}
- result, err := handlers.SessionFs.ReaddirWithTypes(&request)
+ result, err := handlers.SessionFS.ReaddirWithTypes(&request)
if err != nil {
return nil, clientSessionHandlerError(err)
}
@@ -12890,15 +13209,15 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func(
return raw, nil
})
client.SetRequestHandler("sessionFs.readFile", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
- var request SessionFsReadFileRequest
+ var request SessionFSReadFileRequest
if err := json.Unmarshal(params, &request); err != nil {
return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)}
}
handlers := getHandlers(request.SessionID)
- if handlers == nil || handlers.SessionFs == nil {
+ if handlers == nil || handlers.SessionFS == nil {
return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)}
}
- result, err := handlers.SessionFs.ReadFile(&request)
+ result, err := handlers.SessionFS.ReadFile(&request)
if err != nil {
return nil, clientSessionHandlerError(err)
}
@@ -12909,15 +13228,15 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func(
return raw, nil
})
client.SetRequestHandler("sessionFs.rename", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
- var request SessionFsRenameRequest
+ var request SessionFSRenameRequest
if err := json.Unmarshal(params, &request); err != nil {
return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)}
}
handlers := getHandlers(request.SessionID)
- if handlers == nil || handlers.SessionFs == nil {
+ if handlers == nil || handlers.SessionFS == nil {
return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)}
}
- result, err := handlers.SessionFs.Rename(&request)
+ result, err := handlers.SessionFS.Rename(&request)
if err != nil {
return nil, clientSessionHandlerError(err)
}
@@ -12928,15 +13247,15 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func(
return raw, nil
})
client.SetRequestHandler("sessionFs.rm", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
- var request SessionFsRmRequest
+ var request SessionFSRmRequest
if err := json.Unmarshal(params, &request); err != nil {
return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)}
}
handlers := getHandlers(request.SessionID)
- if handlers == nil || handlers.SessionFs == nil {
+ if handlers == nil || handlers.SessionFS == nil {
return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)}
}
- result, err := handlers.SessionFs.Rm(&request)
+ result, err := handlers.SessionFS.Rm(&request)
if err != nil {
return nil, clientSessionHandlerError(err)
}
@@ -12947,15 +13266,15 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func(
return raw, nil
})
client.SetRequestHandler("sessionFs.sqliteExists", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
- var request SessionFsSqliteExistsRequest
+ var request SessionFSSqliteExistsRequest
if err := json.Unmarshal(params, &request); err != nil {
return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)}
}
handlers := getHandlers(request.SessionID)
- if handlers == nil || handlers.SessionFs == nil {
+ if handlers == nil || handlers.SessionFS == nil {
return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)}
}
- result, err := handlers.SessionFs.SqliteExists(&request)
+ result, err := handlers.SessionFS.SqliteExists(&request)
if err != nil {
return nil, clientSessionHandlerError(err)
}
@@ -12966,15 +13285,15 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func(
return raw, nil
})
client.SetRequestHandler("sessionFs.sqliteQuery", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
- var request SessionFsSqliteQueryRequest
+ var request SessionFSSqliteQueryRequest
if err := json.Unmarshal(params, &request); err != nil {
return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)}
}
handlers := getHandlers(request.SessionID)
- if handlers == nil || handlers.SessionFs == nil {
+ if handlers == nil || handlers.SessionFS == nil {
return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)}
}
- result, err := handlers.SessionFs.SqliteQuery(&request)
+ result, err := handlers.SessionFS.SqliteQuery(&request)
if err != nil {
return nil, clientSessionHandlerError(err)
}
@@ -12985,15 +13304,15 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func(
return raw, nil
})
client.SetRequestHandler("sessionFs.stat", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
- var request SessionFsStatRequest
+ var request SessionFSStatRequest
if err := json.Unmarshal(params, &request); err != nil {
return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)}
}
handlers := getHandlers(request.SessionID)
- if handlers == nil || handlers.SessionFs == nil {
+ if handlers == nil || handlers.SessionFS == nil {
return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)}
}
- result, err := handlers.SessionFs.Stat(&request)
+ result, err := handlers.SessionFS.Stat(&request)
if err != nil {
return nil, clientSessionHandlerError(err)
}
@@ -13004,15 +13323,15 @@ func RegisterClientSessionApiHandlers(client *jsonrpc2.Client, getHandlers func(
return raw, nil
})
client.SetRequestHandler("sessionFs.writeFile", func(params json.RawMessage) (json.RawMessage, *jsonrpc2.Error) {
- var request SessionFsWriteFileRequest
+ var request SessionFSWriteFileRequest
if err := json.Unmarshal(params, &request); err != nil {
return nil, &jsonrpc2.Error{Code: -32602, Message: fmt.Sprintf("Invalid params: %v", err)}
}
handlers := getHandlers(request.SessionID)
- if handlers == nil || handlers.SessionFs == nil {
+ if handlers == nil || handlers.SessionFS == nil {
return nil, &jsonrpc2.Error{Code: -32603, Message: fmt.Sprintf("No sessionFs handler registered for session: %s", request.SessionID)}
}
- result, err := handlers.SessionFs.WriteFile(&request)
+ result, err := handlers.SessionFS.WriteFile(&request)
if err != nil {
return nil, clientSessionHandlerError(err)
}
diff --git a/go/rpc/zrpc_encoding.go b/go/rpc/zrpc_encoding.go
index 370a2df91..0d192c600 100644
--- a/go/rpc/zrpc_encoding.go
+++ b/go/rpc/zrpc_encoding.go
@@ -105,6 +105,137 @@ func (r AgentRegistrySpawnValidationError) MarshalJSON() ([]byte, error) {
})
}
+func unmarshalAttachment(data []byte) (Attachment, error) {
+ if string(data) == "null" {
+ return nil, nil
+ }
+ type rawUnion struct {
+ Type AttachmentType `json:"type"`
+ }
+ var raw rawUnion
+ if err := json.Unmarshal(data, &raw); err != nil {
+ return nil, err
+ }
+
+ switch raw.Type {
+ case AttachmentTypeBlob:
+ var d AttachmentBlob
+ if err := json.Unmarshal(data, &d); err != nil {
+ return nil, err
+ }
+ return &d, nil
+ case AttachmentTypeDirectory:
+ var d AttachmentDirectory
+ if err := json.Unmarshal(data, &d); err != nil {
+ return nil, err
+ }
+ return &d, nil
+ case AttachmentTypeExtensionContext:
+ var d AttachmentExtensionContext
+ if err := json.Unmarshal(data, &d); err != nil {
+ return nil, err
+ }
+ return &d, nil
+ case AttachmentTypeFile:
+ var d AttachmentFile
+ if err := json.Unmarshal(data, &d); err != nil {
+ return nil, err
+ }
+ return &d, nil
+ case AttachmentTypeGitHubReference:
+ var d AttachmentGitHubReference
+ if err := json.Unmarshal(data, &d); err != nil {
+ return nil, err
+ }
+ return &d, nil
+ case AttachmentTypeSelection:
+ var d AttachmentSelection
+ if err := json.Unmarshal(data, &d); err != nil {
+ return nil, err
+ }
+ return &d, nil
+ default:
+ return &RawAttachmentData{Discriminator: raw.Type, Raw: data}, nil
+ }
+}
+
+func (r RawAttachmentData) MarshalJSON() ([]byte, error) {
+ if r.Raw != nil {
+ return r.Raw, nil
+ }
+ return json.Marshal(struct {
+ Type AttachmentType `json:"type"`
+ }{
+ Type: r.Discriminator,
+ })
+}
+
+func (r AttachmentBlob) MarshalJSON() ([]byte, error) {
+ type alias AttachmentBlob
+ return json.Marshal(struct {
+ Type AttachmentType `json:"type"`
+ alias
+ }{
+ Type: r.Type(),
+ alias: alias(r),
+ })
+}
+
+func (r AttachmentDirectory) MarshalJSON() ([]byte, error) {
+ type alias AttachmentDirectory
+ return json.Marshal(struct {
+ Type AttachmentType `json:"type"`
+ alias
+ }{
+ Type: r.Type(),
+ alias: alias(r),
+ })
+}
+
+func (r AttachmentExtensionContext) MarshalJSON() ([]byte, error) {
+ type alias AttachmentExtensionContext
+ return json.Marshal(struct {
+ Type AttachmentType `json:"type"`
+ alias
+ }{
+ Type: r.Type(),
+ alias: alias(r),
+ })
+}
+
+func (r AttachmentFile) MarshalJSON() ([]byte, error) {
+ type alias AttachmentFile
+ return json.Marshal(struct {
+ Type AttachmentType `json:"type"`
+ alias
+ }{
+ Type: r.Type(),
+ alias: alias(r),
+ })
+}
+
+func (r AttachmentGitHubReference) MarshalJSON() ([]byte, error) {
+ type alias AttachmentGitHubReference
+ return json.Marshal(struct {
+ Type AttachmentType `json:"type"`
+ alias
+ }{
+ Type: r.Type(),
+ alias: alias(r),
+ })
+}
+
+func (r AttachmentSelection) MarshalJSON() ([]byte, error) {
+ type alias AttachmentSelection
+ return json.Marshal(struct {
+ Type AttachmentType `json:"type"`
+ alias
+ }{
+ Type: r.Type(),
+ alias: alias(r),
+ })
+}
+
func unmarshalAuthInfo(data []byte) (AuthInfo, error) {
if string(data) == "null" {
return nil, nil
@@ -136,13 +267,13 @@ func unmarshalAuthInfo(data []byte) (AuthInfo, error) {
return nil, err
}
return &d, nil
- case AuthInfoTypeGhCli:
- var d GhCliAuthInfo
+ case AuthInfoTypeGhCLI:
+ var d GhCLIAuthInfo
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
}
return &d, nil
- case AuthInfoTypeHmac:
+ case AuthInfoTypeHMAC:
var d HMACAuthInfo
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
@@ -209,8 +340,8 @@ func (r EnvAuthInfo) MarshalJSON() ([]byte, error) {
})
}
-func (r GhCliAuthInfo) MarshalJSON() ([]byte, error) {
- type alias GhCliAuthInfo
+func (r GhCLIAuthInfo) MarshalJSON() ([]byte, error) {
+ type alias GhCLIAuthInfo
return json.Marshal(struct {
Type AuthInfoType `json:"type"`
alias
@@ -566,13 +697,13 @@ func (r ExternalToolTextResultForLlmContentText) MarshalJSON() ([]byte, error) {
func (r *ExternalToolTextResultForLlm) UnmarshalJSON(data []byte) error {
type rawExternalToolTextResultForLlm struct {
- BinaryResultsForLlm []ExternalToolTextResultForLlmBinaryResultsForLlm `json:"binaryResultsForLlm,omitempty"`
- Contents []json.RawMessage `json:"contents,omitempty"`
+ BinaryResultsForLlm []ExternalToolTextResultForLlmBinaryResultsForLlm `json:"binaryResultsForLlm,omitzero"`
+ Contents []json.RawMessage `json:"contents,omitzero"`
Error *string `json:"error,omitempty"`
ResultType *string `json:"resultType,omitempty"`
SessionLog *string `json:"sessionLog,omitempty"`
TextResultForLlm string `json:"textResultForLlm"`
- ToolTelemetry map[string]any `json:"toolTelemetry,omitempty"`
+ ToolTelemetry map[string]any `json:"toolTelemetry,omitzero"`
}
var raw rawExternalToolTextResultForLlm
if err := json.Unmarshal(data, &raw); err != nil {
@@ -658,8 +789,8 @@ func (r *HandlePendingToolCallRequest) UnmarshalJSON(data []byte) error {
}
func (r InstalledPluginSource) MarshalJSON() ([]byte, error) {
- if r.InstalledPluginSourceGithub != nil {
- return json.Marshal(r.InstalledPluginSourceGithub)
+ if r.InstalledPluginSourceGitHub != nil {
+ return json.Marshal(r.InstalledPluginSourceGitHub)
}
if r.InstalledPluginSourceLocal != nil {
return json.Marshal(r.InstalledPluginSourceLocal)
@@ -679,9 +810,9 @@ func (r *InstalledPluginSource) UnmarshalJSON(data []byte) error {
return nil
}
{
- var value InstalledPluginSourceGithub
+ var value InstalledPluginSourceGitHub
if err := json.Unmarshal(data, &value); err == nil {
- *r = InstalledPluginSource{InstalledPluginSourceGithub: &value}
+ *r = InstalledPluginSource{InstalledPluginSourceGitHub: &value}
return nil
}
}
@@ -709,7 +840,7 @@ func (r *InstalledPluginSource) UnmarshalJSON(data []byte) error {
return errors.New("data did not match any union variant for InstalledPluginSource")
}
-func matchesMcpServerConfigHTTP(data []byte) bool {
+func matchesMCPServerConfigHTTP(data []byte) bool {
var rawGroup0 struct {
Command json.RawMessage `json:"command"`
URL json.RawMessage `json:"url"`
@@ -723,7 +854,7 @@ func matchesMcpServerConfigHTTP(data []byte) bool {
return rawGroup0.Command == nil
}
-func matchesMcpServerConfigStdio(data []byte) bool {
+func matchesMCPServerConfigStdio(data []byte) bool {
var rawGroup0 struct {
Command json.RawMessage `json:"command"`
URL json.RawMessage `json:"url"`
@@ -737,74 +868,74 @@ func matchesMcpServerConfigStdio(data []byte) bool {
return rawGroup0.URL == nil
}
-func unmarshalMcpServerConfig(data []byte) (McpServerConfig, error) {
+func unmarshalMCPServerConfig(data []byte) (MCPServerConfig, error) {
if string(data) == "null" {
return nil, nil
}
- if matchesMcpServerConfigHTTP(data) {
- var d McpServerConfigHTTP
+ if matchesMCPServerConfigHTTP(data) {
+ var d MCPServerConfigHTTP
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
}
return &d, nil
}
- if matchesMcpServerConfigStdio(data) {
- var d McpServerConfigStdio
+ if matchesMCPServerConfigStdio(data) {
+ var d MCPServerConfigStdio
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
}
return &d, nil
}
- return &RawMcpServerConfigData{Raw: data}, nil
+ return &RawMCPServerConfigData{Raw: data}, nil
}
-func (r RawMcpServerConfigData) MarshalJSON() ([]byte, error) {
+func (r RawMCPServerConfigData) MarshalJSON() ([]byte, error) {
if r.Raw != nil {
return r.Raw, nil
}
return []byte("null"), nil
}
-func unmarshalMcpServerAuthConfig(data []byte) (McpServerAuthConfig, error) {
+func unmarshalMCPServerAuthConfig(data []byte) (MCPServerAuthConfig, error) {
if string(data) == "null" {
return nil, nil
}
{
var value bool
if err := json.Unmarshal(data, &value); err == nil {
- return McpServerAuthConfigBoolean(value), nil
+ return MCPServerAuthConfigBoolean(value), nil
}
}
{
- var value McpServerAuthConfigRedirectPort
+ var value MCPServerAuthConfigRedirectPort
if err := json.Unmarshal(data, &value); err == nil {
return &value, nil
}
}
- return nil, errors.New("data did not match any union variant for McpServerAuthConfig")
+ return nil, errors.New("data did not match any union variant for MCPServerAuthConfig")
}
-func (r *McpServerConfigHTTP) UnmarshalJSON(data []byte) error {
- type rawMcpServerConfigHTTP struct {
+func (r *MCPServerConfigHTTP) UnmarshalJSON(data []byte) error {
+ type rawMCPServerConfigHTTP struct {
Auth json.RawMessage `json:"auth,omitempty"`
FilterMapping json.RawMessage `json:"filterMapping,omitempty"`
- Headers map[string]string `json:"headers,omitempty"`
+ Headers map[string]string `json:"headers,omitzero"`
IsDefaultServer *bool `json:"isDefaultServer,omitempty"`
OauthClientID *string `json:"oauthClientId,omitempty"`
- OauthGrantType *McpServerConfigHTTPOauthGrantType `json:"oauthGrantType,omitempty"`
+ OauthGrantType *MCPServerConfigHTTPOauthGrantType `json:"oauthGrantType,omitempty"`
OauthPublicClient *bool `json:"oauthPublicClient,omitempty"`
Oidc json.RawMessage `json:"oidc,omitempty"`
Timeout *int64 `json:"timeout,omitempty"`
- Tools []string `json:"tools,omitempty"`
- Type *McpServerConfigHTTPType `json:"type,omitempty"`
+ Tools []string `json:"tools,omitzero"`
+ Type *MCPServerConfigHTTPType `json:"type,omitempty"`
URL string `json:"url"`
}
- var raw rawMcpServerConfigHTTP
+ var raw rawMCPServerConfigHTTP
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
if raw.Auth != nil {
- value, err := unmarshalMcpServerAuthConfig(raw.Auth)
+ value, err := unmarshalMCPServerAuthConfig(raw.Auth)
if err != nil {
return err
}
@@ -823,7 +954,7 @@ func (r *McpServerConfigHTTP) UnmarshalJSON(data []byte) error {
r.OauthGrantType = raw.OauthGrantType
r.OauthPublicClient = raw.OauthPublicClient
if raw.Oidc != nil {
- value, err := unmarshalMcpServerAuthConfig(raw.Oidc)
+ value, err := unmarshalMCPServerAuthConfig(raw.Oidc)
if err != nil {
return err
}
@@ -836,26 +967,26 @@ func (r *McpServerConfigHTTP) UnmarshalJSON(data []byte) error {
return nil
}
-func (r *McpServerConfigStdio) UnmarshalJSON(data []byte) error {
- type rawMcpServerConfigStdio struct {
- Args []string `json:"args,omitempty"`
+func (r *MCPServerConfigStdio) UnmarshalJSON(data []byte) error {
+ type rawMCPServerConfigStdio struct {
+ Args []string `json:"args,omitzero"`
Auth json.RawMessage `json:"auth,omitempty"`
Command string `json:"command"`
Cwd *string `json:"cwd,omitempty"`
- Env map[string]string `json:"env,omitempty"`
+ Env map[string]string `json:"env,omitzero"`
FilterMapping json.RawMessage `json:"filterMapping,omitempty"`
IsDefaultServer *bool `json:"isDefaultServer,omitempty"`
Oidc json.RawMessage `json:"oidc,omitempty"`
Timeout *int64 `json:"timeout,omitempty"`
- Tools []string `json:"tools,omitempty"`
+ Tools []string `json:"tools,omitzero"`
}
- var raw rawMcpServerConfigStdio
+ var raw rawMCPServerConfigStdio
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
r.Args = raw.Args
if raw.Auth != nil {
- value, err := unmarshalMcpServerAuthConfig(raw.Auth)
+ value, err := unmarshalMCPServerAuthConfig(raw.Auth)
if err != nil {
return err
}
@@ -873,7 +1004,7 @@ func (r *McpServerConfigStdio) UnmarshalJSON(data []byte) error {
}
r.IsDefaultServer = raw.IsDefaultServer
if raw.Oidc != nil {
- value, err := unmarshalMcpServerAuthConfig(raw.Oidc)
+ value, err := unmarshalMCPServerAuthConfig(raw.Oidc)
if err != nil {
return err
}
@@ -884,17 +1015,17 @@ func (r *McpServerConfigStdio) UnmarshalJSON(data []byte) error {
return nil
}
-func (r *McpConfigAddRequest) UnmarshalJSON(data []byte) error {
- type rawMcpConfigAddRequest struct {
+func (r *MCPConfigAddRequest) UnmarshalJSON(data []byte) error {
+ type rawMCPConfigAddRequest struct {
Config json.RawMessage `json:"config"`
Name string `json:"name"`
}
- var raw rawMcpConfigAddRequest
+ var raw rawMCPConfigAddRequest
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
if raw.Config != nil {
- value, err := unmarshalMcpServerConfig(raw.Config)
+ value, err := unmarshalMCPServerConfig(raw.Config)
if err != nil {
return err
}
@@ -904,18 +1035,18 @@ func (r *McpConfigAddRequest) UnmarshalJSON(data []byte) error {
return nil
}
-func (r *McpConfigList) UnmarshalJSON(data []byte) error {
- type rawMcpConfigList struct {
+func (r *MCPConfigList) UnmarshalJSON(data []byte) error {
+ type rawMCPConfigList struct {
Servers map[string]json.RawMessage `json:"servers"`
}
- var raw rawMcpConfigList
+ var raw rawMCPConfigList
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
if raw.Servers != nil {
- r.Servers = make(map[string]McpServerConfig, len(raw.Servers))
+ r.Servers = make(map[string]MCPServerConfig, len(raw.Servers))
for key, rawValue := range raw.Servers {
- value, err := unmarshalMcpServerConfig(rawValue)
+ value, err := unmarshalMCPServerConfig(rawValue)
if err != nil {
return err
}
@@ -925,17 +1056,17 @@ func (r *McpConfigList) UnmarshalJSON(data []byte) error {
return nil
}
-func (r *McpConfigUpdateRequest) UnmarshalJSON(data []byte) error {
- type rawMcpConfigUpdateRequest struct {
+func (r *MCPConfigUpdateRequest) UnmarshalJSON(data []byte) error {
+ type rawMCPConfigUpdateRequest struct {
Config json.RawMessage `json:"config"`
Name string `json:"name"`
}
- var raw rawMcpConfigUpdateRequest
+ var raw rawMCPConfigUpdateRequest
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
if raw.Config != nil {
- value, err := unmarshalMcpServerConfig(raw.Config)
+ value, err := unmarshalMCPServerConfig(raw.Config)
if err != nil {
return err
}
@@ -1112,8 +1243,8 @@ func unmarshalUserToolSessionApproval(data []byte) (UserToolSessionApproval, err
return nil, err
}
return &d, nil
- case UserToolSessionApprovalKindMcp:
- var d UserToolSessionApprovalMcp
+ case UserToolSessionApprovalKindMCP:
+ var d UserToolSessionApprovalMCP
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
}
@@ -1196,8 +1327,8 @@ func (r UserToolSessionApprovalExtensionPermissionAccess) MarshalJSON() ([]byte,
})
}
-func (r UserToolSessionApprovalMcp) MarshalJSON() ([]byte, error) {
- type alias UserToolSessionApprovalMcp
+func (r UserToolSessionApprovalMCP) MarshalJSON() ([]byte, error) {
+ type alias UserToolSessionApprovalMCP
return json.Marshal(struct {
Kind UserToolSessionApprovalKind `json:"kind"`
alias
@@ -1337,14 +1468,14 @@ func unmarshalPermissionDecisionApproveForLocationApproval(data []byte) (Permiss
return nil, err
}
return &d, nil
- case PermissionDecisionApproveForLocationApprovalKindMcp:
- var d PermissionDecisionApproveForLocationApprovalMcp
+ case PermissionDecisionApproveForLocationApprovalKindMCP:
+ var d PermissionDecisionApproveForLocationApprovalMCP
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
}
return &d, nil
- case PermissionDecisionApproveForLocationApprovalKindMcpSampling:
- var d PermissionDecisionApproveForLocationApprovalMcpSampling
+ case PermissionDecisionApproveForLocationApprovalKindMCPSampling:
+ var d PermissionDecisionApproveForLocationApprovalMCPSampling
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
}
@@ -1427,8 +1558,8 @@ func (r PermissionDecisionApproveForLocationApprovalExtensionPermissionAccess) M
})
}
-func (r PermissionDecisionApproveForLocationApprovalMcp) MarshalJSON() ([]byte, error) {
- type alias PermissionDecisionApproveForLocationApprovalMcp
+func (r PermissionDecisionApproveForLocationApprovalMCP) MarshalJSON() ([]byte, error) {
+ type alias PermissionDecisionApproveForLocationApprovalMCP
return json.Marshal(struct {
Kind PermissionDecisionApproveForLocationApprovalKind `json:"kind"`
alias
@@ -1438,8 +1569,8 @@ func (r PermissionDecisionApproveForLocationApprovalMcp) MarshalJSON() ([]byte,
})
}
-func (r PermissionDecisionApproveForLocationApprovalMcpSampling) MarshalJSON() ([]byte, error) {
- type alias PermissionDecisionApproveForLocationApprovalMcpSampling
+func (r PermissionDecisionApproveForLocationApprovalMCPSampling) MarshalJSON() ([]byte, error) {
+ type alias PermissionDecisionApproveForLocationApprovalMCPSampling
return json.Marshal(struct {
Kind PermissionDecisionApproveForLocationApprovalKind `json:"kind"`
alias
@@ -1550,14 +1681,14 @@ func unmarshalPermissionDecisionApproveForSessionApproval(data []byte) (Permissi
return nil, err
}
return &d, nil
- case PermissionDecisionApproveForSessionApprovalKindMcp:
- var d PermissionDecisionApproveForSessionApprovalMcp
+ case PermissionDecisionApproveForSessionApprovalKindMCP:
+ var d PermissionDecisionApproveForSessionApprovalMCP
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
}
return &d, nil
- case PermissionDecisionApproveForSessionApprovalKindMcpSampling:
- var d PermissionDecisionApproveForSessionApprovalMcpSampling
+ case PermissionDecisionApproveForSessionApprovalKindMCPSampling:
+ var d PermissionDecisionApproveForSessionApprovalMCPSampling
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
}
@@ -1640,8 +1771,8 @@ func (r PermissionDecisionApproveForSessionApprovalExtensionPermissionAccess) Ma
})
}
-func (r PermissionDecisionApproveForSessionApprovalMcp) MarshalJSON() ([]byte, error) {
- type alias PermissionDecisionApproveForSessionApprovalMcp
+func (r PermissionDecisionApproveForSessionApprovalMCP) MarshalJSON() ([]byte, error) {
+ type alias PermissionDecisionApproveForSessionApprovalMCP
return json.Marshal(struct {
Kind PermissionDecisionApproveForSessionApprovalKind `json:"kind"`
alias
@@ -1651,8 +1782,8 @@ func (r PermissionDecisionApproveForSessionApprovalMcp) MarshalJSON() ([]byte, e
})
}
-func (r PermissionDecisionApproveForSessionApprovalMcpSampling) MarshalJSON() ([]byte, error) {
- type alias PermissionDecisionApproveForSessionApprovalMcpSampling
+func (r PermissionDecisionApproveForSessionApprovalMCPSampling) MarshalJSON() ([]byte, error) {
+ type alias PermissionDecisionApproveForSessionApprovalMCPSampling
return json.Marshal(struct {
Kind PermissionDecisionApproveForSessionApprovalKind `json:"kind"`
alias
@@ -1893,14 +2024,14 @@ func unmarshalPermissionsLocationsAddToolApprovalDetails(data []byte) (Permissio
return nil, err
}
return &d, nil
- case PermissionsLocationsAddToolApprovalDetailsKindMcp:
- var d PermissionsLocationsAddToolApprovalDetailsMcp
+ case PermissionsLocationsAddToolApprovalDetailsKindMCP:
+ var d PermissionsLocationsAddToolApprovalDetailsMCP
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
}
return &d, nil
- case PermissionsLocationsAddToolApprovalDetailsKindMcpSampling:
- var d PermissionsLocationsAddToolApprovalDetailsMcpSampling
+ case PermissionsLocationsAddToolApprovalDetailsKindMCPSampling:
+ var d PermissionsLocationsAddToolApprovalDetailsMCPSampling
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
}
@@ -1983,8 +2114,8 @@ func (r PermissionsLocationsAddToolApprovalDetailsExtensionPermissionAccess) Mar
})
}
-func (r PermissionsLocationsAddToolApprovalDetailsMcp) MarshalJSON() ([]byte, error) {
- type alias PermissionsLocationsAddToolApprovalDetailsMcp
+func (r PermissionsLocationsAddToolApprovalDetailsMCP) MarshalJSON() ([]byte, error) {
+ type alias PermissionsLocationsAddToolApprovalDetailsMCP
return json.Marshal(struct {
Kind PermissionsLocationsAddToolApprovalDetailsKind `json:"kind"`
alias
@@ -1994,8 +2125,8 @@ func (r PermissionsLocationsAddToolApprovalDetailsMcp) MarshalJSON() ([]byte, er
})
}
-func (r PermissionsLocationsAddToolApprovalDetailsMcpSampling) MarshalJSON() ([]byte, error) {
- type alias PermissionsLocationsAddToolApprovalDetailsMcpSampling
+func (r PermissionsLocationsAddToolApprovalDetailsMCPSampling) MarshalJSON() ([]byte, error) {
+ type alias PermissionsLocationsAddToolApprovalDetailsMCPSampling
return json.Marshal(struct {
Kind PermissionsLocationsAddToolApprovalDetailsKind `json:"kind"`
alias
@@ -2058,12 +2189,12 @@ func (r *PermissionLocationAddToolApprovalParams) UnmarshalJSON(data []byte) err
return nil
}
-func unmarshalSendAttachment(data []byte) (SendAttachment, error) {
+func unmarshalPushAttachment(data []byte) (PushAttachment, error) {
if string(data) == "null" {
return nil, nil
}
type rawUnion struct {
- Type SendAttachmentType `json:"type"`
+ Type PushAttachmentType `json:"type"`
}
var raw rawUnion
if err := json.Unmarshal(data, &raw); err != nil {
@@ -2071,56 +2202,73 @@ func unmarshalSendAttachment(data []byte) (SendAttachment, error) {
}
switch raw.Type {
- case SendAttachmentTypeBlob:
- var d SendAttachmentBlob
+ case PushAttachmentTypeBlob:
+ var d PushAttachmentBlob
+ if err := json.Unmarshal(data, &d); err != nil {
+ return nil, err
+ }
+ return &d, nil
+ case PushAttachmentTypeDirectory:
+ var d PushAttachmentDirectory
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
}
return &d, nil
- case SendAttachmentTypeDirectory:
- var d SendAttachmentDirectory
+ case PushAttachmentTypeExtensionContext:
+ var d ExtensionContextPushInput
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
}
return &d, nil
- case SendAttachmentTypeFile:
- var d SendAttachmentFile
+ case PushAttachmentTypeFile:
+ var d PushAttachmentFile
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
}
return &d, nil
- case SendAttachmentTypeGithubReference:
- var d SendAttachmentGithubReference
+ case PushAttachmentTypeGitHubReference:
+ var d PushAttachmentGitHubReference
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
}
return &d, nil
- case SendAttachmentTypeSelection:
- var d SendAttachmentSelection
+ case PushAttachmentTypeSelection:
+ var d PushAttachmentSelection
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
}
return &d, nil
default:
- return &RawSendAttachmentData{Discriminator: raw.Type, Raw: data}, nil
+ return &RawPushAttachmentData{Discriminator: raw.Type, Raw: data}, nil
}
}
-func (r RawSendAttachmentData) MarshalJSON() ([]byte, error) {
+func (r RawPushAttachmentData) MarshalJSON() ([]byte, error) {
if r.Raw != nil {
return r.Raw, nil
}
return json.Marshal(struct {
- Type SendAttachmentType `json:"type"`
+ Type PushAttachmentType `json:"type"`
}{
Type: r.Discriminator,
})
}
-func (r SendAttachmentBlob) MarshalJSON() ([]byte, error) {
- type alias SendAttachmentBlob
+func (r ExtensionContextPushInput) MarshalJSON() ([]byte, error) {
+ type alias ExtensionContextPushInput
+ return json.Marshal(struct {
+ Type PushAttachmentType `json:"type"`
+ alias
+ }{
+ Type: r.Type(),
+ alias: alias(r),
+ })
+}
+
+func (r PushAttachmentBlob) MarshalJSON() ([]byte, error) {
+ type alias PushAttachmentBlob
return json.Marshal(struct {
- Type SendAttachmentType `json:"type"`
+ Type PushAttachmentType `json:"type"`
alias
}{
Type: r.Type(),
@@ -2128,10 +2276,10 @@ func (r SendAttachmentBlob) MarshalJSON() ([]byte, error) {
})
}
-func (r SendAttachmentDirectory) MarshalJSON() ([]byte, error) {
- type alias SendAttachmentDirectory
+func (r PushAttachmentDirectory) MarshalJSON() ([]byte, error) {
+ type alias PushAttachmentDirectory
return json.Marshal(struct {
- Type SendAttachmentType `json:"type"`
+ Type PushAttachmentType `json:"type"`
alias
}{
Type: r.Type(),
@@ -2139,10 +2287,10 @@ func (r SendAttachmentDirectory) MarshalJSON() ([]byte, error) {
})
}
-func (r SendAttachmentFile) MarshalJSON() ([]byte, error) {
- type alias SendAttachmentFile
+func (r PushAttachmentFile) MarshalJSON() ([]byte, error) {
+ type alias PushAttachmentFile
return json.Marshal(struct {
- Type SendAttachmentType `json:"type"`
+ Type PushAttachmentType `json:"type"`
alias
}{
Type: r.Type(),
@@ -2150,10 +2298,10 @@ func (r SendAttachmentFile) MarshalJSON() ([]byte, error) {
})
}
-func (r SendAttachmentGithubReference) MarshalJSON() ([]byte, error) {
- type alias SendAttachmentGithubReference
+func (r PushAttachmentGitHubReference) MarshalJSON() ([]byte, error) {
+ type alias PushAttachmentGitHubReference
return json.Marshal(struct {
- Type SendAttachmentType `json:"type"`
+ Type PushAttachmentType `json:"type"`
alias
}{
Type: r.Type(),
@@ -2161,10 +2309,10 @@ func (r SendAttachmentGithubReference) MarshalJSON() ([]byte, error) {
})
}
-func (r SendAttachmentSelection) MarshalJSON() ([]byte, error) {
- type alias SendAttachmentSelection
+func (r PushAttachmentSelection) MarshalJSON() ([]byte, error) {
+ type alias PushAttachmentSelection
return json.Marshal(struct {
- Type SendAttachmentType `json:"type"`
+ Type PushAttachmentType `json:"type"`
alias
}{
Type: r.Type(),
@@ -2172,16 +2320,39 @@ func (r SendAttachmentSelection) MarshalJSON() ([]byte, error) {
})
}
+func (r *SendAttachmentsToMessageParams) UnmarshalJSON(data []byte) error {
+ type rawSendAttachmentsToMessageParams struct {
+ Attachments []json.RawMessage `json:"attachments"`
+ InstanceID *string `json:"instanceId,omitempty"`
+ }
+ var raw rawSendAttachmentsToMessageParams
+ if err := json.Unmarshal(data, &raw); err != nil {
+ return err
+ }
+ if raw.Attachments != nil {
+ r.Attachments = make([]PushAttachment, 0, len(raw.Attachments))
+ for _, rawItem := range raw.Attachments {
+ value, err := unmarshalPushAttachment(rawItem)
+ if err != nil {
+ return err
+ }
+ r.Attachments = append(r.Attachments, value)
+ }
+ }
+ r.InstanceID = raw.InstanceID
+ return nil
+}
+
func (r *SendRequest) UnmarshalJSON(data []byte) error {
type rawSendRequest struct {
AgentMode *SendAgentMode `json:"agentMode,omitempty"`
- Attachments []json.RawMessage `json:"attachments,omitempty"`
+ Attachments []json.RawMessage `json:"attachments,omitzero"`
Billable *bool `json:"billable,omitempty"`
DisplayPrompt *string `json:"displayPrompt,omitempty"`
Mode *SendMode `json:"mode,omitempty"`
Prepend *bool `json:"prepend,omitempty"`
Prompt string `json:"prompt"`
- RequestHeaders map[string]string `json:"requestHeaders,omitempty"`
+ RequestHeaders map[string]string `json:"requestHeaders,omitzero"`
RequiredTool *string `json:"requiredTool,omitempty"`
Source any `json:"source,omitempty"`
Traceparent *string `json:"traceparent,omitempty"`
@@ -2194,9 +2365,9 @@ func (r *SendRequest) UnmarshalJSON(data []byte) error {
}
r.AgentMode = raw.AgentMode
if raw.Attachments != nil {
- r.Attachments = make([]SendAttachment, 0, len(raw.Attachments))
+ r.Attachments = make([]Attachment, 0, len(raw.Attachments))
for _, rawItem := range raw.Attachments {
- value, err := unmarshalSendAttachment(rawItem)
+ value, err := unmarshalAttachment(rawItem)
if err != nil {
return err
}
@@ -2218,8 +2389,8 @@ func (r *SendRequest) UnmarshalJSON(data []byte) error {
}
func (r SessionInstalledPluginSource) MarshalJSON() ([]byte, error) {
- if r.SessionInstalledPluginSourceGithub != nil {
- return json.Marshal(r.SessionInstalledPluginSourceGithub)
+ if r.SessionInstalledPluginSourceGitHub != nil {
+ return json.Marshal(r.SessionInstalledPluginSourceGitHub)
}
if r.SessionInstalledPluginSourceLocal != nil {
return json.Marshal(r.SessionInstalledPluginSourceLocal)
@@ -2239,9 +2410,9 @@ func (r *SessionInstalledPluginSource) UnmarshalJSON(data []byte) error {
return nil
}
{
- var value SessionInstalledPluginSourceGithub
+ var value SessionInstalledPluginSourceGitHub
if err := json.Unmarshal(data, &value); err == nil {
- *r = SessionInstalledPluginSource{SessionInstalledPluginSourceGithub: &value}
+ *r = SessionInstalledPluginSource{SessionInstalledPluginSourceGitHub: &value}
return nil
}
}
@@ -2887,7 +3058,7 @@ func (r UIElicitationStringOneOfField) MarshalJSON() ([]byte, error) {
func (r *UIElicitationSchema) UnmarshalJSON(data []byte) error {
type rawUIElicitationSchema struct {
Properties map[string]json.RawMessage `json:"properties"`
- Required []string `json:"required,omitempty"`
+ Required []string `json:"required,omitzero"`
Type UIElicitationSchemaType `json:"type"`
}
var raw rawUIElicitationSchema
@@ -2912,7 +3083,7 @@ func (r *UIElicitationSchema) UnmarshalJSON(data []byte) error {
func (r *UIElicitationResponse) UnmarshalJSON(data []byte) error {
type rawUIElicitationResponse struct {
Action UIElicitationResponseAction `json:"action"`
- Content map[string]json.RawMessage `json:"content,omitempty"`
+ Content map[string]json.RawMessage `json:"content,omitzero"`
}
var raw rawUIElicitationResponse
if err := json.Unmarshal(data, &raw); err != nil {
diff --git a/go/rpc/zsession_encoding.go b/go/rpc/zsession_encoding.go
index f06e3b398..6b0e04c60 100644
--- a/go/rpc/zsession_encoding.go
+++ b/go/rpc/zsession_encoding.go
@@ -197,20 +197,20 @@ func (e *SessionEvent) UnmarshalJSON(data []byte) error {
return err
}
e.Data = &d
- case SessionEventTypeMcpAppToolCallComplete:
- var d McpAppToolCallCompleteData
+ case SessionEventTypeMCPAppToolCallComplete:
+ var d MCPAppToolCallCompleteData
if err := json.Unmarshal(raw.Data, &d); err != nil {
return err
}
e.Data = &d
- case SessionEventTypeMcpOauthCompleted:
- var d McpOauthCompletedData
+ case SessionEventTypeMCPOauthCompleted:
+ var d MCPOauthCompletedData
if err := json.Unmarshal(raw.Data, &d); err != nil {
return err
}
e.Data = &d
- case SessionEventTypeMcpOauthRequired:
- var d McpOauthRequiredData
+ case SessionEventTypeMCPOauthRequired:
+ var d MCPOauthRequiredData
if err := json.Unmarshal(raw.Data, &d); err != nil {
return err
}
@@ -311,6 +311,12 @@ func (e *SessionEvent) UnmarshalJSON(data []byte) error {
return err
}
e.Data = &d
+ case SessionEventTypeSessionExtensionsAttachmentsPushed:
+ var d SessionExtensionsAttachmentsPushedData
+ if err := json.Unmarshal(raw.Data, &d); err != nil {
+ return err
+ }
+ e.Data = &d
case SessionEventTypeSessionExtensionsLoaded:
var d SessionExtensionsLoadedData
if err := json.Unmarshal(raw.Data, &d); err != nil {
@@ -335,14 +341,14 @@ func (e *SessionEvent) UnmarshalJSON(data []byte) error {
return err
}
e.Data = &d
- case SessionEventTypeSessionMcpServersLoaded:
- var d SessionMcpServersLoadedData
+ case SessionEventTypeSessionMCPServersLoaded:
+ var d SessionMCPServersLoadedData
if err := json.Unmarshal(raw.Data, &d); err != nil {
return err
}
e.Data = &d
- case SessionEventTypeSessionMcpServerStatusChanged:
- var d SessionMcpServerStatusChangedData
+ case SessionEventTypeSessionMCPServerStatusChanged:
+ var d SessionMCPServerStatusChangedData
if err := json.Unmarshal(raw.Data, &d); err != nil {
return err
}
@@ -592,131 +598,17 @@ func (r RawSessionEventData) MarshalJSON() ([]byte, error) {
return r.Raw, nil
}
-func unmarshalUserMessageAttachment(data []byte) (UserMessageAttachment, error) {
- if string(data) == "null" {
- return nil, nil
- }
- type rawUnion struct {
- Type UserMessageAttachmentType `json:"type"`
- }
- var raw rawUnion
- if err := json.Unmarshal(data, &raw); err != nil {
- return nil, err
- }
-
- switch raw.Type {
- case UserMessageAttachmentTypeBlob:
- var d UserMessageAttachmentBlob
- if err := json.Unmarshal(data, &d); err != nil {
- return nil, err
- }
- return &d, nil
- case UserMessageAttachmentTypeDirectory:
- var d UserMessageAttachmentDirectory
- if err := json.Unmarshal(data, &d); err != nil {
- return nil, err
- }
- return &d, nil
- case UserMessageAttachmentTypeFile:
- var d UserMessageAttachmentFile
- if err := json.Unmarshal(data, &d); err != nil {
- return nil, err
- }
- return &d, nil
- case UserMessageAttachmentTypeGithubReference:
- var d UserMessageAttachmentGithubReference
- if err := json.Unmarshal(data, &d); err != nil {
- return nil, err
- }
- return &d, nil
- case UserMessageAttachmentTypeSelection:
- var d UserMessageAttachmentSelection
- if err := json.Unmarshal(data, &d); err != nil {
- return nil, err
- }
- return &d, nil
- default:
- return &RawUserMessageAttachment{Discriminator: raw.Type, Raw: data}, nil
- }
-}
-
-func (r RawUserMessageAttachment) MarshalJSON() ([]byte, error) {
- if r.Raw != nil {
- return r.Raw, nil
- }
- return json.Marshal(struct {
- Type UserMessageAttachmentType `json:"type"`
- }{
- Type: r.Discriminator,
- })
-}
-
-func (r UserMessageAttachmentBlob) MarshalJSON() ([]byte, error) {
- type alias UserMessageAttachmentBlob
- return json.Marshal(struct {
- Type UserMessageAttachmentType `json:"type"`
- alias
- }{
- Type: r.Type(),
- alias: alias(r),
- })
-}
-
-func (r UserMessageAttachmentDirectory) MarshalJSON() ([]byte, error) {
- type alias UserMessageAttachmentDirectory
- return json.Marshal(struct {
- Type UserMessageAttachmentType `json:"type"`
- alias
- }{
- Type: r.Type(),
- alias: alias(r),
- })
-}
-
-func (r UserMessageAttachmentFile) MarshalJSON() ([]byte, error) {
- type alias UserMessageAttachmentFile
- return json.Marshal(struct {
- Type UserMessageAttachmentType `json:"type"`
- alias
- }{
- Type: r.Type(),
- alias: alias(r),
- })
-}
-
-func (r UserMessageAttachmentGithubReference) MarshalJSON() ([]byte, error) {
- type alias UserMessageAttachmentGithubReference
- return json.Marshal(struct {
- Type UserMessageAttachmentType `json:"type"`
- alias
- }{
- Type: r.Type(),
- alias: alias(r),
- })
-}
-
-func (r UserMessageAttachmentSelection) MarshalJSON() ([]byte, error) {
- type alias UserMessageAttachmentSelection
- return json.Marshal(struct {
- Type UserMessageAttachmentType `json:"type"`
- alias
- }{
- Type: r.Type(),
- alias: alias(r),
- })
-}
-
func (r *UserMessageData) UnmarshalJSON(data []byte) error {
type rawUserMessageData struct {
AgentMode *UserMessageAgentMode `json:"agentMode,omitempty"`
- Attachments []json.RawMessage `json:"attachments,omitempty"`
+ Attachments []json.RawMessage `json:"attachments,omitzero"`
Content string `json:"content"`
InteractionID *string `json:"interactionId,omitempty"`
IsAutopilotContinuation *bool `json:"isAutopilotContinuation,omitempty"`
- NativeDocumentPathFallbackPaths []string `json:"nativeDocumentPathFallbackPaths,omitempty"`
+ NativeDocumentPathFallbackPaths []string `json:"nativeDocumentPathFallbackPaths,omitzero"`
ParentAgentTaskID *string `json:"parentAgentTaskId,omitempty"`
Source *string `json:"source,omitempty"`
- SupportedNativeDocumentMIMETypes []string `json:"supportedNativeDocumentMimeTypes,omitempty"`
+ SupportedNativeDocumentMIMETypes []string `json:"supportedNativeDocumentMimeTypes,omitzero"`
TransformedContent *string `json:"transformedContent,omitempty"`
}
var raw rawUserMessageData
@@ -725,9 +617,9 @@ func (r *UserMessageData) UnmarshalJSON(data []byte) error {
}
r.AgentMode = raw.AgentMode
if raw.Attachments != nil {
- r.Attachments = make([]UserMessageAttachment, 0, len(raw.Attachments))
+ r.Attachments = make([]Attachment, 0, len(raw.Attachments))
for _, rawItem := range raw.Attachments {
- value, err := unmarshalUserMessageAttachment(rawItem)
+ value, err := unmarshalAttachment(rawItem)
if err != nil {
return err
}
@@ -941,7 +833,7 @@ func (r ToolExecutionCompleteContentText) MarshalJSON() ([]byte, error) {
func (r *ToolExecutionCompleteResult) UnmarshalJSON(data []byte) error {
type rawToolExecutionCompleteResult struct {
Content string `json:"content"`
- Contents []json.RawMessage `json:"contents,omitempty"`
+ Contents []json.RawMessage `json:"contents,omitzero"`
DetailedContent *string `json:"detailedContent,omitempty"`
UIResource *ToolExecutionCompleteUIResource `json:"uiResource,omitempty"`
}
@@ -1153,8 +1045,8 @@ func unmarshalPermissionRequest(data []byte) (PermissionRequest, error) {
return nil, err
}
return &d, nil
- case PermissionRequestKindMcp:
- var d PermissionRequestMcp
+ case PermissionRequestKindMCP:
+ var d PermissionRequestMCP
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
}
@@ -1249,8 +1141,8 @@ func (r PermissionRequestHook) MarshalJSON() ([]byte, error) {
})
}
-func (r PermissionRequestMcp) MarshalJSON() ([]byte, error) {
- type alias PermissionRequestMcp
+func (r PermissionRequestMCP) MarshalJSON() ([]byte, error) {
+ type alias PermissionRequestMCP
return json.Marshal(struct {
Kind PermissionRequestKind `json:"kind"`
alias
@@ -1358,8 +1250,8 @@ func unmarshalPermissionPromptRequest(data []byte) (PermissionPromptRequest, err
return nil, err
}
return &d, nil
- case PermissionPromptRequestKindMcp:
- var d PermissionPromptRequestMcp
+ case PermissionPromptRequestKindMCP:
+ var d PermissionPromptRequestMCP
if err := json.Unmarshal(data, &d); err != nil {
return nil, err
}
@@ -1465,8 +1357,8 @@ func (r PermissionPromptRequestHook) MarshalJSON() ([]byte, error) {
})
}
-func (r PermissionPromptRequestMcp) MarshalJSON() ([]byte, error) {
- type alias PermissionPromptRequestMcp
+func (r PermissionPromptRequestMCP) MarshalJSON() ([]byte, error) {
+ type alias PermissionPromptRequestMCP
return json.Marshal(struct {
Kind PermissionPromptRequestKind `json:"kind"`
alias
@@ -1655,6 +1547,26 @@ func (r PermissionApproved) MarshalJSON() ([]byte, error) {
})
}
+func (r *PermissionApprovedForLocation) UnmarshalJSON(data []byte) error {
+ type rawPermissionApprovedForLocation struct {
+ Approval json.RawMessage `json:"approval"`
+ LocationKey string `json:"locationKey"`
+ }
+ var raw rawPermissionApprovedForLocation
+ if err := json.Unmarshal(data, &raw); err != nil {
+ return err
+ }
+ if raw.Approval != nil {
+ value, err := unmarshalUserToolSessionApproval(raw.Approval)
+ if err != nil {
+ return err
+ }
+ r.Approval = value
+ }
+ r.LocationKey = raw.LocationKey
+ return nil
+}
+
func (r PermissionApprovedForLocation) MarshalJSON() ([]byte, error) {
type alias PermissionApprovedForLocation
return json.Marshal(struct {
@@ -1666,6 +1578,24 @@ func (r PermissionApprovedForLocation) MarshalJSON() ([]byte, error) {
})
}
+func (r *PermissionApprovedForSession) UnmarshalJSON(data []byte) error {
+ type rawPermissionApprovedForSession struct {
+ Approval json.RawMessage `json:"approval"`
+ }
+ var raw rawPermissionApprovedForSession
+ if err := json.Unmarshal(data, &raw); err != nil {
+ return err
+ }
+ if raw.Approval != nil {
+ value, err := unmarshalUserToolSessionApproval(raw.Approval)
+ if err != nil {
+ return err
+ }
+ r.Approval = value
+ }
+ return nil
+}
+
func (r PermissionApprovedForSession) MarshalJSON() ([]byte, error) {
type alias PermissionApprovedForSession
return json.Marshal(struct {
@@ -1799,7 +1729,7 @@ func unmarshalElicitationCompletedContent(data []byte) (ElicitationCompletedCont
func (r *ElicitationCompletedData) UnmarshalJSON(data []byte) error {
type rawElicitationCompletedData struct {
Action *ElicitationCompletedAction `json:"action,omitempty"`
- Content map[string]json.RawMessage `json:"content,omitempty"`
+ Content map[string]json.RawMessage `json:"content,omitzero"`
RequestID string `json:"requestId"`
}
var raw rawElicitationCompletedData
@@ -1882,3 +1812,24 @@ func (r *CustomNotificationPayload) UnmarshalJSON(data []byte) error {
}
return errors.New("data did not match any union variant for CustomNotificationPayload")
}
+
+func (r *SessionExtensionsAttachmentsPushedData) UnmarshalJSON(data []byte) error {
+ type rawSessionExtensionsAttachmentsPushedData struct {
+ Attachments []json.RawMessage `json:"attachments"`
+ }
+ var raw rawSessionExtensionsAttachmentsPushedData
+ if err := json.Unmarshal(data, &raw); err != nil {
+ return err
+ }
+ if raw.Attachments != nil {
+ r.Attachments = make([]Attachment, 0, len(raw.Attachments))
+ for _, rawItem := range raw.Attachments {
+ value, err := unmarshalAttachment(rawItem)
+ if err != nil {
+ return err
+ }
+ r.Attachments = append(r.Attachments, value)
+ }
+ }
+ return nil
+}
diff --git a/go/rpc/zsession_events.go b/go/rpc/zsession_events.go
index d991c2429..6d05baa3c 100644
--- a/go/rpc/zsession_events.go
+++ b/go/rpc/zsession_events.go
@@ -53,93 +53,94 @@ func (r RawSessionEventData) Type() SessionEventType {
type SessionEventType string
const (
- SessionEventTypeAbort SessionEventType = "abort"
- SessionEventTypeAssistantIntent SessionEventType = "assistant.intent"
- SessionEventTypeAssistantMessage SessionEventType = "assistant.message"
- SessionEventTypeAssistantMessageDelta SessionEventType = "assistant.message_delta"
- SessionEventTypeAssistantMessageStart SessionEventType = "assistant.message_start"
- SessionEventTypeAssistantReasoning SessionEventType = "assistant.reasoning"
- SessionEventTypeAssistantReasoningDelta SessionEventType = "assistant.reasoning_delta"
- SessionEventTypeAssistantStreamingDelta SessionEventType = "assistant.streaming_delta"
- SessionEventTypeAssistantTurnEnd SessionEventType = "assistant.turn_end"
- SessionEventTypeAssistantTurnStart SessionEventType = "assistant.turn_start"
- SessionEventTypeAssistantUsage SessionEventType = "assistant.usage"
- SessionEventTypeAutoModeSwitchCompleted SessionEventType = "auto_mode_switch.completed"
- SessionEventTypeAutoModeSwitchRequested SessionEventType = "auto_mode_switch.requested"
- SessionEventTypeCapabilitiesChanged SessionEventType = "capabilities.changed"
- SessionEventTypeCommandCompleted SessionEventType = "command.completed"
- SessionEventTypeCommandExecute SessionEventType = "command.execute"
- SessionEventTypeCommandQueued SessionEventType = "command.queued"
- SessionEventTypeCommandsChanged SessionEventType = "commands.changed"
- SessionEventTypeElicitationCompleted SessionEventType = "elicitation.completed"
- SessionEventTypeElicitationRequested SessionEventType = "elicitation.requested"
- SessionEventTypeExitPlanModeCompleted SessionEventType = "exit_plan_mode.completed"
- SessionEventTypeExitPlanModeRequested SessionEventType = "exit_plan_mode.requested"
- SessionEventTypeExternalToolCompleted SessionEventType = "external_tool.completed"
- SessionEventTypeExternalToolRequested SessionEventType = "external_tool.requested"
- SessionEventTypeHookEnd SessionEventType = "hook.end"
- SessionEventTypeHookProgress SessionEventType = "hook.progress"
- SessionEventTypeHookStart SessionEventType = "hook.start"
- SessionEventTypeMcpAppToolCallComplete SessionEventType = "mcp_app.tool_call_complete"
- SessionEventTypeMcpOauthCompleted SessionEventType = "mcp.oauth_completed"
- SessionEventTypeMcpOauthRequired SessionEventType = "mcp.oauth_required"
- SessionEventTypeModelCallFailure SessionEventType = "model.call_failure"
- SessionEventTypePendingMessagesModified SessionEventType = "pending_messages.modified"
- SessionEventTypePermissionCompleted SessionEventType = "permission.completed"
- SessionEventTypePermissionRequested SessionEventType = "permission.requested"
- SessionEventTypeSamplingCompleted SessionEventType = "sampling.completed"
- SessionEventTypeSamplingRequested SessionEventType = "sampling.requested"
- SessionEventTypeSessionAutopilotObjectiveChanged SessionEventType = "session.autopilot_objective_changed"
- SessionEventTypeSessionBackgroundTasksChanged SessionEventType = "session.background_tasks_changed"
- SessionEventTypeSessionCanvasOpened SessionEventType = "session.canvas.opened"
- SessionEventTypeSessionCanvasRegistryChanged SessionEventType = "session.canvas.registry_changed"
- SessionEventTypeSessionCompactionComplete SessionEventType = "session.compaction_complete"
- SessionEventTypeSessionCompactionStart SessionEventType = "session.compaction_start"
- SessionEventTypeSessionContextChanged SessionEventType = "session.context_changed"
- SessionEventTypeSessionCustomAgentsUpdated SessionEventType = "session.custom_agents_updated"
- SessionEventTypeSessionCustomNotification SessionEventType = "session.custom_notification"
- SessionEventTypeSessionError SessionEventType = "session.error"
- SessionEventTypeSessionExtensionsLoaded SessionEventType = "session.extensions_loaded"
- SessionEventTypeSessionHandoff SessionEventType = "session.handoff"
- SessionEventTypeSessionIdle SessionEventType = "session.idle"
- SessionEventTypeSessionInfo SessionEventType = "session.info"
- SessionEventTypeSessionMcpServersLoaded SessionEventType = "session.mcp_servers_loaded"
- SessionEventTypeSessionMcpServerStatusChanged SessionEventType = "session.mcp_server_status_changed"
- SessionEventTypeSessionModeChanged SessionEventType = "session.mode_changed"
- SessionEventTypeSessionModelChange SessionEventType = "session.model_change"
- SessionEventTypeSessionPermissionsChanged SessionEventType = "session.permissions_changed"
- SessionEventTypeSessionPlanChanged SessionEventType = "session.plan_changed"
- SessionEventTypeSessionRemoteSteerableChanged SessionEventType = "session.remote_steerable_changed"
- SessionEventTypeSessionResume SessionEventType = "session.resume"
- SessionEventTypeSessionScheduleCancelled SessionEventType = "session.schedule_cancelled"
- SessionEventTypeSessionScheduleCreated SessionEventType = "session.schedule_created"
- SessionEventTypeSessionShutdown SessionEventType = "session.shutdown"
- SessionEventTypeSessionSkillsLoaded SessionEventType = "session.skills_loaded"
- SessionEventTypeSessionSnapshotRewind SessionEventType = "session.snapshot_rewind"
- SessionEventTypeSessionStart SessionEventType = "session.start"
- SessionEventTypeSessionTaskComplete SessionEventType = "session.task_complete"
- SessionEventTypeSessionTitleChanged SessionEventType = "session.title_changed"
- SessionEventTypeSessionToolsUpdated SessionEventType = "session.tools_updated"
- SessionEventTypeSessionTruncation SessionEventType = "session.truncation"
- SessionEventTypeSessionUsageInfo SessionEventType = "session.usage_info"
- SessionEventTypeSessionWarning SessionEventType = "session.warning"
- SessionEventTypeSessionWorkspaceFileChanged SessionEventType = "session.workspace_file_changed"
- SessionEventTypeSkillInvoked SessionEventType = "skill.invoked"
- SessionEventTypeSubagentCompleted SessionEventType = "subagent.completed"
- SessionEventTypeSubagentDeselected SessionEventType = "subagent.deselected"
- SessionEventTypeSubagentFailed SessionEventType = "subagent.failed"
- SessionEventTypeSubagentSelected SessionEventType = "subagent.selected"
- SessionEventTypeSubagentStarted SessionEventType = "subagent.started"
- SessionEventTypeSystemMessage SessionEventType = "system.message"
- SessionEventTypeSystemNotification SessionEventType = "system.notification"
- SessionEventTypeToolExecutionComplete SessionEventType = "tool.execution_complete"
- SessionEventTypeToolExecutionPartialResult SessionEventType = "tool.execution_partial_result"
- SessionEventTypeToolExecutionProgress SessionEventType = "tool.execution_progress"
- SessionEventTypeToolExecutionStart SessionEventType = "tool.execution_start"
- SessionEventTypeToolUserRequested SessionEventType = "tool.user_requested"
- SessionEventTypeUserInputCompleted SessionEventType = "user_input.completed"
- SessionEventTypeUserInputRequested SessionEventType = "user_input.requested"
- SessionEventTypeUserMessage SessionEventType = "user.message"
+ SessionEventTypeAbort SessionEventType = "abort"
+ SessionEventTypeAssistantIntent SessionEventType = "assistant.intent"
+ SessionEventTypeAssistantMessage SessionEventType = "assistant.message"
+ SessionEventTypeAssistantMessageDelta SessionEventType = "assistant.message_delta"
+ SessionEventTypeAssistantMessageStart SessionEventType = "assistant.message_start"
+ SessionEventTypeAssistantReasoning SessionEventType = "assistant.reasoning"
+ SessionEventTypeAssistantReasoningDelta SessionEventType = "assistant.reasoning_delta"
+ SessionEventTypeAssistantStreamingDelta SessionEventType = "assistant.streaming_delta"
+ SessionEventTypeAssistantTurnEnd SessionEventType = "assistant.turn_end"
+ SessionEventTypeAssistantTurnStart SessionEventType = "assistant.turn_start"
+ SessionEventTypeAssistantUsage SessionEventType = "assistant.usage"
+ SessionEventTypeAutoModeSwitchCompleted SessionEventType = "auto_mode_switch.completed"
+ SessionEventTypeAutoModeSwitchRequested SessionEventType = "auto_mode_switch.requested"
+ SessionEventTypeCapabilitiesChanged SessionEventType = "capabilities.changed"
+ SessionEventTypeCommandCompleted SessionEventType = "command.completed"
+ SessionEventTypeCommandExecute SessionEventType = "command.execute"
+ SessionEventTypeCommandQueued SessionEventType = "command.queued"
+ SessionEventTypeCommandsChanged SessionEventType = "commands.changed"
+ SessionEventTypeElicitationCompleted SessionEventType = "elicitation.completed"
+ SessionEventTypeElicitationRequested SessionEventType = "elicitation.requested"
+ SessionEventTypeExitPlanModeCompleted SessionEventType = "exit_plan_mode.completed"
+ SessionEventTypeExitPlanModeRequested SessionEventType = "exit_plan_mode.requested"
+ SessionEventTypeExternalToolCompleted SessionEventType = "external_tool.completed"
+ SessionEventTypeExternalToolRequested SessionEventType = "external_tool.requested"
+ SessionEventTypeHookEnd SessionEventType = "hook.end"
+ SessionEventTypeHookProgress SessionEventType = "hook.progress"
+ SessionEventTypeHookStart SessionEventType = "hook.start"
+ SessionEventTypeMCPAppToolCallComplete SessionEventType = "mcp_app.tool_call_complete"
+ SessionEventTypeMCPOauthCompleted SessionEventType = "mcp.oauth_completed"
+ SessionEventTypeMCPOauthRequired SessionEventType = "mcp.oauth_required"
+ SessionEventTypeModelCallFailure SessionEventType = "model.call_failure"
+ SessionEventTypePendingMessagesModified SessionEventType = "pending_messages.modified"
+ SessionEventTypePermissionCompleted SessionEventType = "permission.completed"
+ SessionEventTypePermissionRequested SessionEventType = "permission.requested"
+ SessionEventTypeSamplingCompleted SessionEventType = "sampling.completed"
+ SessionEventTypeSamplingRequested SessionEventType = "sampling.requested"
+ SessionEventTypeSessionAutopilotObjectiveChanged SessionEventType = "session.autopilot_objective_changed"
+ SessionEventTypeSessionBackgroundTasksChanged SessionEventType = "session.background_tasks_changed"
+ SessionEventTypeSessionCanvasOpened SessionEventType = "session.canvas.opened"
+ SessionEventTypeSessionCanvasRegistryChanged SessionEventType = "session.canvas.registry_changed"
+ SessionEventTypeSessionCompactionComplete SessionEventType = "session.compaction_complete"
+ SessionEventTypeSessionCompactionStart SessionEventType = "session.compaction_start"
+ SessionEventTypeSessionContextChanged SessionEventType = "session.context_changed"
+ SessionEventTypeSessionCustomAgentsUpdated SessionEventType = "session.custom_agents_updated"
+ SessionEventTypeSessionCustomNotification SessionEventType = "session.custom_notification"
+ SessionEventTypeSessionError SessionEventType = "session.error"
+ SessionEventTypeSessionExtensionsAttachmentsPushed SessionEventType = "session.extensions.attachments_pushed"
+ SessionEventTypeSessionExtensionsLoaded SessionEventType = "session.extensions_loaded"
+ SessionEventTypeSessionHandoff SessionEventType = "session.handoff"
+ SessionEventTypeSessionIdle SessionEventType = "session.idle"
+ SessionEventTypeSessionInfo SessionEventType = "session.info"
+ SessionEventTypeSessionMCPServersLoaded SessionEventType = "session.mcp_servers_loaded"
+ SessionEventTypeSessionMCPServerStatusChanged SessionEventType = "session.mcp_server_status_changed"
+ SessionEventTypeSessionModeChanged SessionEventType = "session.mode_changed"
+ SessionEventTypeSessionModelChange SessionEventType = "session.model_change"
+ SessionEventTypeSessionPermissionsChanged SessionEventType = "session.permissions_changed"
+ SessionEventTypeSessionPlanChanged SessionEventType = "session.plan_changed"
+ SessionEventTypeSessionRemoteSteerableChanged SessionEventType = "session.remote_steerable_changed"
+ SessionEventTypeSessionResume SessionEventType = "session.resume"
+ SessionEventTypeSessionScheduleCancelled SessionEventType = "session.schedule_cancelled"
+ SessionEventTypeSessionScheduleCreated SessionEventType = "session.schedule_created"
+ SessionEventTypeSessionShutdown SessionEventType = "session.shutdown"
+ SessionEventTypeSessionSkillsLoaded SessionEventType = "session.skills_loaded"
+ SessionEventTypeSessionSnapshotRewind SessionEventType = "session.snapshot_rewind"
+ SessionEventTypeSessionStart SessionEventType = "session.start"
+ SessionEventTypeSessionTaskComplete SessionEventType = "session.task_complete"
+ SessionEventTypeSessionTitleChanged SessionEventType = "session.title_changed"
+ SessionEventTypeSessionToolsUpdated SessionEventType = "session.tools_updated"
+ SessionEventTypeSessionTruncation SessionEventType = "session.truncation"
+ SessionEventTypeSessionUsageInfo SessionEventType = "session.usage_info"
+ SessionEventTypeSessionWarning SessionEventType = "session.warning"
+ SessionEventTypeSessionWorkspaceFileChanged SessionEventType = "session.workspace_file_changed"
+ SessionEventTypeSkillInvoked SessionEventType = "skill.invoked"
+ SessionEventTypeSubagentCompleted SessionEventType = "subagent.completed"
+ SessionEventTypeSubagentDeselected SessionEventType = "subagent.deselected"
+ SessionEventTypeSubagentFailed SessionEventType = "subagent.failed"
+ SessionEventTypeSubagentSelected SessionEventType = "subagent.selected"
+ SessionEventTypeSubagentStarted SessionEventType = "subagent.started"
+ SessionEventTypeSystemMessage SessionEventType = "system.message"
+ SessionEventTypeSystemNotification SessionEventType = "system.notification"
+ SessionEventTypeToolExecutionComplete SessionEventType = "tool.execution_complete"
+ SessionEventTypeToolExecutionPartialResult SessionEventType = "tool.execution_partial_result"
+ SessionEventTypeToolExecutionProgress SessionEventType = "tool.execution_progress"
+ SessionEventTypeToolExecutionStart SessionEventType = "tool.execution_start"
+ SessionEventTypeToolUserRequested SessionEventType = "tool.user_requested"
+ SessionEventTypeUserInputCompleted SessionEventType = "user_input.completed"
+ SessionEventTypeUserInputRequested SessionEventType = "user_input.requested"
+ SessionEventTypeUserMessage SessionEventType = "user.message"
)
// Agent intent description for current activity or plan
@@ -177,7 +178,7 @@ func (*AssistantReasoningData) Type() SessionEventType { return SessionEventType
type AssistantMessageData struct {
// Raw Anthropic content array with advisor blocks (server_tool_use, advisor_tool_result) for verbatim round-tripping
// Experimental: AnthropicAdvisorBlocks is part of an experimental API and may change or be removed.
- AnthropicAdvisorBlocks []any `json:"anthropicAdvisorBlocks,omitempty"`
+ AnthropicAdvisorBlocks []any `json:"anthropicAdvisorBlocks,omitzero"`
// Anthropic advisor model ID used for this response, for timeline display on replay
// Experimental: AnthropicAdvisorModel is part of an experimental API and may change or be removed.
AnthropicAdvisorModel *string `json:"anthropicAdvisorModel,omitempty"`
@@ -207,7 +208,7 @@ type AssistantMessageData struct {
// Copilot service request ID (x-copilot-service-request-id header) for CAPI log correlation
ServiceRequestID *string `json:"serviceRequestId,omitempty"`
// Tool invocations requested by the assistant in this message
- ToolRequests []AssistantMessageToolRequest `json:"toolRequests,omitempty"`
+ ToolRequests []AssistantMessageToolRequest `json:"toolRequests,omitzero"`
// Identifier for the agent loop turn that produced this message, matching the corresponding assistant.turn_start event
TurnID *string `json:"turnId,omitempty"`
}
@@ -378,7 +379,7 @@ type ElicitationCompletedData struct {
// The user action: "accept" (submitted form), "decline" (explicitly refused), or "cancel" (dismissed)
Action *ElicitationCompletedAction `json:"action,omitempty"`
// The submitted form data when action is 'accept'; keys match the requested schema fields
- Content map[string]ElicitationCompletedContent `json:"content,omitempty"`
+ Content map[string]ElicitationCompletedContent `json:"content,omitzero"`
// Request ID of the resolved elicitation request; clients should dismiss any UI for this request
RequestID string `json:"requestId"`
}
@@ -598,7 +599,7 @@ type AssistantUsageData struct {
ProviderCallID *string `json:"providerCallId,omitempty"`
// Per-quota resource usage snapshots, keyed by quota identifier
// Internal: QuotaSnapshots is part of the SDK's internal API surface and is not intended for external use.
- QuotaSnapshots map[string]AssistantUsageQuotaSnapshot `json:"quotaSnapshots,omitempty"`
+ QuotaSnapshots map[string]AssistantUsageQuotaSnapshot `json:"quotaSnapshots,omitzero"`
// Reasoning effort level used for model calls, if applicable (e.g. "none", "low", "medium", "high", "xhigh", "max")
ReasoningEffort *string `json:"reasoningEffort,omitempty"`
// Number of output tokens used for reasoning (e.g., chain-of-thought)
@@ -613,45 +614,45 @@ func (*AssistantUsageData) sessionEventData() {}
func (*AssistantUsageData) Type() SessionEventType { return SessionEventTypeAssistantUsage }
// MCP App view called a tool on a connected MCP server (SEP-1865)
-type McpAppToolCallCompleteData struct {
+type MCPAppToolCallCompleteData struct {
// Arguments passed to the tool by the app view, if any
- Arguments map[string]any `json:"arguments,omitempty"`
+ Arguments map[string]any `json:"arguments,omitzero"`
// Wall-clock duration of the underlying tools/call in milliseconds
DurationMs float64 `json:"durationMs"`
// Set when the underlying tools/call threw an error before returning a CallToolResult
- Error *McpAppToolCallCompleteError `json:"error,omitempty"`
+ Error *MCPAppToolCallCompleteError `json:"error,omitempty"`
// Standard MCP CallToolResult returned by the server. Present whether or not the call set isError.
- Result map[string]any `json:"result,omitempty"`
+ Result map[string]any `json:"result,omitzero"`
// Name of the MCP server hosting the tool
ServerName string `json:"serverName"`
// True when the call completed without throwing AND the MCP CallToolResult did not set isError
Success bool `json:"success"`
// The tool's `_meta.ui` block at the time of the call, so consumers can decide whether to forward the result to the model without re-listing tools.
- ToolMeta *McpAppToolCallCompleteToolMeta `json:"toolMeta,omitempty"`
+ ToolMeta *MCPAppToolCallCompleteToolMeta `json:"toolMeta,omitempty"`
// MCP tool name that was invoked
ToolName string `json:"toolName"`
}
-func (*McpAppToolCallCompleteData) sessionEventData() {}
-func (*McpAppToolCallCompleteData) Type() SessionEventType {
- return SessionEventTypeMcpAppToolCallComplete
+func (*MCPAppToolCallCompleteData) sessionEventData() {}
+func (*MCPAppToolCallCompleteData) Type() SessionEventType {
+ return SessionEventTypeMCPAppToolCallComplete
}
// MCP OAuth request completion notification
-type McpOauthCompletedData struct {
+type MCPOauthCompletedData struct {
// Request ID of the resolved OAuth request
RequestID string `json:"requestId"`
}
-func (*McpOauthCompletedData) sessionEventData() {}
-func (*McpOauthCompletedData) Type() SessionEventType { return SessionEventTypeMcpOauthCompleted }
+func (*MCPOauthCompletedData) sessionEventData() {}
+func (*MCPOauthCompletedData) Type() SessionEventType { return SessionEventTypeMCPOauthCompleted }
// Model change details including previous and new model identifiers
type SessionModelChangeData struct {
// Reason the change happened, when not user-initiated. Currently `"rate_limit_auto_switch"` for changes triggered by the auto-mode-switch rate-limit recovery path. UI clients can use this to render contextual copy.
Cause *string `json:"cause,omitempty"`
// Context tier after the model change; null explicitly clears a previously selected tier
- ContextTier *SessionModelChangeDataContextTier `json:"contextTier,omitempty"`
+ ContextTier *ContextTier `json:"contextTier,omitempty"`
// Newly selected model identifier
NewModel string `json:"newModel"`
// Model that was previously selected, if any
@@ -681,7 +682,7 @@ func (*SessionRemoteSteerableChangedData) Type() SessionEventType {
}
// OAuth authentication request for an MCP server
-type McpOauthRequiredData struct {
+type MCPOauthRequiredData struct {
// Unique identifier for this OAuth request; used to respond via session.respondToMcpOAuth()
RequestID string `json:"requestId"`
// Display name of the MCP server that requires OAuth
@@ -689,11 +690,11 @@ type McpOauthRequiredData struct {
// URL of the MCP server that requires OAuth
ServerURL string `json:"serverUrl"`
// Static OAuth client configuration, if the server specifies one
- StaticClientConfig *McpOauthRequiredStaticClientConfig `json:"staticClientConfig,omitempty"`
+ StaticClientConfig *MCPOauthRequiredStaticClientConfig `json:"staticClientConfig,omitempty"`
}
-func (*McpOauthRequiredData) sessionEventData() {}
-func (*McpOauthRequiredData) Type() SessionEventType { return SessionEventTypeMcpOauthRequired }
+func (*MCPOauthRequiredData) sessionEventData() {}
+func (*MCPOauthRequiredData) Type() SessionEventType { return SessionEventTypeMCPOauthRequired }
// Opaque custom notification data. Consumers may branch on source and name, but payload semantics are source-defined.
type SessionCustomNotificationData struct {
@@ -704,7 +705,7 @@ type SessionCustomNotificationData struct {
// Namespace for the custom notification producer
Source string `json:"source"`
// Optional source-defined string identifiers describing the payload subject
- Subject map[string]string `json:"subject,omitempty"`
+ Subject map[string]string `json:"subject,omitzero"`
// Optional source-defined payload schema version
Version *int64 `json:"version,omitempty"`
}
@@ -867,7 +868,7 @@ func (*SamplingCompletedData) Type() SessionEventType { return SessionEventTypeS
// Sampling request from an MCP server; contains the server name and a requestId for correlation
type SamplingRequestedData struct {
// The JSON-RPC request ID from the MCP protocol
- McpRequestID any `json:"mcpRequestId"`
+ MCPRequestID any `json:"mcpRequestId"`
// Unique identifier for this sampling request; used to respond via session.respondToSampling()
RequestID string `json:"requestId"`
// Name of the MCP server that initiated the sampling request
@@ -969,6 +970,17 @@ func (*SessionCustomAgentsUpdatedData) Type() SessionEventType {
return SessionEventTypeSessionCustomAgentsUpdated
}
+// Schema for the `ExtensionsAttachmentsPushedData` type.
+type SessionExtensionsAttachmentsPushedData struct {
+ // Attachments contributed by an extension; the host should surface these as composer pills and forward them via the next session.send call.
+ Attachments []Attachment `json:"attachments"`
+}
+
+func (*SessionExtensionsAttachmentsPushedData) sessionEventData() {}
+func (*SessionExtensionsAttachmentsPushedData) Type() SessionEventType {
+ return SessionEventTypeSessionExtensionsAttachmentsPushed
+}
+
// Schema for the `ExtensionsLoadedData` type.
type SessionExtensionsLoadedData struct {
// Array of discovered extensions and their status
@@ -981,29 +993,29 @@ func (*SessionExtensionsLoadedData) Type() SessionEventType {
}
// Schema for the `McpServerStatusChangedData` type.
-type SessionMcpServerStatusChangedData struct {
+type SessionMCPServerStatusChangedData struct {
// Error message if the server entered a failed state
Error *string `json:"error,omitempty"`
// Name of the MCP server whose status changed
ServerName string `json:"serverName"`
// Connection status: connected, failed, needs-auth, pending, disabled, or not_configured
- Status McpServerStatus `json:"status"`
+ Status MCPServerStatus `json:"status"`
}
-func (*SessionMcpServerStatusChangedData) sessionEventData() {}
-func (*SessionMcpServerStatusChangedData) Type() SessionEventType {
- return SessionEventTypeSessionMcpServerStatusChanged
+func (*SessionMCPServerStatusChangedData) sessionEventData() {}
+func (*SessionMCPServerStatusChangedData) Type() SessionEventType {
+ return SessionEventTypeSessionMCPServerStatusChanged
}
// Schema for the `McpServersLoadedData` type.
-type SessionMcpServersLoadedData struct {
+type SessionMCPServersLoadedData struct {
// Array of MCP server status summaries
- Servers []McpServersLoadedServer `json:"servers"`
+ Servers []MCPServersLoadedServer `json:"servers"`
}
-func (*SessionMcpServersLoadedData) sessionEventData() {}
-func (*SessionMcpServersLoadedData) Type() SessionEventType {
- return SessionEventTypeSessionMcpServersLoaded
+func (*SessionMCPServersLoadedData) sessionEventData() {}
+func (*SessionMCPServersLoadedData) Type() SessionEventType {
+ return SessionEventTypeSessionMCPServersLoaded
}
// Schema for the `SkillsLoadedData` type.
@@ -1029,7 +1041,7 @@ type UserMessageData struct {
// The agent mode that was active when this message was sent
AgentMode *UserMessageAgentMode `json:"agentMode,omitempty"`
// Files, selections, or GitHub references attached to the message
- Attachments []UserMessageAttachment `json:"attachments,omitempty"`
+ Attachments []Attachment `json:"attachments,omitzero"`
// The user's message text as displayed in the timeline
Content string `json:"content"`
// CAPI interaction ID for correlating this user message with its turn
@@ -1037,13 +1049,13 @@ type UserMessageData struct {
// True when this user message was auto-injected by autopilot's continuation loop rather than typed by the user; used to distinguish autopilot-driven turns in telemetry.
IsAutopilotContinuation *bool `json:"isAutopilotContinuation,omitempty"`
// Path-backed native document attachments that stayed on the tagged_files path flow because native upload could not read them or would exceed the request size limit
- NativeDocumentPathFallbackPaths []string `json:"nativeDocumentPathFallbackPaths,omitempty"`
+ NativeDocumentPathFallbackPaths []string `json:"nativeDocumentPathFallbackPaths,omitzero"`
// Parent agent task ID for background telemetry correlated to this user turn
ParentAgentTaskID *string `json:"parentAgentTaskId,omitempty"`
// Origin of this message, used for timeline filtering (e.g., "skill-pdf" for skill-injected messages that should be hidden from the user)
Source *string `json:"source,omitempty"`
// Normalized document MIME types that were sent natively instead of through tagged_files XML
- SupportedNativeDocumentMIMETypes []string `json:"supportedNativeDocumentMimeTypes,omitempty"`
+ SupportedNativeDocumentMIMETypes []string `json:"supportedNativeDocumentMimeTypes,omitzero"`
// Transformed version of the message sent to the model, with XML wrapping, timestamps, and other augmentations for prompt caching
TransformedContent *string `json:"transformedContent,omitempty"`
}
@@ -1088,7 +1100,7 @@ type SessionStartData struct {
// Working directory and git context at session start
Context *WorkingDirectoryContext `json:"context,omitempty"`
// Context tier selected at session creation time for models with tiered context pricing; null when no tier is selected (e.g., non-tiered model)
- ContextTier *SessionStartDataContextTier `json:"contextTier,omitempty"`
+ ContextTier *ContextTier `json:"contextTier,omitempty"`
// Version string of the Copilot application
CopilotVersion string `json:"copilotVersion"`
// When set, identifies a parent session whose context this session continues — e.g., a detached headless rem-agent run launched on the parent's interactive shutdown. Telemetry from this session is reported under the parent's session_id.
@@ -1121,7 +1133,7 @@ type SessionResumeData struct {
// Updated working directory and git context at resume time
Context *WorkingDirectoryContext `json:"context,omitempty"`
// Context tier currently selected at resume time; null when no tier is active
- ContextTier *SessionResumeDataContextTier `json:"contextTier,omitempty"`
+ ContextTier *ContextTier `json:"contextTier,omitempty"`
// When true, tool calls and permission requests left in flight by the previous session lifetime remain pending after resume and the agentic loop awaits their results. User sends are queued behind the pending work until all such requests reach a terminal state. When false (the default), any such tool calls and permission requests are immediately marked as interrupted on resume.
ContinuePendingWork *bool `json:"continuePendingWork,omitempty"`
// Total number of persisted events in the session at the time of resume
@@ -1177,7 +1189,7 @@ type SessionShutdownData struct {
// System message token count at shutdown
SystemTokens *int64 `json:"systemTokens,omitempty"`
// Session-wide per-token-type accumulated token counts
- TokenDetails map[string]ShutdownTokenDetail `json:"tokenDetails,omitempty"`
+ TokenDetails map[string]ShutdownTokenDetail `json:"tokenDetails,omitzero"`
// Tool definitions token count at shutdown
ToolDefinitionsTokens *int64 `json:"toolDefinitionsTokens,omitempty"`
// Cumulative time spent in API calls during the session, in milliseconds
@@ -1205,7 +1217,7 @@ func (*SessionTitleChangedData) Type() SessionEventType { return SessionEventTyp
// Skill invocation details including content, allowed tools, and plugin metadata
type SkillInvokedData struct {
// Tool names that should be auto-approved when this skill is active
- AllowedTools []string `json:"allowedTools,omitempty"`
+ AllowedTools []string `json:"allowedTools,omitzero"`
// Full content of the skill file, injected into the conversation for the model
Content string `json:"content"`
// Description of the skill from its SKILL.md frontmatter
@@ -1415,7 +1427,7 @@ type ToolExecutionCompleteData struct {
// Tool definition metadata, present for MCP tools with MCP Apps support
ToolDescription *ToolExecutionCompleteToolDescription `json:"toolDescription,omitempty"`
// Tool-specific telemetry data (e.g., CodeQL check counts, grep match counts)
- ToolTelemetry map[string]any `json:"toolTelemetry,omitempty"`
+ ToolTelemetry map[string]any `json:"toolTelemetry,omitzero"`
// Identifier for the agent loop turn this tool was invoked in, matching the corresponding assistant.turn_start event
TurnID *string `json:"turnId,omitempty"`
}
@@ -1445,9 +1457,11 @@ type ToolExecutionStartData struct {
// When true, the tool output should be displayed expanded (verbatim) in the CLI timeline
DisplayVerbatim *bool `json:"displayVerbatim,omitempty"`
// Name of the MCP server hosting this tool, when the tool is an MCP tool
- McpServerName *string `json:"mcpServerName,omitempty"`
+ MCPServerName *string `json:"mcpServerName,omitempty"`
// Original tool name on the MCP server, when the tool is an MCP tool
- McpToolName *string `json:"mcpToolName,omitempty"`
+ MCPToolName *string `json:"mcpToolName,omitempty"`
+ // Model identifier that generated this tool call
+ Model *string `json:"model,omitempty"`
// Tool call ID of the parent tool invocation when this event originates from a sub-agent
// Deprecated: ParentToolCallID is deprecated.
ParentToolCallID *string `json:"parentToolCallId,omitempty"`
@@ -1509,7 +1523,7 @@ type UserInputRequestedData struct {
// Whether the user can provide a free-form text response in addition to predefined choices
AllowFreeform *bool `json:"allowFreeform,omitempty"`
// Predefined choices for the user to select from, if applicable
- Choices []string `json:"choices,omitempty"`
+ Choices []string `json:"choices,omitzero"`
// The question or prompt to present to the user
Question string `json:"question"`
// Unique identifier for this input request; used to respond via session.respondToUserInput()
@@ -1592,9 +1606,9 @@ type AssistantMessageToolRequest struct {
// Resolved intention summary describing what this specific call does
IntentionSummary *string `json:"intentionSummary,omitempty"`
// Name of the MCP server hosting this tool, when the tool is an MCP tool
- McpServerName *string `json:"mcpServerName,omitempty"`
+ MCPServerName *string `json:"mcpServerName,omitempty"`
// Original tool name on the MCP server, when the tool is an MCP tool
- McpToolName *string `json:"mcpToolName,omitempty"`
+ MCPToolName *string `json:"mcpToolName,omitempty"`
// Name of the tool being invoked
Name string `json:"name"`
// Unique identifier for this tool call
@@ -1658,7 +1672,7 @@ type AssistantUsageQuotaSnapshot struct {
// Schema for the `CanvasRegistryChangedCanvas` type.
type CanvasRegistryChangedCanvas struct {
// Actions the agent or host may invoke
- Actions []CanvasRegistryChangedCanvasAction `json:"actions,omitempty"`
+ Actions []CanvasRegistryChangedCanvasAction `json:"actions,omitzero"`
// Provider-local canvas identifier
CanvasID string `json:"canvasId"`
// Short, single-sentence description shown to the agent in canvas catalogs.
@@ -1670,7 +1684,7 @@ type CanvasRegistryChangedCanvas struct {
// Owning extension display name, when available
ExtensionName *string `json:"extensionName,omitempty"`
// JSON Schema for canvas open input
- InputSchema map[string]any `json:"inputSchema,omitempty"`
+ InputSchema map[string]any `json:"inputSchema,omitzero"`
}
// Schema for the `CanvasRegistryChangedCanvasAction` type.
@@ -1678,7 +1692,7 @@ type CanvasRegistryChangedCanvasAction struct {
// Action description
Description *string `json:"description,omitempty"`
// JSON Schema for action input
- InputSchema map[string]any `json:"inputSchema,omitempty"`
+ InputSchema map[string]any `json:"inputSchema,omitzero"`
// Action name
Name string `json:"name"`
}
@@ -1690,7 +1704,7 @@ type CapabilitiesChangedUI struct {
// Whether elicitation is now supported
Elicitation *bool `json:"elicitation,omitempty"`
// Whether MCP Apps (SEP-1865) UI passthrough is now supported
- McpApps *bool `json:"mcpApps,omitempty"`
+ MCPApps *bool `json:"mcpApps,omitempty"`
}
// Schema for the `CommandsChangedCommand` type.
@@ -1796,7 +1810,7 @@ type ElicitationRequestedSchema struct {
// Form field definitions, keyed by field name
Properties map[string]any `json:"properties"`
// List of required field names
- Required []string `json:"required,omitempty"`
+ Required []string `json:"required,omitzero"`
// Schema type indicator (always 'object')
Type ElicitationRequestedSchemaType `json:"type"`
}
@@ -1832,37 +1846,37 @@ type HookEndError struct {
}
// Set when the underlying tools/call threw an error before returning a CallToolResult
-type McpAppToolCallCompleteError struct {
+type MCPAppToolCallCompleteError struct {
// Human-readable error message
Message string `json:"message"`
}
// The tool's `_meta.ui` block at the time of the call, so consumers can decide whether to forward the result to the model without re-listing tools.
-type McpAppToolCallCompleteToolMeta struct {
+type MCPAppToolCallCompleteToolMeta struct {
// Schema for the `McpAppToolCallCompleteToolMetaUI` type.
- UI *McpAppToolCallCompleteToolMetaUI `json:"ui,omitempty"`
+ UI *MCPAppToolCallCompleteToolMetaUI `json:"ui,omitempty"`
}
// Schema for the `McpAppToolCallCompleteToolMetaUI` type.
-type McpAppToolCallCompleteToolMetaUI struct {
+type MCPAppToolCallCompleteToolMetaUI struct {
// `ui://` URI declared by the tool's `_meta.ui.resourceUri`
ResourceURI *string `json:"resourceUri,omitempty"`
// Tool visibility per SEP-1865 (typically a subset of `["model","app"]`)
- Visibility []string `json:"visibility,omitempty"`
+ Visibility []string `json:"visibility,omitzero"`
}
// Static OAuth client configuration, if the server specifies one
-type McpOauthRequiredStaticClientConfig struct {
+type MCPOauthRequiredStaticClientConfig struct {
// OAuth client ID for the server
ClientID string `json:"clientId"`
// Optional non-default OAuth grant type. When set to 'client_credentials', the OAuth flow runs headlessly using the client_id + keychain-stored secret (no browser, no callback server).
- GrantType *McpOauthRequiredStaticClientConfigGrantType `json:"grantType,omitempty"`
+ GrantType *MCPOauthRequiredStaticClientConfigGrantType `json:"grantType,omitempty"`
// Whether this is a public OAuth client
PublicClient *bool `json:"publicClient,omitempty"`
}
// Schema for the `McpServersLoadedServer` type.
-type McpServersLoadedServer struct {
+type MCPServersLoadedServer struct {
// Error message if the server failed to connect
Error *string `json:"error,omitempty"`
// Server name (config key)
@@ -1872,11 +1886,11 @@ type McpServersLoadedServer struct {
// Version of the plugin that supplied the effective MCP server config, only when source is plugin
PluginVersion *string `json:"pluginVersion,omitempty"`
// Configuration source: user, workspace, plugin, or builtin
- Source *McpServerSource `json:"source,omitempty"`
+ Source *MCPServerSource `json:"source,omitempty"`
// Connection status: connected, failed, needs-auth, pending, disabled, or not_configured
- Status McpServerStatus `json:"status"`
+ Status MCPServerStatus `json:"status"`
// Transport mechanism: stdio, http, sse (deprecated), or memory (in-process MCP server)
- Transport *McpServerTransport `json:"transport,omitempty"`
+ Transport *MCPServerTransport `json:"transport,omitempty"`
}
// Derived user-facing permission prompt details for UI consumers
@@ -1981,7 +1995,7 @@ func (PermissionPromptRequestHook) Kind() PermissionPromptRequestKind {
}
// MCP tool invocation permission prompt
-type PermissionPromptRequestMcp struct {
+type PermissionPromptRequestMCP struct {
// Arguments to pass to the MCP tool
Args *any `json:"args,omitempty"`
// Name of the MCP server providing the tool
@@ -1994,9 +2008,9 @@ type PermissionPromptRequestMcp struct {
ToolTitle string `json:"toolTitle"`
}
-func (PermissionPromptRequestMcp) permissionPromptRequest() {}
-func (PermissionPromptRequestMcp) Kind() PermissionPromptRequestKind {
- return PermissionPromptRequestKindMcp
+func (PermissionPromptRequestMCP) permissionPromptRequest() {}
+func (PermissionPromptRequestMCP) Kind() PermissionPromptRequestKind {
+ return PermissionPromptRequestKindMCP
}
// Memory operation permission prompt
@@ -2169,7 +2183,7 @@ func (PermissionRequestHook) Kind() PermissionRequestKind {
}
// MCP tool invocation permission request
-type PermissionRequestMcp struct {
+type PermissionRequestMCP struct {
// Arguments to pass to the MCP tool
Args any `json:"args,omitempty"`
// Whether this MCP tool is read-only (no side effects)
@@ -2184,9 +2198,9 @@ type PermissionRequestMcp struct {
ToolTitle string `json:"toolTitle"`
}
-func (PermissionRequestMcp) permissionRequest() {}
-func (PermissionRequestMcp) Kind() PermissionRequestKind {
- return PermissionRequestKindMcp
+func (PermissionRequestMCP) permissionRequest() {}
+func (PermissionRequestMCP) Kind() PermissionRequestKind {
+ return PermissionRequestKindMCP
}
// Memory operation permission request
@@ -2242,7 +2256,7 @@ type PermissionRequestShell struct {
// File paths that may be read or written by the command
PossiblePaths []string `json:"possiblePaths"`
// URLs that may be accessed by the command
- PossibleUrls []PermissionRequestShellPossibleURL `json:"possibleUrls"`
+ PossibleURLs []PermissionRequestShellPossibleURL `json:"possibleUrls"`
// Tool call ID that triggered this permission request
ToolCallID *string `json:"toolCallId,omitempty"`
// Optional warning message about risks of running this command
@@ -2438,7 +2452,7 @@ type ShutdownModelMetric struct {
// Request count and cost metrics
Requests ShutdownModelMetricRequests `json:"requests"`
// Token count details per type
- TokenDetails map[string]ShutdownModelMetricTokenDetail `json:"tokenDetails,omitempty"`
+ TokenDetails map[string]ShutdownModelMetricTokenDetail `json:"tokenDetails,omitzero"`
// Accumulated nano-AI units cost for this model
// Experimental: TotalNanoAiu is part of an experimental API and may change or be removed.
TotalNanoAiu *float64 `json:"totalNanoAiu,omitempty"`
@@ -2503,7 +2517,7 @@ type SystemMessageMetadata struct {
// Version identifier of the prompt template used
PromptVersion *string `json:"promptVersion,omitempty"`
// Template variables used when constructing the prompt
- Variables map[string]any `json:"variables,omitempty"`
+ Variables map[string]any `json:"variables,omitzero"`
}
// Structured metadata identifying what triggered this notification
@@ -2676,7 +2690,7 @@ type ToolExecutionCompleteContentResourceLink struct {
// Human-readable description of the resource
Description *string `json:"description,omitempty"`
// Icons associated with this resource
- Icons []ToolExecutionCompleteContentResourceLinkIcon `json:"icons,omitempty"`
+ Icons []ToolExecutionCompleteContentResourceLinkIcon `json:"icons,omitzero"`
// MIME type of the resource content
MIMEType *string `json:"mimeType,omitempty"`
// Resource name identifier
@@ -2731,7 +2745,7 @@ type ToolExecutionCompleteContentResourceLinkIcon struct {
// MIME type of the icon image
MIMEType *string `json:"mimeType,omitempty"`
// Available icon sizes (e.g., ['16x16', '32x32'])
- Sizes []string `json:"sizes,omitempty"`
+ Sizes []string `json:"sizes,omitzero"`
// URL or path to the icon image
Src string `json:"src"`
// Theme variant this icon is intended for
@@ -2751,7 +2765,7 @@ type ToolExecutionCompleteResult struct {
// Concise tool result text sent to the LLM for chat completion, potentially truncated for token efficiency
Content string `json:"content"`
// Structured content blocks (text, images, audio, resources) returned by the tool in their native format
- Contents []ToolExecutionCompleteContent `json:"contents,omitempty"`
+ Contents []ToolExecutionCompleteContent `json:"contents,omitzero"`
// Full detailed tool result for UI/timeline display, preserving complete content such as diffs. Falls back to content when absent.
DetailedContent *string `json:"detailedContent,omitempty"`
// MCP Apps UI resource content for rendering in a sandboxed iframe
@@ -2779,7 +2793,7 @@ type ToolExecutionCompleteToolDescriptionMetaUI struct {
// URI of the UI resource
ResourceURI *string `json:"resourceUri,omitempty"`
// Who can access this tool
- Visibility []ToolExecutionCompleteToolDescriptionMetaUIVisibility `json:"visibility,omitempty"`
+ Visibility []ToolExecutionCompleteToolDescriptionMetaUIVisibility `json:"visibility,omitzero"`
}
// MCP Apps UI resource content for rendering in a sandboxed iframe
@@ -2814,10 +2828,10 @@ type ToolExecutionCompleteUIResourceMetaUI struct {
// Schema for the `ToolExecutionCompleteUIResourceMetaUICsp` type.
type ToolExecutionCompleteUIResourceMetaUICsp struct {
- BaseURIDomains []string `json:"baseUriDomains,omitempty"`
- ConnectDomains []string `json:"connectDomains,omitempty"`
- FrameDomains []string `json:"frameDomains,omitempty"`
- ResourceDomains []string `json:"resourceDomains,omitempty"`
+ BaseURIDomains []string `json:"baseUriDomains,omitzero"`
+ ConnectDomains []string `json:"connectDomains,omitzero"`
+ FrameDomains []string `json:"frameDomains,omitzero"`
+ ResourceDomains []string `json:"resourceDomains,omitzero"`
}
// Schema for the `ToolExecutionCompleteUIResourceMetaUIPermissions` type.
@@ -2848,133 +2862,6 @@ type ToolExecutionCompleteUIResourceMetaUIPermissionsGeolocation struct {
type ToolExecutionCompleteUIResourceMetaUIPermissionsMicrophone struct {
}
-// A user message attachment — a file, directory, code selection, blob, or GitHub reference
-type UserMessageAttachment interface {
- userMessageAttachment()
- Type() UserMessageAttachmentType
-}
-
-type RawUserMessageAttachment struct {
- Discriminator UserMessageAttachmentType
- Raw json.RawMessage
-}
-
-func (RawUserMessageAttachment) userMessageAttachment() {}
-func (r RawUserMessageAttachment) Type() UserMessageAttachmentType {
- return r.Discriminator
-}
-
-// Blob attachment with inline base64-encoded data
-type UserMessageAttachmentBlob struct {
- // Base64-encoded content
- Data string `json:"data"`
- // User-facing display name for the attachment
- DisplayName *string `json:"displayName,omitempty"`
- // MIME type of the inline data
- MIMEType string `json:"mimeType"`
-}
-
-func (UserMessageAttachmentBlob) userMessageAttachment() {}
-func (UserMessageAttachmentBlob) Type() UserMessageAttachmentType {
- return UserMessageAttachmentTypeBlob
-}
-
-// Directory attachment
-type UserMessageAttachmentDirectory struct {
- // User-facing display name for the attachment
- DisplayName string `json:"displayName"`
- // Absolute directory path
- Path string `json:"path"`
-}
-
-func (UserMessageAttachmentDirectory) userMessageAttachment() {}
-func (UserMessageAttachmentDirectory) Type() UserMessageAttachmentType {
- return UserMessageAttachmentTypeDirectory
-}
-
-// File attachment
-type UserMessageAttachmentFile struct {
- // User-facing display name for the attachment
- DisplayName string `json:"displayName"`
- // Optional line range to scope the attachment to a specific section of the file
- LineRange *UserMessageAttachmentFileLineRange `json:"lineRange,omitempty"`
- // Absolute file path
- Path string `json:"path"`
-}
-
-func (UserMessageAttachmentFile) userMessageAttachment() {}
-func (UserMessageAttachmentFile) Type() UserMessageAttachmentType {
- return UserMessageAttachmentTypeFile
-}
-
-// GitHub issue, pull request, or discussion reference
-type UserMessageAttachmentGithubReference struct {
- // Issue, pull request, or discussion number
- Number int64 `json:"number"`
- // Type of GitHub reference
- ReferenceType UserMessageAttachmentGithubReferenceType `json:"referenceType"`
- // Current state of the referenced item (e.g., open, closed, merged)
- State string `json:"state"`
- // Title of the referenced item
- Title string `json:"title"`
- // URL to the referenced item on GitHub
- URL string `json:"url"`
-}
-
-func (UserMessageAttachmentGithubReference) userMessageAttachment() {}
-func (UserMessageAttachmentGithubReference) Type() UserMessageAttachmentType {
- return UserMessageAttachmentTypeGithubReference
-}
-
-// Code selection attachment from an editor
-type UserMessageAttachmentSelection struct {
- // User-facing display name for the selection
- DisplayName string `json:"displayName"`
- // Absolute path to the file containing the selection
- FilePath string `json:"filePath"`
- // Position range of the selection within the file
- Selection UserMessageAttachmentSelectionDetails `json:"selection"`
- // The selected text content
- Text string `json:"text"`
-}
-
-func (UserMessageAttachmentSelection) userMessageAttachment() {}
-func (UserMessageAttachmentSelection) Type() UserMessageAttachmentType {
- return UserMessageAttachmentTypeSelection
-}
-
-// Optional line range to scope the attachment to a specific section of the file
-type UserMessageAttachmentFileLineRange struct {
- // End line number (1-based, inclusive)
- End int64 `json:"end"`
- // Start line number (1-based)
- Start int64 `json:"start"`
-}
-
-// Position range of the selection within the file
-type UserMessageAttachmentSelectionDetails struct {
- // End position of the selection
- End UserMessageAttachmentSelectionDetailsEnd `json:"end"`
- // Start position of the selection
- Start UserMessageAttachmentSelectionDetailsStart `json:"start"`
-}
-
-// End position of the selection
-type UserMessageAttachmentSelectionDetailsEnd struct {
- // End character offset within the line (0-based)
- Character int64 `json:"character"`
- // End line number (0-based)
- Line int64 `json:"line"`
-}
-
-// Start position of the selection
-type UserMessageAttachmentSelectionDetailsStart struct {
- // Start character offset within the line (0-based)
- Character int64 `json:"character"`
- // Start line number (0-based)
- Line int64 `json:"line"`
-}
-
// Working directory and git context at session start
type WorkingDirectoryContext struct {
// Base commit of current git branch at session start time
@@ -3145,24 +3032,24 @@ const (
)
// Optional non-default OAuth grant type. When set to 'client_credentials', the OAuth flow runs headlessly using the client_id + keychain-stored secret (no browser, no callback server).
-type McpOauthRequiredStaticClientConfigGrantType string
+type MCPOauthRequiredStaticClientConfigGrantType string
const (
- McpOauthRequiredStaticClientConfigGrantTypeClientCredentials McpOauthRequiredStaticClientConfigGrantType = "client_credentials"
+ MCPOauthRequiredStaticClientConfigGrantTypeClientCredentials MCPOauthRequiredStaticClientConfigGrantType = "client_credentials"
)
// Transport mechanism: stdio, http, sse (deprecated), or memory (in-process MCP server)
-type McpServerTransport string
+type MCPServerTransport string
const (
// Server communicates over streamable HTTP.
- McpServerTransportHTTP McpServerTransport = "http"
+ MCPServerTransportHTTP MCPServerTransport = "http"
// Server is backed by an in-memory runtime implementation.
- McpServerTransportMemory McpServerTransport = "memory"
+ MCPServerTransportMemory MCPServerTransport = "memory"
// Server communicates over Server-Sent Events (deprecated).
- McpServerTransportSse McpServerTransport = "sse"
+ MCPServerTransportSSE MCPServerTransport = "sse"
// Server communicates over stdio with a local child process.
- McpServerTransportStdio McpServerTransport = "stdio"
+ MCPServerTransportStdio MCPServerTransport = "stdio"
)
// Where the failed model call originated
@@ -3170,7 +3057,7 @@ type ModelCallFailureSource string
const (
// Model call from MCP sampling.
- ModelCallFailureSourceMcpSampling ModelCallFailureSource = "mcp_sampling"
+ ModelCallFailureSourceMCPSampling ModelCallFailureSource = "mcp_sampling"
// Model call from a sub-agent.
ModelCallFailureSourceSubagent ModelCallFailureSource = "subagent"
// Model call from the top-level agent.
@@ -3186,7 +3073,7 @@ const (
PermissionPromptRequestKindExtensionManagement PermissionPromptRequestKind = "extension-management"
PermissionPromptRequestKindExtensionPermissionAccess PermissionPromptRequestKind = "extension-permission-access"
PermissionPromptRequestKindHook PermissionPromptRequestKind = "hook"
- PermissionPromptRequestKindMcp PermissionPromptRequestKind = "mcp"
+ PermissionPromptRequestKindMCP PermissionPromptRequestKind = "mcp"
PermissionPromptRequestKindMemory PermissionPromptRequestKind = "memory"
PermissionPromptRequestKindPath PermissionPromptRequestKind = "path"
PermissionPromptRequestKindRead PermissionPromptRequestKind = "read"
@@ -3214,7 +3101,7 @@ const (
PermissionRequestKindExtensionManagement PermissionRequestKind = "extension-management"
PermissionRequestKindExtensionPermissionAccess PermissionRequestKind = "extension-permission-access"
PermissionRequestKindHook PermissionRequestKind = "hook"
- PermissionRequestKindMcp PermissionRequestKind = "mcp"
+ PermissionRequestKindMCP PermissionRequestKind = "mcp"
PermissionRequestKindMemory PermissionRequestKind = "memory"
PermissionRequestKindRead PermissionRequestKind = "read"
PermissionRequestKindShell PermissionRequestKind = "shell"
@@ -3269,33 +3156,6 @@ const (
PlanChangedOperationUpdate PlanChangedOperation = "update"
)
-type SessionModelChangeDataContextTier string
-
-const (
- // Default context tier with standard context window size.
- SessionModelChangeDataContextTierDefault SessionModelChangeDataContextTier = "default"
- // Extended context tier with a larger context window.
- SessionModelChangeDataContextTierLongContext SessionModelChangeDataContextTier = "long_context"
-)
-
-type SessionResumeDataContextTier string
-
-const (
- // Default context tier with standard context window size.
- SessionResumeDataContextTierDefault SessionResumeDataContextTier = "default"
- // Extended context tier with a larger context window.
- SessionResumeDataContextTierLongContext SessionResumeDataContextTier = "long_context"
-)
-
-type SessionStartDataContextTier string
-
-const (
- // Default context tier with standard context window size.
- SessionStartDataContextTierDefault SessionStartDataContextTier = "default"
- // Extended context tier with a larger context window.
- SessionStartDataContextTierLongContext SessionStartDataContextTier = "long_context"
-)
-
// What triggered the skill invocation: `user-invoked` (explicit user action, such as via a slash command or UI affordance), `agent-invoked` (agent requested the skill), or `context-load` (loaded as part of another context, such as preloading skills configured on a custom agent or subagent)
type SkillInvokedTrigger string
@@ -3386,37 +3246,14 @@ const (
UserMessageAgentModeShell UserMessageAgentMode = "shell"
)
-// Type of GitHub reference
-type UserMessageAttachmentGithubReferenceType string
-
-const (
- // GitHub discussion reference.
- UserMessageAttachmentGithubReferenceTypeDiscussion UserMessageAttachmentGithubReferenceType = "discussion"
- // GitHub issue reference.
- UserMessageAttachmentGithubReferenceTypeIssue UserMessageAttachmentGithubReferenceType = "issue"
- // GitHub pull request reference.
- UserMessageAttachmentGithubReferenceTypePr UserMessageAttachmentGithubReferenceType = "pr"
-)
-
-// Type discriminator for UserMessageAttachment.
-type UserMessageAttachmentType string
-
-const (
- UserMessageAttachmentTypeBlob UserMessageAttachmentType = "blob"
- UserMessageAttachmentTypeDirectory UserMessageAttachmentType = "directory"
- UserMessageAttachmentTypeFile UserMessageAttachmentType = "file"
- UserMessageAttachmentTypeGithubReference UserMessageAttachmentType = "github_reference"
- UserMessageAttachmentTypeSelection UserMessageAttachmentType = "selection"
-)
-
// Hosting platform type of the repository (github or ado)
type WorkingDirectoryContextHostType string
const (
// Repository is hosted on Azure DevOps.
- WorkingDirectoryContextHostTypeAdo WorkingDirectoryContextHostType = "ado"
+ WorkingDirectoryContextHostTypeADO WorkingDirectoryContextHostType = "ado"
// Repository is hosted on GitHub.
- WorkingDirectoryContextHostTypeGithub WorkingDirectoryContextHostType = "github"
+ WorkingDirectoryContextHostTypeGitHub WorkingDirectoryContextHostType = "github"
)
// Whether the file was newly created or updated
@@ -3431,17 +3268,6 @@ const (
// Type aliases for convenience.
type (
- Attachment = UserMessageAttachment
- AttachmentType = UserMessageAttachmentType
PermissionRequestCommand = PermissionRequestShellCommand
PossibleURL = PermissionRequestShellPossibleURL
)
-
-// Constant aliases for convenience.
-const (
- AttachmentTypeBlob = UserMessageAttachmentTypeBlob
- AttachmentTypeDirectory = UserMessageAttachmentTypeDirectory
- AttachmentTypeFile = UserMessageAttachmentTypeFile
- AttachmentTypeGithubReference = UserMessageAttachmentTypeGithubReference
- AttachmentTypeSelection = UserMessageAttachmentTypeSelection
-)
diff --git a/go/samples/manual_tool_resume/main.go b/go/samples/manual_tool_resume/main.go
index 1e0a23f5b..a7391ff40 100644
--- a/go/samples/manual_tool_resume/main.go
+++ b/go/samples/manual_tool_resume/main.go
@@ -143,7 +143,7 @@ func main() {
}
session2, err := client2.ResumeSession(ctx, sessionID, &copilot.ResumeSessionConfig{
Tools: []copilot.Tool{tool},
- ContinuePendingWork: true,
+ ContinuePendingWork: copilot.Bool(true),
})
if err != nil {
panic(err)
@@ -177,7 +177,7 @@ func main() {
}
session3, err := client3.ResumeSession(ctx, sessionID, &copilot.ResumeSessionConfig{
Tools: []copilot.Tool{tool},
- ContinuePendingWork: true,
+ ContinuePendingWork: copilot.Bool(true),
})
if err != nil {
panic(err)
diff --git a/go/sdk_protocol_version.go b/go/sdk_protocol_version.go
index 95249568b..eb17c7bbd 100644
--- a/go/sdk_protocol_version.go
+++ b/go/sdk_protocol_version.go
@@ -2,11 +2,11 @@
package copilot
-// SdkProtocolVersion is the SDK protocol version.
+// SDKProtocolVersion is the SDK protocol version.
// This must match the version expected by the copilot-agent-runtime server.
-const SdkProtocolVersion = 3
+const SDKProtocolVersion = 3
-// GetSdkProtocolVersion returns the SDK protocol version.
-func GetSdkProtocolVersion() int {
- return SdkProtocolVersion
+// GetSDKProtocolVersion returns the SDK protocol version.
+func GetSDKProtocolVersion() int {
+ return SDKProtocolVersion
}
diff --git a/go/session.go b/go/session.go
index fa03f5cc7..3e37a3483 100644
--- a/go/session.go
+++ b/go/session.go
@@ -53,7 +53,7 @@ type Session struct {
SessionID string
workspacePath string
client *jsonrpc2.Client
- clientSessionApis *rpc.ClientSessionApiHandlers
+ clientSessionAPIs *rpc.ClientSessionAPIHandlers
handlers []sessionHandler
nextHandlerID uint64
handlerMutex sync.RWMutex
@@ -88,7 +88,7 @@ type Session struct {
closeOnce sync.Once // guards eventCh close so Disconnect is safe to call more than once
// RPC provides typed session-scoped RPC methods.
- RPC *rpc.SessionRpc
+ RPC *rpc.SessionRPC
}
// WorkspacePath returns the path to the session workspace directory when infinite
@@ -283,14 +283,14 @@ func newSession(sessionID string, client *jsonrpc2.Client, workspacePath string)
SessionID: sessionID,
workspacePath: workspacePath,
client: client,
- clientSessionApis: &rpc.ClientSessionApiHandlers{},
+ clientSessionAPIs: &rpc.ClientSessionAPIHandlers{},
handlers: make([]sessionHandler, 0),
toolHandlers: make(map[string]ToolHandler),
commandHandlers: make(map[string]CommandHandler),
eventCh: make(chan SessionEvent, 128),
- RPC: rpc.NewSessionRpc(client, sessionID),
+ RPC: rpc.NewSessionRPC(client, sessionID),
}
- s.clientSessionApis.Canvas = newCanvasClientSessionAdapter(s)
+ s.clientSessionAPIs.Canvas = newCanvasClientSessionAdapter(s)
go s.processEvents()
return s
}
@@ -311,7 +311,7 @@ func newSession(sessionID string, client *jsonrpc2.Client, workspacePath string)
// messageID, err := session.Send(context.Background(), copilot.MessageOptions{
// Prompt: "Explain this code",
// Attachments: []copilot.Attachment{
-// &copilot.UserMessageAttachmentFile{DisplayName: "main.go", Path: "./main.go"},
+// &copilot.AttachmentFile{DisplayName: "main.go", Path: "./main.go"},
// },
// })
// if err != nil {
@@ -652,14 +652,14 @@ func (s *Session) handleHooksInvoke(hookType string, rawInput json.RawMessage) (
return hooks.OnPreToolUse(input, invocation)
case "preMcpToolCall":
- if hooks.OnPreMcpToolCall == nil {
+ if hooks.OnPreMCPToolCall == nil {
return nil, nil
}
- var input PreMcpToolCallHookInput
+ var input PreMCPToolCallHookInput
if err := json.Unmarshal(rawInput, &input); err != nil {
return nil, fmt.Errorf("invalid hook input: %w", err)
}
- return hooks.OnPreMcpToolCall(input, invocation)
+ return hooks.OnPreMCPToolCall(input, invocation)
case "postToolUse":
if hooks.OnPostToolUse == nil {
@@ -867,25 +867,28 @@ func (s *Session) handleElicitationRequest(elicitCtx ElicitationContext, request
return
}
- rpcContent := make(map[string]rpc.UIElicitationFieldValue)
- for k, v := range result.Content {
- contentValue, err := toRPCContent(v)
- if err != nil {
- s.RPC.UI.HandlePendingElicitation(ctx, &rpc.UIHandlePendingElicitationRequest{
- RequestID: requestID,
- Result: rpc.UIElicitationResponse{
- Action: rpc.UIElicitationResponseActionCancel,
- },
- })
- return
+ var rpcContent map[string]rpc.UIElicitationFieldValue
+ if result.Content != nil {
+ rpcContent = make(map[string]rpc.UIElicitationFieldValue, len(result.Content))
+ for k, v := range result.Content {
+ contentValue, err := toRPCContent(v)
+ if err != nil {
+ s.RPC.UI.HandlePendingElicitation(ctx, &rpc.UIHandlePendingElicitationRequest{
+ RequestID: requestID,
+ Result: rpc.UIElicitationResponse{
+ Action: rpc.UIElicitationResponseActionCancel,
+ },
+ })
+ return
+ }
+ rpcContent[k] = contentValue
}
- rpcContent[k] = contentValue
}
s.RPC.UI.HandlePendingElicitation(ctx, &rpc.UIHandlePendingElicitationRequest{
RequestID: requestID,
Result: rpc.UIElicitationResponse{
- Action: rpc.UIElicitationResponseAction(result.Action),
+ Action: result.Action,
Content: rpcContent,
},
})
@@ -983,13 +986,17 @@ func (s *Session) assertElicitation() error {
}
// Elicitation shows a generic elicitation dialog with a custom schema.
-func (ui *SessionUI) Elicitation(ctx context.Context, message string, requestedSchema rpc.UIElicitationSchema) (*ElicitationResult, error) {
+func (ui *SessionUI) Elicitation(ctx context.Context, message string, requestedSchema ElicitationSchema) (*ElicitationResult, error) {
if err := ui.session.assertElicitation(); err != nil {
return nil, err
}
+ rpcSchema, err := toRPCUIElicitationSchema(requestedSchema)
+ if err != nil {
+ return nil, err
+ }
rpcResult, err := ui.session.RPC.UI.Elicitation(ctx, &rpc.UIElicitationRequest{
Message: message,
- RequestedSchema: requestedSchema,
+ RequestedSchema: rpcSchema,
})
if err != nil {
return nil, err
@@ -997,6 +1004,60 @@ func (ui *SessionUI) Elicitation(ctx context.Context, message string, requestedS
return fromRPCElicitationResult(rpcResult), nil
}
+func toRPCUIElicitationSchema(schema ElicitationSchema) (rpc.UIElicitationSchema, error) {
+ var properties map[string]rpc.UIElicitationSchemaProperty
+ if schema.Properties != nil {
+ properties = make(map[string]rpc.UIElicitationSchemaProperty, len(schema.Properties))
+ for name, property := range schema.Properties {
+ rpcProperty, err := toRPCUIElicitationSchemaProperty(name, property)
+ if err != nil {
+ return rpc.UIElicitationSchema{}, err
+ }
+ properties[name] = rpcProperty
+ }
+ }
+
+ return rpc.UIElicitationSchema{
+ Properties: properties,
+ Required: append([]string(nil), schema.Required...),
+ Type: rpc.UIElicitationSchemaTypeObject,
+ }, nil
+}
+
+func toRPCUIElicitationSchemaProperty(name string, property any) (rpc.UIElicitationSchemaProperty, error) {
+ if property == nil {
+ return nil, fmt.Errorf("elicitation schema property %q is nil", name)
+ }
+ if rpcProperty, ok := property.(rpc.UIElicitationSchemaProperty); ok {
+ return rpcProperty, nil
+ }
+
+ data, err := json.Marshal(property)
+ if err != nil {
+ return nil, fmt.Errorf("marshal elicitation schema property %q: %w", name, err)
+ }
+ wrapperData, err := json.Marshal(struct {
+ Properties map[string]json.RawMessage `json:"properties"`
+ Type rpc.UIElicitationSchemaType `json:"type"`
+ }{
+ Properties: map[string]json.RawMessage{name: data},
+ Type: rpc.UIElicitationSchemaTypeObject,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("marshal elicitation schema wrapper for property %q: %w", name, err)
+ }
+
+ var rpcSchema rpc.UIElicitationSchema
+ if err := json.Unmarshal(wrapperData, &rpcSchema); err != nil {
+ return nil, fmt.Errorf("decode elicitation schema property %q: %w", name, err)
+ }
+ rpcProperty, ok := rpcSchema.Properties[name]
+ if !ok {
+ return nil, fmt.Errorf("decode elicitation schema property %q: property missing after conversion", name)
+ }
+ return rpcProperty, nil
+}
+
// Confirm shows a confirmation dialog and returns the user's boolean answer.
// Returns false if the user declines or cancels.
func (ui *SessionUI) Confirm(ctx context.Context, message string) (bool, error) {
@@ -1057,7 +1118,7 @@ func (ui *SessionUI) Select(ctx context.Context, message string, options []strin
// Input shows a text input dialog. Returns the entered text, or empty string and
// false if the user declines/cancels.
-func (ui *SessionUI) Input(ctx context.Context, message string, opts *UiInputOptions) (string, bool, error) {
+func (ui *SessionUI) Input(ctx context.Context, message string, opts *UIInputOptions) (string, bool, error) {
if err := ui.session.assertElicitation(); err != nil {
return "", false, err
}
@@ -1111,17 +1172,20 @@ func fromRPCElicitationResult(r *rpc.UIElicitationResponse) *ElicitationResult {
if r == nil {
return nil
}
- content := make(map[string]any)
- for k, v := range r.Content {
- content[k] = fromRPCContent(v)
+ var content map[string]ElicitationFieldValue
+ if r.Content != nil {
+ content = make(map[string]ElicitationFieldValue, len(r.Content))
+ for k, v := range r.Content {
+ content[k] = fromRPCContent(v)
+ }
}
return &ElicitationResult{
- Action: string(r.Action),
+ Action: r.Action,
Content: content,
}
}
-func fromRPCContent(value rpc.UIElicitationFieldValue) any {
+func fromRPCContent(value rpc.UIElicitationFieldValue) ElicitationFieldValue {
switch v := value.(type) {
case nil:
return nil
@@ -1137,6 +1201,16 @@ func fromRPCContent(value rpc.UIElicitationFieldValue) any {
return nil
}
+func fromRPCElicitationRequestedSchema(schema *rpc.ElicitationRequestedSchema) *ElicitationSchema {
+ if schema == nil {
+ return nil
+ }
+ return &ElicitationSchema{
+ Properties: schema.Properties,
+ Required: schema.Required,
+ }
+}
+
// dispatchEvent enqueues an event for delivery to user handlers and fires
// broadcast handlers concurrently.
//
@@ -1225,35 +1299,13 @@ func (s *Session) handleBroadcastEvent(event SessionEvent) {
if handler == nil {
return
}
- var requestedSchema map[string]any
- if d.RequestedSchema != nil {
- requestedSchema = map[string]any{
- "type": string(d.RequestedSchema.Type),
- "properties": d.RequestedSchema.Properties,
- }
- if len(d.RequestedSchema.Required) > 0 {
- requestedSchema["required"] = d.RequestedSchema.Required
- }
- }
- mode := ""
- if d.Mode != nil {
- mode = string(*d.Mode)
- }
- elicitationSource := ""
- if d.ElicitationSource != nil {
- elicitationSource = *d.ElicitationSource
- }
- url := ""
- if d.URL != nil {
- url = *d.URL
- }
s.handleElicitationRequest(ElicitationContext{
SessionID: s.SessionID,
Message: d.Message,
- RequestedSchema: requestedSchema,
- Mode: mode,
- ElicitationSource: elicitationSource,
- URL: url,
+ RequestedSchema: fromRPCElicitationRequestedSchema(d.RequestedSchema),
+ Mode: d.Mode,
+ ElicitationSource: d.ElicitationSource,
+ URL: d.URL,
}, d.RequestID)
case *CapabilitiesChangedData:
@@ -1495,6 +1547,9 @@ type SetModelOptions struct {
// ReasoningSummary sets the reasoning summary mode for the new model.
// Use ReasoningSummaryNone to suppress summary output regardless of whether reasoning is enabled.
ReasoningSummary *ReasoningSummary
+ // ContextTier explicitly selects a context window tier for models that support it.
+ // Leave nil to use normal model behavior with no explicit tier.
+ ContextTier *ContextTier
// ModelCapabilities overrides individual model capabilities resolved by the runtime.
// Only non-nil fields are applied over the runtime-resolved capabilities.
ModelCapabilities *rpc.ModelCapabilitiesOverride
@@ -1516,6 +1571,7 @@ func (s *Session) SetModel(ctx context.Context, model string, opts *SetModelOpti
if opts != nil {
params.ReasoningEffort = opts.ReasoningEffort
params.ReasoningSummary = opts.ReasoningSummary
+ params.ContextTier = opts.ContextTier
params.ModelCapabilities = opts.ModelCapabilities
}
_, err := s.RPC.Model.SwitchTo(ctx, params)
diff --git a/go/session_fs_provider.go b/go/session_fs_provider.go
index 50922d7bc..d2227d629 100644
--- a/go/session_fs_provider.go
+++ b/go/session_fs_provider.go
@@ -12,12 +12,12 @@ import (
"github.com/github/copilot-sdk/go/rpc"
)
-// SessionFsProvider is the interface that SDK users implement to provide
+// SessionFSProvider is the interface that SDK users implement to provide
// a session filesystem. Methods use idiomatic Go error handling: return an
// error for failures (the adapter maps os.ErrNotExist → ENOENT automatically).
//
-// To add SQLite support, also implement [SessionFsSqliteProvider] on the same type.
-type SessionFsProvider interface {
+// To add SQLite support, also implement [SessionFSSqliteProvider] on the same type.
+type SessionFSProvider interface {
// ReadFile reads the full content of a file. Return os.ErrNotExist (or wrap it)
// if the file does not exist.
ReadFile(path string) (string, error)
@@ -31,7 +31,7 @@ type SessionFsProvider interface {
Exists(path string) (bool, error)
// Stat returns metadata about a file or directory.
// Return os.ErrNotExist if the path does not exist.
- Stat(path string) (*SessionFsFileInfo, error)
+ Stat(path string) (*SessionFSFileInfo, error)
// Mkdir creates a directory. If recursive is true, create parent directories as needed.
// mode is an optional POSIX-style permission mode (e.g., 0o755). Pass nil to use the OS default.
MakeDirectory(path string, recursive bool, mode *int) error
@@ -40,7 +40,7 @@ type SessionFsProvider interface {
ReadDirectory(path string) ([]string, error)
// ReaddirWithTypes lists entries with type information.
// Return os.ErrNotExist if the directory does not exist.
- ReadDirectoryWithTypes(path string) ([]rpc.SessionFsReaddirWithTypesEntry, error)
+ ReadDirectoryWithTypes(path string) ([]rpc.SessionFSReaddirWithTypesEntry, error)
// Rm removes a file or directory. If recursive is true, remove contents too.
// If force is true, do not return an error when the path does not exist.
Remove(path string, recursive bool, force bool) error
@@ -48,32 +48,32 @@ type SessionFsProvider interface {
Rename(src string, dest string) error
}
-// SessionFsSqliteProvider is an optional interface that a [SessionFsProvider]
+// SessionFSSqliteProvider is an optional interface that a [SessionFSProvider]
// may also implement to support per-session SQLite databases. The adapter
// checks for this interface at runtime using a type assertion. If the
// provider does not implement it, SQLite requests return an "unsupported" error.
//
// Providers are already session-scoped (created per session by the factory),
// so these methods do not take a session ID parameter.
-type SessionFsSqliteProvider interface {
+type SessionFSSqliteProvider interface {
// SqliteQuery executes a SQLite query against the provider's per-session database.
- SqliteQuery(queryType rpc.SessionFsSqliteQueryType, query string, params map[string]any) (*SessionFsSqliteQueryResult, error)
+ SqliteQuery(queryType rpc.SessionFSSqliteQueryType, query string, params map[string]any) (*SessionFSSqliteQueryResult, error)
// SqliteExists checks whether the provider has a SQLite database for the session.
SqliteExists() (bool, error)
}
-// SessionFsSqliteQueryResult holds the result of a SQLite query execution.
+// SessionFSSqliteQueryResult holds the result of a SQLite query execution.
// Same shape as the generated RPC type but without the Error field,
// since providers signal errors by returning a Go error.
-type SessionFsSqliteQueryResult struct {
+type SessionFSSqliteQueryResult struct {
Columns []string `json:"columns"`
Rows []map[string]any `json:"rows"`
RowsAffected int64 `json:"rowsAffected"`
LastInsertRowid *int64 `json:"lastInsertRowid,omitempty"`
}
-// SessionFsFileInfo holds file metadata returned by SessionFsProvider.Stat.
-type SessionFsFileInfo struct {
+// SessionFSFileInfo holds file metadata returned by SessionFSProvider.Stat.
+type SessionFSFileInfo struct {
IsFile bool
IsDirectory bool
Size int64
@@ -81,62 +81,62 @@ type SessionFsFileInfo struct {
Birthtime time.Time
}
-// sessionFsAdapter wraps a SessionFsProvider to implement rpc.SessionFsHandler,
-// converting idiomatic Go errors into SessionFsError results.
-type sessionFsAdapter struct {
- provider SessionFsProvider
+// sessionFSAdapter wraps a SessionFSProvider to implement rpc.SessionFSHandler,
+// converting idiomatic Go errors into SessionFSError results.
+type sessionFSAdapter struct {
+ provider SessionFSProvider
}
-func newSessionFsAdapter(provider SessionFsProvider) rpc.SessionFsHandler {
- return &sessionFsAdapter{provider: provider}
+func newSessionFSAdapter(provider SessionFSProvider) rpc.SessionFSHandler {
+ return &sessionFSAdapter{provider: provider}
}
-func (a *sessionFsAdapter) ReadFile(request *rpc.SessionFsReadFileRequest) (*rpc.SessionFsReadFileResult, error) {
+func (a *sessionFSAdapter) ReadFile(request *rpc.SessionFSReadFileRequest) (*rpc.SessionFSReadFileResult, error) {
content, err := a.provider.ReadFile(request.Path)
if err != nil {
- return &rpc.SessionFsReadFileResult{Error: toSessionFsError(err)}, nil
+ return &rpc.SessionFSReadFileResult{Error: toSessionFSError(err)}, nil
}
- return &rpc.SessionFsReadFileResult{Content: content}, nil
+ return &rpc.SessionFSReadFileResult{Content: content}, nil
}
-func (a *sessionFsAdapter) WriteFile(request *rpc.SessionFsWriteFileRequest) (*rpc.SessionFsError, error) {
+func (a *sessionFSAdapter) WriteFile(request *rpc.SessionFSWriteFileRequest) (*rpc.SessionFSError, error) {
var mode *int
if request.Mode != nil {
m := int(*request.Mode)
mode = &m
}
if err := a.provider.WriteFile(request.Path, request.Content, mode); err != nil {
- return toSessionFsError(err), nil
+ return toSessionFSError(err), nil
}
return nil, nil
}
-func (a *sessionFsAdapter) AppendFile(request *rpc.SessionFsAppendFileRequest) (*rpc.SessionFsError, error) {
+func (a *sessionFSAdapter) AppendFile(request *rpc.SessionFSAppendFileRequest) (*rpc.SessionFSError, error) {
var mode *int
if request.Mode != nil {
m := int(*request.Mode)
mode = &m
}
if err := a.provider.AppendFile(request.Path, request.Content, mode); err != nil {
- return toSessionFsError(err), nil
+ return toSessionFSError(err), nil
}
return nil, nil
}
-func (a *sessionFsAdapter) Exists(request *rpc.SessionFsExistsRequest) (*rpc.SessionFsExistsResult, error) {
+func (a *sessionFSAdapter) Exists(request *rpc.SessionFSExistsRequest) (*rpc.SessionFSExistsResult, error) {
exists, err := a.provider.Exists(request.Path)
if err != nil {
- return &rpc.SessionFsExistsResult{Exists: false}, nil
+ return &rpc.SessionFSExistsResult{Exists: false}, nil
}
- return &rpc.SessionFsExistsResult{Exists: exists}, nil
+ return &rpc.SessionFSExistsResult{Exists: exists}, nil
}
-func (a *sessionFsAdapter) Stat(request *rpc.SessionFsStatRequest) (*rpc.SessionFsStatResult, error) {
+func (a *sessionFSAdapter) Stat(request *rpc.SessionFSStatRequest) (*rpc.SessionFSStatResult, error) {
info, err := a.provider.Stat(request.Path)
if err != nil {
- return &rpc.SessionFsStatResult{Error: toSessionFsError(err)}, nil
+ return &rpc.SessionFSStatResult{Error: toSessionFSError(err)}, nil
}
- return &rpc.SessionFsStatResult{
+ return &rpc.SessionFSStatResult{
IsFile: info.IsFile,
IsDirectory: info.IsDirectory,
Size: info.Size,
@@ -145,7 +145,7 @@ func (a *sessionFsAdapter) Stat(request *rpc.SessionFsStatRequest) (*rpc.Session
}, nil
}
-func (a *sessionFsAdapter) Mkdir(request *rpc.SessionFsMkdirRequest) (*rpc.SessionFsError, error) {
+func (a *sessionFSAdapter) Mkdir(request *rpc.SessionFSMkdirRequest) (*rpc.SessionFSError, error) {
recursive := request.Recursive != nil && *request.Recursive
var mode *int
if request.Mode != nil {
@@ -153,65 +153,65 @@ func (a *sessionFsAdapter) Mkdir(request *rpc.SessionFsMkdirRequest) (*rpc.Sessi
mode = &m
}
if err := a.provider.MakeDirectory(request.Path, recursive, mode); err != nil {
- return toSessionFsError(err), nil
+ return toSessionFSError(err), nil
}
return nil, nil
}
-func (a *sessionFsAdapter) Readdir(request *rpc.SessionFsReaddirRequest) (*rpc.SessionFsReaddirResult, error) {
+func (a *sessionFSAdapter) Readdir(request *rpc.SessionFSReaddirRequest) (*rpc.SessionFSReaddirResult, error) {
entries, err := a.provider.ReadDirectory(request.Path)
if err != nil {
- return &rpc.SessionFsReaddirResult{Error: toSessionFsError(err)}, nil
+ return &rpc.SessionFSReaddirResult{Error: toSessionFSError(err)}, nil
}
- return &rpc.SessionFsReaddirResult{Entries: entries}, nil
+ return &rpc.SessionFSReaddirResult{Entries: entries}, nil
}
-func (a *sessionFsAdapter) ReaddirWithTypes(request *rpc.SessionFsReaddirWithTypesRequest) (*rpc.SessionFsReaddirWithTypesResult, error) {
+func (a *sessionFSAdapter) ReaddirWithTypes(request *rpc.SessionFSReaddirWithTypesRequest) (*rpc.SessionFSReaddirWithTypesResult, error) {
entries, err := a.provider.ReadDirectoryWithTypes(request.Path)
if err != nil {
- return &rpc.SessionFsReaddirWithTypesResult{Error: toSessionFsError(err)}, nil
+ return &rpc.SessionFSReaddirWithTypesResult{Error: toSessionFSError(err)}, nil
}
- return &rpc.SessionFsReaddirWithTypesResult{Entries: entries}, nil
+ return &rpc.SessionFSReaddirWithTypesResult{Entries: entries}, nil
}
-func (a *sessionFsAdapter) Rm(request *rpc.SessionFsRmRequest) (*rpc.SessionFsError, error) {
+func (a *sessionFSAdapter) Rm(request *rpc.SessionFSRmRequest) (*rpc.SessionFSError, error) {
recursive := request.Recursive != nil && *request.Recursive
force := request.Force != nil && *request.Force
if err := a.provider.Remove(request.Path, recursive, force); err != nil {
- return toSessionFsError(err), nil
+ return toSessionFSError(err), nil
}
return nil, nil
}
-func (a *sessionFsAdapter) Rename(request *rpc.SessionFsRenameRequest) (*rpc.SessionFsError, error) {
+func (a *sessionFSAdapter) Rename(request *rpc.SessionFSRenameRequest) (*rpc.SessionFSError, error) {
if err := a.provider.Rename(request.Src, request.Dest); err != nil {
- return toSessionFsError(err), nil
+ return toSessionFSError(err), nil
}
return nil, nil
}
-func (a *sessionFsAdapter) SqliteQuery(request *rpc.SessionFsSqliteQueryRequest) (*rpc.SessionFsSqliteQueryResult, error) {
- sp, ok := a.provider.(SessionFsSqliteProvider)
+func (a *sessionFSAdapter) SqliteQuery(request *rpc.SessionFSSqliteQueryRequest) (*rpc.SessionFSSqliteQueryResult, error) {
+ sp, ok := a.provider.(SessionFSSqliteProvider)
if !ok {
msg := "SQLite is not supported by this session filesystem provider"
- return &rpc.SessionFsSqliteQueryResult{
+ return &rpc.SessionFSSqliteQueryResult{
Columns: []string{},
Rows: []map[string]any{},
RowsAffected: 0,
- Error: &rpc.SessionFsError{Code: rpc.SessionFsErrorCodeUNKNOWN, Message: &msg},
+ Error: &rpc.SessionFSError{Code: rpc.SessionFSErrorCodeUNKNOWN, Message: &msg},
}, nil
}
result, err := sp.SqliteQuery(request.QueryType, request.Query, request.Params)
if err != nil {
- return &rpc.SessionFsSqliteQueryResult{
+ return &rpc.SessionFSSqliteQueryResult{
Columns: []string{},
Rows: []map[string]any{},
RowsAffected: 0,
- Error: toSessionFsError(err),
+ Error: toSessionFSError(err),
}, nil
}
if result == nil {
- return &rpc.SessionFsSqliteQueryResult{
+ return &rpc.SessionFSSqliteQueryResult{
Columns: []string{},
Rows: []map[string]any{},
RowsAffected: 0,
@@ -222,7 +222,7 @@ func (a *sessionFsAdapter) SqliteQuery(request *rpc.SessionFsSqliteQueryRequest)
rowid := *result.LastInsertRowid
wireRowid = &rowid
}
- return &rpc.SessionFsSqliteQueryResult{
+ return &rpc.SessionFSSqliteQueryResult{
Columns: result.Columns,
Rows: result.Rows,
RowsAffected: result.RowsAffected,
@@ -230,23 +230,23 @@ func (a *sessionFsAdapter) SqliteQuery(request *rpc.SessionFsSqliteQueryRequest)
}, nil
}
-func (a *sessionFsAdapter) SqliteExists(request *rpc.SessionFsSqliteExistsRequest) (*rpc.SessionFsSqliteExistsResult, error) {
- sp, ok := a.provider.(SessionFsSqliteProvider)
+func (a *sessionFSAdapter) SqliteExists(request *rpc.SessionFSSqliteExistsRequest) (*rpc.SessionFSSqliteExistsResult, error) {
+ sp, ok := a.provider.(SessionFSSqliteProvider)
if !ok {
- return &rpc.SessionFsSqliteExistsResult{Exists: false}, nil
+ return &rpc.SessionFSSqliteExistsResult{Exists: false}, nil
}
exists, err := sp.SqliteExists()
if err != nil {
- return &rpc.SessionFsSqliteExistsResult{Exists: false}, nil
+ return &rpc.SessionFSSqliteExistsResult{Exists: false}, nil
}
- return &rpc.SessionFsSqliteExistsResult{Exists: exists}, nil
+ return &rpc.SessionFSSqliteExistsResult{Exists: exists}, nil
}
-func toSessionFsError(err error) *rpc.SessionFsError {
- code := rpc.SessionFsErrorCodeUNKNOWN
+func toSessionFSError(err error) *rpc.SessionFSError {
+ code := rpc.SessionFSErrorCodeUNKNOWN
if errors.Is(err, os.ErrNotExist) {
- code = rpc.SessionFsErrorCodeENOENT
+ code = rpc.SessionFSErrorCodeENOENT
}
msg := err.Error()
- return &rpc.SessionFsError{Code: code, Message: &msg}
+ return &rpc.SessionFSError{Code: code, Message: &msg}
}
diff --git a/go/session_test.go b/go/session_test.go
index 405d7bf7c..85bca1a05 100644
--- a/go/session_test.go
+++ b/go/session_test.go
@@ -1,13 +1,20 @@
package copilot
import (
+ "bufio"
+ "context"
"encoding/json"
"fmt"
+ "io"
+ "strconv"
"strings"
"sync"
"sync/atomic"
"testing"
"time"
+
+ "github.com/github/copilot-sdk/go/internal/jsonrpc2"
+ "github.com/github/copilot-sdk/go/rpc"
)
// newTestSession creates a session with an event channel and starts the consumer goroutine.
@@ -30,6 +37,136 @@ func ptr[T any](value T) *T {
return &value
}
+func TestSession_SetModelForwardsContextTier(t *testing.T) {
+ tier := ContextTierLongContext
+ params := captureSetModelRequest(t, &SetModelOptions{ContextTier: &tier})
+
+ if params["sessionId"] != "session-1" {
+ t.Fatalf("expected sessionId session-1, got %v", params["sessionId"])
+ }
+ if params["modelId"] != "gpt-4.1" {
+ t.Fatalf("expected modelId gpt-4.1, got %v", params["modelId"])
+ }
+ if params["contextTier"] != "long_context" {
+ t.Fatalf("expected contextTier long_context, got %v", params["contextTier"])
+ }
+}
+
+func TestSession_SetModelOmitsContextTierWhenUnset(t *testing.T) {
+ params := captureSetModelRequest(t, nil)
+
+ if _, ok := params["contextTier"]; ok {
+ t.Fatalf("expected contextTier to be omitted, got %v", params["contextTier"])
+ }
+}
+
+func captureSetModelRequest(t *testing.T, opts *SetModelOptions) map[string]any {
+ t.Helper()
+
+ stdinR, stdinW := io.Pipe()
+ stdoutR, stdoutW := io.Pipe()
+ defer stdinR.Close()
+ defer stdinW.Close()
+ defer stdoutR.Close()
+ defer stdoutW.Close()
+
+ client := jsonrpc2.NewClient(stdinW, stdoutR)
+ client.Start()
+ defer client.Stop()
+
+ paramsCh := make(chan map[string]any, 1)
+ errCh := make(chan error, 1)
+
+ go func() {
+ frame, err := readTestJSONRPCFrame(stdinR)
+ if err != nil {
+ errCh <- err
+ return
+ }
+
+ var request struct {
+ ID json.RawMessage `json:"id"`
+ Method string `json:"method"`
+ Params map[string]any `json:"params"`
+ }
+ if err := json.Unmarshal(frame, &request); err != nil {
+ errCh <- err
+ return
+ }
+ if request.Method != "session.model.switchTo" {
+ errCh <- fmt.Errorf("expected session.model.switchTo, got %s", request.Method)
+ return
+ }
+
+ paramsCh <- request.Params
+
+ response := map[string]any{
+ "jsonrpc": "2.0",
+ "id": json.RawMessage(request.ID),
+ "result": map[string]any{},
+ }
+ data, err := json.Marshal(response)
+ if err != nil {
+ errCh <- err
+ return
+ }
+ if _, err := fmt.Fprintf(stdoutW, "Content-Length: %d\r\n\r\n%s", len(data), data); err != nil {
+ errCh <- err
+ return
+ }
+ }()
+
+ session := &Session{
+ SessionID: "session-1",
+ client: client,
+ RPC: rpc.NewSessionRPC(client, "session-1"),
+ }
+ if err := session.SetModel(context.Background(), "gpt-4.1", opts); err != nil {
+ t.Fatalf("SetModel failed: %v", err)
+ }
+
+ select {
+ case params := <-paramsCh:
+ return params
+ case err := <-errCh:
+ t.Fatal(err)
+ case <-time.After(2 * time.Second):
+ t.Fatal("timed out waiting for session.model.switchTo request")
+ }
+ return nil
+}
+
+func readTestJSONRPCFrame(r io.Reader) ([]byte, error) {
+ reader := bufio.NewReader(r)
+ var contentLength int
+ for {
+ line, err := reader.ReadString('\n')
+ if err != nil {
+ return nil, err
+ }
+ line = strings.TrimSpace(line)
+ if line == "" {
+ break
+ }
+ name, value, ok := strings.Cut(line, ":")
+ if !ok {
+ return nil, fmt.Errorf("invalid header line %q", line)
+ }
+ if name == "Content-Length" {
+ contentLength, err = strconv.Atoi(strings.TrimSpace(value))
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ if contentLength == 0 {
+ return nil, fmt.Errorf("missing Content-Length header")
+ }
+ data := make([]byte, contentLength)
+ _, err := io.ReadFull(reader, data)
+ return data, err
+}
+
func TestSession_On(t *testing.T) {
t.Run("multiple handlers all receive events", func(t *testing.T) {
session, cleanup := newTestSession()
@@ -581,7 +718,7 @@ func TestSession_ElicitationHandler(t *testing.T) {
}
session.registerElicitationHandler(func(ctx ElicitationContext) (ElicitationResult, error) {
- return ElicitationResult{Action: "accept"}, nil
+ return ElicitationResult{Action: ElicitationActionAccept}, nil
})
if session.getElicitationHandler() == nil {
@@ -619,7 +756,7 @@ func TestSession_ElicitationHandler(t *testing.T) {
session.registerElicitationHandler(func(ctx ElicitationContext) (ElicitationResult, error) {
return ElicitationResult{
- Action: "accept",
+ Action: ElicitationActionAccept,
Content: map[string]any{"color": "blue"},
}, nil
})
@@ -631,7 +768,7 @@ func TestSession_ElicitationHandler(t *testing.T) {
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
- if result.Action != "accept" {
+ if result.Action != ElicitationActionAccept {
t.Errorf("Expected action 'accept', got %q", result.Action)
}
if result.Content["color"] != "blue" {
@@ -746,6 +883,16 @@ func TestSession_HookForwardCompatibility(t *testing.T) {
}
func TestSession_ElicitationRequestSchema(t *testing.T) {
+ t.Run("nil content values are allowed", func(t *testing.T) {
+ value, err := toRPCContent(nil)
+ if err != nil {
+ t.Fatalf("Expected nil content to be accepted, got %v", err)
+ }
+ if value != nil {
+ t.Fatalf("Expected nil RPC content, got %T", value)
+ }
+ })
+
t.Run("elicitation.requested passes full schema to handler", func(t *testing.T) {
// Verify the schema extraction logic from handleBroadcastEvent
// preserves type, properties, and required.
@@ -755,28 +902,20 @@ func TestSession_ElicitationRequestSchema(t *testing.T) {
}
required := []string{"name", "age"}
- // Replicate the schema extraction logic from handleBroadcastEvent
- requestedSchema := map[string]any{
- "type": "object",
- "properties": properties,
- }
- if len(required) > 0 {
- requestedSchema["required"] = required
+ requestedSchema := ElicitationSchema{
+ Properties: properties,
+ Required: required,
}
- if requestedSchema["type"] != "object" {
- t.Errorf("Expected schema type 'object', got %v", requestedSchema["type"])
- }
- props, ok := requestedSchema["properties"].(map[string]any)
- if !ok || props == nil {
+ props := requestedSchema.Properties
+ if props == nil {
t.Fatal("Expected schema properties map")
}
if len(props) != 2 {
t.Errorf("Expected 2 properties, got %d", len(props))
}
- req, ok := requestedSchema["required"].([]string)
- if !ok || len(req) != 2 {
- t.Errorf("Expected required [name, age], got %v", requestedSchema["required"])
+ if len(requestedSchema.Required) != 2 {
+ t.Errorf("Expected required [name, age], got %v", requestedSchema.Required)
}
})
@@ -785,18 +924,44 @@ func TestSession_ElicitationRequestSchema(t *testing.T) {
"optional_field": map[string]any{"type": "string"},
}
- requestedSchema := map[string]any{
- "type": "object",
- "properties": properties,
+ requestedSchema := ElicitationSchema{
+ Properties: properties,
}
- // Simulate: if len(schema.Required) > 0 { ... } — with empty required
- var required []string
- if len(required) > 0 {
- requestedSchema["required"] = required
+
+ if requestedSchema.Required != nil {
+ t.Error("Expected Required to be nil when omitted")
}
+ })
- if _, exists := requestedSchema["required"]; exists {
- t.Error("Expected no 'required' key when Required is empty")
+ t.Run("schema conversion adds object type", func(t *testing.T) {
+ requestedSchema := ElicitationSchema{
+ Properties: map[string]any{
+ "name": map[string]any{"type": "string"},
+ },
+ }
+
+ rpcSchema, err := toRPCUIElicitationSchema(requestedSchema)
+ if err != nil {
+ t.Fatalf("toRPCUIElicitationSchema failed: %v", err)
+ }
+ if rpcSchema.Type != rpc.UIElicitationSchemaTypeObject {
+ t.Errorf("Expected RPC schema type object, got %q", rpcSchema.Type)
+ }
+ if _, ok := rpcSchema.Properties["name"].(*rpc.UIElicitationSchemaPropertyString); !ok {
+ t.Fatalf("Expected name property to decode as string schema, got %T", rpcSchema.Properties["name"])
+ }
+ })
+
+ t.Run("schema conversion preserves typed properties", func(t *testing.T) {
+ property := &rpc.UIElicitationSchemaPropertyString{}
+ rpcSchema, err := toRPCUIElicitationSchema(ElicitationSchema{
+ Properties: map[string]any{"name": property},
+ })
+ if err != nil {
+ t.Fatalf("toRPCUIElicitationSchema failed: %v", err)
+ }
+ if rpcSchema.Properties["name"] != property {
+ t.Fatalf("Expected typed property to be preserved, got %T", rpcSchema.Properties["name"])
}
})
}
diff --git a/go/toolset.go b/go/toolset.go
index c64e8b7fd..f9b60eccf 100644
--- a/go/toolset.go
+++ b/go/toolset.go
@@ -69,9 +69,9 @@ func (s *ToolSet) AddCustom(name string) *ToolSet {
return s
}
-// AddMcp adds an MCP tool pattern. Matches tools advertised by any configured
+// AddMCP adds an MCP tool pattern. Matches tools advertised by any configured
// MCP server.
-func (s *ToolSet) AddMcp(toolName string) *ToolSet {
+func (s *ToolSet) AddMCP(toolName string) *ToolSet {
validateToolName("mcp", toolName)
s.items = append(s.items, "mcp:"+toolName)
return s
diff --git a/go/toolset_test.go b/go/toolset_test.go
index babe63502..96d90f1d1 100644
--- a/go/toolset_test.go
+++ b/go/toolset_test.go
@@ -17,8 +17,8 @@ func TestToolSet_emitsSourceQualifiedStrings(t *testing.T) {
AddBuiltIn("*").
AddCustom("my_tool").
AddCustom("*").
- AddMcp("github-list_issues").
- AddMcp("*").
+ AddMCP("github-list_issues").
+ AddMCP("*").
ToSlice()
want := []string{
"builtin:bash",
@@ -56,7 +56,7 @@ func TestToolSet_rejectsInvalidNames(t *testing.T) {
fn func()
}{
{"colon in builtin", func() { NewToolSet().AddBuiltIn("has:colon") }},
- {"space in mcp", func() { NewToolSet().AddMcp("has space") }},
+ {"space in mcp", func() { NewToolSet().AddMCP("has space") }},
{"empty custom", func() { NewToolSet().AddCustom("") }},
}
for _, c := range cases {
@@ -111,10 +111,10 @@ func TestNewClient_modeEmptyAcceptsBaseDirectory(t *testing.T) {
}
}
-func TestNewClient_modeEmptyAcceptsUriConnection(t *testing.T) {
+func TestNewClient_modeEmptyAcceptsURIConnection(t *testing.T) {
c := NewClient(&ClientOptions{
Mode: ModeEmpty,
- Connection: UriConnection{URL: "8080"},
+ Connection: URIConnection{URL: "8080"},
})
if c.options.Mode != ModeEmpty {
t.Errorf("expected ModeEmpty, got %q", c.options.Mode)
diff --git a/go/types.go b/go/types.go
index 30216adf0..7ffd454a3 100644
--- a/go/types.go
+++ b/go/types.go
@@ -20,7 +20,7 @@ const (
// RuntimeConnection describes how a [Client] connects to the Copilot runtime.
//
-// Construct one with a [StdioConnection], [TcpConnection], or [UriConnection]
+// Construct one with a [StdioConnection], [TCPConnection], or [URIConnection]
// literal and pass it via [ClientOptions.Connection]. When [ClientOptions.Connection]
// is nil, the default is an empty [StdioConnection] (the SDK spawns the bundled
// runtime and communicates over stdin/stdout).
@@ -39,9 +39,9 @@ type StdioConnection struct {
func (StdioConnection) runtimeConnection() {}
-// TcpConnection spawns a runtime child process that listens on a TCP socket
+// TCPConnection spawns a runtime child process that listens on a TCP socket
// and connects to it.
-type TcpConnection struct {
+type TCPConnection struct {
// Port is the TCP port the runtime listens on. 0 (the default) lets the
// runtime pick a free port; the chosen port is then available via
// [Client.RuntimePort] after [Client.Start] returns.
@@ -56,11 +56,11 @@ type TcpConnection struct {
Args []string
}
-func (TcpConnection) runtimeConnection() {}
+func (TCPConnection) runtimeConnection() {}
-// UriConnection connects to an already-running runtime at the given URL.
+// URIConnection connects to an already-running runtime at the given URL.
// The SDK does not spawn a process in this mode.
-type UriConnection struct {
+type URIConnection struct {
// URL of the runtime. Accepts "port", "host:port", or a full URL such
// as "http://host:port".
URL string
@@ -69,7 +69,7 @@ type UriConnection struct {
ConnectionToken string
}
-func (UriConnection) runtimeConnection() {}
+func (URIConnection) runtimeConnection() {}
// ClientOptions configures the [Client].
type ClientOptions struct {
@@ -86,7 +86,7 @@ type ClientOptions struct {
// This does not affect where the Go SDK extracts the embedded CLI
// binary; use embeddedcli.Config.Dir to control that install/cache
// location.
- // Ignored when connecting to an existing runtime via [UriConnection].
+ // Ignored when connecting to an existing runtime via [URIConnection].
BaseDirectory string
// LogLevel for the runtime. When empty (the default), the runtime
// uses its own default level; the SDK does not pass --log-level.
@@ -111,11 +111,11 @@ type ClientOptions struct {
// querying the runtime. Useful in BYOK mode to return models available
// from your custom provider.
OnListModels func(ctx context.Context) ([]ModelInfo, error)
- // SessionFs configures a custom session filesystem provider.
+ // SessionFS configures a custom session filesystem provider.
// When provided, the client registers as the session filesystem provider
// on connection, routing session-scoped file I/O through per-session
// handlers.
- SessionFs *SessionFsConfig
+ SessionFS *SessionFSConfig
// Telemetry configures OpenTelemetry integration for the runtime.
// When non-nil, COPILOT_OTEL_ENABLED=true is set and any populated
// fields are mapped to the corresponding environment variables.
@@ -123,12 +123,12 @@ type ClientOptions struct {
// SessionIdleTimeoutSeconds configures the server-wide session idle
// timeout in seconds. Sessions without activity for this duration are
// automatically cleaned up. Set to 0 or leave unset to disable.
- // Ignored when connecting to an existing runtime via [UriConnection].
+ // Ignored when connecting to an existing runtime via [URIConnection].
SessionIdleTimeoutSeconds int
// EnableRemoteSessions enables remote session support (Mission Control
// integration). When true, sessions in a GitHub repository working
// directory are accessible from GitHub web and mobile.
- // Ignored when connecting to an existing runtime via [UriConnection].
+ // Ignored when connecting to an existing runtime via [URIConnection].
EnableRemoteSessions bool
// Mode controls the default tool surface and feature flags presented to
// sessions created by this client. The zero value ([ModeCopilotCli])
@@ -136,7 +136,7 @@ type ClientOptions struct {
// multi-tenant safe defaults — see [ClientMode] for details.
//
// When Mode is [ModeEmpty], NewClient requires either BaseDirectory,
- // SessionFs, or a [UriConnection] so the runtime has persistent storage
+ // SessionFS, or a [URIConnection] so the runtime has persistent storage
// for session state.
Mode ClientMode
}
@@ -673,8 +673,8 @@ type ErrorOccurredHookOutput struct {
// ErrorOccurredHandler handles error-occurred hook invocations
type ErrorOccurredHandler func(input ErrorOccurredHookInput, invocation HookInvocation) (*ErrorOccurredHookOutput, error)
-// PreMcpToolCallHookInput is the input for a pre-mcp-tool-call hook
-type PreMcpToolCallHookInput struct {
+// PreMCPToolCallHookInput is the input for a pre-mcp-tool-call hook
+type PreMCPToolCallHookInput struct {
SessionID string `json:"sessionId"`
Timestamp time.Time `json:"-"`
WorkingDirectory string `json:"cwd"`
@@ -686,8 +686,8 @@ type PreMcpToolCallHookInput struct {
}
// MarshalJSON implements json.Marshaler, emitting Timestamp as Unix milliseconds.
-func (h PreMcpToolCallHookInput) MarshalJSON() ([]byte, error) {
- type alias PreMcpToolCallHookInput
+func (h PreMCPToolCallHookInput) MarshalJSON() ([]byte, error) {
+ type alias PreMCPToolCallHookInput
return json.Marshal(&struct {
Timestamp int64 `json:"timestamp"`
alias
@@ -695,8 +695,8 @@ func (h PreMcpToolCallHookInput) MarshalJSON() ([]byte, error) {
}
// UnmarshalJSON implements json.Unmarshaler, parsing Timestamp from Unix milliseconds.
-func (h *PreMcpToolCallHookInput) UnmarshalJSON(data []byte) error {
- type alias PreMcpToolCallHookInput
+func (h *PreMCPToolCallHookInput) UnmarshalJSON(data []byte) error {
+ type alias PreMCPToolCallHookInput
aux := &struct {
Timestamp int64 `json:"timestamp"`
*alias
@@ -708,13 +708,13 @@ func (h *PreMcpToolCallHookInput) UnmarshalJSON(data []byte) error {
return nil
}
-// PreMcpToolCallHookOutput is the output for a pre-mcp-tool-call hook
-type PreMcpToolCallHookOutput struct {
+// PreMCPToolCallHookOutput is the output for a pre-mcp-tool-call hook
+type PreMCPToolCallHookOutput struct {
MetaToUse any `json:"metaToUse"`
}
-// PreMcpToolCallHandler handles pre-mcp-tool-call hook invocations
-type PreMcpToolCallHandler func(input PreMcpToolCallHookInput, invocation HookInvocation) (*PreMcpToolCallHookOutput, error)
+// PreMCPToolCallHandler handles pre-mcp-tool-call hook invocations
+type PreMCPToolCallHandler func(input PreMCPToolCallHookInput, invocation HookInvocation) (*PreMCPToolCallHookOutput, error)
// HookInvocation provides context about a hook invocation
type HookInvocation struct {
@@ -730,7 +730,7 @@ type SessionHooks struct {
OnSessionStart SessionStartHandler
OnSessionEnd SessionEndHandler
OnErrorOccurred ErrorOccurredHandler
- OnPreMcpToolCall PreMcpToolCallHandler
+ OnPreMCPToolCall PreMCPToolCallHandler
}
// MCPServerConfig is implemented by MCP server configuration types.
@@ -743,19 +743,15 @@ type MCPServerConfig interface {
//
// The Tools field controls which tools from the server are exposed:
// - nil (omitted from the wire): all tools (CLI default)
-// - &[]string{"*"}: explicit "all tools"
-// - &[]string{}: no tools
-// - &[]string{"foo","bar"}: only those tools
-//
-// The pointer-to-slice form is required so that a nil pointer (omitted from
-// the wire) is distinguishable from a non-nil pointer to an empty slice
-// (sent as `"tools": []`).
+// - []string{"*"}: explicit "all tools"
+// - []string{}: no tools
+// - []string{"foo","bar"}: only those tools
type MCPStdioServerConfig struct {
- Tools *[]string `json:"tools,omitempty"`
+ Tools []string `json:"tools,omitzero"`
Timeout int `json:"timeout,omitempty"`
Command string `json:"command"`
- Args []string `json:"args,omitempty"`
- Env map[string]string `json:"env,omitempty"`
+ Args []string `json:"args,omitzero"`
+ Env map[string]string `json:"env,omitzero"`
WorkingDirectory string `json:"cwd,omitempty"`
}
@@ -777,10 +773,10 @@ func (c MCPStdioServerConfig) MarshalJSON() ([]byte, error) {
//
// See [MCPStdioServerConfig] for the semantics of the Tools field.
type MCPHTTPServerConfig struct {
- Tools *[]string `json:"tools,omitempty"`
+ Tools []string `json:"tools,omitzero"`
Timeout int `json:"timeout,omitempty"`
URL string `json:"url"`
- Headers map[string]string `json:"headers,omitempty"`
+ Headers map[string]string `json:"headers,omitzero"`
}
func (MCPHTTPServerConfig) mcpServerConfig() {}
@@ -797,7 +793,7 @@ func (c MCPHTTPServerConfig) MarshalJSON() ([]byte, error) {
})
}
-// CustomAgentConfig configures a custom agent
+// CustomAgentConfig configures a custom agent.
type CustomAgentConfig struct {
// Name is the unique name of the custom agent
Name string `json:"name"`
@@ -805,8 +801,9 @@ type CustomAgentConfig struct {
DisplayName string `json:"displayName,omitempty"`
// Description of what the agent does
Description string `json:"description,omitempty"`
- // Tools is the list of tool names the agent can use (nil for all tools)
- Tools []string `json:"tools,omitempty"`
+ // Tools is the list of tool names the agent can use. Nil omits the field
+ // (all tools); an empty non-nil slice sends "tools": [] (no tools).
+ Tools []string `json:"tools,omitzero"`
// Prompt is the prompt content for the agent
Prompt string `json:"prompt"`
// MCPServers are MCP servers specific to this agent
@@ -859,23 +856,23 @@ type LargeToolOutputConfig struct {
OutputDirectory string `json:"outputDir,omitempty"`
}
-// SessionFsCapabilities declares optional provider capabilities.
-type SessionFsCapabilities struct {
+// SessionFSCapabilities declares optional provider capabilities.
+type SessionFSCapabilities struct {
// Sqlite indicates whether the provider supports SQLite query/exists operations.
Sqlite bool
}
-// SessionFsConfig configures a custom session filesystem provider.
-type SessionFsConfig struct {
+// SessionFSConfig configures a custom session filesystem provider.
+type SessionFSConfig struct {
// InitialWorkingDirectory is the initial working directory for sessions.
InitialWorkingDirectory string
// SessionStatePath is the path within each session's filesystem where the runtime stores
// session-scoped files such as events, checkpoints, and temp files.
SessionStatePath string
// Conventions identifies the path conventions used by this filesystem provider.
- Conventions rpc.SessionFsSetProviderConventions
+ Conventions rpc.SessionFSSetProviderConventions
// Capabilities declares optional provider capabilities such as SQLite support.
- Capabilities *SessionFsCapabilities
+ Capabilities *SessionFSCapabilities
}
// SessionConfig configures a new session
@@ -894,16 +891,20 @@ type SessionConfig struct {
// ReasoningSummary mode for models that support configurable reasoning summaries.
// Use ReasoningSummaryNone to suppress summary output regardless of whether reasoning is enabled.
ReasoningSummary ReasoningSummary
+ // ContextTier pins the session to a context window tier for models that support it.
+ // Use ContextTierDefault or ContextTierLongContext for the currently known tiers.
+ ContextTier ContextTier
// ConfigDirectory overrides the default configuration directory location.
// When specified, the session will use this directory for storing config and state.
ConfigDirectory string
- // EnableConfigDiscovery, when true, automatically discovers MCP server configurations
+ // EnableConfigDiscovery, when non-nil, controls automatic discovery of MCP server configurations
// (e.g. .mcp.json, .vscode/mcp.json) and skill directories from the working directory
// and merges them with any explicitly provided MCPServers and SkillDirectories, with
// explicit values taking precedence on name collision.
+ // Nil leaves the runtime default unchanged; use Bool(false) to explicitly disable discovery.
// Custom instruction files (.github/copilot-instructions.md, AGENTS.md, etc.) are
// always loaded from the working directory regardless of this setting.
- EnableConfigDiscovery bool
+ EnableConfigDiscovery *bool
// SkipEmbeddingRetrieval, when non-nil, controls embedding-based retrieval
// for this session. Use in multitenant deployments to prevent cross-session
// information leakage through the shared embedding cache.
@@ -1033,9 +1034,9 @@ type SessionConfig struct {
// handler. Equivalent to calling session.On(handler) immediately after creation,
// but executes earlier in the lifecycle so no events are missed.
OnEvent SessionEventHandler
- // CreateSessionFsProvider supplies a handler for session filesystem operations.
- // This takes effect only when ClientOptions.SessionFs is configured.
- CreateSessionFsProvider func(session *Session) SessionFsProvider
+ // CreateSessionFSProvider supplies a handler for session filesystem operations.
+ // This takes effect only when ClientOptions.SessionFS is configured.
+ CreateSessionFSProvider func(session *Session) SessionFSProvider
// Commands registers slash-commands for this session. Each command appears as
// /name in the CLI TUI for the user to invoke. The Handler is called when the
// command is executed.
@@ -1050,9 +1051,9 @@ type SessionConfig struct {
// OnAutoModeSwitchRequest is a handler for auto-mode-switch requests from the server.
// When provided, enables autoModeSwitch.request callbacks for the session.
OnAutoModeSwitchRequest AutoModeSwitchRequestHandler
- // EnableMcpApps enables MCP Apps (SEP-1865) UI passthrough on this session.
+ // EnableMCPApps enables MCP Apps (SEP-1865) UI passthrough on this session.
//
- // Experimental: EnableMcpApps is part of an experimental wire-protocol
+ // Experimental: EnableMCPApps is part of an experimental wire-protocol
// surface (SEP-1865) and may change or be removed in a future release.
//
// When true AND the runtime has MCP Apps enabled (via the MCP_APPS feature
@@ -1072,7 +1073,7 @@ type SessionConfig struct {
// that can display ui:// MCP App bundles. Setting it without a renderer will
// cause MCP servers to register UI-enabled tool variants the consumer cannot
// display.
- EnableMcpApps bool
+ EnableMCPApps bool
// GitHubToken is an optional per-session GitHub token used for authentication.
// When provided, the session authenticates as the token's owner instead of
// using the global client-level auth.
@@ -1094,6 +1095,12 @@ type SessionConfig struct {
RequestCanvasRenderer *bool
// RequestExtensions asks the host to surface declared canvases as agent-visible extensions.
RequestExtensions *bool
+ // ExtensionSDKPath optionally overrides the bundled `@github/copilot-sdk` drop
+ // injected into extension subprocesses. When set to an absolute path containing
+ // a valid `copilot-sdk/` folder (with `index.js` and `extension.js` at the
+ // root), the host injects the override into every forked extension; invalid or
+ // missing paths fall back to the bundled SDK silently.
+ ExtensionSDKPath *string
// CanvasHandler receives inbound canvas.open / canvas.close / canvas.action.invoke
// requests for this session. The SDK does not maintain a per-canvas registry;
// the handler must dispatch on CanvasProviderOpenRequest.CanvasID itself.
@@ -1104,7 +1111,7 @@ type SessionConfig struct {
type Tool struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
- Parameters map[string]any `json:"parameters,omitempty"`
+ Parameters map[string]any `json:"parameters,omitzero"`
OverridesBuiltInTool bool `json:"overridesBuiltInTool,omitempty"`
SkipPermission bool `json:"skipPermission,omitempty"`
// Handler is optional. When nil, the SDK exposes the tool declaration but does
@@ -1175,23 +1182,45 @@ type SessionCapabilities struct {
type UICapabilities struct {
// Elicitation indicates whether the host supports interactive elicitation dialogs.
Elicitation bool `json:"elicitation,omitempty"`
- // McpApps indicates whether the runtime has accepted the session's MCP Apps
- // (SEP-1865) opt-in. True when the consumer set EnableMcpApps=true on
+ // MCPApps indicates whether the runtime has accepted the session's MCP Apps
+ // (SEP-1865) opt-in. True when the consumer set EnableMCPApps=true on
// create/resume AND the runtime's MCP_APPS feature flag (or
// COPILOT_MCP_APPS=true env override) is on. Otherwise false, indicating
// the runtime silently dropped the opt-in.
//
- // Experimental: McpApps is part of an experimental wire-protocol surface
+ // Experimental: MCPApps is part of an experimental wire-protocol surface
// (SEP-1865) and may change or be removed in a future release.
- McpApps bool `json:"mcpApps,omitempty"`
+ MCPApps bool `json:"mcpApps,omitempty"`
}
+// ElicitationAction is the user response to an elicitation request.
+type ElicitationAction = rpc.UIElicitationResponseAction
+
+// Elicitation action values.
+const (
+ ElicitationActionAccept ElicitationAction = rpc.UIElicitationResponseActionAccept
+ ElicitationActionCancel ElicitationAction = rpc.UIElicitationResponseActionCancel
+ ElicitationActionDecline ElicitationAction = rpc.UIElicitationResponseActionDecline
+)
+
+// ElicitationFieldValue is a primitive value submitted for an elicitation form field.
+// Supported values are string, numeric types, bool, []string, and []any containing strings.
+type ElicitationFieldValue = any
+
// ElicitationResult is the user's response to an elicitation dialog.
type ElicitationResult struct {
- // Action is the user response: "accept" (submitted), "decline" (rejected), or "cancel" (dismissed).
- Action string `json:"action"`
- // Content holds form values submitted by the user (present when Action is "accept").
- Content map[string]any `json:"content,omitempty"`
+ // Action is the user response: accept, decline, or cancel.
+ Action ElicitationAction `json:"action"`
+ // Content holds form values submitted by the user when Action is accept.
+ Content map[string]ElicitationFieldValue `json:"content,omitzero"`
+}
+
+// ElicitationSchema describes the form fields for an elicitation request.
+type ElicitationSchema struct {
+ // Properties contains form field definitions keyed by field name.
+ Properties map[string]any `json:"properties"`
+ // Required lists field names that must be submitted.
+ Required []string `json:"required,omitzero"`
}
// ElicitationContext describes an elicitation request from the server,
@@ -1203,13 +1232,13 @@ type ElicitationContext struct {
// Message describes what information is needed from the user.
Message string
// RequestedSchema is a JSON Schema describing the form fields (form mode only).
- RequestedSchema map[string]any
+ RequestedSchema *ElicitationSchema
// Mode is "form" for structured input, "url" for browser redirect.
- Mode string
+ Mode *ElicitationRequestedMode
// ElicitationSource is the source that initiated the request (e.g. MCP server name).
- ElicitationSource string
+ ElicitationSource *string
// URL to open in the user's browser (url mode only).
- URL string
+ URL *string
}
// ElicitationHandler handles elicitation requests from the server (e.g. from MCP tools).
@@ -1217,8 +1246,8 @@ type ElicitationContext struct {
// If the handler returns an error the SDK auto-cancels the request.
type ElicitationHandler func(ctx ElicitationContext) (ElicitationResult, error)
-// UiInputOptions configures a text input field for the Input convenience method.
-type UiInputOptions struct {
+// UIInputOptions configures a text input field for the Input convenience method.
+type UIInputOptions struct {
// Title label for the input field.
Title string
// Description text shown below the field.
@@ -1288,6 +1317,9 @@ type ResumeSessionConfig struct {
// ReasoningSummary mode for models that support configurable reasoning summaries.
// Use ReasoningSummaryNone to suppress summary output regardless of whether reasoning is enabled.
ReasoningSummary ReasoningSummary
+ // ContextTier pins the session to a context window tier for models that support it.
+ // Use ContextTierDefault or ContextTierLongContext for the currently known tiers.
+ ContextTier ContextTier
// OnPermissionRequest is an optional handler for permission requests from the server.
// When nil, permission requests are surfaced as events and left pending for the
// consumer to resolve via pending permission RPCs.
@@ -1301,13 +1333,14 @@ type ResumeSessionConfig struct {
WorkingDirectory string
// ConfigDirectory overrides the default configuration directory location.
ConfigDirectory string
- // EnableConfigDiscovery, when true, automatically discovers MCP server configurations
+ // EnableConfigDiscovery, when non-nil, controls automatic discovery of MCP server configurations
// (e.g. .mcp.json, .vscode/mcp.json) and skill directories from the working directory
// and merges them with any explicitly provided MCPServers and SkillDirectories, with
// explicit values taking precedence on name collision.
+ // Nil leaves the runtime default unchanged; use Bool(false) to explicitly disable discovery.
// Custom instruction files (.github/copilot-instructions.md, AGENTS.md, etc.) are
// always loaded from the working directory regardless of this setting.
- EnableConfigDiscovery bool
+ EnableConfigDiscovery *bool
// SkipEmbeddingRetrieval, when non-nil, controls embedding-based retrieval
// for this session. Use in multitenant deployments to prevent cross-session
// information leakage through the shared embedding cache.
@@ -1386,21 +1419,22 @@ type ResumeSessionConfig struct {
// SuppressResumeEvent, when true, skips emitting the session.resume event.
// Useful for reconnecting to a session without triggering resume-related side effects.
SuppressResumeEvent bool
- // ContinuePendingWork, when true, instructs the runtime to continue any tool calls
- // or permission prompts that were still pending when the session was last suspended.
- // When false (the default), the runtime treats pending work as interrupted on resume.
+ // ContinuePendingWork, when non-nil, controls whether the runtime continues any
+ // tool calls or permission prompts that were still pending when the session was
+ // last suspended. Nil leaves the runtime default unchanged; use Bool(false) to
+ // explicitly treat pending work as interrupted on resume.
//
// For permission requests, the runtime re-emits permission.requested so the
// registered OnPermissionRequest handler can re-prompt; for external tool calls,
// the consumer is expected to supply the result via the corresponding low-level
// RPC method.
- ContinuePendingWork bool
+ ContinuePendingWork *bool
// OnEvent is an optional event handler registered before the session.resume RPC
// is issued, ensuring early events are delivered. See SessionConfig.OnEvent.
OnEvent SessionEventHandler
- // CreateSessionFsProvider supplies a handler for session filesystem operations.
- // This takes effect only when ClientOptions.SessionFs is configured.
- CreateSessionFsProvider func(session *Session) SessionFsProvider
+ // CreateSessionFSProvider supplies a handler for session filesystem operations.
+ // This takes effect only when ClientOptions.SessionFS is configured.
+ CreateSessionFSProvider func(session *Session) SessionFSProvider
// Commands registers slash-commands for this session. See SessionConfig.Commands.
Commands []CommandDefinition
// OnElicitationRequest is a handler for elicitation requests from the server.
@@ -1412,12 +1446,12 @@ type ResumeSessionConfig struct {
// OnAutoModeSwitchRequest is a handler for auto-mode-switch requests from the server.
// See SessionConfig.OnAutoModeSwitchRequest.
OnAutoModeSwitchRequest AutoModeSwitchRequestHandler
- // EnableMcpApps enables MCP Apps (SEP-1865) UI passthrough on resume.
- // See SessionConfig.EnableMcpApps.
+ // EnableMCPApps enables MCP Apps (SEP-1865) UI passthrough on resume.
+ // See SessionConfig.EnableMCPApps.
//
- // Experimental: EnableMcpApps is part of an experimental wire-protocol
+ // Experimental: EnableMCPApps is part of an experimental wire-protocol
// surface (SEP-1865) and may change or be removed in a future release.
- EnableMcpApps bool
+ EnableMCPApps bool
// Canvases declares canvases this session provides. Sent over the wire on
// `session.resume`. See SessionConfig.Canvases.
Canvases []CanvasDeclaration
@@ -1429,6 +1463,9 @@ type ResumeSessionConfig struct {
RequestCanvasRenderer *bool
// RequestExtensions asks the host to surface declared canvases as agent-visible extensions.
RequestExtensions *bool
+ // ExtensionSDKPath optionally overrides the bundled `@github/copilot-sdk` drop
+ // injected into extension subprocesses. See SessionConfig.ExtensionSDKPath.
+ ExtensionSDKPath *string
// CanvasHandler receives inbound canvas.* requests for this session. See SessionConfig.CanvasHandler.
CanvasHandler CanvasHandler `json:"-"`
// ExtensionInfo identifies the stable extension providing this session's canvases.
@@ -1437,8 +1474,8 @@ type ResumeSessionConfig struct {
type ProviderConfig struct {
// Type is the provider type: "openai", "azure", or "anthropic". Defaults to "openai".
Type string `json:"type,omitempty"`
- // WireApi is the API format (openai/azure only): "completions" or "responses". Defaults to "completions".
- WireApi string `json:"wireApi,omitempty"`
+ // WireAPI is the API format (openai/azure only): "completions" or "responses". Defaults to "completions".
+ WireAPI string `json:"wireApi,omitempty"`
// BaseURL is the API endpoint URL
BaseURL string `json:"baseUrl"`
// APIKey is the API key. Optional for local providers like Ollama.
@@ -1481,7 +1518,7 @@ type AzureProviderOptions struct {
// ToolBinaryResult represents binary payloads returned by tools.
type ToolBinaryResult struct {
Data string `json:"data"`
- MimeType string `json:"mimeType"`
+ MIMEType string `json:"mimeType"`
Type string `json:"type"`
Description string `json:"description,omitempty"`
}
@@ -1529,7 +1566,7 @@ type ModelVisionLimits struct {
// ModelLimits contains model limits
type ModelLimits struct {
MaxPromptTokens *int `json:"max_prompt_tokens,omitempty"`
- MaxContextWindowTokens int `json:"max_context_window_tokens"`
+ MaxContextWindowTokens *int `json:"max_context_window_tokens,omitempty"`
Vision *ModelVisionLimits `json:"vision,omitempty"`
}
@@ -1645,6 +1682,7 @@ type createSessionRequest struct {
ClientName string `json:"clientName,omitempty"`
ReasoningEffort string `json:"reasoningEffort,omitempty"`
ReasoningSummary ReasoningSummary `json:"reasoningSummary,omitempty"`
+ ContextTier ContextTier `json:"contextTier,omitempty"`
Tools []Tool `json:"tools,omitempty"`
SystemMessage *SystemMessageConfig `json:"systemMessage,omitempty"`
AvailableTools []string `json:"availableTools"`
@@ -1689,13 +1727,14 @@ type createSessionRequest struct {
LargeOutput *LargeToolOutputConfig `json:"largeOutput,omitempty"`
Commands []wireCommand `json:"commands,omitempty"`
RequestElicitation *bool `json:"requestElicitation,omitempty"`
- RequestMcpApps *bool `json:"requestMcpApps,omitempty"`
+ RequestMCPApps *bool `json:"requestMcpApps,omitempty"`
GitHubToken string `json:"gitHubToken,omitempty"`
RemoteSession rpc.RemoteSessionMode `json:"remoteSession,omitempty"`
Cloud *CloudSessionOptions `json:"cloud,omitempty"`
Canvases []CanvasDeclaration `json:"canvases,omitempty"`
RequestCanvasRenderer *bool `json:"requestCanvasRenderer,omitempty"`
RequestExtensions *bool `json:"requestExtensions,omitempty"`
+ ExtensionSDKPath *string `json:"extensionSdkPath,omitempty"`
ExtensionInfo *ExtensionInfo `json:"extensionInfo,omitempty"`
Traceparent string `json:"traceparent,omitempty"`
Tracestate string `json:"tracestate,omitempty"`
@@ -1721,6 +1760,7 @@ type resumeSessionRequest struct {
Model string `json:"model,omitempty"`
ReasoningEffort string `json:"reasoningEffort,omitempty"`
ReasoningSummary ReasoningSummary `json:"reasoningSummary,omitempty"`
+ ContextTier ContextTier `json:"contextTier,omitempty"`
Tools []Tool `json:"tools,omitempty"`
SystemMessage *SystemMessageConfig `json:"systemMessage,omitempty"`
AvailableTools []string `json:"availableTools"`
@@ -1767,13 +1807,14 @@ type resumeSessionRequest struct {
LargeOutput *LargeToolOutputConfig `json:"largeOutput,omitempty"`
Commands []wireCommand `json:"commands,omitempty"`
RequestElicitation *bool `json:"requestElicitation,omitempty"`
- RequestMcpApps *bool `json:"requestMcpApps,omitempty"`
+ RequestMCPApps *bool `json:"requestMcpApps,omitempty"`
GitHubToken string `json:"gitHubToken,omitempty"`
RemoteSession rpc.RemoteSessionMode `json:"remoteSession,omitempty"`
Canvases []CanvasDeclaration `json:"canvases,omitempty"`
OpenCanvases []rpc.OpenCanvasInstance `json:"openCanvases,omitempty"`
RequestCanvasRenderer *bool `json:"requestCanvasRenderer,omitempty"`
RequestExtensions *bool `json:"requestExtensions,omitempty"`
+ ExtensionSDKPath *string `json:"extensionSdkPath,omitempty"`
ExtensionInfo *ExtensionInfo `json:"extensionInfo,omitempty"`
Traceparent string `json:"traceparent,omitempty"`
Tracestate string `json:"tracestate,omitempty"`
diff --git a/go/types_test.go b/go/types_test.go
index 6d83c8ec0..f4132fa3d 100644
--- a/go/types_test.go
+++ b/go/types_test.go
@@ -152,6 +152,57 @@ func TestCustomAgentConfig_JSONIncludesModel(t *testing.T) {
}
}
+func TestCustomAgentConfig_JSONIncludesEmptyTools(t *testing.T) {
+ cfg := CustomAgentConfig{
+ Name: "no-tools-agent",
+ Prompt: "You are an agent without tools.",
+ Tools: []string{},
+ }
+
+ data, err := json.Marshal(cfg)
+ if err != nil {
+ t.Fatalf("failed to marshal CustomAgentConfig: %v", err)
+ }
+
+ var decoded map[string]any
+ if err := json.Unmarshal(data, &decoded); err != nil {
+ t.Fatalf("failed to unmarshal CustomAgentConfig: %v", err)
+ }
+
+ rawTools, present := decoded["tools"]
+ if !present {
+ t.Fatal("expected tools to be present for an empty non-nil slice")
+ }
+ tools, ok := rawTools.([]any)
+ if !ok {
+ t.Fatalf("expected tools array, got %T", rawTools)
+ }
+ if len(tools) != 0 {
+ t.Fatalf("expected empty tools array, got %v", tools)
+ }
+}
+
+func TestCustomAgentConfig_JSONOmitsNilTools(t *testing.T) {
+ cfg := CustomAgentConfig{
+ Name: "all-tools-agent",
+ Prompt: "You are an agent with default tools.",
+ }
+
+ data, err := json.Marshal(cfg)
+ if err != nil {
+ t.Fatalf("failed to marshal CustomAgentConfig: %v", err)
+ }
+
+ var decoded map[string]any
+ if err := json.Unmarshal(data, &decoded); err != nil {
+ t.Fatalf("failed to unmarshal CustomAgentConfig: %v", err)
+ }
+
+ if _, present := decoded["tools"]; present {
+ t.Errorf("expected tools to be omitted for nil slice, got %v", decoded["tools"])
+ }
+}
+
func TestCustomAgentConfig_JSONOmitsModelWhenEmpty(t *testing.T) {
cfg := CustomAgentConfig{
Name: "no-model-agent",
@@ -172,3 +223,150 @@ func TestCustomAgentConfig_JSONOmitsModelWhenEmpty(t *testing.T) {
t.Errorf("expected model to be omitted when empty, got %v", decoded["model"])
}
}
+
+func TestTool_JSONIncludesEmptyParameters(t *testing.T) {
+ tool := Tool{
+ Name: "accept_anything",
+ Parameters: map[string]any{},
+ }
+
+ data, err := json.Marshal(tool)
+ if err != nil {
+ t.Fatalf("failed to marshal Tool: %v", err)
+ }
+
+ var decoded map[string]any
+ if err := json.Unmarshal(data, &decoded); err != nil {
+ t.Fatalf("failed to unmarshal Tool: %v", err)
+ }
+
+ rawParameters, present := decoded["parameters"]
+ if !present {
+ t.Fatal("expected parameters to be present for an empty non-nil map")
+ }
+ parameters, ok := rawParameters.(map[string]any)
+ if !ok {
+ t.Fatalf("expected parameters object, got %T", rawParameters)
+ }
+ if len(parameters) != 0 {
+ t.Fatalf("expected empty parameters object, got %v", parameters)
+ }
+}
+
+func TestTool_JSONOmitsNilParameters(t *testing.T) {
+ tool := Tool{Name: "no_parameters"}
+
+ data, err := json.Marshal(tool)
+ if err != nil {
+ t.Fatalf("failed to marshal Tool: %v", err)
+ }
+
+ var decoded map[string]any
+ if err := json.Unmarshal(data, &decoded); err != nil {
+ t.Fatalf("failed to unmarshal Tool: %v", err)
+ }
+
+ if _, present := decoded["parameters"]; present {
+ t.Errorf("expected parameters to be omitted for nil map, got %v", decoded["parameters"])
+ }
+}
+
+func TestCanvasDeclaration_JSONIncludesEmptyInputSchema(t *testing.T) {
+ canvas := CanvasDeclaration{
+ ID: "empty-input",
+ DisplayName: "Empty input",
+ Description: "Accepts any input.",
+ InputSchema: map[string]any{},
+ }
+
+ data, err := json.Marshal(canvas)
+ if err != nil {
+ t.Fatalf("failed to marshal CanvasDeclaration: %v", err)
+ }
+
+ var decoded map[string]any
+ if err := json.Unmarshal(data, &decoded); err != nil {
+ t.Fatalf("failed to unmarshal CanvasDeclaration: %v", err)
+ }
+
+ rawInputSchema, present := decoded["inputSchema"]
+ if !present {
+ t.Fatal("expected inputSchema to be present for an empty non-nil map")
+ }
+ inputSchema, ok := rawInputSchema.(map[string]any)
+ if !ok {
+ t.Fatalf("expected inputSchema object, got %T", rawInputSchema)
+ }
+ if len(inputSchema) != 0 {
+ t.Fatalf("expected empty inputSchema object, got %v", inputSchema)
+ }
+}
+
+func TestCanvasDeclaration_JSONOmitsNilInputSchema(t *testing.T) {
+ canvas := CanvasDeclaration{
+ ID: "no-input-schema",
+ DisplayName: "No input schema",
+ Description: "Does not declare input.",
+ }
+
+ data, err := json.Marshal(canvas)
+ if err != nil {
+ t.Fatalf("failed to marshal CanvasDeclaration: %v", err)
+ }
+
+ var decoded map[string]any
+ if err := json.Unmarshal(data, &decoded); err != nil {
+ t.Fatalf("failed to unmarshal CanvasDeclaration: %v", err)
+ }
+
+ if _, present := decoded["inputSchema"]; present {
+ t.Errorf("expected inputSchema to be omitted for nil map, got %v", decoded["inputSchema"])
+ }
+}
+
+func TestElicitationResult_JSONIncludesEmptyContent(t *testing.T) {
+ result := ElicitationResult{
+ Action: ElicitationActionAccept,
+ Content: map[string]any{},
+ }
+
+ data, err := json.Marshal(result)
+ if err != nil {
+ t.Fatalf("failed to marshal ElicitationResult: %v", err)
+ }
+
+ var decoded map[string]any
+ if err := json.Unmarshal(data, &decoded); err != nil {
+ t.Fatalf("failed to unmarshal ElicitationResult: %v", err)
+ }
+
+ rawContent, present := decoded["content"]
+ if !present {
+ t.Fatal("expected content to be present for an empty non-nil map")
+ }
+ content, ok := rawContent.(map[string]any)
+ if !ok {
+ t.Fatalf("expected content object, got %T", rawContent)
+ }
+ if len(content) != 0 {
+ t.Fatalf("expected empty content object, got %v", content)
+ }
+}
+
+func TestElicitationResult_JSONOmitsNilContent(t *testing.T) {
+ result := ElicitationResult{Action: ElicitationActionCancel}
+
+ data, err := json.Marshal(result)
+ if err != nil {
+ t.Fatalf("failed to marshal ElicitationResult: %v", err)
+ }
+
+ var decoded map[string]any
+ if err := json.Unmarshal(data, &decoded); err != nil {
+ t.Fatalf("failed to unmarshal ElicitationResult: %v", err)
+ }
+
+ if _, present := decoded["content"]; present {
+ t.Errorf("expected content to be omitted for nil map, got %v", decoded["content"])
+ }
+}
diff --git a/go/zsession_events.go b/go/zsession_events.go
index cb7a10b22..70ce3e6d5 100644
--- a/go/zsession_events.go
+++ b/go/zsession_events.go
@@ -24,6 +24,17 @@ type (
AssistantUsageCopilotUsageTokenDetail = rpc.AssistantUsageCopilotUsageTokenDetail
AssistantUsageData = rpc.AssistantUsageData
Attachment = rpc.Attachment
+ AttachmentBlob = rpc.AttachmentBlob
+ AttachmentDirectory = rpc.AttachmentDirectory
+ AttachmentExtensionContext = rpc.AttachmentExtensionContext
+ AttachmentFile = rpc.AttachmentFile
+ AttachmentFileLineRange = rpc.AttachmentFileLineRange
+ AttachmentGitHubReference = rpc.AttachmentGitHubReference
+ AttachmentGitHubReferenceType = rpc.AttachmentGitHubReferenceType
+ AttachmentSelection = rpc.AttachmentSelection
+ AttachmentSelectionDetails = rpc.AttachmentSelectionDetails
+ AttachmentSelectionDetailsEnd = rpc.AttachmentSelectionDetailsEnd
+ AttachmentSelectionDetailsStart = rpc.AttachmentSelectionDetailsStart
AttachmentType = rpc.AttachmentType
AutoModeSwitchCompletedData = rpc.AutoModeSwitchCompletedData
AutoModeSwitchRequestedData = rpc.AutoModeSwitchRequestedData
@@ -42,6 +53,7 @@ type (
CommandsChangedData = rpc.CommandsChangedData
CompactionCompleteCompactionTokensUsed = rpc.CompactionCompleteCompactionTokensUsed
CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail = rpc.CompactionCompleteCompactionTokensUsedCopilotUsageTokenDetail
+ ContextTier = rpc.ContextTier
CustomAgentsUpdatedAgent = rpc.CustomAgentsUpdatedAgent
CustomNotificationPayload = rpc.CustomNotificationPayload
ElicitationCompletedAction = rpc.ElicitationCompletedAction
@@ -71,18 +83,18 @@ type (
HookEndError = rpc.HookEndError
HookProgressData = rpc.HookProgressData
HookStartData = rpc.HookStartData
- McpAppToolCallCompleteData = rpc.McpAppToolCallCompleteData
- McpAppToolCallCompleteError = rpc.McpAppToolCallCompleteError
- McpAppToolCallCompleteToolMeta = rpc.McpAppToolCallCompleteToolMeta
- McpAppToolCallCompleteToolMetaUI = rpc.McpAppToolCallCompleteToolMetaUI
- McpOauthCompletedData = rpc.McpOauthCompletedData
- McpOauthRequiredData = rpc.McpOauthRequiredData
- McpOauthRequiredStaticClientConfig = rpc.McpOauthRequiredStaticClientConfig
- McpOauthRequiredStaticClientConfigGrantType = rpc.McpOauthRequiredStaticClientConfigGrantType
- McpServersLoadedServer = rpc.McpServersLoadedServer
- McpServerSource = rpc.McpServerSource
- McpServerStatus = rpc.McpServerStatus
- McpServerTransport = rpc.McpServerTransport
+ MCPAppToolCallCompleteData = rpc.MCPAppToolCallCompleteData
+ MCPAppToolCallCompleteError = rpc.MCPAppToolCallCompleteError
+ MCPAppToolCallCompleteToolMeta = rpc.MCPAppToolCallCompleteToolMeta
+ MCPAppToolCallCompleteToolMetaUI = rpc.MCPAppToolCallCompleteToolMetaUI
+ MCPOauthCompletedData = rpc.MCPOauthCompletedData
+ MCPOauthRequiredData = rpc.MCPOauthRequiredData
+ MCPOauthRequiredStaticClientConfig = rpc.MCPOauthRequiredStaticClientConfig
+ MCPOauthRequiredStaticClientConfigGrantType = rpc.MCPOauthRequiredStaticClientConfigGrantType
+ MCPServersLoadedServer = rpc.MCPServersLoadedServer
+ MCPServerSource = rpc.MCPServerSource
+ MCPServerStatus = rpc.MCPServerStatus
+ MCPServerTransport = rpc.MCPServerTransport
ModelCallFailureData = rpc.ModelCallFailureData
ModelCallFailureSource = rpc.ModelCallFailureSource
PendingMessagesModifiedData = rpc.PendingMessagesModifiedData
@@ -103,7 +115,7 @@ type (
PermissionPromptRequestExtensionPermissionAccess = rpc.PermissionPromptRequestExtensionPermissionAccess
PermissionPromptRequestHook = rpc.PermissionPromptRequestHook
PermissionPromptRequestKind = rpc.PermissionPromptRequestKind
- PermissionPromptRequestMcp = rpc.PermissionPromptRequestMcp
+ PermissionPromptRequestMCP = rpc.PermissionPromptRequestMCP
PermissionPromptRequestMemory = rpc.PermissionPromptRequestMemory
PermissionPromptRequestPath = rpc.PermissionPromptRequestPath
PermissionPromptRequestPathAccessKind = rpc.PermissionPromptRequestPathAccessKind
@@ -118,7 +130,7 @@ type (
PermissionRequestExtensionPermissionAccess = rpc.PermissionRequestExtensionPermissionAccess
PermissionRequestHook = rpc.PermissionRequestHook
PermissionRequestKind = rpc.PermissionRequestKind
- PermissionRequestMcp = rpc.PermissionRequestMcp
+ PermissionRequestMCP = rpc.PermissionRequestMCP
PermissionRequestMemory = rpc.PermissionRequestMemory
PermissionRequestMemoryAction = rpc.PermissionRequestMemoryAction
PermissionRequestMemoryDirection = rpc.PermissionRequestMemoryDirection
@@ -139,7 +151,6 @@ type (
RawSessionEventData = rpc.RawSessionEventData
RawSystemNotification = rpc.RawSystemNotification
RawToolExecutionCompleteContent = rpc.RawToolExecutionCompleteContent
- RawUserMessageAttachment = rpc.RawUserMessageAttachment
ReasoningSummary = rpc.ReasoningSummary
SamplingCompletedData = rpc.SamplingCompletedData
SamplingRequestedData = rpc.SamplingRequestedData
@@ -156,28 +167,26 @@ type (
SessionEvent = rpc.SessionEvent
SessionEventData = rpc.SessionEventData
SessionEventType = rpc.SessionEventType
+ SessionExtensionsAttachmentsPushedData = rpc.SessionExtensionsAttachmentsPushedData
SessionExtensionsLoadedData = rpc.SessionExtensionsLoadedData
SessionHandoffData = rpc.SessionHandoffData
SessionIdleData = rpc.SessionIdleData
SessionInfoData = rpc.SessionInfoData
- SessionMcpServersLoadedData = rpc.SessionMcpServersLoadedData
- SessionMcpServerStatusChangedData = rpc.SessionMcpServerStatusChangedData
+ SessionMCPServersLoadedData = rpc.SessionMCPServersLoadedData
+ SessionMCPServerStatusChangedData = rpc.SessionMCPServerStatusChangedData
SessionMode = rpc.SessionMode
SessionModeChangedData = rpc.SessionModeChangedData
SessionModelChangeData = rpc.SessionModelChangeData
- SessionModelChangeDataContextTier = rpc.SessionModelChangeDataContextTier
SessionPermissionsChangedData = rpc.SessionPermissionsChangedData
SessionPlanChangedData = rpc.SessionPlanChangedData
SessionRemoteSteerableChangedData = rpc.SessionRemoteSteerableChangedData
SessionResumeData = rpc.SessionResumeData
- SessionResumeDataContextTier = rpc.SessionResumeDataContextTier
SessionScheduleCancelledData = rpc.SessionScheduleCancelledData
SessionScheduleCreatedData = rpc.SessionScheduleCreatedData
SessionShutdownData = rpc.SessionShutdownData
SessionSkillsLoadedData = rpc.SessionSkillsLoadedData
SessionSnapshotRewindData = rpc.SessionSnapshotRewindData
SessionStartData = rpc.SessionStartData
- SessionStartDataContextTier = rpc.SessionStartDataContextTier
SessionTaskCompleteData = rpc.SessionTaskCompleteData
SessionTitleChangedData = rpc.SessionTitleChangedData
SessionToolsUpdatedData = rpc.SessionToolsUpdatedData
@@ -248,25 +257,14 @@ type (
UserInputCompletedData = rpc.UserInputCompletedData
UserInputRequestedData = rpc.UserInputRequestedData
UserMessageAgentMode = rpc.UserMessageAgentMode
- UserMessageAttachment = rpc.UserMessageAttachment
- UserMessageAttachmentBlob = rpc.UserMessageAttachmentBlob
- UserMessageAttachmentDirectory = rpc.UserMessageAttachmentDirectory
- UserMessageAttachmentFile = rpc.UserMessageAttachmentFile
- UserMessageAttachmentFileLineRange = rpc.UserMessageAttachmentFileLineRange
- UserMessageAttachmentGithubReference = rpc.UserMessageAttachmentGithubReference
- UserMessageAttachmentGithubReferenceType = rpc.UserMessageAttachmentGithubReferenceType
- UserMessageAttachmentSelection = rpc.UserMessageAttachmentSelection
- UserMessageAttachmentSelectionDetails = rpc.UserMessageAttachmentSelectionDetails
- UserMessageAttachmentSelectionDetailsEnd = rpc.UserMessageAttachmentSelectionDetailsEnd
- UserMessageAttachmentSelectionDetailsStart = rpc.UserMessageAttachmentSelectionDetailsStart
- UserMessageAttachmentType = rpc.UserMessageAttachmentType
UserMessageData = rpc.UserMessageData
UserToolSessionApproval = rpc.UserToolSessionApproval
UserToolSessionApprovalCommands = rpc.UserToolSessionApprovalCommands
UserToolSessionApprovalCustomTool = rpc.UserToolSessionApprovalCustomTool
UserToolSessionApprovalExtensionManagement = rpc.UserToolSessionApprovalExtensionManagement
UserToolSessionApprovalExtensionPermissionAccess = rpc.UserToolSessionApprovalExtensionPermissionAccess
- UserToolSessionApprovalMcp = rpc.UserToolSessionApprovalMcp
+ UserToolSessionApprovalKind = rpc.UserToolSessionApprovalKind
+ UserToolSessionApprovalMCP = rpc.UserToolSessionApprovalMCP
UserToolSessionApprovalMemory = rpc.UserToolSessionApprovalMemory
UserToolSessionApprovalRead = rpc.UserToolSessionApprovalRead
UserToolSessionApprovalWrite = rpc.UserToolSessionApprovalWrite
@@ -286,10 +284,14 @@ const (
AssistantUsageAPIEndpointResponses = rpc.AssistantUsageAPIEndpointResponses
AssistantUsageAPIEndpointV1Messages = rpc.AssistantUsageAPIEndpointV1Messages
AssistantUsageAPIEndpointWsResponses = rpc.AssistantUsageAPIEndpointWsResponses
+ AttachmentGitHubReferenceTypeDiscussion = rpc.AttachmentGitHubReferenceTypeDiscussion
+ AttachmentGitHubReferenceTypeIssue = rpc.AttachmentGitHubReferenceTypeIssue
+ AttachmentGitHubReferenceTypePr = rpc.AttachmentGitHubReferenceTypePr
AttachmentTypeBlob = rpc.AttachmentTypeBlob
AttachmentTypeDirectory = rpc.AttachmentTypeDirectory
+ AttachmentTypeExtensionContext = rpc.AttachmentTypeExtensionContext
AttachmentTypeFile = rpc.AttachmentTypeFile
- AttachmentTypeGithubReference = rpc.AttachmentTypeGithubReference
+ AttachmentTypeGitHubReference = rpc.AttachmentTypeGitHubReference
AttachmentTypeSelection = rpc.AttachmentTypeSelection
AutoModeSwitchResponseNo = rpc.AutoModeSwitchResponseNo
AutoModeSwitchResponseYes = rpc.AutoModeSwitchResponseYes
@@ -303,6 +305,8 @@ const (
AutopilotObjectiveChangedStatusPaused = rpc.AutopilotObjectiveChangedStatusPaused
CanvasOpenedAvailabilityReady = rpc.CanvasOpenedAvailabilityReady
CanvasOpenedAvailabilityStale = rpc.CanvasOpenedAvailabilityStale
+ ContextTierDefault = rpc.ContextTierDefault
+ ContextTierLongContext = rpc.ContextTierLongContext
ElicitationCompletedActionAccept = rpc.ElicitationCompletedActionAccept
ElicitationCompletedActionCancel = rpc.ElicitationCompletedActionCancel
ElicitationCompletedActionDecline = rpc.ElicitationCompletedActionDecline
@@ -321,22 +325,22 @@ const (
ExtensionsLoadedExtensionStatusStarting = rpc.ExtensionsLoadedExtensionStatusStarting
HandoffSourceTypeLocal = rpc.HandoffSourceTypeLocal
HandoffSourceTypeRemote = rpc.HandoffSourceTypeRemote
- McpOauthRequiredStaticClientConfigGrantTypeClientCredentials = rpc.McpOauthRequiredStaticClientConfigGrantTypeClientCredentials
- McpServerSourceBuiltin = rpc.McpServerSourceBuiltin
- McpServerSourcePlugin = rpc.McpServerSourcePlugin
- McpServerSourceUser = rpc.McpServerSourceUser
- McpServerSourceWorkspace = rpc.McpServerSourceWorkspace
- McpServerStatusConnected = rpc.McpServerStatusConnected
- McpServerStatusDisabled = rpc.McpServerStatusDisabled
- McpServerStatusFailed = rpc.McpServerStatusFailed
- McpServerStatusNeedsAuth = rpc.McpServerStatusNeedsAuth
- McpServerStatusNotConfigured = rpc.McpServerStatusNotConfigured
- McpServerStatusPending = rpc.McpServerStatusPending
- McpServerTransportHTTP = rpc.McpServerTransportHTTP
- McpServerTransportMemory = rpc.McpServerTransportMemory
- McpServerTransportSse = rpc.McpServerTransportSse
- McpServerTransportStdio = rpc.McpServerTransportStdio
- ModelCallFailureSourceMcpSampling = rpc.ModelCallFailureSourceMcpSampling
+ MCPOauthRequiredStaticClientConfigGrantTypeClientCredentials = rpc.MCPOauthRequiredStaticClientConfigGrantTypeClientCredentials
+ MCPServerSourceBuiltin = rpc.MCPServerSourceBuiltin
+ MCPServerSourcePlugin = rpc.MCPServerSourcePlugin
+ MCPServerSourceUser = rpc.MCPServerSourceUser
+ MCPServerSourceWorkspace = rpc.MCPServerSourceWorkspace
+ MCPServerStatusConnected = rpc.MCPServerStatusConnected
+ MCPServerStatusDisabled = rpc.MCPServerStatusDisabled
+ MCPServerStatusFailed = rpc.MCPServerStatusFailed
+ MCPServerStatusNeedsAuth = rpc.MCPServerStatusNeedsAuth
+ MCPServerStatusNotConfigured = rpc.MCPServerStatusNotConfigured
+ MCPServerStatusPending = rpc.MCPServerStatusPending
+ MCPServerTransportHTTP = rpc.MCPServerTransportHTTP
+ MCPServerTransportMemory = rpc.MCPServerTransportMemory
+ MCPServerTransportSSE = rpc.MCPServerTransportSSE
+ MCPServerTransportStdio = rpc.MCPServerTransportStdio
+ ModelCallFailureSourceMCPSampling = rpc.ModelCallFailureSourceMCPSampling
ModelCallFailureSourceSubagent = rpc.ModelCallFailureSourceSubagent
ModelCallFailureSourceTopLevel = rpc.ModelCallFailureSourceTopLevel
PermissionPromptRequestKindCommands = rpc.PermissionPromptRequestKindCommands
@@ -344,7 +348,7 @@ const (
PermissionPromptRequestKindExtensionManagement = rpc.PermissionPromptRequestKindExtensionManagement
PermissionPromptRequestKindExtensionPermissionAccess = rpc.PermissionPromptRequestKindExtensionPermissionAccess
PermissionPromptRequestKindHook = rpc.PermissionPromptRequestKindHook
- PermissionPromptRequestKindMcp = rpc.PermissionPromptRequestKindMcp
+ PermissionPromptRequestKindMCP = rpc.PermissionPromptRequestKindMCP
PermissionPromptRequestKindMemory = rpc.PermissionPromptRequestKindMemory
PermissionPromptRequestKindPath = rpc.PermissionPromptRequestKindPath
PermissionPromptRequestKindRead = rpc.PermissionPromptRequestKindRead
@@ -357,7 +361,7 @@ const (
PermissionRequestKindExtensionManagement = rpc.PermissionRequestKindExtensionManagement
PermissionRequestKindExtensionPermissionAccess = rpc.PermissionRequestKindExtensionPermissionAccess
PermissionRequestKindHook = rpc.PermissionRequestKindHook
- PermissionRequestKindMcp = rpc.PermissionRequestKindMcp
+ PermissionRequestKindMCP = rpc.PermissionRequestKindMCP
PermissionRequestKindMemory = rpc.PermissionRequestKindMemory
PermissionRequestKindRead = rpc.PermissionRequestKindRead
PermissionRequestKindShell = rpc.PermissionRequestKindShell
@@ -409,9 +413,9 @@ const (
SessionEventTypeHookEnd = rpc.SessionEventTypeHookEnd
SessionEventTypeHookProgress = rpc.SessionEventTypeHookProgress
SessionEventTypeHookStart = rpc.SessionEventTypeHookStart
- SessionEventTypeMcpAppToolCallComplete = rpc.SessionEventTypeMcpAppToolCallComplete
- SessionEventTypeMcpOauthCompleted = rpc.SessionEventTypeMcpOauthCompleted
- SessionEventTypeMcpOauthRequired = rpc.SessionEventTypeMcpOauthRequired
+ SessionEventTypeMCPAppToolCallComplete = rpc.SessionEventTypeMCPAppToolCallComplete
+ SessionEventTypeMCPOauthCompleted = rpc.SessionEventTypeMCPOauthCompleted
+ SessionEventTypeMCPOauthRequired = rpc.SessionEventTypeMCPOauthRequired
SessionEventTypeModelCallFailure = rpc.SessionEventTypeModelCallFailure
SessionEventTypePendingMessagesModified = rpc.SessionEventTypePendingMessagesModified
SessionEventTypePermissionCompleted = rpc.SessionEventTypePermissionCompleted
@@ -428,12 +432,13 @@ const (
SessionEventTypeSessionCustomAgentsUpdated = rpc.SessionEventTypeSessionCustomAgentsUpdated
SessionEventTypeSessionCustomNotification = rpc.SessionEventTypeSessionCustomNotification
SessionEventTypeSessionError = rpc.SessionEventTypeSessionError
+ SessionEventTypeSessionExtensionsAttachmentsPushed = rpc.SessionEventTypeSessionExtensionsAttachmentsPushed
SessionEventTypeSessionExtensionsLoaded = rpc.SessionEventTypeSessionExtensionsLoaded
SessionEventTypeSessionHandoff = rpc.SessionEventTypeSessionHandoff
SessionEventTypeSessionIdle = rpc.SessionEventTypeSessionIdle
SessionEventTypeSessionInfo = rpc.SessionEventTypeSessionInfo
- SessionEventTypeSessionMcpServersLoaded = rpc.SessionEventTypeSessionMcpServersLoaded
- SessionEventTypeSessionMcpServerStatusChanged = rpc.SessionEventTypeSessionMcpServerStatusChanged
+ SessionEventTypeSessionMCPServersLoaded = rpc.SessionEventTypeSessionMCPServersLoaded
+ SessionEventTypeSessionMCPServerStatusChanged = rpc.SessionEventTypeSessionMCPServerStatusChanged
SessionEventTypeSessionModeChanged = rpc.SessionEventTypeSessionModeChanged
SessionEventTypeSessionModelChange = rpc.SessionEventTypeSessionModelChange
SessionEventTypeSessionPermissionsChanged = rpc.SessionEventTypeSessionPermissionsChanged
@@ -471,13 +476,7 @@ const (
SessionEventTypeUserMessage = rpc.SessionEventTypeUserMessage
SessionModeAutopilot = rpc.SessionModeAutopilot
SessionModeInteractive = rpc.SessionModeInteractive
- SessionModelChangeDataContextTierDefault = rpc.SessionModelChangeDataContextTierDefault
- SessionModelChangeDataContextTierLongContext = rpc.SessionModelChangeDataContextTierLongContext
SessionModePlan = rpc.SessionModePlan
- SessionResumeDataContextTierDefault = rpc.SessionResumeDataContextTierDefault
- SessionResumeDataContextTierLongContext = rpc.SessionResumeDataContextTierLongContext
- SessionStartDataContextTierDefault = rpc.SessionStartDataContextTierDefault
- SessionStartDataContextTierLongContext = rpc.SessionStartDataContextTierLongContext
ShutdownTypeError = rpc.ShutdownTypeError
ShutdownTypeRoutine = rpc.ShutdownTypeRoutine
SkillInvokedTriggerAgentInvoked = rpc.SkillInvokedTriggerAgentInvoked
@@ -514,16 +513,16 @@ const (
UserMessageAgentModeInteractive = rpc.UserMessageAgentModeInteractive
UserMessageAgentModePlan = rpc.UserMessageAgentModePlan
UserMessageAgentModeShell = rpc.UserMessageAgentModeShell
- UserMessageAttachmentGithubReferenceTypeDiscussion = rpc.UserMessageAttachmentGithubReferenceTypeDiscussion
- UserMessageAttachmentGithubReferenceTypeIssue = rpc.UserMessageAttachmentGithubReferenceTypeIssue
- UserMessageAttachmentGithubReferenceTypePr = rpc.UserMessageAttachmentGithubReferenceTypePr
- UserMessageAttachmentTypeBlob = rpc.UserMessageAttachmentTypeBlob
- UserMessageAttachmentTypeDirectory = rpc.UserMessageAttachmentTypeDirectory
- UserMessageAttachmentTypeFile = rpc.UserMessageAttachmentTypeFile
- UserMessageAttachmentTypeGithubReference = rpc.UserMessageAttachmentTypeGithubReference
- UserMessageAttachmentTypeSelection = rpc.UserMessageAttachmentTypeSelection
- WorkingDirectoryContextHostTypeAdo = rpc.WorkingDirectoryContextHostTypeAdo
- WorkingDirectoryContextHostTypeGithub = rpc.WorkingDirectoryContextHostTypeGithub
+ UserToolSessionApprovalKindCommands = rpc.UserToolSessionApprovalKindCommands
+ UserToolSessionApprovalKindCustomTool = rpc.UserToolSessionApprovalKindCustomTool
+ UserToolSessionApprovalKindExtensionManagement = rpc.UserToolSessionApprovalKindExtensionManagement
+ UserToolSessionApprovalKindExtensionPermissionAccess = rpc.UserToolSessionApprovalKindExtensionPermissionAccess
+ UserToolSessionApprovalKindMCP = rpc.UserToolSessionApprovalKindMCP
+ UserToolSessionApprovalKindMemory = rpc.UserToolSessionApprovalKindMemory
+ UserToolSessionApprovalKindRead = rpc.UserToolSessionApprovalKindRead
+ UserToolSessionApprovalKindWrite = rpc.UserToolSessionApprovalKindWrite
+ WorkingDirectoryContextHostTypeADO = rpc.WorkingDirectoryContextHostTypeADO
+ WorkingDirectoryContextHostTypeGitHub = rpc.WorkingDirectoryContextHostTypeGitHub
WorkspaceFileChangedOperationCreate = rpc.WorkspaceFileChangedOperationCreate
WorkspaceFileChangedOperationUpdate = rpc.WorkspaceFileChangedOperationUpdate
)
diff --git a/java/.lastmerge b/java/.lastmerge
index 97be84d7e..2a3e1090c 100644
--- a/java/.lastmerge
+++ b/java/.lastmerge
@@ -1 +1 @@
-60104052cd914949ddf8c7a31e1856cd6db0a57c
+753d4729738c0e1da3fbe767712c829bad0332cd
diff --git a/java/README.md b/java/README.md
index 47c0eaea3..87f3c6984 100644
--- a/java/README.md
+++ b/java/README.md
@@ -13,9 +13,7 @@
## Background
-> ℹ️ **Public Preview:** This SDK tracks the [GitHub Copilot SDKs](https://github.com/github/copilot-sdk) for [.NET](https://github.com/github/copilot-sdk/tree/main/dotnet) and [Node.js](https://github.com/github/copilot-sdk/tree/main/nodejs). While in public preview, minor breaking changes may still occur between releases.
-
-Java SDK for programmatic control of GitHub Copilot CLI, enabling you to build AI-powered applications and agentic workflows.
+Java SDK for programmatic control of GitHub Copilot CLI, enabling you to build AI-powered applications and agentic workflows. The Java SDK tracks the official GitHub Copilot SDK family (TypeScript, Python, Go, .NET, and Rust).
## Installation
@@ -26,18 +24,20 @@ Java SDK for programmatic control of GitHub Copilot CLI, enabling you to build A
### Maven
+Replace `${copilot.sdk.version}` with the latest release from Maven Central.
+
```xml
com.github
copilot-sdk-java
- 1.0.0-beta-10-java.4
+ 1.0.0
```
### Gradle
```groovy
-implementation 'com.github:copilot-sdk-java:1.0.0-beta-10-java.4'
+implementation 'com.github:copilot-sdk-java:1.0.0'
```
#### Snapshot Builds
@@ -56,14 +56,16 @@ Snapshot builds of the next development version are published to Maven Central S
com.github
copilot-sdk-java
- 1.0.0-beta-10-java.5-SNAPSHOT
+ 1.0.1-SNAPSHOT
```
### Gradle
+Replace `${copilot.sdk.version}` with the latest release from Maven Central.
+
```groovy
-implementation 'com.github:copilot-sdk-java:1.0.0-beta-10-java.4-SNAPSHOT'
+implementation 'com.github:copilot-sdk-java:1.0.0-SNAPSHOT'
```
## Quick Start
@@ -136,30 +138,9 @@ jbang https://github.com/github/copilot-sdk/blob/main/java/jbang-example.java
> Want to add your project? Open a PR!
-## CI/CD Workflows
-
-This project uses several GitHub Actions workflows for building, testing, releasing, and syncing with the reference implementation SDK.
-
-See [WORKFLOWS.md](docs/WORKFLOWS.md) for a full overview and details on each workflow.
-
-## Contributing
-
-Contributions are welcome! Please see the [Contributing Guide](CONTRIBUTING.md) for details.
-
-### Agentic Reference Implementation Merge and Sync
-
-This SDK tracks the official [Copilot SDK](https://github.com/github/copilot-sdk) (.NET reference implementation) and ports changes to Java. The reference implementation merge process is automated with AI assistance:
-
-**Automated sync** — A [scheduled GitHub Actions workflow](.github/workflows/reference-impl-sync.yml) runs on the schedule specified in that file. It checks for new reference implementation commits since the last merge (tracked in [`.lastmerge`](.lastmerge)), and if changes are found, creates an issue labeled `reference-impl-sync` and assigns it to the GitHub Copilot coding agent. Any previously open `reference-impl-sync` issues are automatically closed. The sync also updates the `@github/copilot` version in both `pom.xml` and `scripts/codegen/package.json` to keep schemas and test CLI in lockstep.
-
-**Reusable prompt** — The merge workflow is defined in [`agentic-merge-reference-impl.prompt.md`](.github/prompts/agentic-merge-reference-impl.prompt.md). It can be triggered manually from:
-
-- **VS Code Copilot Chat** — type `/agentic-merge-reference-impl`
-- **GitHub Copilot CLI** — use `copilot` CLI with the same skill reference
-
### Development Setup
-Requires JDK 25 or later for development.
+Requires JDK 25 or later for development. The following steps validate the artifact built with JDK 25 runs on both 25 and 17, preserving the MR-JAR behavior.
```bash
# Clone the repository
@@ -170,27 +151,14 @@ cd copilot-sdk/java
git config core.hooksPath .githooks
# Build and test with JDK 25
-mvn clean verify
+mvn test-compile jar:jar
+mvn verify -Dskip.test.harness=true
# Set your paths for JDK 17
# Run the JDK 25 built jar with JDK 17 JVM for tests. Do not re-compile the jar.
mvn jacoco:prepare-agent@wire-up-coverage-instrumentation antrun:run@print-test-jdk-banner surefire:test failsafe:integration-test failsafe:verify jacoco:report@build-coverage-report-from-tests -Denforcer.skip=true
```
-The tests require the official [copilot-sdk](https://github.com/github/copilot-sdk) test harness, which is automatically cloned during build.
-
-## Support
-
-See [SUPPORT.md](SUPPORT.md) for how to file issues and get help.
-
-## Code of Conduct
-
-This project has adopted the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md). See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) for details.
-
-## Security
-
-See [SECURITY.md](SECURITY.md) for reporting security vulnerabilities.
-
## License
MIT — see [LICENSE](LICENSE) for details.
diff --git a/java/docs/adr/adr-001-semver-pre-general-availability.md b/java/docs/adr/adr-001-semver-pre-general-availability.md
index 25008b0f5..b081e1fe3 100644
--- a/java/docs/adr/adr-001-semver-pre-general-availability.md
+++ b/java/docs/adr/adr-001-semver-pre-general-availability.md
@@ -1,3 +1,5 @@
+Status: This ADR's pre-general-availability SemVer policy is superseded by the generally available release; see CHANGELOG and the README for the current SemVer policy.
+
# SemVer requirements pre general-availability of Reference Implementation
## Context and Problem Statement
diff --git a/java/docs/adr/adr-003-sub-module-for-generated-code.md b/java/docs/adr/adr-003-sub-module-for-generated-code.md
new file mode 100644
index 000000000..a43a7cee4
--- /dev/null
+++ b/java/docs/adr/adr-003-sub-module-for-generated-code.md
@@ -0,0 +1,35 @@
+# Sub-module for generated code
+
+## Context and Problem Statement
+
+Regarding the goal of more effectively passing on the stability and deprecation metadata from the `@github/copilot` Zod schema to end consumers of `copilot-sdk-java`, Partner Software Engineer Stephen Toub stated, "The ideal is to do the best each language has to offer."
+
+## Considered Options
+
+* Status quo: keep generated code in the same `copilot-sdk-java` module.
+
+* Option 1: Move all generated code (both `com.github.copilot.generated` and `com.github.copilot.generated.rpc`) to a single internal Maven module (`copilot-sdk-generated`), bundled back into the published `copilot-sdk-java` artifact via `maven-dependency-plugin`.
+
+* Option 2: Move generated code into two internal Maven modules (`copilot-sdk-events` for session-event types, `copilot-sdk-rpc-generated` for RPC types), bundled back into the published artifact.
+
+### Analysis
+
+The generated code is deeply embedded in the public API surface of `copilot-sdk-java`: `CopilotSession.getRpc()` returns `SessionRpc`, `CopilotClient.getRpc()` returns `ServerRpc`, `sendAndWait()` returns `AssistantMessageEvent`, and the event handler API accepts all generated event subclasses. Approximately 730 of 914 generated classes are part of the externally-visible API. Any module split is therefore a build-time concern only — it cannot reduce the consumer-facing footprint.
+
+The dependency direction is clean (hand-written → generated, never reverse), making a split technically feasible without circular dependencies.
+
+However, the specific goal of conveying stability/deprecation metadata requires a `@CopilotExperimental` annotation visible at compile time to both the generated and hand-written code. In the status quo, this annotation lives in `src/main/java/` and is freely importable by `src/generated/java/` since they compile together. In a split-module reactor, the generated module compiles *before* the hand-written module, so the annotation must either be emitted by the codegen script as another generated file, or extracted into a third annotations-only module. Both add complexity without advancing the stability-metadata goal.
+
+Module separation is orthogonal to — and slightly complicates — the stability/deprecation work. The codegen script changes to read and propagate `stability`/`deprecated` from schema nodes are identical regardless of module structure.
+
+## Decision Outcome
+
+Keep the status quo: keep the generated code in the same `copilot-sdk-java` module.
+
+The primary benefit of module separation (compile-time isolation, cleaner PR diffs) does not justify the added reactor complexity, `maven-dependency-plugin` configuration, and annotation-placement constraints — particularly given that the immediate priority is implementing stability/deprecation metadata propagation, which is simpler in a single-module build.
+
+## Related work items
+
+- https://devdiv.visualstudio.com/DevDiv/_workitems/edit/3013416
+
+- https://github.com/github/copilot-sdk/issues/1573
diff --git a/java/jbang-example.java b/java/jbang-example.java
index 888b5d15f..856eb727c 100644
--- a/java/jbang-example.java
+++ b/java/jbang-example.java
@@ -1,5 +1,5 @@
///usr/bin/env jbang "$0" "$@" ; exit $?
-//DEPS com.github:copilot-sdk-java:1.0.0-beta-10-java.4
+//DEPS com.github:copilot-sdk-java:1.0.0
import com.github.copilot.CopilotClient;
import com.github.copilot.generated.AssistantMessageEvent;
import com.github.copilot.generated.SessionUsageInfoEvent;
diff --git a/java/pom.xml b/java/pom.xml
index 12fef2572..c296d77d8 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -7,11 +7,11 @@
com.github
copilot-sdk-java
- 1.0.0-beta-10-java.4
+ 1.0.1-SNAPSHOT
jar
GitHub Copilot SDK :: Java
- SDK for programmatic control of GitHub Copilot CLI
+ Official SDK for programmatic control of GitHub Copilot CLI
https://github.com/github/copilot-sdk
@@ -23,8 +23,8 @@
- GitHub Copilot SDK
- GitHub Copilot SDK
+ GitHub Copilot SDK Team
+ GitHub
https://github.com/github
@@ -33,7 +33,7 @@
scm:git:https://github.com/github/copilot-sdk.git
scm:git:https://github.com/github/copilot-sdk.git
https://github.com/github/copilot-sdk
- java/v1.0.0-beta-10-java.4
+ HEAD
@@ -94,7 +94,7 @@
reference-impl-sync workflow and deal with the subsequent
PR.
-->
- ^1.0.55-5
+ ^1.0.57
@@ -103,17 +103,17 @@
com.fasterxml.jackson.core
jackson-databind
- 2.21.3
+ 2.22.0
com.fasterxml.jackson.core
jackson-annotations
- 2.21
+ 2.22
com.fasterxml.jackson.datatype
jackson-datatype-jsr310
- 2.21.3
+ 2.22.0
@@ -163,6 +163,40 @@
+
+ org.apache.maven.plugins
+ maven-clean-plugin
+ 3.5.0
+
+
+
+ default-clean
+
+ true
+ false
+
+
+
+ post-clean-sweep
+ post-clean
+
+ clean
+
+
+ true
+
+
+
+
org.apache.maven.plugins
maven-compiler-plugin
@@ -329,7 +363,7 @@
org.apache.maven.plugins
maven-failsafe-plugin
- 3.5.5
+ 3.5.6
@@ -344,12 +378,20 @@
${project.build.finalName}
${project.build.testOutputDirectory}
+
+
+ ${copilot.cli.path}
+
org.apache.maven.plugins
maven-surefire-plugin
- 3.5.5
+ 3.5.6
alphabetical
@@ -535,7 +577,7 @@
org.apache.maven.plugins
maven-enforcer-plugin
- 3.5.0
+ 3.6.3
enforce-jdk25
@@ -573,8 +615,6 @@
-
-